diff --git a/emcc.py b/emcc.py index 549eea562a647..97b615b4866ac 100755 --- a/emcc.py +++ b/emcc.py @@ -2326,6 +2326,7 @@ def phase_linker_setup(options, state, newargs): '_wasmfs_read_file', '_wasmfs_write_file', '_wasmfs_open', + '_wasmfs_allocate', '_wasmfs_close', '_wasmfs_write', '_wasmfs_pwrite', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 48bb8cf00557a..5c4df6481236d 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -189,7 +189,9 @@ FS.createPreloadedFile = FS_createPreloadedFile; return bytesRead; }, - // TODO: allocate + allocate: (stream, offset, length) => { + return FS.handleError(__wasmfs_allocate(stream.fd, {{{ splitI64('offset') }}}, {{{ splitI64('length') }}})); + }, // TODO: mmap // TODO: msync // TODO: munmap diff --git a/system/lib/libc/musl/arch/emscripten/syscall_arch.h b/system/lib/libc/musl/arch/emscripten/syscall_arch.h index bad86ad4e98df..89dcfeadc7188 100644 --- a/system/lib/libc/musl/arch/emscripten/syscall_arch.h +++ b/system/lib/libc/musl/arch/emscripten/syscall_arch.h @@ -96,7 +96,7 @@ int __syscall_fchmodat(int dirfd, intptr_t path, int mode, ...); int __syscall_faccessat(int dirfd, intptr_t path, int amode, int flags); int __syscall_pselect6(int nfds, intptr_t readfds, intptr_t writefds, intptr_t exceptfds, intptr_t timeout, intptr_t sigmaks); int __syscall_utimensat(int dirfd, intptr_t path, intptr_t times, int flags); -int __syscall_fallocate(int fd, int mode, uint64_t off, uint64_t len); +int __syscall_fallocate(int fd, int mode, int64_t off, int64_t len); int __syscall_dup3(int fd, int suggestfd, int flags); int __syscall_pipe2(intptr_t fds, int flags); int __syscall_recvmmsg(int sockfd, intptr_t msgvec, size_t vlen, int flags, ...); diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index 8c58589f234c4..56f9229c2576c 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -129,6 +129,10 @@ int _wasmfs_open(char* path, int flags, mode_t mode) { return __syscall_openat(AT_FDCWD, (intptr_t)path, flags, mode); } +int _wasmfs_allocate(int fd, int64_t off, int64_t len) { + return __syscall_fallocate(fd, 0, off, len); +} + int _wasmfs_mknod(char* path, mode_t mode, dev_t dev) { return __syscall_mknodat(AT_FDCWD, (intptr_t)path, mode, dev); } diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 9eb1e0fb5c33d..0e581d7dabe93 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -1358,7 +1358,7 @@ int __syscall_poll(intptr_t fds_, int nfds, int timeout) { return nonzero; } -int __syscall_fallocate(int fd, int mode, uint64_t off, uint64_t len) { +int __syscall_fallocate(int fd, int mode, int64_t off, int64_t len) { assert(mode == 0); // TODO, but other modes were never supported in the old FS auto fileTable = wasmFS.getFileTable().locked(); diff --git a/test/fs/test_fs_js_api.c b/test/fs/test_fs_js_api.c index dae0daa0875ad..5c6338a7dc485 100644 --- a/test/fs/test_fs_js_api.c +++ b/test/fs/test_fs_js_api.c @@ -4,6 +4,46 @@ #include #include +void test_fs_allocate() { + EM_ASM( + FS.writeFile("allocatetestfile", 'a=1\nb=2\n'); + ); + struct stat allocateStat; + stat("allocatetestfile", &allocateStat); + assert(allocateStat.st_size == 8); + + EM_ASM( + // Allocate more space at the very end. + var stream = FS.open("allocatetestfile", "w"); + FS.allocate(stream, 8, 10); + ); + stat("allocatetestfile", &allocateStat); + assert(allocateStat.st_size == 18); + + EM_ASM( + // Reduce allocated space at the very start. + var stream = FS.open("allocatetestfile", "w"); + FS.allocate(stream, 0, 4); + ); + stat("allocatetestfile", &allocateStat); + assert(allocateStat.st_size == 4); + + EM_ASM( + var stream = FS.open("allocatetestfile", "w"); + + var ex; + try { + // Attempt to allocate negative length. + FS.allocate(stream, 0, -1); + } catch (err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 28 /* EINVAL */); + ); + + remove("allocatetestfile"); +} + void test_fs_truncate() { EM_ASM( FS.writeFile('truncatetest', 'a=1\nb=2\n'); @@ -182,12 +222,11 @@ int main() { FS.mkdir('/dir2'); ); - struct stat s; - stat("/dir1", &s); - assert(S_ISDIR(s.st_mode)); - stat("/dir2", &s); - assert(S_ISDIR(s.st_mode)); - + struct stat rmdirStat; + stat("/dir1", &rmdirStat); + assert(S_ISDIR(rmdirStat.st_mode)); + stat("/dir2", &rmdirStat); + assert(S_ISDIR(rmdirStat.st_mode)); EM_ASM( // Remove the multiple directories @@ -255,15 +294,17 @@ int main() { FS.create("createtest", 0400); /* S_IRUSR */ ); - struct stat stats; - stat("mknodtest", &stats); + struct stat mknodStats; + stat("mknodtest", &mknodStats); + + assert(S_ISREG(mknodStats.st_mode)); + assert(mknodStats.st_mode & 0777); - assert(S_ISREG(stats.st_mode)); - assert(stats.st_mode & 0777); + stat("createtest", &mknodStats); + assert(S_ISREG(mknodStats.st_mode)); + assert(mknodStats.st_mode & 0400); - stat("createtest", &stats); - assert(S_ISREG(stats.st_mode)); - assert(stats.st_mode & 0400); + test_fs_allocate(); test_fs_truncate();