Skip to content

Commit ae7bb24

Browse files
committed
Make sure the ino that we give to readdir matches the ino we give to stat
1 parent 1171ada commit ae7bb24

File tree

3 files changed

+92
-13
lines changed

3 files changed

+92
-13
lines changed

src/library_syscall.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -697,23 +697,22 @@ var SyscallsLibrary = {
697697
698698
var startIdx = Math.floor(off / struct_size);
699699
var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count/struct_size))
700+
var node;
700701
for (var idx = startIdx; idx < endIdx; idx++) {
701-
var id;
702702
var type;
703703
var name = stream.getdents[idx];
704704
if (name === '.') {
705-
id = stream.node.id;
705+
node = stream.node;
706706
type = 4; // DT_DIR
707707
}
708708
else if (name === '..') {
709709
var lookup = FS.lookupPath(stream.path, { parent: true });
710-
id = lookup.node.id;
710+
node = lookup.node;
711711
type = 4; // DT_DIR
712712
}
713713
else {
714-
var child;
715714
try {
716-
child = FS.lookupNode(stream.node, name);
715+
node = FS.lookupNode(stream.node, name);
717716
} catch (e) {
718717
// If the entry is not a directory, file, or symlink, nodefs
719718
// lookupNode will raise EINVAL. Skip these and continue.
@@ -722,16 +721,17 @@ var SyscallsLibrary = {
722721
}
723722
throw e;
724723
}
725-
id = child.id;
726-
type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device.
727-
FS.isDir(child.mode) ? 4 : // DT_DIR, directory.
728-
FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link.
724+
type = FS.isChrdev(node.mode) ? 2 : // DT_CHR, character device.
725+
FS.isDir(node.mode) ? 4 : // DT_DIR, directory.
726+
FS.isLink(node.mode) ? 10 : // DT_LNK, symbolic link.
729727
8; // DT_REG, regular file.
730728
}
731-
#if ASSERTIONS
732-
assert(id);
733-
#endif
734-
{{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_ino, 'id', 'i64') }}};
729+
// We use getattr to decide which ino we return to stat, so make sure to
730+
// use it to decide which ino we return to readdir too. noderawfs puts the
731+
// native inode into node.id and doesn't define node_ops.getattr so use
732+
// that as a fallback.
733+
var ino = node.node_ops.getattr?.(node).ino ?? node.id;
734+
{{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_ino, 'ino', 'i64') }}};
735735
{{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_off, '(idx + 1) * struct_size', 'i64') }}};
736736
{{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_reclen, C_STRUCTS.dirent.__size__, 'i16') }}};
737737
{{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_type, 'type', 'i8') }}};
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <stdio.h>
2+
#include <unistd.h>
3+
#include <assert.h>
4+
#include <fcntl.h>
5+
#include <string.h>
6+
#include <sys/stat.h>
7+
#include <assert.h>
8+
#include <errno.h>
9+
#include <string.h>
10+
#include <dirent.h>
11+
12+
13+
#if defined(__EMSCRIPTEN__)
14+
#include <emscripten.h>
15+
#endif
16+
17+
void makedir(const char *dir) {
18+
int rtn = mkdir(dir, 0777);
19+
assert(rtn == 0);
20+
}
21+
22+
void changedir(const char *dir) {
23+
int rtn = chdir(dir);
24+
assert(rtn == 0);
25+
}
26+
27+
void setup() {
28+
#if defined(__EMSCRIPTEN__) && defined(NODEFS)
29+
makedir("working");
30+
emscripten_debugger();
31+
EM_ASM(FS.mount(NODEFS, { root: '.' }, 'working'));
32+
changedir("working");
33+
#endif
34+
}
35+
36+
int main() {
37+
setup();
38+
int res = open("b", O_CREAT, 0777);
39+
assert(res >= 0);
40+
assert(close(res) == 0);
41+
assert(symlink("b", "a") == 0);
42+
int dirfd = open(".", O_RDONLY);
43+
assert(dirfd > 0);
44+
DIR *dirp;
45+
dirp = fdopendir(dirfd);
46+
assert(dirp != NULL);
47+
struct dirent *ep;
48+
int a_ino = -1;
49+
int b_ino = -1;
50+
while ((ep = readdir(dirp))) {
51+
if (strcmp(ep->d_name, "a") == 0) {
52+
a_ino = ep->d_ino;
53+
}
54+
if (strcmp(ep->d_name, "b") == 0) {
55+
b_ino = ep->d_ino;
56+
}
57+
}
58+
assert(a_ino >= 0);
59+
assert(b_ino >= 0);
60+
struct stat sta, stb;
61+
assert(lstat("a", &sta) == 0);
62+
assert(lstat("b", &stb) == 0);
63+
printf("readdir a_ino: %d, b_ino: %d\n", a_ino, b_ino);
64+
printf("stat a_ino: %llu, b_ino: %llu\n", sta.st_ino, stb.st_ino);
65+
assert(a_ino == sta.st_ino);
66+
assert(b_ino == stb.st_ino);
67+
printf("success\n");
68+
}

test/test_core.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5900,6 +5900,17 @@ def test_fs_rename_on_existing(self, args):
59005900
self.set_setting('FORCE_FILESYSTEM')
59015901
self.do_runf('fs/test_fs_rename_on_existing.c', 'success', emcc_args=args)
59025902

5903+
@parameterized({
5904+
'': ([],),
5905+
'nodefs': (['-DNODEFS', '-lnodefs.js'],),
5906+
'noderawfs': (['-sNODERAWFS'],)
5907+
})
5908+
def test_fs_readdir_ino_matches_stat_ino(self, args):
5909+
if self.get_setting('WASMFS'):
5910+
self.set_setting('FORCE_FILESYSTEM')
5911+
self.do_runf('fs/test_fs_readdir_ino_matches_stat_ino.c', 'success', emcc_args=args)
5912+
5913+
59035914
def test_sigalrm(self):
59045915
self.do_runf('test_sigalrm.c', 'Received alarm!')
59055916
self.set_setting('EXIT_RUNTIME')

0 commit comments

Comments
 (0)