diff options
Diffstat (limited to 'std/wasi')
-rw-r--r-- | std/wasi/README.md | 2 | ||||
-rw-r--r-- | std/wasi/snapshot_preview1.ts | 105 | ||||
-rw-r--r-- | std/wasi/testdata/std_fs_read_dir.rs | 9 |
3 files changed, 102 insertions, 14 deletions
diff --git a/std/wasi/README.md b/std/wasi/README.md index 70149c771..06dc36ff5 100644 --- a/std/wasi/README.md +++ b/std/wasi/README.md @@ -27,7 +27,7 @@ This module provides an implementation of the WebAssembly System Interface - [x] fd_prestat_dir_name - [x] fd_pwrite - [x] fd_read -- [ ] fd_readdir +- [x] fd_readdir - [x] fd_renumber - [x] fd_seek - [x] fd_sync diff --git a/std/wasi/snapshot_preview1.ts b/std/wasi/snapshot_preview1.ts index e42d7eec2..72ddd5d23 100644 --- a/std/wasi/snapshot_preview1.ts +++ b/std/wasi/snapshot_preview1.ts @@ -317,15 +317,12 @@ export default class Module { if (options.preopens) { for (const [vpath, path] of Object.entries(options.preopens)) { - const info = Deno.statSync(path); - if (!info.isDirectory) { - throw new TypeError(`${path} is not a directory`); - } - const type = FILETYPE_DIRECTORY; + const entries = Array.from(Deno.readDirSync(path)); const entry = { type, + entries, path, vpath, }; @@ -485,7 +482,10 @@ export default class Module { return ERRNO_BADF; } - entry.handle.close(); + if (entry.handle) { + entry.handle.close(); + } + delete this.fds[fd]; return ERRNO_SUCCESS; @@ -797,7 +797,70 @@ export default class Module { cookie: bigint, bufused_out: number ): number => { - return ERRNO_NOSYS; + const entry = this.fds[fd]; + if (!entry) { + return ERRNO_BADF; + } + + const heap = new Uint8Array(this.memory.buffer); + const view = new DataView(this.memory.buffer); + + let bufused = 0; + + try { + const entries = Array.from(Deno.readDirSync(entry.path)); + for (let i = Number(cookie); i < entries.length; i++) { + const name_data = new TextEncoder().encode(entries[i].name); + + const entry_info = Deno.statSync( + resolve(entry.path, entries[i].name) + ); + const entry_data = new Uint8Array(24 + name_data.byteLength); + const entry_view = new DataView(entry_data.buffer); + + entry_view.setBigUint64(0, BigInt(i + 1), true); + entry_view.setBigUint64( + 8, + BigInt(entry_info.ino ? entry_info.ino : 0), + true + ); + entry_view.setUint32(16, name_data.byteLength, true); + + switch (true) { + case entries[i].isFile: + var type = FILETYPE_REGULAR_FILE; + break; + + case entries[i].isDirectory: + var type = FILETYPE_REGULAR_FILE; + break; + + case entries[i].isSymlink: + var type = FILETYPE_SYMBOLIC_LINK; + break; + + default: + var type = FILETYPE_REGULAR_FILE; + break; + } + + entry_view.setUint8(20, type); + entry_data.set(name_data, 24); + + const data = entry_data.slice( + 0, + Math.min(entry_data.length, buf_len - bufused) + ); + heap.set(data, buf_ptr + bufused); + bufused += data.byteLength; + } + } catch (err) { + return errno(err); + } + + view.setUint32(bufused_out, bufused, true); + + return ERRNO_SUCCESS; }, fd_renumber: (fd: number, to: number): number => { @@ -1126,6 +1189,28 @@ export default class Module { const data = new Uint8Array(this.memory.buffer, path_ptr, path_len); const path = resolve(entry.path, text.decode(data)); + if ((oflags & OFLAGS_DIRECTORY) !== 0) { + // XXX (caspervonb) this isn't ideal as we can't get a rid for the + // directory this way so there's no native fstat but Deno.open + // doesn't work with directories on windows so we'll have to work + // around it for now. + try { + const entries = Array.from(Deno.readDirSync(path)); + const opened_fd = + this.fds.push({ + entries, + path, + }) - 1; + + const view = new DataView(this.memory.buffer); + view.setUint32(opened_fd_out, opened_fd, true); + } catch (err) { + return errno(err); + } + + return ERRNO_SUCCESS; + } + const options = { read: false, write: false, @@ -1140,12 +1225,6 @@ export default class Module { options.write = true; } - if ((oflags & OFLAGS_DIRECTORY) !== 0) { - // TODO (caspervonb) review if we can - // emulate this; unix supports opening - // directories, windows does not. - } - if ((oflags & OFLAGS_EXCL) !== 0) { options.createNew = true; } diff --git a/std/wasi/testdata/std_fs_read_dir.rs b/std/wasi/testdata/std_fs_read_dir.rs new file mode 100644 index 000000000..ad8b70c72 --- /dev/null +++ b/std/wasi/testdata/std_fs_read_dir.rs @@ -0,0 +1,9 @@ +// { "preopens": { "/fixture": "fixture" } } + +fn main() { + let entries = std::fs::read_dir("/fixture").unwrap(); + assert_eq!(entries.count(), 4); + + let entries = std::fs::read_dir("/fixture/directory").unwrap(); + assert_eq!(entries.count(), 2); +} |