summaryrefslogtreecommitdiff
path: root/src/dirent
diff options
context:
space:
mode:
Diffstat (limited to 'src/dirent')
-rw-r--r--src/dirent/__dirent.h9
-rw-r--r--src/dirent/__getdents.c12
-rw-r--r--src/dirent/alphasort.c10
-rw-r--r--src/dirent/closedir.c11
-rw-r--r--src/dirent/dirfd.c7
-rw-r--r--src/dirent/fdopendir.c26
-rw-r--r--src/dirent/opendir.c25
-rw-r--r--src/dirent/readdir.c32
-rw-r--r--src/dirent/readdir_r.c30
-rw-r--r--src/dirent/rewinddir.c13
-rw-r--r--src/dirent/scandir.c50
-rw-r--r--src/dirent/seekdir.c12
-rw-r--r--src/dirent/telldir.c7
13 files changed, 244 insertions, 0 deletions
diff --git a/src/dirent/__dirent.h b/src/dirent/__dirent.h
new file mode 100644
index 00000000..07b3ee68
--- /dev/null
+++ b/src/dirent/__dirent.h
@@ -0,0 +1,9 @@
+struct __DIR_s
+{
+ int lock;
+ int fd;
+ off_t tell;
+ int buf_pos;
+ int buf_end;
+ char buf[2048];
+};
diff --git a/src/dirent/__getdents.c b/src/dirent/__getdents.c
new file mode 100644
index 00000000..4195430b
--- /dev/null
+++ b/src/dirent/__getdents.c
@@ -0,0 +1,12 @@
+#include <dirent.h>
+#include "syscall.h"
+#include "libc.h"
+
+int __getdents(int fd, struct dirent *buf, size_t len)
+{
+ return syscall3(__NR_getdents64, fd, (long)buf, len);
+}
+
+weak_alias(__getdents, getdents);
+
+LFS64(getdents);
diff --git a/src/dirent/alphasort.c b/src/dirent/alphasort.c
new file mode 100644
index 00000000..42050fb7
--- /dev/null
+++ b/src/dirent/alphasort.c
@@ -0,0 +1,10 @@
+#include <string.h>
+#include <dirent.h>
+#include "libc.h"
+
+int alphasort(const struct dirent **a, const struct dirent **b)
+{
+ return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+LFS64(alphasort);
diff --git a/src/dirent/closedir.c b/src/dirent/closedir.c
new file mode 100644
index 00000000..81e9591c
--- /dev/null
+++ b/src/dirent/closedir.c
@@ -0,0 +1,11 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+int closedir(DIR *dir)
+{
+ int ret = close(dir->fd);
+ free(dir);
+ return ret;
+}
diff --git a/src/dirent/dirfd.c b/src/dirent/dirfd.c
new file mode 100644
index 00000000..6c860073
--- /dev/null
+++ b/src/dirent/dirfd.c
@@ -0,0 +1,7 @@
+#include <dirent.h>
+#include "__dirent.h"
+
+int dirfd(DIR *d)
+{
+ return d->fd;
+}
diff --git a/src/dirent/fdopendir.c b/src/dirent/fdopendir.c
new file mode 100644
index 00000000..c4b8e61d
--- /dev/null
+++ b/src/dirent/fdopendir.c
@@ -0,0 +1,26 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include "__dirent.h"
+
+DIR *fdopendir(int fd)
+{
+ DIR *dir;
+ struct stat st;
+
+ if (fstat(fd, &st) < 0 || !S_ISDIR(st.st_mode)) {
+ errno = ENOTDIR;
+ return 0;
+ }
+ if (!(dir = calloc(1, sizeof *dir))) {
+ return 0;
+ }
+
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ dir->fd = fd;
+ return dir;
+}
diff --git a/src/dirent/opendir.c b/src/dirent/opendir.c
new file mode 100644
index 00000000..cefe6ce7
--- /dev/null
+++ b/src/dirent/opendir.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include "__dirent.h"
+
+DIR *opendir(const char *name)
+{
+ int fd;
+ DIR *dir;
+
+ if ((fd = open(name, O_RDONLY|O_DIRECTORY)) < 0)
+ return 0;
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ if (!(dir = calloc(1, sizeof *dir))) {
+ close(fd);
+ return 0;
+ }
+ dir->fd = fd;
+ return dir;
+}
diff --git a/src/dirent/readdir.c b/src/dirent/readdir.c
new file mode 100644
index 00000000..1aeb25a5
--- /dev/null
+++ b/src/dirent/readdir.c
@@ -0,0 +1,32 @@
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "__dirent.h"
+#include "syscall.h"
+#include "libc.h"
+
+int __getdents(int, struct dirent *, size_t);
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *de;
+
+ if (dir->buf_pos >= dir->buf_end) {
+ int len = __getdents(dir->fd, (void *)dir->buf, sizeof dir->buf);
+ if (len < 0) {
+ dir->lock = 0;
+ return NULL;
+ } else if (len == 0) return 0;
+ dir->buf_end = len;
+ dir->buf_pos = 0;
+ }
+ de = (void *)(dir->buf + dir->buf_pos);
+ dir->buf_pos += de->d_reclen;
+ dir->tell = de->d_off;
+ return de;
+}
+
+LFS64(readdir);
diff --git a/src/dirent/readdir_r.c b/src/dirent/readdir_r.c
new file mode 100644
index 00000000..58f60325
--- /dev/null
+++ b/src/dirent/readdir_r.c
@@ -0,0 +1,30 @@
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "__dirent.h"
+#include "libc.h"
+
+int readdir_r(DIR *dir, struct dirent *buf, struct dirent **result)
+{
+ struct dirent *de;
+ int errno_save = errno;
+ int ret;
+
+ LOCK(&dir->lock);
+ errno = 0;
+ de = readdir(dir);
+ if ((ret = errno)) {
+ UNLOCK(&dir->lock);
+ return ret;
+ }
+ errno = errno_save;
+ if (de) memcpy(buf, de, de->d_reclen);
+ else buf = NULL;
+
+ UNLOCK(&dir->lock);
+ *result = buf;
+ return 0;
+}
+
+LFS64_2(readdir_r, readdir64_r);
diff --git a/src/dirent/rewinddir.c b/src/dirent/rewinddir.c
new file mode 100644
index 00000000..c6138f7c
--- /dev/null
+++ b/src/dirent/rewinddir.c
@@ -0,0 +1,13 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+void rewinddir(DIR *dir)
+{
+ LOCK(&dir->lock);
+ lseek(dir->fd, 0, SEEK_SET);
+ dir->buf_pos = dir->buf_end = 0;
+ dir->tell = 0;
+ UNLOCK(&dir->lock);
+}
diff --git a/src/dirent/scandir.c b/src/dirent/scandir.c
new file mode 100644
index 00000000..6a0a9993
--- /dev/null
+++ b/src/dirent/scandir.c
@@ -0,0 +1,50 @@
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stddef.h>
+#include <libc.h>
+
+int scandir(const char *path, struct dirent ***res,
+ int (*sel)(const struct dirent *),
+ int (*cmp)(const struct dirent **, const struct dirent **))
+{
+ DIR *d = opendir(path);
+ struct dirent *de, **names=0, **tmp;
+ size_t cnt=0, len=0, size;
+ int old_errno = errno;
+
+ if (!d) return -1;
+
+ while ((errno=0), (de = readdir(d))) {
+ if (sel && !sel(de)) continue;
+ if (cnt >= len) {
+ len = 2*len+1;
+ if (len > SIZE_MAX/sizeof *names) break;
+ tmp = realloc(names, len * sizeof *names);
+ if (!tmp) break;
+ names = tmp;
+ }
+ size = offsetof(struct dirent,d_name) + strlen(de->d_name) + 1;
+ names[cnt] = malloc(size);
+ if (!names[cnt]) break;
+ memcpy(names[cnt++], de, size);
+ }
+
+ closedir(d);
+
+ if (errno) {
+ old_errno = errno;
+ if (names) while (cnt-->0) free(names[cnt]);
+ free(names);
+ errno = old_errno;
+ return -1;
+ }
+
+ if (cmp) qsort(names, cnt, sizeof *names, (int (*)(const void *, const void *))cmp);
+ *res = names;
+ return cnt;
+}
+
+LFS64(scandir);
diff --git a/src/dirent/seekdir.c b/src/dirent/seekdir.c
new file mode 100644
index 00000000..81a0e331
--- /dev/null
+++ b/src/dirent/seekdir.c
@@ -0,0 +1,12 @@
+#include <dirent.h>
+#include <unistd.h>
+#include "__dirent.h"
+#include "libc.h"
+
+void seekdir(DIR *dir, long off)
+{
+ LOCK(&dir->lock);
+ dir->tell = lseek(dir->fd, off, SEEK_SET);
+ dir->buf_pos = dir->buf_end = 0;
+ UNLOCK(&dir->lock);
+}
diff --git a/src/dirent/telldir.c b/src/dirent/telldir.c
new file mode 100644
index 00000000..cf25acff
--- /dev/null
+++ b/src/dirent/telldir.c
@@ -0,0 +1,7 @@
+#include <dirent.h>
+#include "__dirent.h"
+
+long telldir(DIR *dir)
+{
+ return dir->tell;
+}