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