Skip to content

Conversation

@nhz2
Copy link
Member

@nhz2 nhz2 commented Aug 5, 2024

As noted in #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 #36638 (comment)

@giordano giordano added the filesystem Underlying file system and functions that use it label Aug 5, 2024
@nhz2 nhz2 marked this pull request as ready for review August 6, 2024 03:44
@nhz2 nhz2 requested review from kpamnany and vtjnash August 6, 2024 14:42
Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great!

@vtjnash vtjnash merged commit 57aef91 into JuliaLang:master Aug 8, 2024
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)
Copy link
Member

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)

Copy link
Member Author

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.

Copy link
Member

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.

@nhz2 nhz2 deleted the more-atomic-mv branch August 14, 2024 03:26
lazarusA pushed a commit to lazarusA/julia that referenced this pull request Aug 17, 2024
…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)
LilithHafner pushed a commit that referenced this pull request Aug 31, 2024
KristofferC pushed a commit that referenced this pull request Sep 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

filesystem Underlying file system and functions that use it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants