aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Groffen <grobian@gentoo.org>2018-04-03 19:20:01 +0200
committerFabian Groffen <grobian@gentoo.org>2018-04-03 21:57:51 +0200
commitaf8611e773e9c2ec7c475787f262a33ceec3e98e (patch)
treed55ada4f59b6e6b6ac1b66f3e3e0185703b94900
parentqxpak: improve documentation (diff)
downloadportage-utils-af8611e773e9c2ec7c475787f262a33ceec3e98e.tar.gz
portage-utils-af8611e773e9c2ec7c475787f262a33ceec3e98e.tar.bz2
portage-utils-af8611e773e9c2ec7c475787f262a33ceec3e98e.zip
scandirat: deal properly with flexible struct member
-rw-r--r--libq/scandirat.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/libq/scandirat.c b/libq/scandirat.c
index f0b3201c..ac452239 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