From b5586dcb8c77a47e49d55690a06e0bfd84973f7e Mon Sep 17 00:00:00 2001 From: Rian Hunter Date: Mon, 6 May 2019 17:21:36 -0700 Subject: [PATCH] Fix getdents syscall to handle seekdir/telldir (#8540) Directory seeking was broken, this change makes syscall220() respect the current directory offset. --- src/library_syscall.js | 16 ++++++++++++---- src/struct_info.json | 1 + system/lib/fetch/asmfs.cpp | 6 +++--- tests/dirent/test_readdir.c | 17 +++++++++-------- tests/test_other.py | 32 ++++++++++++++++---------------- 5 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index 1c788a639..87b06e196 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -1081,11 +1081,17 @@ var SyscallsLibrary = { if (!stream.getdents) { stream.getdents = FS.readdir(stream.path); } + + var struct_size = {{{ C_STRUCTS.dirent.__size__ }}}; var pos = 0; - while (stream.getdents.length > 0 && pos + {{{ C_STRUCTS.dirent.__size__ }}} <= count) { + var off = FS.llseek(stream, 0, {{{ cDefine('SEEK_CUR') }}}); + + var idx = Math.floor(off / struct_size); + + while (idx < stream.getdents.length && pos + struct_size <= count) { var id; var type; - var name = stream.getdents.pop(); + var name = stream.getdents[idx]; if (name[0] === '.') { id = 1; type = 4; // DT_DIR @@ -1098,12 +1104,14 @@ var SyscallsLibrary = { 8; // DT_REG, regular file. } {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_ino, 'id', 'i64') }}}; - {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_off, 'stream.position', 'i64') }}}; + {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_off, '(idx + 1) * struct_size', 'i64') }}}; {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_reclen, C_STRUCTS.dirent.__size__, 'i16') }}}; {{{ makeSetValue('dirp + pos', C_STRUCTS.dirent.d_type, 'type', 'i8') }}}; stringToUTF8(name, dirp + pos + {{{ C_STRUCTS.dirent.d_name }}}, 256); - pos += {{{ C_STRUCTS.dirent.__size__ }}}; + pos += struct_size; + idx += 1; } + FS.llseek(stream, idx * struct_size, {{{ cDefine('SEEK_SET') }}}); return pos; }, __syscall221__deps: ['__setErrNo'], diff --git a/src/struct_info.json b/src/struct_info.json index b30b7db1d..65ce6efd8 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -868,6 +868,7 @@ "defines": [ "EOF", "SEEK_END", + "SEEK_CUR", "SEEK_SET" ], "structs": {} diff --git a/system/lib/fetch/asmfs.cpp b/system/lib/fetch/asmfs.cpp index b72ec3a05..516b035e3 100644 --- a/system/lib/fetch/asmfs.cpp +++ b/system/lib/fetch/asmfs.cpp @@ -1910,7 +1910,7 @@ long __syscall220(int which, ...) // getdents64 (get directory entries 64-bit) if (desc->file_pos <= file_pos) { de->d_ino = (ino_t)node; // TODO: Create inode numbers instead of using pointers - de->d_off = file_pos; + de->d_off = file_pos + sizeof(dirent); de->d_reclen = sizeof(dirent); de->d_type = DT_DIR; strcpy(de->d_name, "."); @@ -1923,7 +1923,7 @@ long __syscall220(int which, ...) // getdents64 (get directory entries 64-bit) if (desc->file_pos <= file_pos) { de->d_ino = (ino_t)dotdot; // TODO: Create inode numbers instead of using pointers - de->d_off = file_pos; + de->d_off = file_pos + sizeof(dirent); de->d_reclen = sizeof(dirent); de->d_type = DT_DIR; strcpy(de->d_name, ".."); @@ -1938,7 +1938,7 @@ long __syscall220(int which, ...) // getdents64 (get directory entries 64-bit) if (desc->file_pos <= file_pos) { de->d_ino = (ino_t)node; // TODO: Create inode numbers instead of using pointers - de->d_off = file_pos; + de->d_off = file_pos + sizeof(dirent); de->d_reclen = sizeof(dirent); de->d_type = (node->type == INODE_DIR) ? DT_DIR : DT_REG /*Regular file*/; de->d_name[255] = 0; diff --git a/tests/dirent/test_readdir.c b/tests/dirent/test_readdir.c index 6d3847ba5..cd929b957 100644 --- a/tests/dirent/test_readdir.c +++ b/tests/dirent/test_readdir.c @@ -43,7 +43,7 @@ void cleanup() { void test() { int err; - long loc; + long loc, loc2; DIR *dir; struct dirent *ent; struct dirent ent_r; @@ -118,11 +118,9 @@ void test() { ent = readdir(dir); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); loc = telldir(dir); -#ifndef __EMSCRIPTEN__ - // TODO(https://github.com/emscripten-core/emscripten/issues/8526): Implement telldir/seekdir - assert(loc > 0); + assert(loc >= 0); //printf("loc=%d\n", loc); -#endif + loc2 = ent->d_off; ent = readdir(dir); char name_at_loc[1024]; strcpy(name_at_loc, ent->d_name); @@ -133,11 +131,14 @@ void test() { seekdir(dir, loc); ent = readdir(dir); assert(ent); -#ifndef __EMSCRIPTEN__ - // TODO(https://github.com/emscripten-core/emscripten/issues/8526: Implement telldir/seekdir //printf("check: %s / %s\n", ent->d_name, name_at_loc); assert(!strcmp(ent->d_name, name_at_loc)); -#endif + + seekdir(dir, loc2); + ent = readdir(dir); + assert(ent); + //printf("check: %s / %s\n", ent->d_name, name_at_loc); + assert(!strcmp(ent->d_name, name_at_loc)); // // do a normal read with readdir_r diff --git a/tests/test_other.py b/tests/test_other.py index 91479b0b6..22051ab60 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -4276,12 +4276,12 @@ int main(int argc, char **argv) { 1: make /: -1 open /: 1 - proc, 4 - dev, 4 - home, 4 - tmp, 4 - .., 4 ., 4 + .., 4 + tmp, 4 + home, 4 + dev, 4 + proc, 4 ''', run_js('a.out.js', args=['/'])) # cannot create empty name, cannot open self.assertContained(r''' @@ -4294,21 +4294,21 @@ int main(int argc, char **argv) { 1: make /a//: 0 open /a//: 1 - .., 4 ., 4 + .., 4 ''', run_js('a.out.js', args=['/a//'])) # can create child unnormalized self.assertContained(r''' 1: make /a: 0 open /a: 1 - .., 4 ., 4 + .., 4 2: make /a//b//: 0 open /a//b//: 1 - .., 4 ., 4 + .., 4 ''', run_js('a.out.js', args=['/a', '/a//b//'])) def test_stat_silly(self): @@ -4500,17 +4500,17 @@ int main() # cannot symlink nonexistents self.assertContained(r'''Before: dir - e - d - c - b a + b + c + d + e -Unlinking e -Unlinking d -Unlinking c -Unlinking b Unlinking a +Unlinking b +Unlinking c +Unlinking d +Unlinking e After: dir ''', run_js('a.out.js', args=['', 'abc']))