commit: af8611e773e9c2ec7c475787f262a33ceec3e98e
Author: Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Tue Apr 3 17:20:01 2018 +0000
Commit: Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Tue Apr 3 19:57:51 2018 +0000
URL: https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=af8611e7
scandirat: deal properly with flexible struct member
libq/scandirat.c | 31 +++++++++++++++++++------------
1 file changed, 19 insertions(+), 12 deletions(-)
diff --git a/libq/scandirat.c b/libq/scandirat.c
index f0b3201..ac45223 100644
--- a/libq/scandirat.c
+++ b/libq/scandirat.c
@@ -14,20 +14,17 @@
#if !defined(HAVE_SCANDIRAT)
-#if defined(_DIRENT_HAVE_D_RECLEN)
-# define reclen(de) ((de)->d_reclen)
-#else
-# define reclen(de) (sizeof(*(de)) + strlen((de)->d_name))
-#endif
-
static int
scandirat(int dir_fd, const char *dir, struct dirent ***dirlist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **))
{
- int fd, cnt;
+ int fd;
DIR *dirp;
struct dirent *de, **ret;
+ size_t retlen = 0;
+ size_t retsize = 0;
+#define INCRSZ 64
/* Cannot use O_PATH as we want to use fdopendir() */
fd = openat(dir_fd, dir, O_RDONLY|O_CLOEXEC);
@@ -40,22 +37,32 @@ scandirat(int dir_fd, const char *dir, struct dirent
***dirlist,
}
ret = NULL;
- cnt = 0;
while ((de = readdir(dirp))) {
+ size_t sdesz;
+ size_t sdenamelen;
+
if (filter(de) == 0)
continue;
- ret = realloc(ret, sizeof(*ret) * (cnt + 1));
- ret[cnt++] = xmemdup(de, reclen(de));
+ if (retlen == retsize) {
+ retsize += INCRSZ;
+ ret = xrealloc(ret, sizeof(*ret) * retsize);
+ }
+ sdesz = (void *)de->d_name - (void *)de;
+ sdenamelen = strlen(de->d_name) + 1;
+ ret[retlen] = xmalloc(sdesz + sdenamelen);
+ memcpy(ret[retlen], de, sdesz);
+ strncpy(ret[retlen]->d_name, de->d_name, sdenamelen);
+ retlen++;
}
*dirlist = ret;
- qsort(ret, cnt, sizeof(*ret), (void *)compar);
+ qsort(ret, retlen, sizeof(*ret), (void *)compar);
/* closes underlying fd */
closedir(dirp);
- return cnt;
+ return (int)retlen;
}
#endif