xia-chao opened PR #14420 from xia-chao:fix-wasi-dir-set-times to bytecodealliance:main:
Setting times on a directory descriptor fails with bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened directories are held open with O_PATH, and set_times called std::fs::File::set_times on that raw descriptor. On Linux that is futimens, which returns EBADF for an O_PATH fd. The same directory opened O_RDONLY sets its times fine, so the problem is O_PATH, not the directory.
The descriptor is otherwise fine: fd_filestat_get and stat succeed on it and report a directory, and the doc comment for fd_filestat_set_times says it adjusts an open file or directory.
Fixed by adding set_times_on_fd, which uses utimensat with an empty path and AT_EMPTY_PATH on Linux and Android so the call acts on the descriptor itself. Other platforms are unchanged.
Reproduced with a preview 1 module and a wasm32-wasip2 component calling set-times on the preopen.
xia-chao requested rvolosatovs for a review on PR #14420.
xia-chao requested wasmtime-wasi-reviewers for a review on PR #14420.
xia-chao edited PR #14420:
Setting times on a directory descriptor fails with bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened directories are held open with O_PATH, and set_times called std::fs::File::set_times on that raw descriptor. On Linux that is futimens, which returns EBADF for an O_PATH fd. The same directory opened O_RDONLY sets its times fine, so the problem is O_PATH, not the directory.
The descriptor is otherwise fine: fd_filestat_get and stat succeed on it and report a directory, and the doc comment for fd_filestat_set_times says it adjusts an open file or directory.
Fixed by adding set_times_on_fd, which uses utimensat with an empty path and AT_EMPTY_PATH on Linux and Android so the call acts on the descriptor itself. Other platforms are unchanged.
xia-chao edited PR #14420:
Setting times on a directory fd gives bad-descriptor, on both fd_filestat_set_times and descriptor.set-times. Hit it from a preview 1 module and a wasm32-wasip2 component calling set-times on the preopen.
Preopened dirs are held open with O_PATH, and set_times was calling File::set_times on that fd. On Linux that's futimens, which just answers EBADF for O_PATH. Open the same dir with O_RDONLY instead and it works, so O_PATH is what trips it.
The fd isn't actually bad. fd_filestat_get and stat both succeed on it and report a directory.
Fix is a new set_times_on_fd that does utimensat with an empty path and AT_EMPTY_PATH on Linux and Android, and leaves the other platforms on File::set_times. FreeBSD probably needs the same treatment but I have no way to test it there.
xia-chao edited PR #14420:
Setting times on a directory fd gives bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened dirs are held open with O_PATH. futimens returns EBADF on those, and that's what set_times ended up calling. The fd isn't bad - stat and fd_filestat_get both work on it.
Fix does utimensat with an empty path and AT_EMPTY_PATH on Linux/Android. FreeBSD probably needs the same, but I can't test it there.
xia-chao edited PR #14420:
Setting times on a directory fd gives bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened dirs are held open with O_PATH. futimens returns EBADF on those, and that's what set_times ended up calling. The fd isn't bad - stat and fd_filestat_get both work on it.
Fix does utimensat with an empty path and AT_EMPTY_PATH on Linux/Android.
github-actions[bot] added the label wasi on PR #14420.
:memo: alexcrichton submitted PR review:
Thanks! Could you be sure to add some tests for this too?
:speech_balloon: alexcrichton created PR review comment:
To avoid 3x duplication of this code could the file/dir branches here both go to
filesystem::primitives, a wrapper there has the libstd-based versions, and there could be aset_times_fastperhaps which is conditionally defined for linux/android in a similar manner to some other functions in that module?
alexcrichton unassigned rvolosatovs from PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH.
alexcrichton requested alexcrichton for a review on PR #14420.
xia-chao commented on PR #14420:
Yep, will rework and add tests.
xia-chao edited a comment on PR #14420:
will rework and add tests.
xia-chao edited a comment on PR #14420:
Yep, will rework and add tests.
xia-chao updated PR #14420.
xia-chao requested wasmtime-core-reviewers for a review on PR #14420.
xia-chao commented on PR #14420:
Done
:thumbs_up: alexcrichton submitted PR review.
alexcrichton has enabled auto merge for PR #14420.
xia-chao commented on PR #14420:
Would you mind having a look at #14391 when you get a chance?
https://github.com/bytecodealliance/wasmtime/pull/14391
xia-chao edited a comment on PR #14420:
Would you mind having a look at #14391 when you get a chance?
xia-chao deleted a comment on PR #14420:
Would you mind having a look at #14391 when you get a chance?
alexcrichton has disabled auto merge for PR #14420.
xia-chao updated PR #14420.
xia-chao edited PR #14420:
Setting times on a directory fd gives bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened dirs are held open with O_PATH. futimens returns EBADF on those, and that's what set_times ended up calling. The fd isn't bad - stat and fd_filestat_get both work on it.
Fix does utimensat with an empty path and AT_EMPTY_PATH on Linux/Android.
The preview 1 adapter had its own copy of this - it looked the fd up with get_file, so a directory never got that far.
xia-chao commented on PR #14420:
Added a test that sets times on the scratch directory fd.
xia-chao edited a comment on PR #14420:
CI then failed on the adapter path - it had the same problem, looking the fd up with get_file. Fixed there too, so the diff now touches the adapter.
xia-chao edited a comment on PR #14420:
Pushed one more commit - CI caught a second copy of this in the adapter. Fixed that one too.
alexcrichton added PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH to the merge queue.
github-merge-queue[bot] removed PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH from the merge queue.
xia-chao commented on PR #14420:
Looks like the merge queue tripped on a flake - "Text file busy" in cranelift-isle-veri-caching. Nothing to do with this PR. Mind re-queueing?
xia-chao edited a comment on PR #14420:
Looks like the merge queue tripped on a flake
"Text file busy" in cranelift-isle-veri-caching. Nothing to do with this PR. Mind re-queueing?
alexcrichton added PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH to the merge queue.
github-merge-queue[bot] removed PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH from the merge queue.
xia-chao updated PR #14420.
xia-chao updated PR #14420.
xia-chao edited PR #14420:
Setting times on a directory fd gives bad-descriptor, on both fd_filestat_set_times and descriptor.set-times.
Preopened dirs are held open with O_PATH. futimens returns EBADF on those, and that's what set_times ended up calling. The fd isn't bad - stat and fd_filestat_get both work on it.
Fix does utimensat with an empty path and AT_EMPTY_PATH on Linux/Android.
The preview 1 adapter had its own copy of this - it looked the fd up with get_file, so a directory never got that far.
Note: FreeBSD also opens preopened dirs with O_PATH, so it likely has the same problem - I left it alone since CI only checks the build there.
xia-chao commented on PR #14420:
My bad, the MinGW one is my test - it shouldn't run on Windows at all, the scratch dir is read-only there. Guarded like the test above. Kick it again?
alexcrichton added PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH to the merge queue.
:check: alexcrichton merged PR #14420.
alexcrichton removed PR #14420 wasi: fix set-times on directory descriptors opened with O_PATH from the merge queue.
Last updated: Oct 11 2026 at 04:10 UTC