diff --git a/std/wasi/README.md b/std/wasi/README.md index 3848ae9a62..b81279dbfb 100644 --- a/std/wasi/README.md +++ b/std/wasi/README.md @@ -19,7 +19,7 @@ This module provides an implementation of the WebAssembly System Interface - [x] fd_fdstat_get - [ ] fd_fdstat_set_flags - [ ] fd_fdstat_set_rights -- [ ] fd_filestat_get +- [x] fd_filestat_get - [ ] fd_filestat_set_size - [x] fd_filestat_set_times - [x] fd_pread diff --git a/std/wasi/snapshot_preview1.ts b/std/wasi/snapshot_preview1.ts index 0067499cc4..78b29b968e 100644 --- a/std/wasi/snapshot_preview1.ts +++ b/std/wasi/snapshot_preview1.ts @@ -523,7 +523,76 @@ export default class Module { }, fd_filestat_get: (fd: number, buf_out: number): number => { - return ERRNO_NOSYS; + const entry = this.fds[fd]; + if (!entry) { + return ERRNO_BADF; + } + + const view = new DataView(this.memory.buffer); + + try { + const info = Deno.fstatSync(entry.handle.rid); + + if (entry.type === undefined) { + switch (true) { + case info.isFile: + entry.type = FILETYPE_REGULAR_FILE; + break; + + case info.isDirectory: + entry.type = FILETYPE_DIRECTORY; + break; + + case info.isSymlink: + entry.type = FILETYPE_SYMBOLIC_LINK; + break; + + default: + entry.type = FILETYPE_UNKNOWN; + break; + } + } + + view.setBigUint64(buf_out, BigInt(info.dev ? info.dev : 0), true); + buf_out += 8; + + view.setBigUint64(buf_out, BigInt(info.ino ? info.ino : 0), true); + buf_out += 8; + + view.setUint8(buf_out, entry.type); + buf_out += 8; + + view.setUint32(buf_out, Number(info.nlink), true); + buf_out += 8; + + view.setBigUint64(buf_out, BigInt(info.size), true); + buf_out += 8; + + view.setBigUint64( + buf_out, + BigInt(info.atime ? info.atime.getTime() * 1e6 : 0), + true + ); + buf_out += 8; + + view.setBigUint64( + buf_out, + BigInt(info.mtime ? info.mtime.getTime() * 1e6 : 0), + true + ); + buf_out += 8; + + view.setBigUint64( + buf_out, + BigInt(info.birthtime ? info.birthtime.getTime() * 1e6 : 0), + true + ); + buf_out += 8; + } catch (err) { + return errno(err); + } + + return ERRNO_SUCCESS; }, fd_filestat_set_size: (fd: number, size: bigint): number => { diff --git a/std/wasi/testdata/std_fs_file_metadata.rs b/std/wasi/testdata/std_fs_file_metadata.rs new file mode 100644 index 0000000000..93149fd1c7 --- /dev/null +++ b/std/wasi/testdata/std_fs_file_metadata.rs @@ -0,0 +1,23 @@ +// { "preopens": { "/fixture": "fixture" } } + +fn main() { + let file = std::fs::File::open("/fixture/file").unwrap(); + let metadata = file.metadata().unwrap(); + assert!(metadata.is_file()); + assert!(metadata.len() == 5); + + let file = std::fs::File::open("/fixture/symlink_to_file").unwrap(); + let metadata = file.metadata().unwrap(); + assert!(metadata.is_file()); + assert!(metadata.len() == 5); + + let file = std::fs::File::open("/fixture/directory/file").unwrap(); + let metadata = file.metadata().unwrap(); + assert!(metadata.is_file()); + assert!(metadata.len() == 15); + + let file = std::fs::File::open("/fixture/directory/symlink_to_file").unwrap(); + let metadata = file.metadata().unwrap(); + assert!(metadata.is_file()); + assert!(metadata.len() == 15); +}