-
Notifications
You must be signed in to change notification settings - Fork 30
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
fix: avoid cross-device link errors while moving files #453
Conversation
`fs::rename` does not work on Linux when the source and destinations are at different mount points. This commit mitigates this by using copy + delete instead of move for cases like this.
Coincidentally just today I added code to rattler to detect if two files/directories share the same filesystem. see https://github.com/mamba-org/rattler/blob/02e68c9539c6009cc1370fbf46dc69ca5361d12d/crates/rattler/src/install/mod.rs#L562 . Would that be an option instead of the (imho hacky) string comparison? |
I think rattler also already depends on libc so we might consider adding that dependency. Also isnt EXDEV just a constant? |
I wonder if this is also a problem on macOS? |
Oh, nice! Will try that.
Yes, the problem that I faced was
According to the docs:
Since macOS is Unix based, it might be. Assuming you're on mac, maybe give it a try with the snippet I shared 🐻 |
I think by default on macOS the temporary files are created in the home folder and live on the same fs, so it's usually not a problem. But if I had two different partitions I believe it would show the same behavior. I did run your snippet, and that was running fine :) |
I applied @baszalmstra's suggestion in 20d3122 One thing that I needed to do was create the file/directory before checking the metadata since it fails if the path does not exist. |
Hmm, I believe on Windows we would have the same issue if we try to rename a file from I am wondering if we should opt for a simpler solution. Either extract somewhere adjacent to the final location (instead of the tempfile). For the |
I'm wondering if we can directly extract to the final location. I don't know why it is extracted into temp in the first place.
I can try to use that after we decide which way we want to go 🐻 |
checking if two paths share the same drive on windows is relatively simple. I also implemented that in the code I linked previously. |
@baszalmstra do you prefer doing that or just having a temp folder inside the |
Does that still provide out of source builds? If so the simplicity of that approach makes a lot of sense to me. |
Created #456 |
Background
#447 changed the archive extraction logic to:
/tmp
)However, step 2 uses
fs::rename
which poses a potential issue on Linux systems:We can demonstrate this with the following snippet:
This is because
/tmp
is a different mount point than~/
.The issue
Due to the reason above,
rattler-build build
is not able to move the extracted files for me:This PR simply fixes that issue by copying + deleting files instead of moving for Linux systems.
Error type
Rust throws
std::io::ErrorKind::CrossesDevices
for this case. However, we can directly check this type because it is gated behind#![feature(io_error_more)]
feature. What we can do is enable this feature for the crate but this means that we will need the nightly compiler for builds. I don't think this is feasible.Another thing that we can do is to check
libc::EXDEV
error type:This means adding the
libc
dependency... so let's not do that.For additional context, see the "renaming directories" section of the Kernel documentation.
Long story short, I find it most applicable to have a simple string check until
io_error_more
feature is stabilized:Additional context
The implementation is heavily inspired by
rustup
: https://github.com/rust-lang/rustup/blob/3b0ae079d91144ea9cf99a5fc6d493701a160823/src/utils/utils.rs#L566Here is a related discussion: rust-lang/rustup#1239
🐻