-
Notifications
You must be signed in to change notification settings - Fork 1k
fix: copy_dir and copy_file to preserve symlinks instead of following them.
#4671
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
base: main
Are you sure you want to change the base?
Conversation
7ce58b5 to
5460b37
Compare
|
Thanks for making this patch! Reasonable support for external packagers are still expected, and whether a manual setup is required is largely based on the packagers' opinion: https://rust-lang.github.io/rustup/installation/other.html#using-a-package-manager I have the feeling that we need to somehow support both cases based on whether that's copying the original binary or 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.
Do you have a specific use case where rustup is not working as you'd expect, which this PR allows to fix?
If you can find such a case, I agree with using this new implementation except for this:
Line 845 in 3382f6f
| utils::copy_file(&this_exe_path, &rustup_path)?; |
#1521 is probably too widespread as a fix, and it makes perfect sense to use different copy implementations during self installation and during toolchain installation.
Suggest refining the test cases accordingly if going this way.
src/utils/raw.rs
Outdated
| let dest = dest.join(entry.file_name()); | ||
| if kind.is_dir() { | ||
| copy_dir(&src, &dest)?; | ||
| let src_path = entry.path(); |
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.
Nit: src and dest bindings in the loop body are preventing the input params from being used. Thus, I don't see a very convincing reason to rename them here.
I don't, and I only encountered this looking at the code. It's my understanding that copying symlinks breaks their identity and can cause software to load libraries twice (like the crash that was fixed ad-hoc above). It's also just correct behavior afaik;
I would agree with this and will adjust, so long as you think it's a reasonable patch. I figured at the least I could flag this to note the variance in functionality for copy's. |
|
@cachebag Thanks for your clarification. I think although it has no direct influence now, judging by what I'd expect from the function API then indeed, the old behavior feels more correct to me, and leaving it uncorrected might lead to misuse in the long run. Looking back there is still a slight possibility that we could be missing other cases apart from self installation, so I'd say let's go on polishing this patch by carefully analyzing the call sites. Please don't hesitate to ask me if you don't feel certain about anything! |
That makes sense to me, thank you! |
09c35e1 to
f4c5445
Compare
src/utils/mod.rs
Outdated
|
|
||
| /// Copy a file, preserving symlink targets instead of creating a link to the source. | ||
| /// We use this for component installation where internal symlink structure must be maintained. | ||
| pub(crate) fn copy_file_preserving_symlink(src: &Path, dest: &Path) -> Result<()> { |
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.
-
If I'm not mistaken, the new function you have introduced is identical to the old function you have modified, which means you are not distinguishing the two approaches.
To align with the title of your PR, the symlink-preserving
copy_fileshould just be namedcopy_file(). Also, it might not be worth it to duplicate code here since the fact that the function is duplicated without any changes is not very obvious in my review already; try to DRY it up a bit, for example by makingcopy_file()andcopy_file_symlink_to_source()shorthands ofcopy_file_impl(preserve_symlink: bool)calls. -
Also, the tests are not enough to prove the fact that the both functions are working as intended.
You might need to add more tests to demonstrate this point.
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.
Hopefully I followed that train of thought correctly. I should have led with the unified path instead, sorry about that.
As far as tests, do you have suggestions on how to approach that, or specific cases I should be covering?
f4c5445 to
071f34f
Compare
Previously, copy_dir would follow symlinks and copy the target contents. Now it preserves symlinks by reading the link target and creating a new symlink with the same target.
- copy_file() preserves symlinks (for component installation) - copy_file_symlink_to_source() follows symlinks (for self-installation) Uses copy_file in Transaction::copy_file and modify_file. Uses copy_file_symlink_to_source in self_update.rs and windows.rs. Adds regression tests for symlink preservation.
071f34f to
19eada1
Compare
This PR employs symlink preservation in
copy_fileand adds it tocopy_dir.PR #1504 added symlink preservation to fix crashes in lldb-preview, which contains internal symlinks (liblldb was loading twice due to broken symlinks). Then, PR #1521 later changed
copy_fileto create symlinks pointing to the source path (for Homebrew integration), which may have regressed #1504.This PR restores #1504's behavior: read the symlink target and preserve it. What I'm curious about is what the intended behavior for #1521 was because shouldn't users be able to run
rustup-init --no-self-update? Is that not the recommended way to managerustupvia external package managers?If this PR steers out of scope of the goals of
rustupI'm happy to close it but I feel like the former behavior is preferable for most use cases.