1 use std::fs::{self, File};
2 use std::io::{self, Write};
3 use std::path::Path;
4 use std::{iter, mem, thread, time};
5 
6 use tempdir::TempDir;
7 
8 use tar::{GnuHeader, Header, HeaderMode};
9 
10 #[test]
default_gnu()11 fn default_gnu() {
12     let mut h = Header::new_gnu();
13     assert!(h.as_gnu().is_some());
14     assert!(h.as_gnu_mut().is_some());
15     assert!(h.as_ustar().is_none());
16     assert!(h.as_ustar_mut().is_none());
17 }
18 
19 #[test]
goto_old()20 fn goto_old() {
21     let mut h = Header::new_old();
22     assert!(h.as_gnu().is_none());
23     assert!(h.as_gnu_mut().is_none());
24     assert!(h.as_ustar().is_none());
25     assert!(h.as_ustar_mut().is_none());
26 }
27 
28 #[test]
goto_ustar()29 fn goto_ustar() {
30     let mut h = Header::new_ustar();
31     assert!(h.as_gnu().is_none());
32     assert!(h.as_gnu_mut().is_none());
33     assert!(h.as_ustar().is_some());
34     assert!(h.as_ustar_mut().is_some());
35 }
36 
37 #[test]
link_name()38 fn link_name() {
39     let mut h = Header::new_gnu();
40     t!(h.set_link_name("foo"));
41     assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo"));
42     t!(h.set_link_name("../foo"));
43     assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("../foo"));
44     t!(h.set_link_name("foo/bar"));
45     assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo/bar"));
46     t!(h.set_link_name("foo\\ba"));
47     if cfg!(windows) {
48         assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo/ba"));
49     } else {
50         assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo\\ba"));
51     }
52 
53     let name = "foo\\bar\0";
54     for (slot, val) in h.as_old_mut().linkname.iter_mut().zip(name.as_bytes()) {
55         *slot = *val;
56     }
57     assert_eq!(t!(h.link_name()).unwrap().to_str(), Some("foo\\bar"));
58 
59     assert!(h.set_link_name("\0").is_err());
60 }
61 
62 #[test]
mtime()63 fn mtime() {
64     let h = Header::new_gnu();
65     assert_eq!(t!(h.mtime()), 0);
66 
67     let h = Header::new_ustar();
68     assert_eq!(t!(h.mtime()), 0);
69 
70     let h = Header::new_old();
71     assert_eq!(t!(h.mtime()), 0);
72 }
73 
74 #[test]
user_and_group_name()75 fn user_and_group_name() {
76     let mut h = Header::new_gnu();
77     t!(h.set_username("foo"));
78     t!(h.set_groupname("bar"));
79     assert_eq!(t!(h.username()), Some("foo"));
80     assert_eq!(t!(h.groupname()), Some("bar"));
81 
82     h = Header::new_ustar();
83     t!(h.set_username("foo"));
84     t!(h.set_groupname("bar"));
85     assert_eq!(t!(h.username()), Some("foo"));
86     assert_eq!(t!(h.groupname()), Some("bar"));
87 
88     h = Header::new_old();
89     assert_eq!(t!(h.username()), None);
90     assert_eq!(t!(h.groupname()), None);
91     assert!(h.set_username("foo").is_err());
92     assert!(h.set_groupname("foo").is_err());
93 }
94 
95 #[test]
dev_major_minor()96 fn dev_major_minor() {
97     let mut h = Header::new_gnu();
98     t!(h.set_device_major(1));
99     t!(h.set_device_minor(2));
100     assert_eq!(t!(h.device_major()), Some(1));
101     assert_eq!(t!(h.device_minor()), Some(2));
102 
103     h = Header::new_ustar();
104     t!(h.set_device_major(1));
105     t!(h.set_device_minor(2));
106     assert_eq!(t!(h.device_major()), Some(1));
107     assert_eq!(t!(h.device_minor()), Some(2));
108 
109     h.as_ustar_mut().unwrap().dev_minor[0] = 0x7f;
110     h.as_ustar_mut().unwrap().dev_major[0] = 0x7f;
111     assert!(h.device_major().is_err());
112     assert!(h.device_minor().is_err());
113 
114     h.as_ustar_mut().unwrap().dev_minor[0] = b'g';
115     h.as_ustar_mut().unwrap().dev_major[0] = b'h';
116     assert!(h.device_major().is_err());
117     assert!(h.device_minor().is_err());
118 
119     h = Header::new_old();
120     assert_eq!(t!(h.device_major()), None);
121     assert_eq!(t!(h.device_minor()), None);
122     assert!(h.set_device_major(1).is_err());
123     assert!(h.set_device_minor(1).is_err());
124 }
125 
126 #[test]
set_path()127 fn set_path() {
128     let mut h = Header::new_gnu();
129     t!(h.set_path("foo"));
130     assert_eq!(t!(h.path()).to_str(), Some("foo"));
131     t!(h.set_path("foo/"));
132     assert_eq!(t!(h.path()).to_str(), Some("foo/"));
133     t!(h.set_path("foo/bar"));
134     assert_eq!(t!(h.path()).to_str(), Some("foo/bar"));
135     t!(h.set_path("foo\\bar"));
136     if cfg!(windows) {
137         assert_eq!(t!(h.path()).to_str(), Some("foo/bar"));
138     } else {
139         assert_eq!(t!(h.path()).to_str(), Some("foo\\bar"));
140     }
141 
142     let long_name = iter::repeat("foo").take(100).collect::<String>();
143     let medium1 = iter::repeat("foo").take(52).collect::<String>();
144     let medium2 = iter::repeat("fo/").take(52).collect::<String>();
145 
146     assert!(h.set_path(&long_name).is_err());
147     assert!(h.set_path(&medium1).is_err());
148     assert!(h.set_path(&medium2).is_err());
149     assert!(h.set_path("\0").is_err());
150 
151     h = Header::new_ustar();
152     t!(h.set_path("foo"));
153     assert_eq!(t!(h.path()).to_str(), Some("foo"));
154 
155     assert!(h.set_path(&long_name).is_err());
156     assert!(h.set_path(&medium1).is_err());
157     t!(h.set_path(&medium2));
158     assert_eq!(t!(h.path()).to_str(), Some(&medium2[..]));
159 }
160 
161 #[test]
set_ustar_path_hard()162 fn set_ustar_path_hard() {
163     let mut h = Header::new_ustar();
164     let p = Path::new("a").join(&vec!["a"; 100].join(""));
165     t!(h.set_path(&p));
166     assert_eq!(t!(h.path()), p);
167 }
168 
169 #[test]
set_metadata_deterministic()170 fn set_metadata_deterministic() {
171     let td = t!(TempDir::new("tar-rs"));
172     let tmppath = td.path().join("tmpfile");
173 
174     fn mk_header(path: &Path, readonly: bool) -> Result<Header, io::Error> {
175         let mut file = t!(File::create(path));
176         t!(file.write_all(b"c"));
177         let mut perms = t!(file.metadata()).permissions();
178         perms.set_readonly(readonly);
179         t!(fs::set_permissions(path, perms));
180         let mut h = Header::new_ustar();
181         h.set_metadata_in_mode(&t!(path.metadata()), HeaderMode::Deterministic);
182         Ok(h)
183     }
184 
185     // Create "the same" File twice in a row, one second apart, with differing readonly values.
186     let one = t!(mk_header(tmppath.as_path(), false));
187     thread::sleep(time::Duration::from_millis(1050));
188     let two = t!(mk_header(tmppath.as_path(), true));
189 
190     // Always expected to match.
191     assert_eq!(t!(one.size()), t!(two.size()));
192     assert_eq!(t!(one.path()), t!(two.path()));
193     assert_eq!(t!(one.mode()), t!(two.mode()));
194 
195     // Would not match without `Deterministic`.
196     assert_eq!(t!(one.mtime()), t!(two.mtime()));
197     // TODO: No great way to validate that these would not be filled, but
198     // check them anyway.
199     assert_eq!(t!(one.uid()), t!(two.uid()));
200     assert_eq!(t!(one.gid()), t!(two.gid()));
201 }
202 
203 #[test]
extended_numeric_format()204 fn extended_numeric_format() {
205     let mut h: GnuHeader = unsafe { mem::zeroed() };
206     h.as_header_mut().set_size(42);
207     assert_eq!(h.size, [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 50, 0]);
208     h.as_header_mut().set_size(8589934593);
209     assert_eq!(h.size, [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 1]);
210     h.size = [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 0];
211     assert_eq!(h.as_header().entry_size().unwrap(), 0x0200000000);
212     h.size = [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 51, 0];
213     assert_eq!(h.as_header().entry_size().unwrap(), 43);
214 
215     h.as_header_mut().set_gid(42);
216     assert_eq!(h.gid, [48, 48, 48, 48, 48, 53, 50, 0]);
217     assert_eq!(h.as_header().gid().unwrap(), 42);
218     h.as_header_mut().set_gid(0x7fffffffffffffff);
219     assert_eq!(h.gid, [0xff; 8]);
220     assert_eq!(h.as_header().gid().unwrap(), 0x7fffffffffffffff);
221     h.uid = [0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78];
222     assert_eq!(h.as_header().uid().unwrap(), 0x12345678);
223 
224     h.mtime = [
225         0x80, 0, 0, 0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
226     ];
227     assert_eq!(h.as_header().mtime().unwrap(), 0x0123456789abcdef);
228 }
229 
230 #[test]
byte_slice_conversion()231 fn byte_slice_conversion() {
232     let h = Header::new_gnu();
233     let b: &[u8] = h.as_bytes();
234     let b_conv: &[u8] = Header::from_byte_slice(h.as_bytes()).as_bytes();
235     assert_eq!(b, b_conv);
236 }
237