Repository: tetratelabs/wazero
Pull request #1161 (2023-02-24 06:07:40)

wasi: shares more cached stat info to reduce impact of inode requirement
We formerly cached only the directory type, to avoid re-stat'ing the same directory many times. Since we are there, we can also cache the inode, which is strictly required by wasi and costly to fetch. Note: this only affects the directory: its contents still need a potential fan-out of stats which will be handled in another change.

```
goos: darwin
goarch: arm64
pkg: github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1
                                      │    old.txt    │               new.txt                │
                                      │    sec/op     │    sec/op     vs base                │
_fdReaddir/embed.FS-12                   1.607µ ± ∞ ¹   1.547µ ± ∞ ¹  -3.73% (p=0.032 n=5)
_fdReaddir/embed.FS_-_continued-12       1.119µ ± ∞ ¹   1.125µ ± ∞ ¹       ~ (p=0.690 n=5)
_fdReaddir/os.DirFS-12                  10.377µ ± ∞ ¹   9.777µ ± ∞ ¹  -5.78% (p=0.008 n=5)
_fdReaddir/os.DirFS_-_continued-12       2.648µ ± ∞ ¹   2.555µ ± ∞ ¹       ~ (p=0.151 n=5)
_fdReaddir/sysfs.DirFS-12                10.46µ ± ∞ ¹
_fdReaddir/sysfs.DirFS_-_continued-12    2.594µ ± ∞ ¹
geomean                                  3.320µ         2.568µ        -3.15%               ²

                                      │    old.txt    │                new.txt                │
                                      │     B/op      │     B/op       vs base                │
_fdReaddir/embed.FS-12                    784.0 ± ∞ ¹     784.0 ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/embed.FS_-_continued-12        592.0 ± ∞ ¹     592.0 ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/os.DirFS-12                  3.180Ki ± ∞ ¹   2.977Ki ± ∞ ¹  -6.39% (p=0.008 n=5)
_fdReaddir/os.DirFS_-_continued-12      2.477Ki ± ∞ ¹   2.477Ki ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/sysfs.DirFS-12               3.180Ki ± ∞ ¹
_fdReaddir/sysfs.DirFS_-_continued-12   2.477Ki ± ∞ ¹
geomean                                 1.737Ki         1.344Ki        -1.64%               ³

                                      │   old.txt   │               new.txt               │
                                      │  allocs/op  │  allocs/op   vs base                │
_fdReaddir/embed.FS-12                  18.00 ± ∞ ¹   18.00 ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/embed.FS_-_continued-12      13.00 ± ∞ ¹   13.00 ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/os.DirFS-12                  44.00 ± ∞ ¹   43.00 ± ∞ ¹  -2.27% (p=0.008 n=5)
_fdReaddir/os.DirFS_-_continued-12      34.00 ± ∞ ¹   34.00 ± ∞ ¹       ~ (p=1.000 n=5) ²
_fdReaddir/sysfs.DirFS-12               44.00 ± ∞ ¹
_fdReaddir/sysfs.DirFS_-_continued-12   34.00 ± ∞ ¹
geomean                                 28.39         24.18        -0.57%               ³
```

codefromthecrypt: we are missing a test, as windows fails but others pass this zig test

```
 958/2416 test.Dir.Iterator but dir is deleted during iteration... reached unreachable codeexit status 1
```
codefromthecrypt: isolated the test like this:
```bash
$ zig test  --test-no-exec --enable-cache -target wasm32-wasi  --test-filter "Dir.Iterator but dir is deleted during iteration" --zig-lib-dir ./lib ./lib/std/std.zig
/Users/adrian/oss/zig/zig-cache/o/9791533abbd4e89e6dbfc67f1afd0c4d/test.wasm
$ cp /Users/adrian/oss/zig/zig-cache/o/9791533abbd4e89e6dbfc67f1afd0c4d/test.wasm /tmp
$ cd /tmp
$ wazero run -mount=:/ -hostlogging=filesystem test.wasm
1/40 test_0... OK
2/40 test_0... OK
3/40 test_0... OK
4/40 test_1... OK
5/40 test_0... OK
6/40 test_0... OK
7/40 test_0... OK
8/40 test_0... OK
9/40 test_0... OK
10/40 test_0... OK
11/40 test_0... OK
12/40 test_0... OK
13/40 test_0... OK
14/40 test_0... OK
15/40 test_0... OK
16/40 test_0... OK
17/40 test_0... OK
18/40 test_0... OK
19/40 test_0... OK
20/40 test_0... OK
21/40 test_0... OK
22/40 test_0... OK
23/40 test_0... OK
24/40 test_0... OK
25/40 test_0... OK
26/40 test_0... OK
27/40 test_0... OK
28/40 test_0... OK
29/40 test_0... OK
30/40 test_0... OK
31/40 test.Dir.Iterator but dir is deleted during iteration... ==> wasi_snapshot_preview1.path_create_directory(fd=3,path=zig-cache)
<== errno=EEXIST
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=SYMLINK_FOLLOW,path=zig-cache,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=4,errno=ESUCCESS)
==> wasi_snapshot_preview1.path_create_directory(fd=4,path=tmp)
<== errno=EEXIST
==> wasi_snapshot_preview1.path_open(fd=4,dirflags=SYMLINK_FOLLOW,path=tmp,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=5,errno=ESUCCESS)
==> wasi_snapshot_preview1.path_create_directory(fd=5,path=jP6X3LKDlpT-8IrP)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_open(fd=5,dirflags=SYMLINK_FOLLOW,path=jP6X3LKDlpT-8IrP,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=6,errno=ESUCCESS)
==> wasi_snapshot_preview1.fd_close(fd=4)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_create_directory(fd=6,path=subdir)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_open(fd=6,dirflags=SYMLINK_FOLLOW,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=4,errno=ESUCCESS)
==> wasi_snapshot_preview1.path_create_directory(fd=6,path=subdir/b)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_unlink_file(fd=6,path=subdir)
<== errno=EISDIR
==> wasi_snapshot_preview1.path_open(fd=6,dirflags=,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=7,errno=ESUCCESS)
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1021180,buf_len=1024,cookie=0,result.bufused=1020804)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_open(fd=7,dirflags=,path=b,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=8,errno=ESUCCESS)
==> wasi_snapshot_preview1.fd_readdir(fd=8,buf=1022244,buf_len=1024,cookie=0,result.bufused=1020804)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_readdir(fd=8,buf=1022244,buf_len=1024,cookie=2,result.bufused=1020804)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=8)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_remove_directory(fd=7,path=b)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1021180,buf_len=1024,cookie=3,result.bufused=1020804)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=7)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_remove_directory(fd=6,path=subdir)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=1045948,buf_len=1024,cookie=0,result.bufused=1045620)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=1045948,buf_len=1024,cookie=2,result.bufused=1045620)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=4)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=6)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_unlink_file(fd=5,path=jP6X3LKDlpT-8IrP)
<== errno=EISDIR
==> wasi_snapshot_preview1.path_open(fd=5,dirflags=,path=jP6X3LKDlpT-8IrP,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
<== (opened_fd=4,errno=ESUCCESS)
==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=1021148,buf_len=1024,cookie=0,result.bufused=1020772)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=1021148,buf_len=1024,cookie=2,result.bufused=1020772)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=4)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.path_remove_directory(fd=5,path=jP6X3LKDlpT-8IrP)
<== errno=ESUCCESS
==> wasi_snapshot_preview1.fd_close(fd=5)
<== errno=ESUCCESS
OK
32/40 test_0... OK
33/40 test_0... OK
34/40 test_1... OK
35/40 test_0... OK
36/40 test_0... OK
37/40 test_0... OK
38/40 test_0... OK
39/40 test_0... OK
40/40 test_0... OK
All 40 tests passed.
```

I'll do the same thing on windows.

[test.wasm.zip](https://github.com/tetratelabs/wazero/files/10821451/test.wasm.zip)

codefromthecrypt: lol it passes on my workstation
codefromthecrypt: curious why the GH run can't see the download... my laptop can..

<img width="846" alt="Screenshot 2023-02-24 at 4 14 10 PM" src="https://user-images.githubusercontent.com/64215/221127108-e7421a9c-5fa9-4d56-89ff-3ea951513ccf.png">


evacchi: > curious why the GH run can't see the download... my laptop can..

Do you think we should propagate this to the main fork? it took me a little to figure out https://github.com/evacchi/wazero/pull/4/commits/fb55cea40d31e53d5a9fc13232cc0c511f60aa57
codefromthecrypt: > Do you think we should propagate this to the main fork? it took me a little to figure out https://github.com/evacchi/wazero/commit/fb55cea40d31e53d5a9fc13232cc0c511f60aa57

sure. I'll change the other one
codefromthecrypt: wait if we add ` --repo tetratelabs/wazero` then forks who update the zig or tinygo stuff won't be able to test them (as they don't have access and upstream wouldn't have uploaded yet). am I missing something?
evacchi: > wait if we add ` --repo tetratelabs/wazero` then forks who update the zig or tinygo stuff won't be able to test them (as they don't have access and upstream wouldn't have uploaded yet). am I missing something?

you may be right. Maybe we should add some conditionals 🤔 
codefromthecrypt: looks like with latest zig CI fails even if my workstation doesn't fail on windows. I'll try to debug via CI and mark draft until figured out
codefromthecrypt: here's the windows output.. I'll look at this carefully to see why unreachable

```
970/2123 test.Dir.Iterator but dir is deleted during iteration... ==> wasi_snapshot_preview1.path_create_directory(fd=3,path=zig-cache)
[7788](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7789)
<== errno=EEXIST
[7789](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7790)
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=SYMLINK_FOLLOW,path=zig-cache,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7790](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7791)
<== (opened_fd=7,errno=ESUCCESS)
[7791](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7792)
==> wasi_snapshot_preview1.path_create_directory(fd=7,path=tmp)
[7792](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7793)
<== errno=EEXIST
[7793](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7794)
==> wasi_snapshot_preview1.path_open(fd=7,dirflags=SYMLINK_FOLLOW,path=tmp,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7794](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7795)
<== (opened_fd=8,errno=ESUCCESS)
[7795](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7796)
==> wasi_snapshot_preview1.path_create_directory(fd=8,path=XelMFngXHv396v3x)
[7796](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7797)
<== errno=ESUCCESS
[7797](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7798)
==> wasi_snapshot_preview1.path_open(fd=8,dirflags=SYMLINK_FOLLOW,path=XelMFngXHv396v3x,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7798](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7799)
<== (opened_fd=9,errno=ESUCCESS)
[7799](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7800)
==> wasi_snapshot_preview1.fd_close(fd=7)
[7800](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7801)
<== errno=ESUCCESS
[7801](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7802)
==> wasi_snapshot_preview1.path_create_directory(fd=9,path=subdir)
[7802](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7803)
<== errno=ESUCCESS
[7803](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7804)
==> wasi_snapshot_preview1.path_open(fd=9,dirflags=SYMLINK_FOLLOW,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7804](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7805)
<== (opened_fd=7,errno=ESUCCESS)
[7805](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7806)
==> wasi_snapshot_preview1.path_create_directory(fd=9,path=subdir/b)
[7806](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7807)
<== errno=ESUCCESS
[7807](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7808)
==> wasi_snapshot_preview1.path_unlink_file(fd=9,path=subdir)
[7808](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7809)
<== errno=EISDIR
[7809](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7810)
==> wasi_snapshot_preview1.path_open(fd=9,dirflags=,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7810](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7811)
<== (opened_fd=10,errno=ESUCCESS)
[7811](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7812)
==> wasi_snapshot_preview1.fd_readdir(fd=10,buf=1021180,buf_len=1024,cookie=0,result.bufused=1020804)
[7812](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7813)
<== errno=ESUCCESS
[7813](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7814)
==> wasi_snapshot_preview1.path_open(fd=10,dirflags=,path=b,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7814](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7815)
<== (opened_fd=11,errno=ESUCCESS)
[7815](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7816)
==> wasi_snapshot_preview1.fd_readdir(fd=11,buf=1022244,buf_len=1024,cookie=0,result.bufused=1020804)
[7816](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7817)
<== errno=ESUCCESS
[7817](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7818)
==> wasi_snapshot_preview1.fd_readdir(fd=11,buf=1022244,buf_len=1024,cookie=2,result.bufused=1020804)
[7818](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7819)
<== errno=ESUCCESS
[7819](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7820)
==> wasi_snapshot_preview1.fd_close(fd=11)
[7820](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7821)
<== errno=ESUCCESS
[7821](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7822)
==> wasi_snapshot_preview1.path_remove_directory(fd=10,path=b)
[7822](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7823)
<== errno=ESUCCESS
[7823](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7824)
==> wasi_snapshot_preview1.fd_readdir(fd=10,buf=1021180,buf_len=1024,cookie=3,result.bufused=1020804)
[7824](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7825)
<== errno=ESUCCESS
[7825](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7826)
==> wasi_snapshot_preview1.fd_close(fd=10)
[7826](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7827)
<== errno=ESUCCESS
[7827](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7828)
==> wasi_snapshot_preview1.path_remove_directory(fd=9,path=subdir)
[7828](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7829)
<== errno=ESUCCESS
[7829](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7830)
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1045948,buf_len=1024,cookie=0,result.bufused=1045620)
[7830](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7831)
<== errno=ESUCCESS
[7831](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7832)
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1045948,buf_len=1024,cookie=2,result.bufused=1045620)
[7832](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7833)
<== errno=EBADF
[7833](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7834)
reached unreachable codeexit status 1970/2123 test.Dir.Iterator but dir is deleted during iteration... ==> wasi_snapshot_preview1.path_create_directory(fd=3,path=zig-cache)
[7788](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7789)
<== errno=EEXIST
[7789](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7790)
==> wasi_snapshot_preview1.path_open(fd=3,dirflags=SYMLINK_FOLLOW,path=zig-cache,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7790](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7791)
<== (opened_fd=7,errno=ESUCCESS)
[7791](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7792)
==> wasi_snapshot_preview1.path_create_directory(fd=7,path=tmp)
[7792](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7793)
<== errno=EEXIST
[7793](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7794)
==> wasi_snapshot_preview1.path_open(fd=7,dirflags=SYMLINK_FOLLOW,path=tmp,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7794](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7795)
<== (opened_fd=8,errno=ESUCCESS)
[7795](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7796)
==> wasi_snapshot_preview1.path_create_directory(fd=8,path=XelMFngXHv396v3x)
[7796](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7797)
<== errno=ESUCCESS
[7797](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7798)
==> wasi_snapshot_preview1.path_open(fd=8,dirflags=SYMLINK_FOLLOW,path=XelMFngXHv396v3x,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7798](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7799)
<== (opened_fd=9,errno=ESUCCESS)
[7799](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7800)
==> wasi_snapshot_preview1.fd_close(fd=7)
[7800](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7801)
<== errno=ESUCCESS
[7801](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7802)
==> wasi_snapshot_preview1.path_create_directory(fd=9,path=subdir)
[7802](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7803)
<== errno=ESUCCESS
[7803](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7804)
==> wasi_snapshot_preview1.path_open(fd=9,dirflags=SYMLINK_FOLLOW,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7804](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7805)
<== (opened_fd=7,errno=ESUCCESS)
[7805](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7806)
==> wasi_snapshot_preview1.path_create_directory(fd=9,path=subdir/b)
[7806](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7807)
<== errno=ESUCCESS
[7807](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7808)
==> wasi_snapshot_preview1.path_unlink_file(fd=9,path=subdir)
[7808](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7809)
<== errno=EISDIR
[7809](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7810)
==> wasi_snapshot_preview1.path_open(fd=9,dirflags=,path=subdir,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7810](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7811)
<== (opened_fd=10,errno=ESUCCESS)
[7811](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7812)
==> wasi_snapshot_preview1.fd_readdir(fd=10,buf=1021180,buf_len=1024,cookie=0,result.bufused=1020804)
[7812](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7813)
<== errno=ESUCCESS
[7813](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7814)
==> wasi_snapshot_preview1.path_open(fd=10,dirflags=,path=b,oflags=DIRECTORY,fs_rights_base=FDSTAT_SET_FLAGS|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE,fs_rights_inheriting=FD_DATASYNC|FD_READ|FD_SEEK|FDSTAT_SET_FLAGS|FD_SYNC|FD_TELL|FD_WRITE|FD_ADVISE|FD_ALLOCATE|PATH_CREATE_DIRECTORY|PATH_CREATE_FILE|PATH_LINK_SOURCE|PATH_LINK_TARGET|PATH_OPEN|FD_READDIR|PATH_READLINK|PATH_RENAME_SOURCE|PATH_RENAME_TARGET|PATH_FILESTAT_GET|PATH_FILESTAT_SET_SIZE|PATH_FILESTAT_SET_TIMES|FD_FILESTAT_GET|FD_FILESTAT_SET_SIZE|FD_FILESTAT_SET_TIMES|PATH_SYMLINK|PATH_REMOVE_DIRECTORY|PATH_UNLINK_FILE|POLL_FD_READWRITE,fdflags=)
[7814](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7815)
<== (opened_fd=11,errno=ESUCCESS)
[7815](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7816)
==> wasi_snapshot_preview1.fd_readdir(fd=11,buf=1022244,buf_len=1024,cookie=0,result.bufused=1020804)
[7816](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7817)
<== errno=ESUCCESS
[7817](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7818)
==> wasi_snapshot_preview1.fd_readdir(fd=11,buf=1022244,buf_len=1024,cookie=2,result.bufused=1020804)
[7818](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7819)
<== errno=ESUCCESS
[7819](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7820)
==> wasi_snapshot_preview1.fd_close(fd=11)
[7820](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7821)
<== errno=ESUCCESS
[7821](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7822)
==> wasi_snapshot_preview1.path_remove_directory(fd=10,path=b)
[7822](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7823)
<== errno=ESUCCESS
[7823](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7824)
==> wasi_snapshot_preview1.fd_readdir(fd=10,buf=1021180,buf_len=1024,cookie=3,result.bufused=1020804)
[7824](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7825)
<== errno=ESUCCESS
[7825](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7826)
==> wasi_snapshot_preview1.fd_close(fd=10)
[7826](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7827)
<== errno=ESUCCESS
[7827](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7828)
==> wasi_snapshot_preview1.path_remove_directory(fd=9,path=subdir)
[7828](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7829)
<== errno=ESUCCESS
[7829](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7830)
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1045948,buf_len=1024,cookie=0,result.bufused=1045620)
[7830](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7831)
<== errno=ESUCCESS
[7831](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7832)
==> wasi_snapshot_preview1.fd_readdir(fd=7,buf=1045948,buf_len=1024,cookie=2,result.bufused=1045620)
[7832](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7833)
<== errno=EBADF
[7833](https://github.com/tetratelabs/wazero/actions/runs/4260789712/jobs/7414362935#step:5:7834)
reached unreachable codeexit status 1
```
codefromthecrypt: ok think I got it. 🤞 

Patch:
diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go
index 023a5f18..0c9b4550 100644
--- a/imports/wasi_snapshot_preview1/fs.go
+++ b/imports/wasi_snapshot_preview1/fs.go
@@ -489,6 +489,7 @@ func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) Er
 		}
 	}
 
+	// TODO: this should work against the file descriptor not its last name!
 	if err := f.FS.Utimes(f.Name, atime, mtime); err != nil {
 		return ToErrno(err)
 	}
@@ -841,7 +842,7 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
 		var err error
 		if f, ok := fsc.LookupFile(fd); !ok {
 			return ErrnoBadf
-		} else if dirents, err = dotDirents(f.File); err != nil {
+		} else if dirents, err = dotDirents(f); err != nil {
 			return ToErrno(err)
 		}
 		dir.Dirents = dirents
@@ -851,23 +852,13 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
 	// Check if we have maxDirEntries, and read more from the FS as needed.
 	if entryCount := len(dirents); entryCount < maxDirEntries {
 		l, err := platform.Readdir(rd, maxDirEntries-entryCount)
-		if err == io.EOF { // EOF is not an error
-		} else if err != nil {
-			if errno = ToErrno(err); errno == ErrnoNoent {
-				// Only on Linux platforms, ReadDir returns ErrNotExist for the "removed while opened"
-				// directories. In order to provide consistent behavior, ignore it.
-				// See https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs.zig#L635-L637
-				//
-				// TODO: Once we have our own File type, we should punt this into the behind ReadDir method above.
-			} else {
-				return errno
-			}
-		} else {
-			dir.CountRead += uint64(len(l))
-			dirents = append(dirents, l...)
-			// Replace the cache with up to maxDirEntries, starting at cookie.
-			dir.Dirents = dirents
+		if errno = ToErrno(err); errno != ErrnoSuccess {
+			return errno
 		}
+		dir.CountRead += uint64(len(l))
+		dirents = append(dirents, l...)
+		// Replace the cache with up to maxDirEntries, starting at cookie.
+		dir.Dirents = dirents
 	}
 
 	// Determine how many dirents we can write, excluding a potentially
@@ -899,13 +890,15 @@ func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) Errno {
 
 // dotDirents returns "." and "..", where "." has a real stat because
 // wasi-testsuite does inode validation.
-func dotDirents(f fs.File) ([]*platform.Dirent, error) {
-	var st platform.Stat_t
-	if err := platform.StatFile(f, &st); err != nil {
+func dotDirents(f *sys.FileEntry) ([]*platform.Dirent, error) {
+	ino, ft, err := f.CachedStat()
+	if err != nil {
 		return nil, err
+	} else if ft.Type() != fs.ModeDir {
+		return nil, syscall.ENOTDIR
 	}
 	return []*platform.Dirent{
-		{Name: ".", Ino: st.Ino, Type: fs.ModeDir},
+		{Name: ".", Ino: ino, Type: fs.ModeDir},
 		{Name: "..", Type: fs.ModeDir},
 	}, nil
 }
@@ -1062,7 +1055,9 @@ func writeDirent(buf []byte, dNext uint64, dNamlen uint32, dType bool) {
 func openedDir(fsc *sys.FSContext, fd uint32) (fs.File, *sys.ReadDir, Errno) {
 	if f, ok := fsc.LookupFile(fd); !ok {
 		return nil, nil, ErrnoBadf
-	} else if !f.IsDir() {
+	} else if _, ft, err := f.CachedStat(); err != nil {
+		return nil, nil, ToErrno(err)
+	} else if ft.Type() != fs.ModeDir {
 		// fd_readdir docs don't indicate whether to return ErrnoNotdir or
 		// ErrnoBadf. It has been noticed that rust will crash on ErrnoNotdir,
 		// and POSIX C ref seems to not return this, so we don't either.
@@ -1151,7 +1146,11 @@ func fdSeekFn(_ context.Context, mod api.Module, params []uint64) Errno {
 	if f, ok := fsc.LookupFile(fd); !ok {
 		return ErrnoBadf
 		// fs.FS doesn't declare io.Seeker, but implementations such as os.File implement it.
-	} else if seeker, ok = f.File.(io.Seeker); !ok || f.IsDir() {
+	} else if _, ft, err := f.CachedStat(); err != nil {
+		return ToErrno(err)
+	} else if ft.Type() == fs.ModeDir {
+		return ErrnoBadf
+	} else if seeker, ok = f.File.(io.Seeker); !ok {
 		return ErrnoBadf
 	}
 
@@ -1600,7 +1599,10 @@ func pathOpenFn(_ context.Context, mod api.Module, params []uint64) Errno {
 	if isDir {
 		if f, ok := fsc.LookupFile(newFD); !ok {
 			return ErrnoBadf // unexpected
-		} else if !f.IsDir() {
+		} else if _, ft, err := f.CachedStat(); err != nil {
+			_ = fsc.CloseFile(newFD)
+			return ToErrno(err)
+		} else if ft.Type() != fs.ModeDir {
 			_ = fsc.CloseFile(newFD)
 			return ErrnoNotdir
 		}
@@ -1638,7 +1640,9 @@ func atPath(fsc *sys.FSContext, mem api.Memory, dirFD, path, pathLen uint32) (sy
 
 	if f, ok := fsc.LookupFile(dirFD); !ok {
 		return nil, "", ErrnoBadf // closed
-	} else if !f.IsDir() {
+	} else if _, ft, err := f.CachedStat(); err != nil {
+		return nil, "", ToErrno(err)
+	} else if ft.Type() != fs.ModeDir {
 		return nil, "", ErrnoNotdir
 	} else if f.IsPreopen { // don't append the pre-open name
 		return f.FS, pathName, ErrnoSuccess
@@ -1862,7 +1866,9 @@ func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) Errno {
 	dir, ok := fsc.LookupFile(dirFD)
 	if !ok {
 		return ErrnoBadf // closed
-	} else if !dir.IsDir() {
+	} else if _, ft, err := dir.CachedStat(); err != nil {
+		return ToErrno(err)
+	} else if ft.Type() != fs.ModeDir {
 		return ErrnoNotdir
 	}
 
diff --git a/internal/platform/dir.go b/internal/platform/dir.go
index f9515e54..dd2152bd 100644
--- a/internal/platform/dir.go
+++ b/internal/platform/dir.go
@@ -67,7 +67,8 @@ func (d *Dirent) IsDir() bool {
 // If n > 0, Readdir returns at most n entries or an error.
 // If n <= 0, Readdir returns all remaining entries or an error.
 //
-// Note: The error will be nil or a syscall.Errno. No error is returned on EOF.
+// Note: The error will be nil or a syscall.Errno. There's no error when the
+// file is closed or removed while open. No error is returned on io.EOF.
 func Readdir(f fs.File, n int) (dirents []*Dirent, err error) {
 	// ^^ case format is to match POSIX and similar to os.File.Readdir
 
@@ -76,10 +77,17 @@ func Readdir(f fs.File, n int) (dirents []*Dirent, err error) {
 		var entries []fs.DirEntry
 		entries, err = f.ReadDir(n)
 		if err == io.EOF {
-			err = nil
-		}
-		if err != nil {
-			break
+			err = nil // not an error
+		} else if err = UnwrapOSError(err); err != nil {
+			// Ignore errors when the file was closed or removed.
+			// See https://github.com/ziglang/zig/blob/0.10.1/lib/std/fs.zig#L635-L637
+			switch err {
+			case syscall.EIO, syscall.EBADF: // closed while open
+				err = nil
+			case syscall.ENOENT: // Linux error when removed while open
+				err = nil
+			}
+			return
 		}
 		dirents = make([]*Dirent, 0, len(entries))
 		for _, e := range entries {
@@ -89,6 +97,5 @@ func Readdir(f fs.File, n int) (dirents []*Dirent, err error) {
 	default:
 		err = syscall.ENOTDIR
 	}
-	err = UnwrapOSError(err)
 	return
 }
diff --git a/internal/sys/fs.go b/internal/sys/fs.go
index 692578f9..b8f60ad4 100644
--- a/internal/sys/fs.go
+++ b/internal/sys/fs.go
@@ -163,7 +163,8 @@ type FileEntry struct {
 	// FS is the filesystem associated with the pre-open.
 	FS sysfs.FS
 
-	isDirectory bool
+	// cachedStat includes fields that won't change while a file is open.
+	cachedStat *cachedStat
 
 	// File is always non-nil.
 	File fs.File
@@ -177,21 +178,40 @@ type FileEntry struct {
 	openPerm fs.FileMode
 }
 
-// IsDir returns true if the file is a directory.
-func (f *FileEntry) IsDir() bool {
-	if f.isDirectory {
-		return true
+type cachedStat struct {
+	// Ino is the file serial number, or zero if not available.
+	Ino uint64
+
+	// Type is the same as what's documented on platform.Dirent.
+	Type fs.FileMode
+}
+
+// CachedStat returns the cacheable parts of platform.Stat_t or an error if
+// they couldn't be retrieved.
+func (f *FileEntry) CachedStat() (ino uint64, fileType fs.FileMode, err error) {
+	if f.cachedStat == nil {
+		var st platform.Stat_t
+		if err = f.Stat(&st); err != nil {
+			return
+		}
+		f.cachedStat = &cachedStat{Ino: st.Ino, Type: st.Mode & fs.ModeType}
 	}
-	var stat platform.Stat_t
-	_ = f.Stat(&stat) // Maybe the file hasn't had stat yet.
-	return f.isDirectory
+	return f.cachedStat.Ino, f.cachedStat.Type, nil
 }
 
 // Stat returns the underlying stat of this file.
 func (f *FileEntry) Stat(st *platform.Stat_t) (err error) {
-	err = platform.StatFile(f.File, st)
+	if ld, ok := f.File.(*lazyDir); ok {
+		var sf fs.File
+		if sf, err = ld.file(); err == nil {
+			err = platform.StatFile(sf, st)
+		}
+	} else {
+		err = platform.StatFile(f.File, st)
+	}
+
 	if err == nil {
-		f.isDirectory = st.Mode.IsDir()
+		f.cachedStat = &cachedStat{Ino: st.Ino, Type: st.Mode}
 	}
 	return
 }
@@ -245,20 +265,18 @@ func NewFSContext(stdin io.Reader, stdout, stderr io.Writer, rootFS sysfs.FS) (f
 		preopens := comp.FS()
 		for i, p := range comp.GuestPaths() {
 			fsc.openedFiles.Insert(&FileEntry{
-				FS:          preopens[i],
-				Name:        p,
-				IsPreopen:   true,
-				isDirectory: true,
-				File:        &lazyDir{fs: rootFS},
+				FS:        preopens[i],
+				Name:      p,
+				IsPreopen: true,
+				File:      &lazyDir{fs: rootFS},
 			})
 		}
 	} else {
 		fsc.openedFiles.Insert(&FileEntry{
-			FS:          rootFS,
-			Name:        "/",
-			IsPreopen:   true,
-			isDirectory: true,
-			File:        &lazyDir{fs: rootFS},
+			FS:        rootFS,
+			Name:      "/",
+			IsPreopen: true,
+			File:      &lazyDir{fs: rootFS},
 		})
 	}
 
@@ -330,7 +348,9 @@ func (c *FSContext) ReOpenDir(fd uint32) (*FileEntry, error) {
 	f, ok := c.openedFiles.Lookup(fd)
 	if !ok {
 		return nil, syscall.EBADF
-	} else if !f.IsDir() {
+	} else if _, ft, err := f.CachedStat(); err != nil {
+		return nil, err
+	} else if ft.Type() != fs.ModeDir {
 		return nil, syscall.EISDIR
 	}
 
@@ -364,7 +384,9 @@ func (c *FSContext) ChangeOpenFlag(fd uint32, flag int) error {
 	f, ok := c.LookupFile(fd)
 	if !ok {
 		return syscall.EBADF
-	} else if f.IsDir() {
+	} else if _, ft, err := f.CachedStat(); err != nil {
+		return err
+	} else if ft.Type() == fs.ModeDir {
 		return syscall.EISDIR
 	}
 
diff --git a/internal/wasi_snapshot_preview1/errno.go b/internal/wasi_snapshot_preview1/errno.go
index 4ba41f43..e19e9a69 100644
--- a/internal/wasi_snapshot_preview1/errno.go
+++ b/internal/wasi_snapshot_preview1/errno.go
@@ -266,6 +266,9 @@ var errnoToString = [...]string{
 // error codes. For example, wasi-filesystem and GOOS=js don't map to these
 // Errno.
 func ToErrno(err error) Errno {
+	if err == nil {
+		return ErrnoSuccess
+	}
 	errno := platform.UnwrapOSError(err)
 
 	switch errno {
diff --git a/internal/wasi_snapshot_preview1/logging/logging.go b/internal/wasi_snapshot_preview1/logging/logging.go
index 88c799ac..9e2de87c 100644
--- a/internal/wasi_snapshot_preview1/logging/logging.go
+++ b/internal/wasi_snapshot_preview1/logging/logging.go
@@ -145,7 +145,7 @@ func Config(fnd api.FunctionDefinition) (pSampler logging.ParamSampler, pLoggers
 			logger = logFsRightsBase(idx).Log
 		case "fs_rights_inheriting":
 			logger = logFsRightsInheriting(idx).Log
-		case "result.nread", "result.nwritten", "result.opened_fd", "result.nevents":
+		case "result.nread", "result.nwritten", "result.opened_fd", "result.nevents", "result.bufused":
 			name = resultParamName(name)
 			logger = logMemI32(idx).Log
 			rLoggers = append(rLoggers, resultParamLogger(name, logger))


Test patch:
diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go
index 6e4feff0..9f0a3be0 100644
--- a/imports/wasi_snapshot_preview1/fs_test.go
+++ b/imports/wasi_snapshot_preview1/fs_test.go
@@ -2140,7 +2140,7 @@ func Test_fdReaddir(t *testing.T) {
 }
 
 func Test_fdReaddir_Rewind(t *testing.T) {
-	mod, r, _ := requireProxyModule(t, wazero.NewModuleConfig().WithFS(fstest.FS))
+	mod, r, log := requireProxyModule(t, wazero.NewModuleConfig().WithFS(fstest.FS))
 	defer r.Close(testCtx)
 
 	fsc := mod.(*wasm.CallContext).Sys.FS()
@@ -2191,6 +2191,14 @@ func Test_fdReaddir_Rewind(t *testing.T) {
 	resultBuf, ok = mem.Read(buf, usedAfterRewind)
 	require.True(t, ok)
 	require.Equal(t, dirents, resultBuf)
+	require.Equal(t, `
+==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=8,buf_len=200,cookie=0)
+<== (bufused=129,errno=ESUCCESS)
+==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=8,buf_len=200,cookie=5)
+<== (bufused=0,errno=ESUCCESS)
+==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=8,buf_len=200,cookie=0)
+<== (bufused=129,errno=ESUCCESS)
+`, "\n"+log.String())
 }
 
 func Test_fdReaddir_Errors(t *testing.T) {
@@ -2223,8 +2231,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			bufLen:        1000,
 			expectedErrno: ErrnoFault,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=65536,buf_len=1000,cookie=0,result.bufused=0)
-<== errno=EFAULT
+==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=65536,buf_len=1000,cookie=0)
+<== (bufused=,errno=EFAULT)
 `,
 		},
 		{
@@ -2234,8 +2242,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			resultBufused: 1000, // arbitrary
 			expectedErrno: ErrnoBadf,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=42,buf=0,buf_len=24,cookie=0,result.bufused=1000)
-<== errno=EBADF
+==> wasi_snapshot_preview1.fd_readdir(fd=42,buf=0,buf_len=24,cookie=0)
+<== (bufused=,errno=EBADF)
 `,
 		},
 		{
@@ -2245,8 +2253,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			resultBufused: 1000, // arbitrary
 			expectedErrno: ErrnoBadf,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=0,buf_len=24,cookie=0,result.bufused=1000)
-<== errno=EBADF
+==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=0,buf_len=24,cookie=0)
+<== (bufused=,errno=EBADF)
 `,
 		},
 		{
@@ -2256,8 +2264,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			bufLen:        1000,
 			expectedErrno: ErrnoFault,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=65535,buf_len=1000,cookie=0,result.bufused=0)
-<== errno=EFAULT
+==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=65535,buf_len=1000,cookie=0)
+<== (bufused=,errno=EFAULT)
 `,
 		},
 		{
@@ -2267,8 +2275,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			resultBufused: 1000,
 			expectedErrno: ErrnoInval,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1,cookie=0,result.bufused=1000)
-<== errno=EINVAL
+==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1,cookie=0)
+<== (bufused=,errno=EINVAL)
 `,
 		},
 		{
@@ -2279,8 +2287,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			resultBufused: 2000,
 			expectedErrno: ErrnoInval,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1000,cookie=1,result.bufused=2000)
-<== errno=EINVAL
+==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1000,cookie=1)
+<== (bufused=,errno=EINVAL)
 `,
 		},
 		{
@@ -2292,8 +2300,8 @@ func Test_fdReaddir_Errors(t *testing.T) {
 			resultBufused: 2000,
 			expectedErrno: ErrnoInval,
 			expectedLog: `
-==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1000,cookie=-1,result.bufused=2000)
-<== errno=EINVAL
+==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=1000,cookie=-1)
+<== (bufused=,errno=EINVAL)
 `,
 		},
 	}
@@ -3451,7 +3459,9 @@ func Test_pathOpen(t *testing.T) {
 			expected: func(t *testing.T, fsc *sys.FSContext) {
 				f, ok := fsc.LookupFile(expectedOpenedFd)
 				require.True(t, ok)
-				require.True(t, f.IsDir())
+				_, ft, err := f.CachedStat()
+				require.NoError(t, err)
+				require.Equal(t, fs.ModeDir, ft)
 			},
 			expectedLog: `
 ==> wasi_snapshot_preview1.path_open(fd=3,dirflags=,path=dir,oflags=DIRECTORY,fs_rights_base=,fs_rights_inheriting=,fdflags=)
@@ -3466,7 +3476,9 @@ func Test_pathOpen(t *testing.T) {
 			expected: func(t *testing.T, fsc *sys.FSContext) {
 				f, ok := fsc.LookupFile(expectedOpenedFd)
 				require.True(t, ok)
-				require.True(t, f.IsDir())
+				_, ft, err := f.CachedStat()
+				require.NoError(t, err)
+				require.Equal(t, fs.ModeDir, ft)
 			},
 			expectedLog: `
 ==> wasi_snapshot_preview1.path_open(fd=3,dirflags=,path=dir,oflags=DIRECTORY,fs_rights_base=,fs_rights_inheriting=,fdflags=)
diff --git a/internal/platform/dir_test.go b/internal/platform/dir_test.go
index d04458eb..5b7ec728 100644
--- a/internal/platform/dir_test.go
+++ b/internal/platform/dir_test.go
@@ -3,6 +3,7 @@ package platform_test
 import (
 	"io/fs"
 	"os"
+	"path"
 	"runtime"
 	"sort"
 	"syscall"
@@ -124,14 +125,12 @@ func TestReaddir(t *testing.T) {
 				require.Zero(t, len(dirents))
 			})
 
-			// windows and fstest.MapFS allow you to read a closed dir
-			if runtime.GOOS != "windows" && tc.name != "fstest.MapFS" {
-				t.Run("closed dir", func(t *testing.T) {
-					require.NoError(t, dirF.Close())
-					_, err := platform.Readdir(dirF, -1)
-					require.EqualErrno(t, syscall.EIO, err)
-				})
-			}
+			// Don't err if something else closed the directory while reading.
+			t.Run("closed dir", func(t *testing.T) {
+				require.NoError(t, dirF.Close())
+				_, err := platform.Readdir(dirF, -1)
+				require.NoError(t, err)
+			})
 
 			fileF, err := tc.fs.Open("empty.txt")
 			require.NoError(t, err)
@@ -157,4 +156,28 @@ func TestReaddir(t *testing.T) {
 			})
 		})
 	}
+
+	// Don't err if something else removed the directory while reading.
+	t.Run("removed while open", func(t *testing.T) {
+		dirF, err := dirFS.Open("dir")
+		require.NoError(t, err)
+		defer dirF.Close()
+
+		dirents, err := platform.Readdir(dirF, 1)
+		require.NoError(t, err)
+		require.Equal(t, 1, len(dirents))
+
+		// Speculatively try to remove even if it won't likely work
+		// on windows.
+		err = os.RemoveAll(path.Join(tmpDir, "dir"))
+		if err != nil && runtime.GOOS == "windows" {
+			t.Skip()
+		} else {
+			require.NoError(t, err)
+		}
+
+		_, err = platform.Readdir(dirF, 1)
+		require.NoError(t, err)
+		// don't validate the contents as due to caching it might be present.
+	})
 }
diff --git a/internal/sys/sys_test.go b/internal/sys/sys_test.go
index 6edb7112..88c2727d 100644
--- a/internal/sys/sys_test.go
+++ b/internal/sys/sys_test.go
@@ -2,12 +2,13 @@ package sys
 
 import (
 	"bytes"
+	"io/fs"
 	"testing"
 	"time"
 
+	"github.com/tetratelabs/wazero/internal/fstest"
 	"github.com/tetratelabs/wazero/internal/platform"
 	"github.com/tetratelabs/wazero/internal/sysfs"
-	testfs "github.com/tetratelabs/wazero/internal/testing/fs"
 	"github.com/tetratelabs/wazero/internal/testing/require"
 	"github.com/tetratelabs/wazero/sys"
 )
@@ -28,7 +29,7 @@ func TestContext_WalltimeNanos(t *testing.T) {
 }
 
 func TestDefaultSysContext(t *testing.T) {
-	testFS := sysfs.Adapt(testfs.FS{})
+	testFS := sysfs.Adapt(fstest.FS)
 
 	sysCtx, err := NewContext(
 		0,      // max
@@ -67,17 +68,54 @@ func TestDefaultSysContext(t *testing.T) {
 	expectedOpenedFiles.Insert(noopStdout)
 	expectedOpenedFiles.Insert(noopStderr)
 	expectedOpenedFiles.Insert(&FileEntry{
-		IsPreopen:   true,
-		isDirectory: true,
-		Name:        "/",
-		FS:          testFS,
-		File:        &lazyDir{fs: testFS},
+		IsPreopen: true,
+		Name:      "/",
+		FS:        testFS,
+		File:      &lazyDir{fs: testFS},
 	})
 
 	require.Equal(t, expectedOpenedFiles, expectedFS.openedFiles)
 	require.Equal(t, expectedFS, sysCtx.FS())
 }
 
+func TestFileEntry_cachedStat(t *testing.T) {
+	t.Parallel()
+
+	tmpDir := t.TempDir()
+	require.NoError(t, fstest.WriteTestFiles(tmpDir))
+	dirFS := sysfs.NewDirFS(tmpDir)
+
+	// get the expected inode
+	var st platform.Stat_t
+	require.NoError(t, platform.Stat(tmpDir, &st))
+
+	tests := []struct {
+		name        string
+		fs          sysfs.FS
+		expectedIno uint64
+	}{
+		{name: "sysfs.FS", fs: dirFS, expectedIno: st.Ino},
+		{name: "fs.FS", fs: sysfs.Adapt(fstest.FS), expectedIno: 0},
+	}
+
+	for _, tc := range tests {
+		tc := tc
+
+		t.Run(tc.name, func(t *testing.T) {
+			fsc, _ := NewFSContext(nil, nil, nil, tc.fs)
+			defer fsc.Close(testCtx)
+
+			f, ok := fsc.LookupFile(FdPreopen)
+			require.True(t, ok)
+			ino, ft, err := f.CachedStat()
+			require.NoError(t, err)
+			require.Equal(t, fs.ModeDir, ft)
+			require.Equal(t, tc.expectedIno, ino)
+			require.Equal(t, &cachedStat{Ino: tc.expectedIno, Type: fs.ModeDir}, f.cachedStat)
+		})
+	}
+}
+
 func TestNewContext_Args(t *testing.T) {
 	tests := []struct {
 		name         string