-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Make mv more atomic by trying rename before deleting dst
#55384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
vtjnash
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great!
| function _mv_noreplace(src::AbstractString, dst::AbstractString) | ||
| # Error if dst exists. | ||
| # This check currently has TOCTTOU issues. | ||
| checkfor_mv_cp_cptree(src, dst, "moving"; force=false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could add this as a flags argument to libuv uv_fs_rename, since many kernels seem to support it now (and it could be emulated with this TOCTOU in the event the kernel does not)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found a discussion about
adding this to rust at rust-lang/libs-team#131
Also, https://man7.org/linux/man-pages/man2/rename.2.html says "RENAME_NOREPLACE requires support from the underlying filesystem." but I don't understand how to check if a specific file system supports this, or exactly what happens if the filesystem doesn't support the flag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably EINVAL:
EINVAL The filesystem does not support one of the flags in flags.
…ng#55384) As noted in JuliaLang#41584 and https://discourse.julialang.org/t/safe-overwriting-of-files/117758/3 `mv` is usually expected to be "best effort atomic". Currently calling `mv` with `force=true` calls `checkfor_mv_cp_cptree(src, dst, "moving"; force=true)` before renaming. `checkfor_mv_cp_cptree` will delete `dst` if exists and isn't the same as `src`. If `dst` is an existing file and julia stops after deleting `dst` but before doing the rename, `dst` will be removed but will not be replaced with `src`. This PR changes `mv` with `force=true` to first try rename, and only delete `dst` if that fails. Assuming file system support and the first rename works, julia stopping will not lead to `dst` being removed without being replaced. This also replaces a stopgap solution from JuliaLang#36638 (comment)
As noted in #41584 and https://discourse.julialang.org/t/safe-overwriting-of-files/117758/3
mvis usually expected to be "best effort atomic".Currently calling
mvwithforce=truecallscheckfor_mv_cp_cptree(src, dst, "moving"; force=true)before renaming.checkfor_mv_cp_cptreewill deletedstif exists and isn't the same assrc.If
dstis an existing file and julia stops after deletingdstbut before doing the rename,dstwill be removed but will not be replaced withsrc.This PR changes
mvwithforce=trueto first try rename, and only deletedstif that fails. Assuming file system support and the first rename works, julia stopping will not lead todstbeing removed without being replaced.This also replaces a stopgap solution from #36638 (comment)