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 tempfile::Builder;
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 // set_path documentation explictly states it removes any ".", signfying the
143 // current directory, from the path. This test ensures that documented
144 // beavhior occurs
145 t!(h.set_path("./control"));
146 assert_eq!(t!(h.path()).to_str(), Some("control"));
147
148 let long_name = iter::repeat("foo").take(100).collect::<String>();
149 let medium1 = iter::repeat("foo").take(52).collect::<String>();
150 let medium2 = iter::repeat("fo/").take(52).collect::<String>();
151
152 assert!(h.set_path(&long_name).is_err());
153 assert!(h.set_path(&medium1).is_err());
154 assert!(h.set_path(&medium2).is_err());
155 assert!(h.set_path("\0").is_err());
156
157 assert!(h.set_path("..").is_err());
158 assert!(h.set_path("foo/..").is_err());
159 assert!(h.set_path("foo/../bar").is_err());
160
161 h = Header::new_ustar();
162 t!(h.set_path("foo"));
163 assert_eq!(t!(h.path()).to_str(), Some("foo"));
164
165 assert!(h.set_path(&long_name).is_err());
166 assert!(h.set_path(&medium1).is_err());
167 t!(h.set_path(&medium2));
168 assert_eq!(t!(h.path()).to_str(), Some(&medium2[..]));
169 }
170
171 #[test]
set_ustar_path_hard()172 fn set_ustar_path_hard() {
173 let mut h = Header::new_ustar();
174 let p = Path::new("a").join(&vec!["a"; 100].join(""));
175 t!(h.set_path(&p));
176 assert_eq!(t!(h.path()), p);
177 }
178
179 #[test]
set_metadata_deterministic()180 fn set_metadata_deterministic() {
181 let td = t!(Builder::new().prefix("tar-rs").tempdir());
182 let tmppath = td.path().join("tmpfile");
183
184 fn mk_header(path: &Path, readonly: bool) -> Result<Header, io::Error> {
185 let mut file = t!(File::create(path));
186 t!(file.write_all(b"c"));
187 let mut perms = t!(file.metadata()).permissions();
188 perms.set_readonly(readonly);
189 t!(fs::set_permissions(path, perms));
190 let mut h = Header::new_ustar();
191 h.set_metadata_in_mode(&t!(path.metadata()), HeaderMode::Deterministic);
192 Ok(h)
193 }
194
195 // Create "the same" File twice in a row, one second apart, with differing readonly values.
196 let one = t!(mk_header(tmppath.as_path(), false));
197 thread::sleep(time::Duration::from_millis(1050));
198 let two = t!(mk_header(tmppath.as_path(), true));
199
200 // Always expected to match.
201 assert_eq!(t!(one.size()), t!(two.size()));
202 assert_eq!(t!(one.path()), t!(two.path()));
203 assert_eq!(t!(one.mode()), t!(two.mode()));
204
205 // Would not match without `Deterministic`.
206 assert_eq!(t!(one.mtime()), t!(two.mtime()));
207 // TODO: No great way to validate that these would not be filled, but
208 // check them anyway.
209 assert_eq!(t!(one.uid()), t!(two.uid()));
210 assert_eq!(t!(one.gid()), t!(two.gid()));
211 }
212
213 #[test]
extended_numeric_format()214 fn extended_numeric_format() {
215 let mut h: GnuHeader = unsafe { mem::zeroed() };
216 h.as_header_mut().set_size(42);
217 assert_eq!(h.size, [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 50, 0]);
218 h.as_header_mut().set_size(8589934593);
219 assert_eq!(h.size, [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 1]);
220 h.size = [0x80, 0, 0, 0, 0, 0, 0, 0x02, 0, 0, 0, 0];
221 assert_eq!(h.as_header().entry_size().unwrap(), 0x0200000000);
222 h.size = [48, 48, 48, 48, 48, 48, 48, 48, 48, 53, 51, 0];
223 assert_eq!(h.as_header().entry_size().unwrap(), 43);
224
225 h.as_header_mut().set_gid(42);
226 assert_eq!(h.gid, [48, 48, 48, 48, 48, 53, 50, 0]);
227 assert_eq!(h.as_header().gid().unwrap(), 42);
228 h.as_header_mut().set_gid(0x7fffffffffffffff);
229 assert_eq!(h.gid, [0xff; 8]);
230 assert_eq!(h.as_header().gid().unwrap(), 0x7fffffffffffffff);
231 h.uid = [0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78];
232 assert_eq!(h.as_header().uid().unwrap(), 0x12345678);
233
234 h.mtime = [
235 0x80, 0, 0, 0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
236 ];
237 assert_eq!(h.as_header().mtime().unwrap(), 0x0123456789abcdef);
238 }
239
240 #[test]
byte_slice_conversion()241 fn byte_slice_conversion() {
242 let h = Header::new_gnu();
243 let b: &[u8] = h.as_bytes();
244 let b_conv: &[u8] = Header::from_byte_slice(h.as_bytes()).as_bytes();
245 assert_eq!(b, b_conv);
246 }
247