/* * Copyright 2013 The Emscripten Authors. All rights reserved. * Emscripten is available under two separate licenses, the MIT license and the * University of Illinois/NCSA Open Source License. Both these licenses can be * found in the LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #define CHECK(cond) if (!(cond)) { printf("errno: %s\n", strerror(errno)); assert(cond); } static void create_file(const char *path, const char *buffer, int mode) { int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode); CHECK(fd >= 0); int err = write(fd, buffer, sizeof(char) * strlen(buffer)); assert(err == (sizeof(char) * strlen(buffer))); close(fd); } void setup() { int err; err = mkdir("testtmp", 0777); // can't call it tmp, that already exists CHECK(!err); chdir("testtmp"); err = mkdir("nocanread", 0111); CHECK(!err); err = mkdir("foobar", 0777); CHECK(!err); create_file("foobar/file.txt", "ride into the danger zone", 0666); } void test() { int err; long loc, loc2; DIR *dir; struct dirent *ent; struct dirent ent_r; struct dirent *result; int i; // check bad opendir input dir = opendir("noexist"); assert(!dir); assert(errno == ENOENT); // NODERAWFS tests run as root, and the root user can opendir any directory #ifndef NODERAWFS dir = opendir("nocanread"); assert(!dir); assert(errno == EACCES); #endif dir = opendir("foobar/file.txt"); assert(!dir); assert(errno == ENOTDIR); // check bad readdir input //dir = opendir("foobar"); //closedir(dir); //ent = readdir(dir); //assert(!ent); // XXX musl doesn't have enough error handling for this: assert(errno == EBADF); // check bad readdir_r input //dir = opendir("foobar"); //closedir(dir); //err = readdir_r(dir, NULL, &result); // XXX musl doesn't have enough error handling for this: assert(err == EBADF); // // do a normal read with readdir // dir = opendir("foobar"); assert(dir); int seen[3] = { 0, 0, 0 }; for (i = 0; i < 3; i++) { errno = 0; ent = readdir(dir); if (ent) { fprintf(stderr, "%d file: %s (%d : %lu)\n", i, ent->d_name, ent->d_reclen, sizeof(*ent)); } else { fprintf(stderr, "ent: %p, errno: %d\n", ent, errno); assert(ent); } assert(ent->d_reclen == sizeof(*ent)); if (!seen[0] && !strcmp(ent->d_name, ".")) { assert(ent->d_type & DT_DIR); seen[0] = 1; continue; } if (!seen[1] && !strcmp(ent->d_name, "..")) { assert(ent->d_type & DT_DIR); seen[1] = 1; continue; } if (!seen[2] && !strcmp(ent->d_name, "file.txt")) { assert(ent->d_type & DT_REG); seen[2] = 1; continue; } assert(0 && "odd filename"); } ent = readdir(dir); if (ent) printf("surprising ent: %p : %s\n", ent, ent->d_name); assert(!ent); // test rewinddir rewinddir(dir); ent = readdir(dir); assert(ent && ent->d_ino); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); // test seek / tell rewinddir(dir); ent = readdir(dir); assert(ent && ent->d_ino); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); loc = telldir(dir); assert(loc >= 0); //printf("loc=%d\n", loc); loc2 = ent->d_off; ent = readdir(dir); assert(ent && ent->d_ino); char name_at_loc[1024]; strcpy(name_at_loc, ent->d_name); //printf("name_at_loc: %s\n", name_at_loc); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); ent = readdir(dir); #ifndef WASMFS_NODERAWFS // WasmFS + NODERAWFS lacks ino numbers in directory listings, see // https://github.com/emscripten-core/emscripten/issues/19418 // This is not an issue for "." and ".." (the other checks before and after // us) since "." and ".." are added by WasmFS code itself; only "file.txt" is // added from the node JS API, and as a result it has inode 0. assert(ent && ent->d_ino); #endif assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); seekdir(dir, loc); ent = readdir(dir); assert(ent && ent->d_ino); //printf("check: %s / %s\n", ent->d_name, name_at_loc); assert(!strcmp(ent->d_name, name_at_loc)); seekdir(dir, loc2); ent = readdir(dir); assert(ent && ent->d_ino); //printf("check: %s / %s\n", ent->d_name, name_at_loc); assert(!strcmp(ent->d_name, name_at_loc)); // // do a normal read with readdir_r // rewinddir(dir); err = readdir_r(dir, &ent_r, &result); assert(!err); assert(&ent_r == result); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); err = readdir_r(dir, &ent_r, &result); assert(!err); assert(&ent_r == result); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); err = readdir_r(dir, &ent_r, &result); assert(!err); assert(&ent_r == result); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); err = readdir_r(dir, &ent_r, &result); assert(!err); assert(!result); err = closedir(dir); assert(!err); puts("success"); } void test_scandir() { struct dirent **namelist; int n; n = scandir(".", &namelist, NULL, alphasort); printf("n: %d\n", n); if (n < 0) return; else { while (n--) { printf("name: %s\n", namelist[n]->d_name); free(namelist[n]); } free(namelist); } } int main() { setup(); test(); test_scandir(); return 0; }