std::fs::rename
sometimes fails on Windows due to missing FILE_RENAME_POSIX_SEMANTICS
#123985
Description
When opening a file on Windows, the default flags indicate sharing for read, write and delete. If you attempt to atomically rename a file over another file while it is being read, however, this results in an access-denied error despite the expectation that those access flags would allow for this to occur.
This makes all attempts at writing atomic-file-replace operations extremely racy and difficult to get right on Windows, while working as expected on other platforms.
By default, Rust's stdlib rename should make use of the new FILE_RENAME_POSIX_SEMANTICS
when available. This will allow a file to stay open while the underlying file is atomically replaced with new contents.
This surfaced recently in Deno as a failure in the DiskCache
implementation on Windows (https://github.com/denoland/deno/blob/main/cli/cache/disk_cache.rs#L123). If a file is being read at the same time an atomic write happens on another thread, the write operation fails with an "access denied" error, but only on Windows.
Justification
There is precedent for using POSIX semantics on Windows by default: for example, recursive directory deletes use this where available, and junction points (implemented in #121709) are created with POSIX semantics.
In addition, users can opt out of POSIX rename semantics by opening files without the DELETE
sharing mode.
API Background
As of Windows 10 1709 and later, a new FILE_RENAME_POSIX_SEMANTICS
flag is available for the FileRenameInformationEx
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntsetinformationfile
Related bugs in other frameworks
Activity