aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Waychison <mikew@google.com>2011-08-02 15:46:50 -0700
committermaximilian attems <max@stro.at>2011-08-03 10:14:21 +0200
commit6a36efee1559964d0aaa7e8073c0472e956b202b (patch)
tree1b4d3763b61a2c4a451c89565450a2d580475080
parent0083b0b87387e9aa7363f1b3403b465855d4d1cd (diff)
downloadklibc-6a36efee1559964d0aaa7e8073c0472e956b202b.tar.gz
[klibc] Add scandir() support.
Add support for scandir() as defined in POSIX.1-2008. Signed-off-by: Mike Waychison <mikew@google.com> Reviewed-by: H. Peter Anvin <hpa@zytor.com> Signed-off-by: maximilian attems <max@stro.at>
-rw-r--r--usr/include/dirent.h5
-rw-r--r--usr/klibc/Kbuild2
-rw-r--r--usr/klibc/scandir.c71
3 files changed, 77 insertions, 1 deletions
diff --git a/usr/include/dirent.h b/usr/include/dirent.h
index e32447489d8e1..0bcf40bbf1177 100644
--- a/usr/include/dirent.h
+++ b/usr/include/dirent.h
@@ -30,4 +30,9 @@ static __inline__ int dirfd(DIR * __d)
return __d->__fd;
}
+__extern int scandir(const char *, struct dirent ***,
+ int (*)(const struct dirent *),
+ int (*)(const struct dirent **,
+ const struct dirent **));
+
#endif /* _DIRENT_H */
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index af4036708ba51..40e61da5da1cb 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -42,7 +42,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \
seteuid.o setegid.o \
getenv.o setenv.o putenv.o __put_env.o unsetenv.o \
clearenv.o nullenv.o \
- getopt.o getopt_long.o readdir.o remove.o \
+ getopt.o getopt_long.o readdir.o scandir.o remove.o \
syslog.o closelog.o pty.o getpt.o posix_openpt.o isatty.o reboot.o \
time.o utime.o llseek.o nice.o getpriority.o \
qsort.o bsearch.o \
diff --git a/usr/klibc/scandir.c b/usr/klibc/scandir.c
new file mode 100644
index 0000000000000..9b9598039d6da
--- /dev/null
+++ b/usr/klibc/scandir.c
@@ -0,0 +1,71 @@
+/*
+ * scandir.c: scandir
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <dirent.h>
+
+int scandir(const char *dirp, struct dirent ***namelist,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **, const struct dirent **))
+{
+ struct dirent **nl = NULL, **next_nl;
+ struct dirent *dirent;
+ size_t count = 0;
+ size_t allocated = 0;
+ DIR *dir;
+
+ dir = opendir(dirp);
+ if (!dir)
+ return -1;
+
+ while (1) {
+ dirent = readdir(dir);
+ if (!dirent)
+ break;
+ if (!filter || filter(dirent)) {
+ struct dirent *copy;
+ copy = malloc(sizeof(*copy));
+ if (!copy)
+ goto cleanup_fail;
+ memcpy(copy, dirent, sizeof(*copy));
+
+ /* Extend the array if needed */
+ if (count == allocated) {
+ if (allocated == 0)
+ allocated = 15; /* ~1 page worth */
+ else
+ allocated *= 2;
+ next_nl = realloc(nl, allocated);
+ if (!next_nl) {
+ free(copy);
+ goto cleanup_fail;
+ }
+ nl = next_nl;
+ }
+
+ nl[count++] = copy;
+ }
+ }
+
+ qsort(nl, count, sizeof(struct dirent *),
+ (int (*)(const void *, const void *))compar);
+
+ closedir(dir);
+
+ *namelist = nl;
+ return count;
+
+cleanup_fail:
+ while (count) {
+ dirent = nl[--count];
+ free(dirent);
+ }
+ free(nl);
+ closedir(dir);
+ errno = ENOMEM;
+ return -1;
+}