summaryrefslogtreecommitdiff
path: root/userland/libc
diff options
context:
space:
mode:
Diffstat (limited to 'userland/libc')
-rw-r--r--userland/libc/dirent/scandir.c60
-rw-r--r--userland/libc/include/stdlib.h2
2 files changed, 62 insertions, 0 deletions
diff --git a/userland/libc/dirent/scandir.c b/userland/libc/dirent/scandir.c
index 564cbc8..3ac040a 100644
--- a/userland/libc/dirent/scandir.c
+++ b/userland/libc/dirent/scandir.c
@@ -1,12 +1,72 @@
#include <dirent.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
int nop_compar(const struct dirent **d1, const struct dirent **d2) {
*d2 = *d1;
return 0;
}
+// Differs from scandir in the sense that the namelist has its own way
+// of allocating its entries(in this case it allocates it as a large
+// chunk). As a result the usual free() operation can not be ran on
+// the elements.
+//
+// Instead scandir_sane_free() should be used to deallocate the
+// namelist.
+int scandir_sane(const char *dir, struct dirent ***namelist,
+ int (*sel)(const struct dirent *),
+ int (*compar)(const struct dirent **,
+ const struct dirent **)) {
+ if (!compar) {
+ compar = nop_compar;
+ }
+
+ int fd = open(dir, O_RDONLY);
+ if (-1 == fd) {
+ // TODO: Figure out what to set errno to
+ return -1;
+ }
+
+ size_t capacity = 128;
+ size_t num_entries;
+ struct dirent *chunk = NULL;
+ for (;;) {
+ chunk = realloc(chunk, sizeof(struct dirent) * capacity);
+ int rc = pread(fd, chunk, sizeof(struct dirent) * capacity, 0);
+ if (-1 == rc) {
+ free(chunk);
+ // TODO: Figure out what to set errno to
+ return -1;
+ }
+ if (sizeof(struct dirent) * capacity == (size_t)rc) {
+ // The directory **may** contain more entries.
+ // Redo
+ capacity *= 2;
+ continue;
+ }
+ num_entries = rc / (sizeof(struct dirent));
+ break;
+ }
+
+ *namelist = allocarray(num_entries, sizeof(struct dirent *));
+
+ for (size_t i = 0; i < num_entries; i++) {
+ (*namelist)[i] = &chunk[i];
+ }
+
+ close(fd);
+ return num_entries;
+}
+
+void scandir_sane_free(struct dirent **namelist) {
+ free(namelist[0]); // First pointer is the start of the chunk in the
+ // current implementation
+ free(namelist);
+}
+
int scandir(const char *dir, struct dirent ***namelist,
int (*sel)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **)) {
diff --git a/userland/libc/include/stdlib.h b/userland/libc/include/stdlib.h
index 7e23035..a389e8c 100644
--- a/userland/libc/include/stdlib.h
+++ b/userland/libc/include/stdlib.h
@@ -10,6 +10,8 @@ typedef size_t size_t; // only for 32 bit
void *malloc(size_t s);
void *calloc(size_t nelem, size_t elsize);
+void *allocarray(size_t nmemb, size_t size);
+void *reallocarray(void *ptr, size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *p);
char *getenv(const char *name);