text: /*
   * 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 <assert.h>
  #include <dirent.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <signal.h>
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <unistd.h>
  #include <sys/stat.h>
  
  static void create_file(const char *path, const char *buffer, int mode) {
    int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, mode);
    assert(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("nocanread", 0111);
    assert(!err);
    err = mkdir("foobar", 0777);
    assert(!err);
    create_file("foobar/file.txt", "ride into the danger zone", 0666);
  }
  
  void cleanup() {
    rmdir("nocanread");
    unlink("foobar/file.txt");
    rmdir("foobar");
  }
  
  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);
    dir = opendir("nocanread");
    assert(!dir);
    assert(errno == EACCES);
    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);
      //printf("ent, errno: %p, %d\n", ent, errno);
      assert(ent);
      //printf("%d file: %s (%d : %d)\n", i, ent->d_name, ent->d_reclen, sizeof(*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(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
  
    // test seek / tell
    rewinddir(dir);
    ent = readdir(dir);
    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);
    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);
    assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
    seekdir(dir, loc);
    ent = readdir(dir);
    assert(ent);
    //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);
    //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() {
    atexit(cleanup);
    signal(SIGABRT, cleanup);
    setup();
    test();
    test_scandir();
  
  #ifdef REPORT_RESULT
    REPORT_RESULT(0);
  #endif
    return EXIT_SUCCESS;
  }
  