Skip to content

Commit

Permalink
feat: support handle very large uid/gid in PAX style tar
Browse files Browse the repository at this point in the history
This commit add process to read large uid/gid from PAX extensions
to fix very large UIDs/GIDs (>=2097151, limit of USTAR tar) lost
in PAX style tar during unpack.

Fix: alexcrichton#332

Signed-off-by: Qinqi Qu <quqinqi@linux.alibaba.com>
  • Loading branch information
adamqqqplay committed Jul 17, 2023
1 parent 61c726b commit 8e9e82d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,12 @@ impl<'a> EntriesFields<'a> {
}

let mut pax_size: Option<u64> = None;
let mut pax_uid: Option<u64> = None;
let mut pax_gid: Option<u64> = None;
if let Some(pax_extensions_ref) = &pax_extensions {
pax_size = pax_extensions_value(pax_extensions_ref, "size");
pax_size = pax_extensions_value(pax_extensions_ref, PAX_SIZE);
pax_uid = pax_extensions_value(pax_extensions_ref, PAX_UID);
pax_gid = pax_extensions_value(pax_extensions_ref, PAX_GID);
}

let file_pos = self.next;
Expand All @@ -327,6 +331,15 @@ impl<'a> EntriesFields<'a> {
size = pax_size;
}
}

if pax_uid.is_some() {
header.set_uid(pax_uid.unwrap());
}

if pax_gid.is_some() {
header.set_gid(pax_gid.unwrap());
}

let ret = EntryFields {
size: size,
header_pos: header_pos,
Expand Down
30 changes: 30 additions & 0 deletions src/pax.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
#![allow(dead_code)]
use std::io;
use std::slice;
use std::str;

use crate::other;

// Keywords for PAX extended header records.
pub const PAX_NONE: &str = ""; // Indicates that no PAX key is suitable
pub const PAX_PATH: &str = "path";
pub const PAX_LINKPATH: &str = "linkpath";
pub const PAX_SIZE: &str = "size";
pub const PAX_UID: &str = "uid";
pub const PAX_GID: &str = "gid";
pub const PAX_UNAME: &str = "uname";
pub const PAX_GNAME: &str = "gname";
pub const PAX_MTIME: &str = "mtime";
pub const PAX_ATIME: &str = "atime";
pub const PAX_CTIME: &str = "ctime"; // Removed from later revision of PAX spec, but was valid
pub const PAX_CHARSET: &str = "charset"; // Currently unused
pub const PAX_COMMENT: &str = "comment"; // Currently unused

pub const PAX_SCHILYXATTR: &str = "SCHILY.xattr.";

// Keywords for GNU sparse files in a PAX extended header.
pub const PAX_GNUSPARSE: &str = "GNU.sparse.";
pub const PAX_GNUSPARSENUMBLOCKS: &str = "GNU.sparse.numblocks";
pub const PAX_GNUSPARSEOFFSET: &str = "GNU.sparse.offset";
pub const PAX_GNUSPARSENUMBYTES: &str = "GNU.sparse.numbytes";
pub const PAX_GNUSPARSEMAP: &str = "GNU.sparse.map";
pub const PAX_GNUSPARSENAME: &str = "GNU.sparse.name";
pub const PAX_GNUSPARSEMAJOR: &str = "GNU.sparse.major";
pub const PAX_GNUSPARSEMINOR: &str = "GNU.sparse.minor";
pub const PAX_GNUSPARSESIZE: &str = "GNU.sparse.size";
pub const PAX_GNUSPARSEREALSIZE: &str = "GNU.sparse.realsize";

/// An iterator over the pax extensions in an archive entry.
///
/// This iterator yields structures which can themselves be parsed into
Expand Down
27 changes: 27 additions & 0 deletions tests/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1488,3 +1488,30 @@ fn ownership_preserving() {
assert!(ar.unpack(td.path()).is_err());
}
}

#[test]
#[cfg(unix)]
fn pax_and_gnu_uid_gid() {
let tarlist = [tar!("biguid_gnu.tar"), tar!("biguid_pax.tar")];

for file in &tarlist {
let td = t!(TempBuilder::new().prefix("tar-rs").tempdir());
let rdr = Cursor::new(file);
let mut ar = Archive::new(rdr);
ar.set_preserve_ownerships(true);

if unsafe { libc::getuid() } == 0 {
t!(ar.unpack(td.path()));
let meta = fs::metadata(td.path().join("test.txt")).unwrap();
let uid = std::os::unix::prelude::MetadataExt::uid(&meta);
let gid = std::os::unix::prelude::MetadataExt::gid(&meta);
// 4294967294 = u32::MAX - 1
assert_eq!(uid, 4294967294);
assert_eq!(gid, 4294967294);
} else {
// it's not possible to unpack tar while preserving ownership
// without root permissions
assert!(ar.unpack(td.path()).is_err());
}
}
}
Binary file added tests/archives/biguid_gnu.tar
Binary file not shown.
Binary file added tests/archives/biguid_pax.tar
Binary file not shown.

0 comments on commit 8e9e82d

Please sign in to comment.