Avoid setting permissions during tar extraction (#11191)

## Summary

As in our zip operation (and like pip), we want to explicitly avoid
setting permissions during unpacking -- apart from setting the
executable bit.

This depends on https://github.com/astral-sh/tokio-tar/pull/8.

Closes https://github.com/astral-sh/uv/issues/11188.
This commit is contained in:
Charlie Marsh 2025-02-03 14:29:11 -05:00 committed by GitHub
parent 7b43baf251
commit 85461c2c90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 8 additions and 20 deletions

4
Cargo.lock generated
View file

@ -155,8 +155,8 @@ dependencies = [
[[package]]
name = "astral-tokio-tar"
version = "0.4.2"
source = "git+https://github.com/astral-sh/tokio-tar?rev=c06006a2cf6a6ca42e11775ddf1502dee8a8c688#c06006a2cf6a6ca42e11775ddf1502dee8a8c688"
version = "0.5.0"
source = "git+https://github.com/astral-sh/tokio-tar?rev=ba2b140f27d081c463335f0d68b5f8df8e6c845e#ba2b140f27d081c463335f0d68b5f8df8e6c845e"
dependencies = [
"filetime",
"futures-core",

View file

@ -73,7 +73,7 @@ uv-workspace = { path = "crates/uv-workspace" }
anstream = { version = "0.6.15" }
anyhow = { version = "1.0.89" }
arcstr = { version = "1.2.0" }
astral-tokio-tar = { git = "https://github.com/astral-sh/tokio-tar", rev = "c06006a2cf6a6ca42e11775ddf1502dee8a8c688" }
astral-tokio-tar = { git = "https://github.com/astral-sh/tokio-tar", rev = "ba2b140f27d081c463335f0d68b5f8df8e6c845e" }
async-channel = { version = "2.3.1" }
async-compression = { version = "0.4.12", features = ["bzip2", "gzip", "xz", "zstd"] }
async-trait = { version = "0.1.82" }

View file

@ -3,7 +3,6 @@ use std::pin::Pin;
use futures::StreamExt;
use rustc_hash::FxHashSet;
use tokio_tar::EntryType;
use tokio_util::compat::{FuturesAsyncReadCompatExt, TokioAsyncReadCompatExt};
use tracing::warn;
@ -150,10 +149,6 @@ async fn untar_in(
// Memoize filesystem calls to canonicalize paths.
let mut memo = FxHashSet::default();
// Delay any directory entries until the end, to ensure that directory permissions do not
// interfere with descendant extraction.
let mut directories = Vec::new();
let mut entries = archive.entries()?;
let mut pinned = Pin::new(&mut entries);
while let Some(entry) = pinned.next().await {
@ -170,12 +165,6 @@ async fn untar_in(
continue;
}
// Defer the creation of any directory entries.
if file.header().entry_type() == EntryType::Directory {
directories.push(file);
continue;
}
// Unpack the file into the destination directory.
#[cfg_attr(not(unix), allow(unused_variables))]
let unpacked_at = file.unpack_in_memo(&dst, &mut memo).await?;
@ -206,12 +195,6 @@ async fn untar_in(
}
}
// Create any deferred directories in topological order.
directories.sort_by(|a, b| b.path_bytes().cmp(&a.path_bytes()));
for mut dir in directories {
dir.unpack_in_memo(&dst, &mut memo).await?;
}
Ok(())
}
@ -229,6 +212,7 @@ pub async fn untar_gz<R: tokio::io::AsyncRead + Unpin>(
&mut decompressed_bytes as &mut (dyn tokio::io::AsyncRead + Unpin),
)
.set_preserve_mtime(false)
.set_preserve_permissions(false)
.build();
Ok(untar_in(archive, target.as_ref()).await?)
}
@ -247,6 +231,7 @@ pub async fn untar_bz2<R: tokio::io::AsyncRead + Unpin>(
&mut decompressed_bytes as &mut (dyn tokio::io::AsyncRead + Unpin),
)
.set_preserve_mtime(false)
.set_preserve_permissions(false)
.build();
Ok(untar_in(archive, target.as_ref()).await?)
}
@ -265,6 +250,7 @@ pub async fn untar_zst<R: tokio::io::AsyncRead + Unpin>(
&mut decompressed_bytes as &mut (dyn tokio::io::AsyncRead + Unpin),
)
.set_preserve_mtime(false)
.set_preserve_permissions(false)
.build();
Ok(untar_in(archive, target.as_ref()).await?)
}
@ -283,6 +269,7 @@ pub async fn untar_xz<R: tokio::io::AsyncRead + Unpin>(
&mut decompressed_bytes as &mut (dyn tokio::io::AsyncRead + Unpin),
)
.set_preserve_mtime(false)
.set_preserve_permissions(false)
.build();
untar_in(archive, target.as_ref()).await?;
Ok(())
@ -300,6 +287,7 @@ pub async fn untar<R: tokio::io::AsyncRead + Unpin>(
let archive =
tokio_tar::ArchiveBuilder::new(&mut reader as &mut (dyn tokio::io::AsyncRead + Unpin))
.set_preserve_mtime(false)
.set_preserve_permissions(false)
.build();
untar_in(archive, target.as_ref()).await?;
Ok(())