Skip to content

Commit 03b0b2c

Browse files
committed
NODEFS readlink should take current mountpoint into account
1 parent fdf24b4 commit 03b0b2c

File tree

7 files changed

+94
-13
lines changed

7 files changed

+94
-13
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,5 @@ a license to everyone to use it as detailed in LICENSE.)
171171
* Petr Babicka <[email protected]>
172172
* Akira Takahashi <[email protected]>
173173
* Victor Costan <[email protected]>
174+
* Jan Jongboom <[email protected]> (copyright owned by Telenor Digital AS)
174175

src/library_fs.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ mergeInto(LibraryManager.library, {
9797
while (FS.isLink(current.mode)) {
9898
var link = FS.readlink(current_path);
9999
current_path = PATH.resolve(PATH.dirname(current_path), link);
100-
100+
101101
var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
102102
current = lookup.node;
103103

@@ -427,7 +427,7 @@ mergeInto(LibraryManager.library, {
427427
// we employ a simple trick: the pointer to a stream is its fd plus 1. This
428428
// means that all valid streams have a valid non-zero pointer while allowing
429429
// the fs for stdin to be the standard value of zero.
430-
//
430+
//
431431
//
432432
getStreamFromPtr: function(ptr) {
433433
return FS.streams[ptr - 1];
@@ -838,7 +838,7 @@ mergeInto(LibraryManager.library, {
838838
if (!link.node_ops.readlink) {
839839
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
840840
}
841-
return link.node_ops.readlink(link);
841+
return PATH.resolve('.', link.node_ops.readlink(link));
842842
},
843843
stat: function(path, dontFollow) {
844844
var lookup = FS.lookupPath(path, { follow: !dontFollow });

src/library_nodefs.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mergeInto(LibraryManager.library, {
22
$NODEFS__deps: ['$FS', '$PATH'],
3-
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }',
3+
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); var NODEJS_PATH = require("path"); NODEFS.staticInit(); }',
44
$NODEFS: {
55
isWindows: false,
66
staticInit: function() {
@@ -24,7 +24,7 @@ mergeInto(LibraryManager.library, {
2424
try {
2525
stat = fs.lstatSync(path);
2626
if (NODEFS.isWindows) {
27-
// On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
27+
// On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
2828
// propagate write bits to execute bits.
2929
stat.mode = stat.mode | ((stat.mode & 146) >> 1);
3030
}
@@ -203,7 +203,9 @@ mergeInto(LibraryManager.library, {
203203
readlink: function(node) {
204204
var path = NODEFS.realPath(node);
205205
try {
206-
return fs.readlinkSync(path);
206+
path = fs.readlinkSync(path);
207+
path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);
208+
return PATH.join(node.mount.mountpoint, path);
207209
} catch (e) {
208210
if (!e.code) throw e;
209211
throw new FS.ErrnoError(ERRNO_CODES[e.code]);

tests/test_core.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4709,6 +4709,22 @@ def test_unistd_links(self):
47094709
Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
47104710
self.do_run(src, expected, js_engines=[NODE_JS])
47114711

4712+
def test_unistd_symlink_on_nodefs(self):
4713+
self.clear()
4714+
if not self.is_emscripten_abi(): return self.skip('asmjs-unknown-emscripten needed for inline js')
4715+
orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
4716+
for fs in ['NODEFS']:
4717+
if WINDOWS and fs == 'NODEFS':
4718+
print >> sys.stderr, 'Skipping NODEFS part of this test for test_unistd_symlink_on_nodefs on Windows, since it would require administrative privileges.'
4719+
# Also, other detected discrepancies if you do end up running this test on NODEFS:
4720+
# test expects /, but Windows gives \ as path slashes.
4721+
# Calling readlink() on a non-link gives error 22 EINVAL on Unix, but simply error 0 OK on Windows.
4722+
continue
4723+
src = open(path_from_root('tests', 'unistd', 'symlink_on_nodefs.c'), 'r').read()
4724+
expected = open(path_from_root('tests', 'unistd', 'symlink_on_nodefs.out'), 'r').read()
4725+
Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
4726+
self.do_run(src, expected, js_engines=[NODE_JS])
4727+
47124728
def test_unistd_sleep(self):
47134729
src = open(path_from_root('tests', 'unistd', 'sleep.c'), 'r').read()
47144730
expected = open(path_from_root('tests', 'unistd', 'sleep.out'), 'r').read()

tests/unistd/links.out

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
readlink(link)
2-
ret: 17
2+
ret: 7
33
errno: 0
4-
result: ../test/../there!
4+
result: /there!
55

66
readlink(file)
77
ret: -1
88
errno: 22
9-
result: ../test/../there!
9+
result: /there!
1010

1111
readlink(folder)
1212
ret: -1
1313
errno: 22
14-
result: ../test/../there!
14+
result: /there!
1515

1616
symlink/overwrite
1717
ret: -1
@@ -21,11 +21,11 @@ symlink/normal
2121
ret: 0
2222
errno: 0
2323
readlink(created link)
24-
ret: 20
24+
ret: 29
2525
errno: 0
26-
result: new-nonexistent-path
26+
result: /working/new-nonexistent-path
2727

2828
readlink(short buffer)
2929
ret: 3
3030
errno: 0
31-
result: ../-nonexistent-path
31+
result: /thrking/new-nonexistent-path

tests/unistd/symlink_on_nodefs.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include <stdio.h>
2+
#include <errno.h>
3+
#include <unistd.h>
4+
#include <emscripten.h>
5+
#include <sys/stat.h>
6+
#include <sys/types.h>
7+
#include <limits.h>
8+
#include <stdlib.h>
9+
10+
int main() {
11+
EM_ASM(
12+
fs.mkdirSync('./new-directory', '0777');
13+
fs.writeFileSync('./new-directory/test', 'Link it');
14+
fs.symlinkSync(fs.realpathSync('./new-directory'), './symlink');
15+
16+
FS.mkdir('working');
17+
FS.mount(NODEFS, { root: '.' }, 'working');
18+
19+
FS.mkdir('direct-link');
20+
FS.mount(NODEFS, { root: './symlink' }, 'direct-link');
21+
);
22+
23+
{
24+
char* path = "/working/symlink/test";
25+
printf("reading %s\n", path);
26+
27+
FILE* fd = fopen(path, "r");
28+
if (fd == NULL) {
29+
printf("failed to open file %s\n", path);
30+
}
31+
else {
32+
char buffer[8];
33+
fread(buffer, 1, 7, fd);
34+
printf("buffer is %s\n", buffer);
35+
fclose(fd);
36+
}
37+
}
38+
39+
printf("\n");
40+
41+
{
42+
char* path = "/direct-link/test";
43+
printf("reading %s\n", path);
44+
45+
FILE* fd = fopen(path, "r");
46+
if (fd != NULL) {
47+
// This should not happen, it resolves to ../new-directory which is not mounted
48+
printf("opened file %s\n", path);
49+
fclose(fd);
50+
}
51+
else {
52+
printf("failed to open file %s\n", path);
53+
}
54+
}
55+
56+
return 0;
57+
}

tests/unistd/symlink_on_nodefs.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
reading /working/symlink/test
2+
buffer is Link it
3+
4+
reading /direct-link/test
5+
failed to open file /direct-link/test

0 commit comments

Comments
 (0)