std: add fs::rename_noreplace - #162027
valentynkit wants to merge 5 commits into
Conversation
|
Reminder, once the PR becomes ready for a review, use |
|
Added one suggestion to improve the documentation comment. With that suggestion applied, r=me. |
|
@bors delegate+ |
|
✌️ @valentynkit, you can now approve this pull request! If @joshtriplett told you to " |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Unlike `fs::rename`, the destination is never overwritten, returning `ErrorKind::AlreadyExists` if `to` already exists. Platform-specific APIs used: `renameat2` with `RENAME_NOREPLACE` flag on `Linux` and `Android`, `renamex_np` with `RENAME_EXCL` on `Apple`, and `MoveFileExW` without the `MOVEFILE_REPLACE_EXISTING` flag on `Windows`. On other Unix platforms, and on Linux, Android and Apple when the kernel or the filesystem doesn't support it, `link` followed by `unlink` is used instead. Platforms with neither return `Unsupported`.
Co-authored-by: Josh Triplett <josh@joshtriplett.org>
windows-bindgen no longer generates the `MOVE_FILE_FLAGS` alias, so `u32` is used instead.
1e22abe to
7b7ed95
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
|
@rustbot ready Since this change wasn't part of the requested suggestion, I'd rather not approve it myself using the delegation, even so it's straightforward change. Would you mind taking a quick look? |
|
@bors r=joshtriplett,Mark-Simulacrum |
…=joshtriplett,Mark-Simulacrum std: add `fs::rename_noreplace` Tracking issue: rust-lang#161427 Accepted ACP: rust-lang/libs-team#131 ## Summary Add `fs::rename_noreplace`. Unlike `fs::rename`, the destination is never overwritten, instead returns `ErrorKind::AlreadyExists` if `to` already exists. Platform-specific APIs used: - [`renameat2`](https://man7.org/linux/man-pages/man2/renameat2.2.html) with `RENAME_NOREPLACE` flag on Linux and Android - `renamex_np` with `RENAME_EXCL` on Apple - [`MoveFileExW`](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-movefileexw) without the `MOVEFILE_REPLACE_EXISTING` flag on Windows. Extracted functionality into `rename_inner` to avoid duplication for `rename` and `rename_noreplace` - On other Unix platforms and on WASI, and on Linux, Android and Apple when the kernel or the filesystem doesn't support it, `link` followed by `unlink` is used instead. - Platforms with neither return `Unsupported`. Linux and Android case, has different error handling than Apple because the platforms report these conditions differently. On Linux the syscall may not exist at all (`ENOSYS`), and `EINVAL` covers "filesystem doesn't support the flag" and flag misuse (incorrect combinations of flags, as example). On Apple `renamex_np` is called directly, and Darwin use `ENOTSUP` for not supported case, and keeps `EINVAL` only for misuse combinations. > EINVAL An invalid flag was specified in flags. > EINVAL Both RENAME_NOREPLACE and RENAME_EXCHANGE were specified in flags. > EINVAL The filesystem does not support one of the flags in flags. [`renameat2`](https://man7.org/linux/man-pages/man2/renameat2.2.html) ## Open questions 1. `ENOSYS` on Linux and Android could be cached, unlike `EINVAL` case which on the same machine, when using different filesystem may return different result. In this PR I deliberately avoided adding caching to avoid premature optimization, but could add it if you think it worth it. 2. The `link` + `unlink` fallback can't move directories: `link` returns `EPERM`. Should it report `Unsupported` there instead? r? libs
Rollup of 18 pull requests Successful merges: - #158102 (When compiling without a specified `--edition`, emit a message) - #162027 (std: add `fs::rename_noreplace`) - #162761 (Lower attributes for functions without bodies) - #163161 (implement FCW for `rustc_allowed_through_unstable_modules` items) - #163613 (Tweak the rendering of "not general enough" errors on the old trait solver) - #162062 (core: fix the docs of PanicInfo::location) - #163140 (document safety requirements for atomic intrinsics) - #163342 (Don't imply incorrect things about `Global` in the docs of `System`) - #163445 (Add safety comments for alloc::str) - #163503 (Mark Rc strong/weak count methods must_use) - #163548 (fs::set_permissions_nofollow: Android support, test cleanup) - #163585 ([triagebot] Create `debugger_visualizer` assign group) - #163597 (Add `SplitPathsRef` implementation for motor to make std build) - #163602 (Move media & home dirs tests to fs tests.) - #163667 (Finalize changes on expect messages for library/core/src/fmt/mod.rs) - #163682 ([rustdoc] Correctly link to (imported) enum variants with "jump to def") - #163683 (Fix GCC codegen backend comment in bootstrap) - #163703 (Move more `rustdoc-html tests` in the right location) Failed merges: - #161491 (Rip out old solver coherence)
|
|
This pull request was unapproved. This PR was contained in a rollup (#163729), which was unapproved. |
`test_rename_noreplace_directory()` fails on kernels before Linux 3.15, because they lack `renameat2`, so std implementation falls back to `link`/`unlink`, which couldn't move directories, so expectations of the test were wrong. Test now accepts `PermissionDenied` on Unix, in fallback case.
Sorry, my bad for not catching this during implementation. Test was updated to support fallback approach. |
|
@bors try jobs=test-arm-android |
This comment has been minimized.
This comment has been minimized.
std: add `fs::rename_noreplace` try-job: test-arm-android
|
@rustbot ready |
View all comments
Tracking issue: #161427
Accepted ACP: rust-lang/libs-team#131
Summary
Add
fs::rename_noreplace. Unlikefs::rename, the destination is never overwritten, instead returnsErrorKind::AlreadyExistsiftoalready exists.Platform-specific APIs used:
renameat2withRENAME_NOREPLACEflag on Linux and Androidrenamex_npwithRENAME_EXCLon AppleMoveFileExWwithout theMOVEFILE_REPLACE_EXISTINGflag on Windows. Extracted functionality intorename_innerto avoid duplication forrenameandrename_noreplacelinkfollowed byunlinkis used instead.Unsupported.Linux and Android case, has different error handling than Apple because the platforms report these conditions differently. On Linux the syscall may not exist at all (
ENOSYS), andEINVALcovers "filesystem doesn't support the flag" and flag misuse (incorrect combinations of flags, as example). On Applerenamex_npis called directly, and Darwin useENOTSUPfor not supported case, and keepsEINVALonly for misuse combinations.Open questions
ENOSYSon Linux and Android could be cached, unlikeEINVALcase which on the same machine, when using different filesystem may return different result. In this PR I deliberately avoided adding caching to avoid premature optimization, but could add it if you think it worth it.link+unlinkfallback can't move directories:linkreturnsEPERM. Should it reportUnsupportedthere instead?r? libs