Skip to content
Closed
17 changes: 16 additions & 1 deletion src/library_path.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@

mergeInto(LibraryManager.library, {
$PATH: {
isAbs: (path) => path.charAt(0) === '/',
isAbs: (path) => {
#if ENVIRONMENT_MAY_BE_NODE
if (typeof ENVIRONMENT_IS_NODE != 'undefined' && ENVIRONMENT_IS_NODE && typeof nodePath !== 'undefined' && nodePath.isAbsolute !== undefined) {
return nodePath.isAbsolute(path);
}
#endif
return path.charAt(0) === '/';
},
// split a filename into [root, dir, basename, ext], unix version
// 'root' is just a slash, or nothing.
splitPath: (filename) => {
Expand Down Expand Up @@ -37,6 +44,14 @@ mergeInto(LibraryManager.library, {
return parts;
},
normalize: (path) => {
#if ENVIRONMENT_MAY_BE_NODE
if (typeof ENVIRONMENT_IS_NODE != 'undefined' && ENVIRONMENT_IS_NODE && typeof nodePath !== 'undefined' && nodePath.normalize !== undefined) {
const normalized = nodePath.normalize(path);
if (normalized) {
return normalized.replace(/\\/g, '/');
}
}
#endif
var isAbsolute = PATH.isAbs(path),
trailingSlash = path.substr(-1) === '/';
// Normalize the path
Expand Down
9 changes: 8 additions & 1 deletion test/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from tools.shared import TEMP_DIR, EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE
from tools.shared import EMSCRIPTEN_TEMP_DIR
from tools.shared import get_canonical_temp_dir, path_from_root
from tools.utils import MACOS, WINDOWS, read_file, read_binary, write_file, write_binary, exit_with_error
from tools.utils import MACOS, WINDOWS, LINUX, read_file, read_binary, write_file, write_binary, exit_with_error
from tools import shared, line_endings, building, config, utils

logger = logging.getLogger('common')
Expand Down Expand Up @@ -154,6 +154,13 @@ def no_mac(note=''):
return lambda f: f


def no_linux(note=''):
assert not callable(note)
if LINUX:
return unittest.skip(note)
return lambda f: f


def no_windows(note=''):
assert not callable(note)
if WINDOWS:
Expand Down
218 changes: 218 additions & 0 deletions test/dirent/test_readdir_windows.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/*
* 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>
#include <limits.h>

void cleanup();

#define ASSERT_WITH_CLEANUP(cond) if (!(cond)) { cleanup(); assert(cond); }

#define CHECK(cond) if (!(cond)) { printf("errno: %s\n", strerror(errno)); ASSERT_WITH_CLEANUP(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_WITH_CLEANUP(err == (sizeof(char) * strlen(buffer)));

close(fd);
}

char windir[PATH_MAX] = {0};
char tempdir[PATH_MAX] = {0};
char testtmp[PATH_MAX] = {0};

void setup() {
sprintf(testtmp, "%s\\testtmp", tempdir);
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 cleanup() {
rmdir("nocanread");
unlink("foobar\\file.txt");
rmdir("foobar");
chdir("..");
rmdir("testtmp");
}

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_WITH_CLEANUP(!dir);
ASSERT_WITH_CLEANUP(errno == ENOENT);
char filepath[PATH_MAX] = {0};
sprintf(filepath, "%s\\foobar\\file.txt", testtmp);
dir = opendir(filepath);
ASSERT_WITH_CLEANUP(!dir);

//
// do a normal read with readdir
//
char dirpath[PATH_MAX] = {0};
sprintf(dirpath, "%s\\foobar", testtmp);
dir = opendir(dirpath);
ASSERT_WITH_CLEANUP(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_WITH_CLEANUP(ent);
}
ASSERT_WITH_CLEANUP(ent->d_reclen == sizeof(*ent));
if (!seen[0] && !strcmp(ent->d_name, ".")) {
ASSERT_WITH_CLEANUP(ent->d_type & DT_DIR);
seen[0] = 1;
continue;
}
if (!seen[1] && !strcmp(ent->d_name, "..")) {
ASSERT_WITH_CLEANUP(ent->d_type & DT_DIR);
seen[1] = 1;
continue;
}
if (!seen[2] && !strcmp(ent->d_name, "file.txt")) {
ASSERT_WITH_CLEANUP(ent->d_type & DT_REG);
seen[2] = 1;
continue;
}
ASSERT_WITH_CLEANUP(0 && "odd filename");
}
ent = readdir(dir);
if (ent) printf("surprising ent: %p : %s\n", ent, ent->d_name);
ASSERT_WITH_CLEANUP(!ent);

// test rewinddir
rewinddir(dir);
ent = readdir(dir);
ASSERT_WITH_CLEANUP(ent && ent->d_ino);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));

// test seek / tell
rewinddir(dir);
ent = readdir(dir);
ASSERT_WITH_CLEANUP(ent && ent->d_ino);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
loc = telldir(dir);
ASSERT_WITH_CLEANUP(loc >= 0);
//printf("loc=%d\n", loc);
loc2 = ent->d_off;
ent = readdir(dir);
ASSERT_WITH_CLEANUP(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_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
ent = readdir(dir);
ASSERT_WITH_CLEANUP(ent && ent->d_ino);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
seekdir(dir, loc);
ent = readdir(dir);
ASSERT_WITH_CLEANUP(ent && ent->d_ino);
//printf("check: %s / %s\n", ent->d_name, name_at_loc);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, name_at_loc));

seekdir(dir, loc2);
ent = readdir(dir);
ASSERT_WITH_CLEANUP(ent && ent->d_ino);
//printf("check: %s / %s\n", ent->d_name, name_at_loc);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, name_at_loc));

//
// do a normal read with readdir_r
//
rewinddir(dir);
err = readdir_r(dir, &ent_r, &result);
ASSERT_WITH_CLEANUP(!err);
ASSERT_WITH_CLEANUP(&ent_r == result);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
err = readdir_r(dir, &ent_r, &result);
ASSERT_WITH_CLEANUP(!err);
ASSERT_WITH_CLEANUP(&ent_r == result);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
err = readdir_r(dir, &ent_r, &result);
ASSERT_WITH_CLEANUP(!err);
ASSERT_WITH_CLEANUP(&ent_r == result);
ASSERT_WITH_CLEANUP(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt"));
err = readdir_r(dir, &ent_r, &result);
ASSERT_WITH_CLEANUP(!err);
ASSERT_WITH_CLEANUP(!result);

err = closedir(dir);
ASSERT_WITH_CLEANUP(!err);

// Read the windir and verify
dir = opendir(windir);
ASSERT_WITH_CLEANUP(dir);
err = closedir(dir);
ASSERT_WITH_CLEANUP(!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(int argc, char * argv[]) {
if (argc < 3) {
printf("test_readdir_windows args: %%WINDIR%% %%TEMP%%\n");
return -1;
}
strcpy(windir, argv[1]);
strcpy(tempdir, argv[2]);
// atexit(cleanup); Doesn't work on windows
signal(SIGABRT, cleanup);
setup();
test();
test_scandir();
cleanup();

return EXIT_SUCCESS;
}
9 changes: 9 additions & 0 deletions test/dirent/test_readdir_windows.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
0 file: . (280 : 280)
1 file: .. (280 : 280)
2 file: file.txt (280 : 280)
success
n: 4
name: nocanread
name: foobar
name: ..
name: .
10 changes: 9 additions & 1 deletion test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from tools import shared, building, config, webassembly
import common
from common import RunnerCore, path_from_root, requires_native_clang, test_file, create_file
from common import skip_if, needs_dylink, no_windows, no_mac, is_slow_test, parameterized
from common import skip_if, needs_dylink, no_windows, no_mac, no_linux, is_slow_test, parameterized
from common import env_modify, with_env_modify, disabled, node_pthreads, also_with_wasm_bigint
from common import read_file, read_binary, requires_v8, requires_node
from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON
Expand Down Expand Up @@ -5655,6 +5655,14 @@ def test_fileno(self):
def test_readdir(self):
self.do_run_in_out_file_test('dirent/test_readdir.c')

@no_mac("uses windows only paths for testing")
@no_linux("uses windows only paths for testing")
@also_with_noderawfs
def test_readdir_windows(self):
self.require_node()
self.emcc_args += ['-sNODERAWFS']
self.do_run_in_out_file_test('dirent/test_readdir_windows.c', args=[os.environ["WINDIR"], os.environ["TEMP"]])

@also_with_wasm_bigint
def test_readdir_empty(self):
self.do_run_in_out_file_test('dirent/test_readdir_empty.c')
Expand Down