Skip to content

Commit

Permalink
Make entrypoint writes atomic to avoid overwriting symlinks (#5165)
Browse files Browse the repository at this point in the history
## Summary

It turns out that if `path` is a symlink,
`File::create(path)?.write_all(content.as_ref())?` will overwrite the
_target_ file. That means an entrypoint named `python` would actually
overwrite the user's source Python executable, which is symlinked into
the virtual environment.

This PR replaces that code with our atomic write method.

Closes #5152.

## Test Plan

I ran through the test plan
`https://github.com/astral-sh/uv/issues/5152`, but used an executable
named `bar` linked to `foo.txt` instead...
  • Loading branch information
charliermarsh authored Jul 17, 2024
1 parent f74235b commit 8edfdbe
Showing 1 changed file with 14 additions and 2 deletions.
16 changes: 14 additions & 2 deletions crates/install-wheel-rs/src/wheel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,19 @@ fn install_script(
let start = format_shebang(&layout.sys_executable, &layout.os_name)
.as_bytes()
.to_vec();
let mut target = File::create(&script_absolute)?;

let mut target = tempfile::NamedTempFile::new_in(&layout.scheme.scripts)?;
let size_and_encoded_hash = copy_and_hash(&mut start.chain(script), &mut target)?;
target.persist(&script_absolute).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!(
"Failed to persist temporary file to {}: {}",
path.user_display(),
err.error
),
)
})?;
fs::remove_file(&path)?;
Some(size_and_encoded_hash)
} else {
Expand Down Expand Up @@ -604,7 +615,8 @@ pub(crate) fn write_file_recorded(
relative_path.display()
);

File::create(site_packages.join(relative_path))?.write_all(content.as_ref())?;
uv_fs::write_atomic_sync(site_packages.join(relative_path), content.as_ref())?;

let hash = Sha256::new().chain_update(content.as_ref()).finalize();
let encoded_hash = format!("sha256={}", BASE64URL_NOPAD.encode(&hash));
record.push(RecordEntry {
Expand Down

0 comments on commit 8edfdbe

Please sign in to comment.