Skip to content

fs: rename_exclusive (renameat2 + Windows impl)#415

Draft
joshuamegnauth54 wants to merge 1 commit into
bytecodealliance:mainfrom
joshuamegnauth54:rename-exclusive
Draft

fs: rename_exclusive (renameat2 + Windows impl)#415
joshuamegnauth54 wants to merge 1 commit into
bytecodealliance:mainfrom
joshuamegnauth54:rename-exclusive

Conversation

@joshuamegnauth54

Copy link
Copy Markdown

Closes: #406

POSIX's rename atomically replaces targets. However, if a caller wants to optionally replace a target, they have to check if the target exists and then rename onto the target. This sequence of events is subject to TOCTOU where the target may be created between the check and the call to rename().

renameat2 for some of the Unixes and MoveFileExW on Windows both support atomically checking if a target exists on rename. renameat2 is supported on Linux, FreeBSD 16 (not exposed yet in libc), Redox, and macOS.


I tested this on Linux but not Windows. I wrote the Windows code by looking up examples and using Microsoft's documentation. rename_excl_unchecked reuses the existing rename_unchecked code but calls renameat2 instead on Unix. I copied Rustix's feature gates for Unix. FreeBSD 16-CURRENT supports renameat2, so it can be enabled whenever it's released and Rust's libc and Rustix gains wrappers for it.

The Windows version supports moving files across volumes. It seemed like the correct thing to do and MoveFileExW supports it natively. The problem is that file security isn't moved/copied, so it has to manually stored and then restored. The Windows code is significantly shorter without this feature. It's only one call to MoveFileExW without it. 😹

Anyway, I'm relying on CI to yell at me if the Windows code is incorrect. I tried to be really careful as well as write a lot of comments to document my thinking. The Unix code is straightforward, though.

Windows sources:

Closes: bytecodealliance#406

POSIX's `rename` atomically replaces targets. However, if a caller wants
to optionally replace a target, they have to check if the target exists
and then rename onto the target. This sequence of events is subject to
TOCTOU where the target may be created between the check and the call to
rename().

`renameat2` for some of the Unixes and MoveFileExW on Windows both
support atomically checking if a target exists on rename. `renameat2` is
supported on Linux, FreeBSD 16 (not exposed yet in libc), Redox, and
macOS.
@joshuamegnauth54 joshuamegnauth54 marked this pull request as draft July 2, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support for renameat2?

1 participant