| extern crate tar; |
| extern crate tempfile; |
| |
| use std::fs::{create_dir, File}; |
| use std::io::Read; |
| |
| use tempfile::Builder; |
| |
| macro_rules! t { |
| ($e:expr) => { |
| match $e { |
| Ok(v) => v, |
| Err(e) => panic!("{} returned {}", stringify!($e), e), |
| } |
| }; |
| } |
| |
| #[test] |
| fn absolute_symlink() { |
| 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::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("/bar")); |
| 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()); |
| t!(ar.unpack(td.path())); |
| |
| t!(td.path().join("foo").symlink_metadata()); |
| |
| let mut ar = tar::Archive::new(&bytes[..]); |
| let mut entries = t!(ar.entries()); |
| let entry = t!(entries.next().unwrap()); |
| assert_eq!(&*entry.link_name_bytes().unwrap(), b"/bar"); |
| } |
| |
| #[test] |
| fn absolute_hardlink() { |
| let td = t!(Builder::new().prefix("tar").tempdir()); |
| 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_cksum(); |
| t!(ar.append(&header, &[][..])); |
| |
| let mut header = tar::Header::new_gnu(); |
| header.set_size(0); |
| header.set_entry_type(tar::EntryType::Link); |
| t!(header.set_path("bar")); |
| // This absolute path under tempdir will be created at unpack time |
| t!(header.set_link_name(td.path().join("foo"))); |
| header.set_cksum(); |
| t!(ar.append(&header, &[][..])); |
| |
| let bytes = t!(ar.into_inner()); |
| let mut ar = tar::Archive::new(&bytes[..]); |
| |
| t!(ar.unpack(td.path())); |
| t!(td.path().join("foo").metadata()); |
| t!(td.path().join("bar").metadata()); |
| } |
| |
| #[test] |
| fn relative_hardlink() { |
| 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_cksum(); |
| t!(ar.append(&header, &[][..])); |
| |
| let mut header = tar::Header::new_gnu(); |
| header.set_size(0); |
| header.set_entry_type(tar::EntryType::Link); |
| t!(header.set_path("bar")); |
| t!(header.set_link_name("foo")); |
| 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()); |
| t!(ar.unpack(td.path())); |
| t!(td.path().join("foo").metadata()); |
| t!(td.path().join("bar").metadata()); |
| } |
| |
| #[test] |
| fn absolute_link_deref_error() { |
| 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::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("/")); |
| 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("foo/bar")); |
| 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()); |
| assert!(ar.unpack(td.path()).is_err()); |
| t!(td.path().join("foo").symlink_metadata()); |
| assert!(File::open(td.path().join("foo").join("bar")).is_err()); |
| } |
| |
| #[test] |
| fn relative_link_deref_error() { |
| 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::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("../../../../")); |
| 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("foo/bar")); |
| 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()); |
| assert!(ar.unpack(td.path()).is_err()); |
| t!(td.path().join("foo").symlink_metadata()); |
| assert!(File::open(td.path().join("foo").join("bar")).is_err()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn directory_maintains_permissions() { |
| 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::Directory); |
| 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()); |
| t!(ar.unpack(td.path())); |
| let f = t!(File::open(td.path().join("foo"))); |
| let md = t!(f.metadata()); |
| assert!(md.is_dir()); |
| assert_eq!(md.permissions().mode(), 0o40777); |
| } |
| |
| #[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()); |
| |
| let mut header = tar::Header::new_gnu(); |
| header.set_size(0); |
| header.set_entry_type(tar::EntryType::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("bar")); |
| 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/foo")); |
| 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("foo/bar")); |
| 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()); |
| t!(ar.unpack(td.path())); |
| |
| t!(File::open(td.path().join("bar/foo"))); |
| t!(File::open(td.path().join("bar/bar"))); |
| t!(File::open(td.path().join("foo/foo"))); |
| t!(File::open(td.path().join("foo/bar"))); |
| } |
| |
| #[test] |
| #[cfg(not(windows))] // dangling symlinks have weird permissions |
| fn modify_outside_with_relative_symlink() { |
| 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::Symlink); |
| t!(header.set_path("symlink")); |
| t!(header.set_link_name("..")); |
| 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("symlink/foo/bar")); |
| 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 tar_dir = td.path().join("tar"); |
| create_dir(&tar_dir).unwrap(); |
| assert!(ar.unpack(tar_dir).is_err()); |
| assert!(!td.path().join("foo").exists()); |
| } |
| |
| #[test] |
| fn parent_paths_error() { |
| 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::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("..")); |
| 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("foo/bar")); |
| 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()); |
| assert!(ar.unpack(td.path()).is_err()); |
| t!(td.path().join("foo").symlink_metadata()); |
| assert!(File::open(td.path().join("foo").join("bar")).is_err()); |
| } |
| |
| #[test] |
| #[cfg(unix)] |
| fn good_parent_paths_ok() { |
| use std::path::PathBuf; |
| 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::Symlink); |
| t!(header.set_path(PathBuf::from("foo").join("bar"))); |
| t!(header.set_link_name(PathBuf::from("..").join("bar"))); |
| 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_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()); |
| t!(ar.unpack(td.path())); |
| t!(td.path().join("foo").join("bar").read_link()); |
| let dst = t!(td.path().join("foo").join("bar").canonicalize()); |
| t!(File::open(dst)); |
| } |
| |
| #[test] |
| fn modify_hard_link_just_created() { |
| 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::Link); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("../test")); |
| header.set_cksum(); |
| t!(ar.append(&header, &[][..])); |
| |
| let mut header = tar::Header::new_gnu(); |
| header.set_size(1); |
| header.set_entry_type(tar::EntryType::Regular); |
| t!(header.set_path("foo")); |
| header.set_cksum(); |
| t!(ar.append(&header, &b"x"[..])); |
| |
| let bytes = t!(ar.into_inner()); |
| let mut ar = tar::Archive::new(&bytes[..]); |
| |
| let td = t!(Builder::new().prefix("tar").tempdir()); |
| |
| let test = td.path().join("test"); |
| t!(File::create(&test)); |
| |
| let dir = td.path().join("dir"); |
| assert!(ar.unpack(&dir).is_err()); |
| |
| let mut contents = Vec::new(); |
| t!(t!(File::open(&test)).read_to_end(&mut contents)); |
| assert_eq!(contents.len(), 0); |
| } |
| |
| #[test] |
| fn modify_symlink_just_created() { |
| 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::Symlink); |
| t!(header.set_path("foo")); |
| t!(header.set_link_name("../test")); |
| header.set_cksum(); |
| t!(ar.append(&header, &[][..])); |
| |
| let mut header = tar::Header::new_gnu(); |
| header.set_size(1); |
| header.set_entry_type(tar::EntryType::Regular); |
| t!(header.set_path("foo")); |
| header.set_cksum(); |
| t!(ar.append(&header, &b"x"[..])); |
| |
| let bytes = t!(ar.into_inner()); |
| let mut ar = tar::Archive::new(&bytes[..]); |
| |
| let td = t!(Builder::new().prefix("tar").tempdir()); |
| |
| let test = td.path().join("test"); |
| t!(File::create(&test)); |
| |
| let dir = td.path().join("dir"); |
| t!(ar.unpack(&dir)); |
| |
| let mut contents = Vec::new(); |
| t!(t!(File::open(&test)).read_to_end(&mut contents)); |
| assert_eq!(contents.len(), 0); |
| } |