diff --git a/emcc.py b/emcc.py index 38fb44da6f3d..4c1c1836e011 100755 --- a/emcc.py +++ b/emcc.py @@ -2338,6 +2338,8 @@ def phase_linker_setup(options, state, newargs): '_wasmfs_read', '_wasmfs_pread', '_wasmfs_symlink', + '_wasmfs_truncate', + '_wasmfs_ftruncate', '_wasmfs_stat', '_wasmfs_lstat', '_wasmfs_chmod', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 72490ec2477e..ee881ded6215 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -279,8 +279,12 @@ FS.createPreloadedFile = FS_createPreloadedFile; // TDOO: chown // TODO: lchown // TODO: fchown - // TODO: truncate - // TODO: ftruncate + truncate: (path, len) => { + return FS.handleError(withStackSave(() => (__wasmfs_truncate(stringToUTF8OnStack(path), {{{ splitI64('len') }}})))); + }, + ftruncate: (fd, len) => { + return FS.handleError(__wasmfs_ftruncate(fd, {{{ splitI64('len') }}})); + }, // TODO: utime findObject: (path) => { var result = __wasmfs_identify(path); diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index b154f4bf7c65..5fdc8545ddde 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -223,6 +223,14 @@ int _wasmfs_pread(int fd, void *buf, size_t count, off_t offset) { return numBytes; } +int _wasmfs_truncate(char* path, off_t length) { + return __syscall_truncate64((intptr_t)path, length); +} + +int _wasmfs_ftruncate(int fd, off_t length) { + return __syscall_ftruncate64(fd, length); +} + int _wasmfs_close(int fd) { return __wasi_fd_close(fd); } diff --git a/test/fs/test_fs_js_api.c b/test/fs/test_fs_js_api.c index 5503be3611fe..dae0daa0875a 100644 --- a/test/fs/test_fs_js_api.c +++ b/test/fs/test_fs_js_api.c @@ -4,6 +4,70 @@ #include #include +void test_fs_truncate() { + EM_ASM( + FS.writeFile('truncatetest', 'a=1\nb=2\n'); + ); + + struct stat s; + stat("truncatetest", &s); + assert(s.st_size == 8); + + EM_ASM( + FS.truncate('truncatetest', 2); + ); + stat("truncatetest", &s); + assert(s.st_size == 2); + + EM_ASM( + FS.truncate('truncatetest', 10); + ); + stat("truncatetest", &s); + assert(s.st_size == 10); + + EM_ASM( + var truncateStream = FS.open('truncatetest', 'w'); + FS.ftruncate(truncateStream.fd, 4); + ); + stat("truncatetest", &s); + assert(s.st_size == 4); + + EM_ASM( + var ex; + try { + FS.truncate('truncatetest', -10); + } catch(err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 28 /* EINVAL */); + + try { + var truncateStream = FS.open('truncatetest', 'w'); + FS.ftruncate(truncateStream.fd, -10); + } catch(err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 28 /* EINVAL */); + + try { + FS.truncate('nonexistent', 10); + } catch(err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 44 /* ENOENT */); + + var ex; + try { + FS.ftruncate(99, 10); + } catch(err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 8 /* EBADF */); + ); + + remove("truncatetest"); +} + int main() { /********** test FS.open() **********/ EM_ASM( @@ -201,6 +265,8 @@ int main() { assert(S_ISREG(stats.st_mode)); assert(stats.st_mode & 0400); + test_fs_truncate(); + remove("mknodtest"); remove("createtest"); remove("testfile");