@@ -387,6 +387,82 @@ const char *strerror(int errno)
return buf;
}
+/* See comment of FILE above */
+typedef struct {
+ char dummy[1];
+} DIR;
+
+static __attribute__((unused))
+DIR *fdopendir(int fd)
+{
+ if (fd < 0) {
+ SET_ERRNO(EBADF);
+ return NULL;
+ }
+ return (DIR *)(intptr_t)~fd;
+}
+
+static __attribute__((unused))
+DIR *opendir(const char *name)
+{
+ int fd;
+
+ fd = open(name, O_RDONLY);
+ if (fd == -1)
+ return NULL;
+ return fdopendir(fd);
+}
+
+static __attribute__((unused))
+int closedir(DIR *dirp)
+{
+ intptr_t i = (intptr_t)dirp;
+
+ if (i >= 0) {
+ SET_ERRNO(EBADF);
+ return -1;
+ }
+ return close(~i);
+}
+
+static __attribute__((unused))
+struct dirent *readdir(DIR *dirp)
+{
+ static struct dirent dirent;
+
+ char buf[sizeof(struct linux_dirent64) + NAME_MAX];
+ struct linux_dirent64 *ldir = (void *)buf;
+ intptr_t i = (intptr_t)dirp;
+ int fd, ret;
+
+ if (i >= 0) {
+ SET_ERRNO(EBADF);
+ return NULL;
+ }
+
+ fd = ~i;
+
+ ret = getdents64(fd, ldir, sizeof(buf));
+ if (ret == -1 || ret == 0)
+ return NULL;
+
+ /*
+ * getdents64() returns as many entries as fit the buffer.
+ * readdir() can only return one entry at a time.
+ * Make sure the non-returned ones are not skipped.
+ */
+ ret = lseek(fd, ldir->d_off, SEEK_SET);
+ if (ret == -1)
+ return NULL;
+
+ dirent = (struct dirent) {
+ .d_ino = ldir->d_ino,
+ };
+ strlcpy(dirent.d_name, ldir->d_name, sizeof(dirent.d_name));
+
+ return &dirent;
+}
+
/* make sure to include all global symbols */
#include "nolibc.h"
@@ -179,6 +179,11 @@ struct linux_dirent64 {
char d_name[];
};
+struct dirent {
+ ino_t d_ino;
+ char d_name[256];
+};
+
/* The format of the struct as returned by the libc to the application, which
* significantly differs from the format returned by the stat() syscall flavours.
*/
@@ -767,6 +767,42 @@ int test_getdents64(const char *dir)
return ret;
}
+int test_directories(void)
+{
+ int comm = 0, cmdline = 0;
+ struct dirent *dirent;
+ DIR *dir;
+ int ret;
+
+ dir = opendir("/proc/self");
+ if (!dir)
+ return 1;
+
+ while (1) {
+ errno = 0;
+ dirent = readdir(dir);
+ if (!dirent)
+ break;
+
+ if (strcmp(dirent->d_name, "comm") == 0)
+ comm++;
+ else if (strcmp(dirent->d_name, "cmdline") == 0)
+ cmdline++;
+ }
+
+ if (errno)
+ return 1;
+
+ ret = closedir(dir);
+ if (ret)
+ return 1;
+
+ if (comm != 1 || cmdline != 1)
+ return 1;
+
+ return 0;
+}
+
int test_getpagesize(void)
{
int x = getpagesize();
@@ -1059,6 +1095,7 @@ int run_syscall(int min, int max)
CASE_TEST(fork); EXPECT_SYSZR(1, test_fork()); break;
CASE_TEST(getdents64_root); EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
CASE_TEST(getdents64_null); EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;
+ CASE_TEST(directories); EXPECT_SYSZR(proc, test_directories()); break;
CASE_TEST(gettimeofday_tv); EXPECT_SYSZR(1, gettimeofday(&tv, NULL)); break;
CASE_TEST(gettimeofday_tv_tz);EXPECT_SYSZR(1, gettimeofday(&tv, &tz)); break;
CASE_TEST(getpagesize); EXPECT_SYSZR(1, test_getpagesize()); break;