diff options
Diffstat (limited to 'vendor/tar')
-rw-r--r-- | vendor/tar/.cargo-checksum.json | 2 | ||||
-rw-r--r-- | vendor/tar/Cargo.lock | 207 | ||||
-rw-r--r-- | vendor/tar/Cargo.toml | 18 | ||||
-rw-r--r-- | vendor/tar/src/archive.rs | 29 | ||||
-rw-r--r-- | vendor/tar/src/entry.rs | 180 | ||||
-rw-r--r-- | vendor/tar/tests/all.rs | 107 | ||||
-rw-r--r-- | vendor/tar/tests/entry.rs | 31 |
7 files changed, 479 insertions, 95 deletions
diff --git a/vendor/tar/.cargo-checksum.json b/vendor/tar/.cargo-checksum.json index 508f784e8..792994f55 100644 --- a/vendor/tar/.cargo-checksum.json +++ b/vendor/tar/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"9872bf9e41b9cadee45b688c9537030a993ca49a266fc7859029d8c74810d1d5","Cargo.toml":"8353c71aa4d394efa7aaeac3004d0a16fd0c7124b7bd57ea91ba87a7b2015f15","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"71079f1a0962c2cf288058f38d24735bddabd1427ac2dee72ec18cc5ae4bceed","examples/extract_file.rs":"dc487f6631d824175afc3ee33de99e80718a8ca3f9e57fddd7cac0a46c07d3ae","examples/list.rs":"36e412205eaffea8ab7f39be4173594b74e36acb369e091362b1975ee4a7a14b","examples/raw_list.rs":"0a735576ac354457d6d5a4d395d044fae99bf67a7c69960ca784a6f6a1743651","examples/write.rs":"419ac3e4155035e32b52cd8e6ae987a2d99cf82f60abbfb315c2a2c4f8e8fd19","src/archive.rs":"85a0091e02690c62379137988cd9b2689009536a0b941f1ab0581db26e9ebce6","src/builder.rs":"2914f394d44c133557532bf5765fe63e0def30ec0b447f8f2bc620e932a2036a","src/entry.rs":"705016636f7fdcad4fe20d7d2672be2b94cc53bb05e47628f5212b89e17a40fe","src/entry_type.rs":"0786688729a96b4a3135b28d40b95c3d4feaad66b9574c490cbea14814ab975f","src/error.rs":"a20813fbc52f1f2e3a79654f62de6001759f6504a06acee5b0819d4865398587","src/header.rs":"fb2b1fa943c19635826b3f2becfb82527be7d08fdac115af840da3ff06152908","src/lib.rs":"5468e413205c907c367c35d28a528389103d68fd6a5b5979bbedba7c9e6b6c99","src/pax.rs":"54002e31151f9c50e02a3da26b3cacd1d3c9a3902daee008ab76d112cf5a2430","tests/all.rs":"567a05d54e369d22efe40f3507a26e21f7878b95bd05c811250b2c350761791b","tests/entry.rs":"c1411ee09da9edb659b508867f0960e804966dfd33801f4a7afaefda331479dd","tests/header/mod.rs":"02b05639f63c39a47559650c7209817bb60282deb4f679d5b001ed936343d9de"},"package":"4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"}
\ No newline at end of file +{"files":{"Cargo.lock":"a074bb3491e0d988605218e794859ddb067bb624e793a053645fbbabadde83f6","Cargo.toml":"638559bf51f1b89359ece700138f774bc0a5c1513046e306d6109dc045799b84","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"71079f1a0962c2cf288058f38d24735bddabd1427ac2dee72ec18cc5ae4bceed","examples/extract_file.rs":"dc487f6631d824175afc3ee33de99e80718a8ca3f9e57fddd7cac0a46c07d3ae","examples/list.rs":"36e412205eaffea8ab7f39be4173594b74e36acb369e091362b1975ee4a7a14b","examples/raw_list.rs":"0a735576ac354457d6d5a4d395d044fae99bf67a7c69960ca784a6f6a1743651","examples/write.rs":"419ac3e4155035e32b52cd8e6ae987a2d99cf82f60abbfb315c2a2c4f8e8fd19","src/archive.rs":"9238c58f5a253034f490ede4c42de6e1b89986ee6db343920ee34b3dcfa5b238","src/builder.rs":"2914f394d44c133557532bf5765fe63e0def30ec0b447f8f2bc620e932a2036a","src/entry.rs":"0e4b0438cbc4cbec30a821ce8f23619fe9e53c17022a022de609d642e220193c","src/entry_type.rs":"0786688729a96b4a3135b28d40b95c3d4feaad66b9574c490cbea14814ab975f","src/error.rs":"a20813fbc52f1f2e3a79654f62de6001759f6504a06acee5b0819d4865398587","src/header.rs":"fb2b1fa943c19635826b3f2becfb82527be7d08fdac115af840da3ff06152908","src/lib.rs":"5468e413205c907c367c35d28a528389103d68fd6a5b5979bbedba7c9e6b6c99","src/pax.rs":"54002e31151f9c50e02a3da26b3cacd1d3c9a3902daee008ab76d112cf5a2430","tests/all.rs":"7a64869cd99a4642f2db71aa7d283633199e59b88ccca112cb467b0739e64e83","tests/entry.rs":"af12d84160e5459ebaee6ecdd68e0c811438c37c0cb881ad210e7f94132b9739","tests/header/mod.rs":"02b05639f63c39a47559650c7209817bb60282deb4f679d5b001ed936343d9de"},"package":"ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96"}
\ No newline at end of file diff --git a/vendor/tar/Cargo.lock b/vendor/tar/Cargo.lock index dd53b90b5..f63a631ad 100644 --- a/vendor/tar/Cargo.lock +++ b/vendor/tar/Cargo.lock @@ -3,113 +3,144 @@ version = 3 [[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "filetime" -version = "0.2.15" +name = "errno" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ - "cfg-if", + "errno-dragonfly", "libc", - "redox_syscall", - "winapi", + "windows-sys", ] [[package]] -name = "getrandom" -version = "0.2.3" +name = "errno-dragonfly" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ - "cfg-if", + "cc", "libc", - "wasi", ] [[package]] -name = "libc" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" - -[[package]] -name = "ppv-lite86" -version = "0.2.10" +name = "fastrand" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] [[package]] -name = "rand" -version = "0.8.4" +name = "filetime" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" dependencies = [ + "cfg-if", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "redox_syscall 0.2.16", + "windows-sys", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "hermit-abi" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" + +[[package]] +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "ppv-lite86", - "rand_core", + "cfg-if", ] [[package]] -name = "rand_core" -version = "0.6.3" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "getrandom", + "hermit-abi", + "libc", + "windows-sys", ] [[package]] -name = "rand_hc" -version = "0.3.1" +name = "libc" +version = "0.2.147" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "rand_core", + "bitflags", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "rustix" +version = "0.37.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" dependencies = [ - "winapi", + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", ] [[package]] name = "tar" -version = "0.4.38" +version = "0.4.39" dependencies = [ "filetime", "libc", @@ -119,51 +150,89 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys", ] [[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-targets" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows_x86_64_gnu" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "xattr" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc" dependencies = [ "libc", ] diff --git a/vendor/tar/Cargo.toml b/vendor/tar/Cargo.toml index 23771b564..6225b778f 100644 --- a/vendor/tar/Cargo.toml +++ b/vendor/tar/Cargo.toml @@ -12,23 +12,35 @@ [package] edition = "2018" name = "tar" -version = "0.4.38" +version = "0.4.39" authors = ["Alex Crichton <alex@alexcrichton.com>"] exclude = ["tests/archives/*"] -description = "A Rust implementation of a TAR file reader and writer. This library does not\ncurrently handle compression, but it is abstract over all I/O readers and\nwriters. Additionally, great lengths are taken to ensure that the entire\ncontents are never required to be entirely resident in memory all at once.\n" +description = """ +A Rust implementation of a TAR file reader and writer. This library does not +currently handle compression, but it is abstract over all I/O readers and +writers. Additionally, great lengths are taken to ensure that the entire +contents are never required to be entirely resident in memory all at once. +""" homepage = "https://github.com/alexcrichton/tar-rs" documentation = "https://docs.rs/tar" readme = "README.md" -keywords = ["tar", "tarfile", "encoding"] +keywords = [ + "tar", + "tarfile", + "encoding", +] license = "MIT/Apache-2.0" repository = "https://github.com/alexcrichton/tar-rs" + [dependencies.filetime] version = "0.2.8" + [dev-dependencies.tempfile] version = "3" [features] default = ["xattr"] + [target."cfg(unix)".dependencies.libc] version = "0.2" diff --git a/vendor/tar/src/archive.rs b/vendor/tar/src/archive.rs index 1bed51249..c7a9d9803 100644 --- a/vendor/tar/src/archive.rs +++ b/vendor/tar/src/archive.rs @@ -22,8 +22,10 @@ pub struct Archive<R: ?Sized + Read> { pub struct ArchiveInner<R: ?Sized> { pos: Cell<u64>, + mask: u32, unpack_xattrs: bool, preserve_permissions: bool, + preserve_ownerships: bool, preserve_mtime: bool, overwrite: bool, ignore_zeros: bool, @@ -52,8 +54,10 @@ impl<R: Read> Archive<R> { pub fn new(obj: R) -> Archive<R> { Archive { inner: ArchiveInner { + mask: u32::MIN, unpack_xattrs: false, preserve_permissions: false, + preserve_ownerships: false, preserve_mtime: true, overwrite: true, ignore_zeros: false, @@ -106,6 +110,20 @@ impl<R: Read> Archive<R> { me._unpack(dst.as_ref()) } + /// Set the mask of the permission bits when unpacking this entry. + /// + /// The mask will be inverted when applying against a mode, similar to how + /// `umask` works on Unix. In logical notation it looks like: + /// + /// ```text + /// new_mode = old_mode & (~mask) + /// ``` + /// + /// The mask is 0 by default and is currently only implemented on Unix. + pub fn set_mask(&mut self, mask: u32) { + self.inner.mask = mask; + } + /// Indicate whether extended file attributes (xattrs on Unix) are preserved /// when unpacking this archive. /// @@ -126,6 +144,15 @@ impl<R: Read> Archive<R> { self.inner.preserve_permissions = preserve; } + /// Indicate whether numeric ownership ids (like uid and gid on Unix) + /// are preserved when unpacking this entry. + /// + /// This flag is disabled by default and is currently only implemented on + /// Unix. + pub fn set_preserve_ownerships(&mut self, preserve: bool) { + self.inner.preserve_ownerships = preserve; + } + /// Indicate whether files and symlinks should be overwritten on extraction. pub fn set_overwrite(&mut self, overwrite: bool) { self.inner.overwrite = overwrite; @@ -304,10 +331,12 @@ impl<'a> EntriesFields<'a> { long_pathname: None, long_linkname: None, pax_extensions: None, + mask: self.archive.inner.mask, unpack_xattrs: self.archive.inner.unpack_xattrs, preserve_permissions: self.archive.inner.preserve_permissions, preserve_mtime: self.archive.inner.preserve_mtime, overwrite: self.archive.inner.overwrite, + preserve_ownerships: self.archive.inner.preserve_ownerships, }; // Store where the next entry is, rounding up by 512 bytes (the size of diff --git a/vendor/tar/src/entry.rs b/vendor/tar/src/entry.rs index 8f0b62acf..c81554fcb 100644 --- a/vendor/tar/src/entry.rs +++ b/vendor/tar/src/entry.rs @@ -31,6 +31,7 @@ pub struct EntryFields<'a> { pub long_pathname: Option<Vec<u8>>, pub long_linkname: Option<Vec<u8>>, pub pax_extensions: Option<Vec<u8>>, + pub mask: u32, pub header: Header, pub size: u64, pub header_pos: u64, @@ -38,6 +39,7 @@ pub struct EntryFields<'a> { pub data: Vec<EntryIo<'a>>, pub unpack_xattrs: bool, pub preserve_permissions: bool, + pub preserve_ownerships: bool, pub preserve_mtime: bool, pub overwrite: bool, } @@ -230,6 +232,20 @@ impl<'a, R: Read> Entry<'a, R> { self.fields.unpack_in(dst.as_ref()) } + /// Set the mask of the permission bits when unpacking this entry. + /// + /// The mask will be inverted when applying against a mode, similar to how + /// `umask` works on Unix. In logical notation it looks like: + /// + /// ```text + /// new_mode = old_mode & (~mask) + /// ``` + /// + /// The mask is 0 by default and is currently only implemented on Unix. + pub fn set_mask(&mut self, mask: u32) { + self.fields.mask = mask; + } + /// Indicate whether extended file attributes (xattrs on Unix) are preserved /// when unpacking this entry. /// @@ -444,13 +460,51 @@ impl<'a> EntryFields<'a> { /// Returns access to the header of this entry in the archive. fn unpack(&mut self, target_base: Option<&Path>, dst: &Path) -> io::Result<Unpacked> { + fn set_perms_ownerships( + dst: &Path, + f: Option<&mut std::fs::File>, + header: &Header, + mask: u32, + perms: bool, + ownerships: bool, + ) -> io::Result<()> { + // ownerships need to be set first to avoid stripping SUID bits in the permissions ... + if ownerships { + set_ownerships(dst, &f, header.uid()?, header.gid()?)?; + } + // ... then set permissions, SUID bits set here is kept + if let Ok(mode) = header.mode() { + set_perms(dst, f, mode, mask, perms)?; + } + + Ok(()) + } + + fn get_mtime(header: &Header) -> Option<FileTime> { + header.mtime().ok().map(|mtime| { + // For some more information on this see the comments in + // `Header::fill_platform_from`, but the general idea is that + // we're trying to avoid 0-mtime files coming out of archives + // since some tools don't ingest them well. Perhaps one day + // when Cargo stops working with 0-mtime archives we can remove + // this. + let mtime = if mtime == 0 { 1 } else { mtime }; + FileTime::from_unix_time(mtime as i64, 0) + }) + } + let kind = self.header.entry_type(); if kind.is_dir() { self.unpack_dir(dst)?; - if let Ok(mode) = self.header.mode() { - set_perms(dst, None, mode, self.preserve_permissions)?; - } + set_perms_ownerships( + dst, + None, + &self.header, + self.mask, + self.preserve_permissions, + self.preserve_ownerships, + )?; return Ok(Unpacked::__Nonexhaustive); } else if kind.is_hard_link() || kind.is_symlink() { let src = match self.link_name()? { @@ -522,7 +576,14 @@ impl<'a> EntryFields<'a> { ), ) })?; - }; + if self.preserve_mtime { + if let Some(mtime) = get_mtime(&self.header) { + filetime::set_symlink_file_times(dst, mtime, mtime).map_err(|e| { + TarError::new(format!("failed to set mtime for `{}`", dst.display()), e) + })?; + } + } + } return Ok(Unpacked::__Nonexhaustive); #[cfg(target_arch = "wasm32")] @@ -553,9 +614,14 @@ impl<'a> EntryFields<'a> { // Only applies to old headers. if self.header.as_ustar().is_none() && self.path_bytes().ends_with(b"/") { self.unpack_dir(dst)?; - if let Ok(mode) = self.header.mode() { - set_perms(dst, None, mode, self.preserve_permissions)?; - } + set_perms_ownerships( + dst, + None, + &self.header, + self.mask, + self.preserve_permissions, + self.preserve_ownerships, + )?; return Ok(Unpacked::__Nonexhaustive); } @@ -618,35 +684,105 @@ impl<'a> EntryFields<'a> { })?; if self.preserve_mtime { - if let Ok(mtime) = self.header.mtime() { - // For some more information on this see the comments in - // `Header::fill_platform_from`, but the general idea is that - // we're trying to avoid 0-mtime files coming out of archives - // since some tools don't ingest them well. Perhaps one day - // when Cargo stops working with 0-mtime archives we can remove - // this. - let mtime = if mtime == 0 { 1 } else { mtime }; - let mtime = FileTime::from_unix_time(mtime as i64, 0); + if let Some(mtime) = get_mtime(&self.header) { filetime::set_file_handle_times(&f, Some(mtime), Some(mtime)).map_err(|e| { TarError::new(format!("failed to set mtime for `{}`", dst.display()), e) })?; } } - if let Ok(mode) = self.header.mode() { - set_perms(dst, Some(&mut f), mode, self.preserve_permissions)?; - } + set_perms_ownerships( + dst, + Some(&mut f), + &self.header, + self.mask, + self.preserve_permissions, + self.preserve_ownerships, + )?; if self.unpack_xattrs { set_xattrs(self, dst)?; } return Ok(Unpacked::File(f)); + fn set_ownerships( + dst: &Path, + f: &Option<&mut std::fs::File>, + uid: u64, + gid: u64, + ) -> Result<(), TarError> { + _set_ownerships(dst, f, uid, gid).map_err(|e| { + TarError::new( + format!( + "failed to set ownerships to uid={:?}, gid={:?} \ + for `{}`", + uid, + gid, + dst.display() + ), + e, + ) + }) + } + + #[cfg(unix)] + fn _set_ownerships( + dst: &Path, + f: &Option<&mut std::fs::File>, + uid: u64, + gid: u64, + ) -> io::Result<()> { + use std::convert::TryInto; + use std::os::unix::prelude::*; + + let uid: libc::uid_t = uid.try_into().map_err(|_| { + io::Error::new(io::ErrorKind::Other, format!("UID {} is too large!", uid)) + })?; + let gid: libc::gid_t = gid.try_into().map_err(|_| { + io::Error::new(io::ErrorKind::Other, format!("GID {} is too large!", gid)) + })?; + match f { + Some(f) => unsafe { + let fd = f.as_raw_fd(); + if libc::fchown(fd, uid, gid) != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + }, + None => unsafe { + let path = std::ffi::CString::new(dst.as_os_str().as_bytes()).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("path contains null character: {:?}", e), + ) + })?; + if libc::lchown(path.as_ptr(), uid, gid) != 0 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } + }, + } + } + + // Windows does not support posix numeric ownership IDs + #[cfg(any(windows, target_arch = "wasm32"))] + fn _set_ownerships( + _: &Path, + _: &Option<&mut std::fs::File>, + _: u64, + _: u64, + ) -> io::Result<()> { + Ok(()) + } + fn set_perms( dst: &Path, f: Option<&mut std::fs::File>, mode: u32, + mask: u32, preserve: bool, ) -> Result<(), TarError> { - _set_perms(dst, f, mode, preserve).map_err(|e| { + _set_perms(dst, f, mode, mask, preserve).map_err(|e| { TarError::new( format!( "failed to set permissions to {:o} \ @@ -664,11 +800,13 @@ impl<'a> EntryFields<'a> { dst: &Path, f: Option<&mut std::fs::File>, mode: u32, + mask: u32, preserve: bool, ) -> io::Result<()> { use std::os::unix::prelude::*; let mode = if preserve { mode } else { mode & 0o777 }; + let mode = mode & !mask; let perm = fs::Permissions::from_mode(mode as _); match f { Some(f) => f.set_permissions(perm), @@ -681,6 +819,7 @@ impl<'a> EntryFields<'a> { dst: &Path, f: Option<&mut std::fs::File>, mode: u32, + _mask: u32, _preserve: bool, ) -> io::Result<()> { if mode & 0o200 == 0o200 { @@ -706,6 +845,7 @@ impl<'a> EntryFields<'a> { dst: &Path, f: Option<&mut std::fs::File>, mode: u32, + mask: u32, _preserve: bool, ) -> io::Result<()> { Err(io::Error::new(io::ErrorKind::Other, "Not implemented")) diff --git a/vendor/tar/tests/all.rs b/vendor/tar/tests/all.rs index 11103bd6b..8c5359c56 100644 --- a/vendor/tar/tests/all.rs +++ b/vendor/tar/tests/all.rs @@ -579,10 +579,21 @@ fn extracting_malicious_tarball() { t!(a.append(&header, io::repeat(1).take(1))); }; append("/tmp/abs_evil.txt"); - append("//tmp/abs_evil2.txt"); + // std parse `//` as UNC path, see rust-lang/rust#100833 + append( + #[cfg(not(windows))] + "//tmp/abs_evil2.txt", + #[cfg(windows)] + "C://tmp/abs_evil2.txt", + ); append("///tmp/abs_evil3.txt"); append("/./tmp/abs_evil4.txt"); - append("//./tmp/abs_evil5.txt"); + append( + #[cfg(not(windows))] + "//./tmp/abs_evil5.txt", + #[cfg(windows)] + "C://./tmp/abs_evil5.txt", + ); append("///./tmp/abs_evil6.txt"); append("/../tmp/rel_evil.txt"); append("../rel_evil2.txt"); @@ -757,6 +768,40 @@ fn backslash_treated_well() { assert!(fs::metadata(td.path().join("foo\\bar")).is_ok()); } +#[test] +#[cfg(unix)] +fn set_mask() { + use ::std::os::unix::fs::PermissionsExt; + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_mode(0o777); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("bar")); + header.set_mode(0o421); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let td = t!(TempBuilder::new().prefix("tar-rs").tempdir()); + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + ar.set_mask(0o211); + t!(ar.unpack(td.path())); + + let md = t!(fs::metadata(td.path().join("foo"))); + assert_eq!(md.permissions().mode(), 0o100566); + let md = t!(fs::metadata(td.path().join("bar"))); + assert_eq!(md.permissions().mode(), 0o100420); +} + #[cfg(unix)] #[test] fn nul_bytes_in_path() { @@ -792,6 +837,10 @@ fn unpack_links() { let md = t!(fs::symlink_metadata(td.path().join("lnk"))); assert!(md.file_type().is_symlink()); + + let mtime = FileTime::from_last_modification_time(&md); + assert_eq!(mtime.unix_seconds(), 1448291033); + assert_eq!( &*t!(fs::read_link(td.path().join("lnk"))), Path::new("file") @@ -1385,3 +1434,57 @@ fn header_size_overflow() { err ); } + +#[test] +#[cfg(unix)] +fn ownership_preserving() { + use std::os::unix::prelude::*; + + let mut rdr = Vec::new(); + let mut ar = Builder::new(&mut rdr); + let data: &[u8] = &[]; + let mut header = Header::new_gnu(); + // file 1 with uid = 580800000, gid = 580800000 + header.set_gid(580800000); + header.set_uid(580800000); + t!(header.set_path("iamuid580800000")); + header.set_size(0); + header.set_cksum(); + t!(ar.append(&header, data)); + // file 2 with uid = 580800001, gid = 580800000 + header.set_uid(580800001); + t!(header.set_path("iamuid580800001")); + header.set_cksum(); + t!(ar.append(&header, data)); + // file 3 with uid = 580800002, gid = 580800002 + header.set_gid(580800002); + header.set_uid(580800002); + t!(header.set_path("iamuid580800002")); + header.set_cksum(); + t!(ar.append(&header, data)); + t!(ar.finish()); + + let rdr = Cursor::new(t!(ar.into_inner())); + let td = t!(TempBuilder::new().prefix("tar-rs").tempdir()); + let mut ar = Archive::new(rdr); + ar.set_preserve_ownerships(true); + + if unsafe { libc::getuid() } == 0 { + assert!(ar.unpack(td.path()).is_ok()); + // validate against premade files + // iamuid580800001 has this ownership: 580800001:580800000 + let meta = std::fs::metadata(td.path().join("iamuid580800000")).unwrap(); + assert_eq!(meta.uid(), 580800000); + assert_eq!(meta.gid(), 580800000); + let meta = std::fs::metadata(td.path().join("iamuid580800001")).unwrap(); + assert_eq!(meta.uid(), 580800001); + assert_eq!(meta.gid(), 580800000); + let meta = std::fs::metadata(td.path().join("iamuid580800002")).unwrap(); + assert_eq!(meta.uid(), 580800002); + assert_eq!(meta.gid(), 580800002); + } else { + // it's not possible to unpack tar while preserving ownership + // without root permissions + assert!(ar.unpack(td.path()).is_err()); + } +} diff --git a/vendor/tar/tests/entry.rs b/vendor/tar/tests/entry.rs index fa8eeaee7..62df663e8 100644 --- a/vendor/tar/tests/entry.rs +++ b/vendor/tar/tests/entry.rs @@ -181,6 +181,37 @@ fn directory_maintains_permissions() { } #[test] +#[cfg(unix)] +fn set_entry_mask() { + use ::std::os::unix::fs::PermissionsExt; + + let mut ar = tar::Builder::new(Vec::new()); + + let mut header = tar::Header::new_gnu(); + header.set_size(0); + header.set_entry_type(tar::EntryType::Regular); + t!(header.set_path("foo")); + header.set_mode(0o777); + header.set_cksum(); + t!(ar.append(&header, &[][..])); + + let bytes = t!(ar.into_inner()); + let mut ar = tar::Archive::new(&bytes[..]); + let td = t!(Builder::new().prefix("tar").tempdir()); + let foo_path = td.path().join("foo"); + + let mut entries = t!(ar.entries()); + let mut foo = t!(entries.next().unwrap()); + foo.set_mask(0o027); + t!(foo.unpack(&foo_path)); + + let f = t!(File::open(foo_path)); + let md = t!(f.metadata()); + assert!(md.is_file()); + assert_eq!(md.permissions().mode(), 0o100750); +} + +#[test] #[cfg(not(windows))] // dangling symlinks have weird permissions fn modify_link_just_created() { let mut ar = tar::Builder::new(Vec::new()); |