1 extern crate tar;
2 extern crate tempfile;
3 
4 use std::fs::{create_dir, File};
5 use std::io::Read;
6 
7 use tempfile::Builder;
8 
9 macro_rules! t {
10     ($e:expr) => {
11         match $e {
12             Ok(v) => v,
13             Err(e) => panic!("{} returned {}", stringify!($e), e),
14         }
15     };
16 }
17 
18 #[test]
absolute_symlink()19 fn absolute_symlink() {
20     let mut ar = tar::Builder::new(Vec::new());
21 
22     let mut header = tar::Header::new_gnu();
23     header.set_size(0);
24     header.set_entry_type(tar::EntryType::Symlink);
25     t!(header.set_path("foo"));
26     t!(header.set_link_name("/bar"));
27     header.set_cksum();
28     t!(ar.append(&header, &[][..]));
29 
30     let bytes = t!(ar.into_inner());
31     let mut ar = tar::Archive::new(&bytes[..]);
32 
33     let td = t!(Builder::new().prefix("tar").tempdir());
34     t!(ar.unpack(td.path()));
35 
36     t!(td.path().join("foo").symlink_metadata());
37 
38     let mut ar = tar::Archive::new(&bytes[..]);
39     let mut entries = t!(ar.entries());
40     let entry = t!(entries.next().unwrap());
41     assert_eq!(&*entry.link_name_bytes().unwrap(), b"/bar");
42 }
43 
44 #[test]
absolute_hardlink()45 fn absolute_hardlink() {
46     let td = t!(Builder::new().prefix("tar").tempdir());
47     let mut ar = tar::Builder::new(Vec::new());
48 
49     let mut header = tar::Header::new_gnu();
50     header.set_size(0);
51     header.set_entry_type(tar::EntryType::Regular);
52     t!(header.set_path("foo"));
53     header.set_cksum();
54     t!(ar.append(&header, &[][..]));
55 
56     let mut header = tar::Header::new_gnu();
57     header.set_size(0);
58     header.set_entry_type(tar::EntryType::Link);
59     t!(header.set_path("bar"));
60     // This absolute path under tempdir will be created at unpack time
61     t!(header.set_link_name(td.path().join("foo")));
62     header.set_cksum();
63     t!(ar.append(&header, &[][..]));
64 
65     let bytes = t!(ar.into_inner());
66     let mut ar = tar::Archive::new(&bytes[..]);
67 
68     t!(ar.unpack(td.path()));
69     t!(td.path().join("foo").metadata());
70     t!(td.path().join("bar").metadata());
71 }
72 
73 #[test]
relative_hardlink()74 fn relative_hardlink() {
75     let mut ar = tar::Builder::new(Vec::new());
76 
77     let mut header = tar::Header::new_gnu();
78     header.set_size(0);
79     header.set_entry_type(tar::EntryType::Regular);
80     t!(header.set_path("foo"));
81     header.set_cksum();
82     t!(ar.append(&header, &[][..]));
83 
84     let mut header = tar::Header::new_gnu();
85     header.set_size(0);
86     header.set_entry_type(tar::EntryType::Link);
87     t!(header.set_path("bar"));
88     t!(header.set_link_name("foo"));
89     header.set_cksum();
90     t!(ar.append(&header, &[][..]));
91 
92     let bytes = t!(ar.into_inner());
93     let mut ar = tar::Archive::new(&bytes[..]);
94 
95     let td = t!(Builder::new().prefix("tar").tempdir());
96     t!(ar.unpack(td.path()));
97     t!(td.path().join("foo").metadata());
98     t!(td.path().join("bar").metadata());
99 }
100 
101 #[test]
absolute_link_deref_error()102 fn absolute_link_deref_error() {
103     let mut ar = tar::Builder::new(Vec::new());
104 
105     let mut header = tar::Header::new_gnu();
106     header.set_size(0);
107     header.set_entry_type(tar::EntryType::Symlink);
108     t!(header.set_path("foo"));
109     t!(header.set_link_name("/"));
110     header.set_cksum();
111     t!(ar.append(&header, &[][..]));
112 
113     let mut header = tar::Header::new_gnu();
114     header.set_size(0);
115     header.set_entry_type(tar::EntryType::Regular);
116     t!(header.set_path("foo/bar"));
117     header.set_cksum();
118     t!(ar.append(&header, &[][..]));
119 
120     let bytes = t!(ar.into_inner());
121     let mut ar = tar::Archive::new(&bytes[..]);
122 
123     let td = t!(Builder::new().prefix("tar").tempdir());
124     assert!(ar.unpack(td.path()).is_err());
125     t!(td.path().join("foo").symlink_metadata());
126     assert!(File::open(td.path().join("foo").join("bar")).is_err());
127 }
128 
129 #[test]
relative_link_deref_error()130 fn relative_link_deref_error() {
131     let mut ar = tar::Builder::new(Vec::new());
132 
133     let mut header = tar::Header::new_gnu();
134     header.set_size(0);
135     header.set_entry_type(tar::EntryType::Symlink);
136     t!(header.set_path("foo"));
137     t!(header.set_link_name("../../../../"));
138     header.set_cksum();
139     t!(ar.append(&header, &[][..]));
140 
141     let mut header = tar::Header::new_gnu();
142     header.set_size(0);
143     header.set_entry_type(tar::EntryType::Regular);
144     t!(header.set_path("foo/bar"));
145     header.set_cksum();
146     t!(ar.append(&header, &[][..]));
147 
148     let bytes = t!(ar.into_inner());
149     let mut ar = tar::Archive::new(&bytes[..]);
150 
151     let td = t!(Builder::new().prefix("tar").tempdir());
152     assert!(ar.unpack(td.path()).is_err());
153     t!(td.path().join("foo").symlink_metadata());
154     assert!(File::open(td.path().join("foo").join("bar")).is_err());
155 }
156 
157 #[test]
158 #[cfg(unix)]
directory_maintains_permissions()159 fn directory_maintains_permissions() {
160     use ::std::os::unix::fs::PermissionsExt;
161 
162     let mut ar = tar::Builder::new(Vec::new());
163 
164     let mut header = tar::Header::new_gnu();
165     header.set_size(0);
166     header.set_entry_type(tar::EntryType::Directory);
167     t!(header.set_path("foo"));
168     header.set_mode(0o777);
169     header.set_cksum();
170     t!(ar.append(&header, &[][..]));
171 
172     let bytes = t!(ar.into_inner());
173     let mut ar = tar::Archive::new(&bytes[..]);
174 
175     let td = t!(Builder::new().prefix("tar").tempdir());
176     t!(ar.unpack(td.path()));
177     let f = t!(File::open(td.path().join("foo")));
178     let md = t!(f.metadata());
179     assert!(md.is_dir());
180     assert_eq!(md.permissions().mode(), 0o40777);
181 }
182 
183 #[test]
184 #[cfg(not(windows))] // dangling symlinks have weird permissions
modify_link_just_created()185 fn modify_link_just_created() {
186     let mut ar = tar::Builder::new(Vec::new());
187 
188     let mut header = tar::Header::new_gnu();
189     header.set_size(0);
190     header.set_entry_type(tar::EntryType::Symlink);
191     t!(header.set_path("foo"));
192     t!(header.set_link_name("bar"));
193     header.set_cksum();
194     t!(ar.append(&header, &[][..]));
195 
196     let mut header = tar::Header::new_gnu();
197     header.set_size(0);
198     header.set_entry_type(tar::EntryType::Regular);
199     t!(header.set_path("bar/foo"));
200     header.set_cksum();
201     t!(ar.append(&header, &[][..]));
202 
203     let mut header = tar::Header::new_gnu();
204     header.set_size(0);
205     header.set_entry_type(tar::EntryType::Regular);
206     t!(header.set_path("foo/bar"));
207     header.set_cksum();
208     t!(ar.append(&header, &[][..]));
209 
210     let bytes = t!(ar.into_inner());
211     let mut ar = tar::Archive::new(&bytes[..]);
212 
213     let td = t!(Builder::new().prefix("tar").tempdir());
214     t!(ar.unpack(td.path()));
215 
216     t!(File::open(td.path().join("bar/foo")));
217     t!(File::open(td.path().join("bar/bar")));
218     t!(File::open(td.path().join("foo/foo")));
219     t!(File::open(td.path().join("foo/bar")));
220 }
221 
222 #[test]
223 #[cfg(not(windows))] // dangling symlinks have weird permissions
modify_outside_with_relative_symlink()224 fn modify_outside_with_relative_symlink() {
225     let mut ar = tar::Builder::new(Vec::new());
226 
227     let mut header = tar::Header::new_gnu();
228     header.set_size(0);
229     header.set_entry_type(tar::EntryType::Symlink);
230     t!(header.set_path("symlink"));
231     t!(header.set_link_name(".."));
232     header.set_cksum();
233     t!(ar.append(&header, &[][..]));
234 
235     let mut header = tar::Header::new_gnu();
236     header.set_size(0);
237     header.set_entry_type(tar::EntryType::Regular);
238     t!(header.set_path("symlink/foo/bar"));
239     header.set_cksum();
240     t!(ar.append(&header, &[][..]));
241 
242     let bytes = t!(ar.into_inner());
243     let mut ar = tar::Archive::new(&bytes[..]);
244 
245     let td = t!(Builder::new().prefix("tar").tempdir());
246     let tar_dir = td.path().join("tar");
247     create_dir(&tar_dir).unwrap();
248     assert!(ar.unpack(tar_dir).is_err());
249     assert!(!td.path().join("foo").exists());
250 }
251 
252 #[test]
parent_paths_error()253 fn parent_paths_error() {
254     let mut ar = tar::Builder::new(Vec::new());
255 
256     let mut header = tar::Header::new_gnu();
257     header.set_size(0);
258     header.set_entry_type(tar::EntryType::Symlink);
259     t!(header.set_path("foo"));
260     t!(header.set_link_name(".."));
261     header.set_cksum();
262     t!(ar.append(&header, &[][..]));
263 
264     let mut header = tar::Header::new_gnu();
265     header.set_size(0);
266     header.set_entry_type(tar::EntryType::Regular);
267     t!(header.set_path("foo/bar"));
268     header.set_cksum();
269     t!(ar.append(&header, &[][..]));
270 
271     let bytes = t!(ar.into_inner());
272     let mut ar = tar::Archive::new(&bytes[..]);
273 
274     let td = t!(Builder::new().prefix("tar").tempdir());
275     assert!(ar.unpack(td.path()).is_err());
276     t!(td.path().join("foo").symlink_metadata());
277     assert!(File::open(td.path().join("foo").join("bar")).is_err());
278 }
279 
280 #[test]
281 #[cfg(unix)]
good_parent_paths_ok()282 fn good_parent_paths_ok() {
283     use std::path::PathBuf;
284     let mut ar = tar::Builder::new(Vec::new());
285 
286     let mut header = tar::Header::new_gnu();
287     header.set_size(0);
288     header.set_entry_type(tar::EntryType::Symlink);
289     t!(header.set_path(PathBuf::from("foo").join("bar")));
290     t!(header.set_link_name(PathBuf::from("..").join("bar")));
291     header.set_cksum();
292     t!(ar.append(&header, &[][..]));
293 
294     let mut header = tar::Header::new_gnu();
295     header.set_size(0);
296     header.set_entry_type(tar::EntryType::Regular);
297     t!(header.set_path("bar"));
298     header.set_cksum();
299     t!(ar.append(&header, &[][..]));
300 
301     let bytes = t!(ar.into_inner());
302     let mut ar = tar::Archive::new(&bytes[..]);
303 
304     let td = t!(Builder::new().prefix("tar").tempdir());
305     t!(ar.unpack(td.path()));
306     t!(td.path().join("foo").join("bar").read_link());
307     let dst = t!(td.path().join("foo").join("bar").canonicalize());
308     t!(File::open(dst));
309 }
310 
311 #[test]
modify_hard_link_just_created()312 fn modify_hard_link_just_created() {
313     let mut ar = tar::Builder::new(Vec::new());
314 
315     let mut header = tar::Header::new_gnu();
316     header.set_size(0);
317     header.set_entry_type(tar::EntryType::Link);
318     t!(header.set_path("foo"));
319     t!(header.set_link_name("../test"));
320     header.set_cksum();
321     t!(ar.append(&header, &[][..]));
322 
323     let mut header = tar::Header::new_gnu();
324     header.set_size(1);
325     header.set_entry_type(tar::EntryType::Regular);
326     t!(header.set_path("foo"));
327     header.set_cksum();
328     t!(ar.append(&header, &b"x"[..]));
329 
330     let bytes = t!(ar.into_inner());
331     let mut ar = tar::Archive::new(&bytes[..]);
332 
333     let td = t!(Builder::new().prefix("tar").tempdir());
334 
335     let test = td.path().join("test");
336     t!(File::create(&test));
337 
338     let dir = td.path().join("dir");
339     assert!(ar.unpack(&dir).is_err());
340 
341     let mut contents = Vec::new();
342     t!(t!(File::open(&test)).read_to_end(&mut contents));
343     assert_eq!(contents.len(), 0);
344 }
345 
346 #[test]
modify_symlink_just_created()347 fn modify_symlink_just_created() {
348     let mut ar = tar::Builder::new(Vec::new());
349 
350     let mut header = tar::Header::new_gnu();
351     header.set_size(0);
352     header.set_entry_type(tar::EntryType::Symlink);
353     t!(header.set_path("foo"));
354     t!(header.set_link_name("../test"));
355     header.set_cksum();
356     t!(ar.append(&header, &[][..]));
357 
358     let mut header = tar::Header::new_gnu();
359     header.set_size(1);
360     header.set_entry_type(tar::EntryType::Regular);
361     t!(header.set_path("foo"));
362     header.set_cksum();
363     t!(ar.append(&header, &b"x"[..]));
364 
365     let bytes = t!(ar.into_inner());
366     let mut ar = tar::Archive::new(&bytes[..]);
367 
368     let td = t!(Builder::new().prefix("tar").tempdir());
369 
370     let test = td.path().join("test");
371     t!(File::create(&test));
372 
373     let dir = td.path().join("dir");
374     t!(ar.unpack(&dir));
375 
376     let mut contents = Vec::new();
377     t!(t!(File::open(&test)).read_to_end(&mut contents));
378     assert_eq!(contents.len(), 0);
379 }
380