-
Notifications
You must be signed in to change notification settings - Fork 24
Description
Proposal
Add std::fs::rename_noreplace, which is equivalent to std::fs::rename but with the semantic that an existing target location will never be overwritten and always yield an error instead.
Problem statement
There is no easy way to rename/move a file without accidentally overwriting the target location should it exist. There is no way to emulate the desired behavior in an atomic way, meaning that all workarounds suffer from TOCTTOU issues.
Motivation, use-cases
It is a common pattern for software to do file system writes into a temporary location next to the target and then move it in place once it is ready. This is useful because move operations are atomic. In many cases overwriting the target when it exists is a desired semantic, but in some cases it is not.
For example when extracting a compressed directory, the software would first extract the content into a temporary location then move it over. When destination files exist, it wants to handle it in some special way (e.g. chose a different name or ask the user). The existence check needs to be done atomically with the move operation, otherwise race hazards may occur.
Solution sketches
A new function std::fs::rename_noreplace is introduced. On Linux, it defers to the renameat2 syscall with the RENAME_NOREPLACE flag set. On MacOS, it uses the renameatx_np call with RENAME_EXCL. On Windows, this is the default behavior so the MOVEFILE_REPLACE_EXISTING need to be omitted.
I could not find any equivalent syscall on non-Linux unix systems (*BSD), and don't know how to deal with that aspect.
Alternatively, we could change the semantics of the current rename function (they are explicitly documented as unstable), and optionally add a rename_replace command.
As a second alternative, we could expose more of the platform specific syscalls: for example, Linux renameat2 also has a flag for atomically swapping two paths.
Links and related work
https://internals.rust-lang.org/t/rename-file-without-overriding-existing-target/17637
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.