Skip to content

Commit cecff3a

Browse files
Guard against self-deletion in uv venv and uv tool (#10206)
## Summary Closes #1327.
1 parent 4b5a89d commit cecff3a

5 files changed

Lines changed: 31 additions & 4 deletions

File tree

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/uv-tool/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,14 @@ uv-settings = { workspace = true }
2929
uv-state = { workspace = true }
3030
uv-static = { workspace = true }
3131
uv-virtualenv = { workspace = true }
32+
3233
fs-err = { workspace = true }
3334
pathdiff = { workspace = true }
3435
serde = { workspace = true }
3536
thiserror = { workspace = true }
3637
toml = { workspace = true }
3738
toml_edit = { workspace = true }
3839
tracing = { workspace = true }
40+
41+
[target.'cfg(target_os = "windows")'.dependencies]
42+
self-replace = { workspace = true }

crates/uv-tool/src/lib.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,16 @@ impl InstalledTools {
184184
environment_path.user_display()
185185
);
186186

187-
// TODO(charlie): On Windows, if the current executable is in the directory,
188-
// we need to use `safe_delete`.
187+
// On Windows, if the current executable is in the directory, guard against self-deletion.
188+
#[cfg(windows)]
189+
if let Ok(itself) = std::env::current_exe() {
190+
let target = std::path::absolute(&environment_path)?;
191+
if itself.starts_with(&target) {
192+
debug!("Detected self-delete of executable: {}", itself.display());
193+
self_replace::self_delete_outside_path(&environment_path)?;
194+
}
195+
}
196+
189197
fs_err::remove_dir_all(environment_path)?;
190198

191199
Ok(())

crates/uv-virtualenv/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ itertools = { workspace = true }
3232
pathdiff = { workspace = true }
3333
thiserror = { workspace = true }
3434
tracing = { workspace = true }
35+
36+
[target.'cfg(target_os = "windows")'.dependencies]
37+
self-replace = { workspace = true }

crates/uv-virtualenv/src/virtualenv.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,19 @@ pub(crate) fn create(
105105
if allow_existing {
106106
debug!("Allowing existing directory");
107107
} else if location.join("pyvenv.cfg").is_file() {
108-
// TODO(charlie): On Windows, if the current executable is in the directory,
109-
// we need to use `safe_delete`.
110108
debug!("Removing existing directory");
109+
110+
// On Windows, if the current executable is in the directory, guard against
111+
// self-deletion.
112+
#[cfg(windows)]
113+
if let Ok(itself) = std::env::current_exe() {
114+
let target = std::path::absolute(location)?;
115+
if itself.starts_with(&target) {
116+
debug!("Detected self-delete of executable: {}", itself.display());
117+
self_replace::self_delete_outside_path(location)?;
118+
}
119+
}
120+
111121
fs::remove_dir_all(location)?;
112122
fs::create_dir_all(location)?;
113123
} else if location

0 commit comments

Comments
 (0)