diff options
-rw-r--r-- | src/library_nodefs.js | 58 | ||||
-rw-r--r-- | tests/test_core.py | 6 | ||||
-rw-r--r-- | tests/unistd/access.c | 10 | ||||
-rw-r--r-- | tests/unistd/truncate.c | 6 |
4 files changed, 77 insertions, 3 deletions
diff --git a/src/library_nodefs.js b/src/library_nodefs.js index d8df1689..2be54076 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -1,7 +1,11 @@ mergeInto(LibraryManager.library, { $NODEFS__deps: ['$FS', '$PATH'], - $NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); }', + $NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }', $NODEFS: { + isWindows: false, + staticInit: function() { + NODEFS.isWindows = !!process.platform.match(/^win/); + }, mount: function (mount) { assert(ENVIRONMENT_IS_NODE); return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0); @@ -19,6 +23,11 @@ mergeInto(LibraryManager.library, { var stat; try { stat = fs.lstatSync(path); + if (NODEFS.isWindows) { + // On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so + // propagate write bits to execute bits. + stat.mode = stat.mode | ((stat.mode & 146) >> 1); + } } catch (e) { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); @@ -35,6 +44,41 @@ mergeInto(LibraryManager.library, { parts.reverse(); return PATH.join.apply(null, parts); }, + // This maps the integer permission modes from http://linux.die.net/man/3/open + // to node.js-specific file open permission strings at http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback + flagsToPermissionStringMap: { + 0/*O_RDONLY*/: 'r', + 1/*O_WRONLY*/: 'r+', + 2/*O_RDWR*/: 'r+', + 64/*O_CREAT*/: 'r', + 65/*O_WRONLY|O_CREAT*/: 'r+', + 66/*O_RDWR|O_CREAT*/: 'r+', + 129/*O_WRONLY|O_EXCL*/: 'rx+', + 193/*O_WRONLY|O_CREAT|O_EXCL*/: 'rx+', + 514/*O_RDWR|O_TRUNC*/: 'w+', + 577/*O_WRONLY|O_CREAT|O_TRUNC*/: 'w', + 578/*O_CREAT|O_RDWR|O_TRUNC*/: 'w+', + 705/*O_WRONLY|O_CREAT|O_EXCL|O_TRUNC*/: 'wx', + 706/*O_RDWR|O_CREAT|O_EXCL|O_TRUNC*/: 'wx+', + 1024/*O_APPEND*/: 'a', + 1025/*O_WRONLY|O_APPEND*/: 'a', + 1026/*O_RDWR|O_APPEND*/: 'a+', + 1089/*O_WRONLY|O_CREAT|O_APPEND*/: 'a', + 1090/*O_RDWR|O_CREAT|O_APPEND*/: 'a+', + 1153/*O_WRONLY|O_EXCL|O_APPEND*/: 'ax', + 1154/*O_RDWR|O_EXCL|O_APPEND*/: 'ax+', + 1217/*O_WRONLY|O_CREAT|O_EXCL|O_APPEND*/: 'ax', + 1218/*O_RDWR|O_CREAT|O_EXCL|O_APPEND*/: 'ax+', + 4096/*O_RDONLY|O_DSYNC*/: 'rs', + 4098/*O_RDWR|O_DSYNC*/: 'rs+' + }, + flagsToPermissionString: function(flags) { + if (flags in NODEFS.flagsToPermissionStringMap) { + return NODEFS.flagsToPermissionStringMap[flags]; + } else { + return flags; + } + }, node_ops: { getattr: function(node) { var path = NODEFS.realPath(node); @@ -45,6 +89,14 @@ mergeInto(LibraryManager.library, { if (!e.code) throw e; throw new FS.ErrnoError(ERRNO_CODES[e.code]); } + // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake them with default blksize of 4096. + // See http://support.microsoft.com/kb/140365 + if (NODEFS.isWindows && !stat.blksize) { + stat.blksize = 4096; + } + if (NODEFS.isWindows && !stat.blocks) { + stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0; + } return { dev: stat.dev, ino: stat.ino, @@ -163,7 +215,7 @@ mergeInto(LibraryManager.library, { var path = NODEFS.realPath(stream.node); try { if (FS.isFile(stream.node.mode)) { - stream.nfd = fs.openSync(path, stream.flags); + stream.nfd = fs.openSync(path, NODEFS.flagsToPermissionString(stream.flags)); } } catch (e) { if (!e.code) throw e; @@ -172,7 +224,7 @@ mergeInto(LibraryManager.library, { }, close: function (stream) { try { - if (FS.isFile(stream.node.mode)) { + if (FS.isFile(stream.node.mode) && stream.nfd) { fs.closeSync(stream.nfd); } } catch (e) { diff --git a/tests/test_core.py b/tests/test_core.py index 4ab8f8e1..69fb31f3 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7841,6 +7841,12 @@ def process(filename): self.clear() if not self.is_le32(): return self.skip('le32 needed for inline js') for fs in ['MEMFS', 'NODEFS']: + if WINDOWS and fs == 'NODEFS': + print >> sys.stderr, 'Skipping NODEFS part of this test for test_unistd_links on Windows, since it would require administrative privileges.' + # Also, other detected discrepancies if you do end up running this test on NODEFS: + # test expects /, but Windows gives \ as path slashes. + # Calling readlink() on a non-link gives error 22 EINVAL on Unix, but simply error 0 OK on Windows. + continue src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read() expected = open(path_from_root('tests', 'unistd', 'links.out'), 'r').read() Building.COMPILER_TEST_OPTS += ['-D' + fs] diff --git a/tests/unistd/access.c b/tests/unistd/access.c index 57d38f5c..92b52e5e 100644 --- a/tests/unistd/access.c +++ b/tests/unistd/access.c @@ -33,5 +33,15 @@ int main() { errno = 0; printf("\n"); } + + // Restore full permissions on all created files so that python test runner rmtree + // won't have problems on deleting the files. On Windows, calling shutil.rmtree() + // will fail if any of the files are read-only. + EM_ASM( + FS.chmod('forbidden', 0777); + FS.chmod('readable', 0777); + FS.chmod('writeable', 0777); + FS.chmod('allaccess', 0777); + ); return 0; } diff --git a/tests/unistd/truncate.c b/tests/unistd/truncate.c index e63a4c13..5620f502 100644 --- a/tests/unistd/truncate.c +++ b/tests/unistd/truncate.c @@ -76,5 +76,11 @@ int main() { memset(&s, 0, sizeof s); errno = 0; + // Restore full permissions on all created files so that python test runner rmtree + // won't have problems on deleting the files. On Windows, calling shutil.rmtree() + // will fail if any of the files are read-only. + EM_ASM( + FS.chmod('toread', 0777); + ); return 0; } |