diff options
author | Mike Waychison <mikew@google.com> | 2011-08-02 15:46:50 -0700 |
---|---|---|
committer | maximilian attems <max@stro.at> | 2011-08-03 10:14:21 +0200 |
commit | 6a36efee1559964d0aaa7e8073c0472e956b202b (patch) | |
tree | 1b4d3763b61a2c4a451c89565450a2d580475080 | |
parent | 0083b0b87387e9aa7363f1b3403b465855d4d1cd (diff) | |
download | klibc-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.h | 5 | ||||
-rw-r--r-- | usr/klibc/Kbuild | 2 | ||||
-rw-r--r-- | usr/klibc/scandir.c | 71 |
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; +} |