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