Skip to content

Commit e35d017

Browse files
authored
Fix for getdents (readdir) under NODEFS. (#16124)
The test case here was taken from #15308. The main bugfix here is to use `stream.node` rather than just `stream` when attempting to get node properties from a stream. There were some extra properties added to the streams back in #15167, but this change reverts that and instead fixes up the streams returned by NODERAWFS such that they have the correct/expected fields.
1 parent 0ae5b2b commit e35d017

File tree

6 files changed

+54
-10
lines changed

6 files changed

+54
-10
lines changed

src/library_fs.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,13 +1061,10 @@ FS.staticInit();` +
10611061
var stream = FS.createStream({
10621062
node: node,
10631063
path: FS.getPath(node), // we want the absolute path to the node
1064-
id: node.id,
10651064
flags: flags,
1066-
mode: node.mode,
10671065
seekable: true,
10681066
position: 0,
10691067
stream_ops: node.stream_ops,
1070-
node_ops: node.node_ops,
10711068
// used by the file family libc calls (fopen, fwrite, ferror, etc.)
10721069
ungotten: [],
10731070
error: false

src/library_noderawfs.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ mergeInto(LibraryManager.library, {
2929
}`,
3030
$NODERAWFS: {
3131
lookup: function(parent, name) {
32+
#if ASSERTIONS
33+
assert(parent)
34+
assert(parent.path)
35+
#endif
3236
return FS.lookupPath(parent.path + '/' + name).node;
3337
},
3438
lookupPath: function(path, opts) {
@@ -38,7 +42,7 @@ mergeInto(LibraryManager.library, {
3842
}
3943
var st = fs.lstatSync(path);
4044
var mode = NODEFS.getMode(path);
41-
return { path: path, node: { id: st.ino, mode: mode }};
45+
return { path: path, node: { id: st.ino, mode: mode, node_ops: NODERAWFS, path: path }};
4246
},
4347
createStandardStreams: function() {
4448
FS.streams[0] = { fd: 0, nfd: 0, position: 0, path: '', flags: 0, tty: true, seekable: false };
@@ -90,7 +94,8 @@ mergeInto(LibraryManager.library, {
9094
}
9195
var newMode = NODEFS.getMode(pathTruncated);
9296
var fd = suggestFD != null ? suggestFD : FS.nextfd(nfd);
93-
var stream = { fd: fd, nfd: nfd, position: 0, path: path, id: st.ino, flags: flags, mode: newMode, node_ops: NODERAWFS, seekable: true };
97+
var node = { id: st.ino, mode: newMode, node_ops: NODERAWFS, path: path }
98+
var stream = { fd: fd, nfd: nfd, position: 0, path: path, flags: flags, node: node, seekable: true };
9499
FS.streams[fd] = stream;
95100
return stream;
96101
},

src/library_syscall.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ var SyscallsLibrary = {
858858
var type;
859859
var name = stream.getdents[idx];
860860
if (name === '.') {
861-
id = stream.id;
861+
id = stream.node.id;
862862
type = 4; // DT_DIR
863863
}
864864
else if (name === '..') {
@@ -867,7 +867,7 @@ var SyscallsLibrary = {
867867
type = 4; // DT_DIR
868868
}
869869
else {
870-
var child = FS.lookupNode(stream, name);
870+
var child = FS.lookupNode(stream.node, name);
871871
id = child.id;
872872
type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device.
873873
FS.isDir(child.mode) ? 4 : // DT_DIR, directory.

tests/dirent/test_readdir.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ void test() {
9393
for (i = 0; i < 3; i++) {
9494
errno = 0;
9595
ent = readdir(dir);
96-
//printf("ent, errno: %p, %d\n", ent, errno);
97-
assert(ent);
98-
//printf("%d file: %s (%d : %d)\n", i, ent->d_name, ent->d_reclen, sizeof(*ent));
96+
if (ent) {
97+
fprintf(stderr, "%d file: %s (%d : %lu)\n", i, ent->d_name, ent->d_reclen, sizeof(*ent));
98+
} else {
99+
fprintf(stderr, "ent: %p, errno: %d\n", ent, errno);
100+
assert(ent);
101+
}
99102
assert(ent->d_reclen == sizeof(*ent));
100103
if (!seen[0] && !strcmp(ent->d_name, ".")) {
101104
assert(ent->d_type & DT_DIR);

tests/fs/test_nodefs_readdir.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#include <assert.h>
2+
#include <dirent.h>
3+
#include <emscripten.h>
4+
#include <stdio.h>
5+
6+
void list_dir(const char *path) {
7+
printf("listing contents of dir=%s\n", path);
8+
struct dirent* entry;
9+
DIR* dir = opendir(path);
10+
assert(dir);
11+
int n = 0;
12+
while ((entry = readdir(dir)) != NULL) {
13+
printf("%s\n", entry->d_name);
14+
++n;
15+
}
16+
assert(n);
17+
closedir(dir);
18+
}
19+
20+
int main(int argc, char * argv[]) {
21+
list_dir("/");
22+
23+
// mount the current folder as a NODEFS instance
24+
// inside of emscripten and create folders nodefs/a
25+
// in mounted directory
26+
EM_ASM(
27+
FS.mkdir('/working');
28+
FS.mount(NODEFS, { root: '.' }, '/working');
29+
);
30+
31+
list_dir("/working");
32+
puts("success");
33+
}

tests/test_core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5433,6 +5433,12 @@ def test_fs_nodefs_nofollow(self):
54335433
self.emcc_args += ['-lnodefs.js']
54345434
self.do_runf(test_file('fs/test_nodefs_nofollow.c'), 'success', js_engines=[config.NODE_JS])
54355435

5436+
def test_fs_nodefs_readdir(self):
5437+
# externally setup an existing folder structure: existing/a
5438+
os.makedirs(os.path.join(self.working_dir, 'existing', 'a'))
5439+
self.emcc_args += ['-lnodefs.js']
5440+
self.do_runf(test_file('fs/test_nodefs_readdir.c'), 'success')
5441+
54365442
@no_windows('no symlink support on windows')
54375443
def test_fs_noderawfs_nofollow(self):
54385444
self.set_setting('NODERAWFS')

0 commit comments

Comments
 (0)