]>
Commit | Line | Data |
---|---|---|
7cac9316 XL |
1 | use std::fs::{self, File}; |
2 | use std::io::{self, Write}; | |
3 | use std::path::Path; | |
ff7c6d11 | 4 | use std::{iter, mem, thread, time}; |
7cac9316 | 5 | |
3dfed10e | 6 | use tempfile::Builder; |
7cac9316 | 7 | |
a1dfa0c6 | 8 | use tar::{GnuHeader, Header, HeaderMode}; |
7cac9316 XL |
9 | |
10 | #[test] | |
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] | |
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] | |
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] | |
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 | ||
ff7c6d11 XL |
62 | #[test] |
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 | ||
7cac9316 XL |
74 | #[test] |
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] | |
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 | ||
ff7c6d11 XL |
109 | h.as_ustar_mut().unwrap().dev_minor[0] = 0x7f; |
110 | h.as_ustar_mut().unwrap().dev_major[0] = 0x7f; | |
7cac9316 XL |
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] | |
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 | ||
3dfed10e XL |
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 | ||
7cac9316 XL |
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] | |
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] | |
176 | fn set_metadata_deterministic() { | |
3dfed10e | 177 | let td = t!(Builder::new().prefix("tar-rs").tempdir()); |
7cac9316 XL |
178 | let tmppath = td.path().join("tmpfile"); |
179 | ||
180 | fn mk_header(path: &Path, readonly: bool) -> Result<Header, io::Error> { | |
a1dfa0c6 XL |
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) | |
7cac9316 XL |
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 | } | |
ff7c6d11 XL |
208 | |
209 | #[test] | |
210 | fn extended_numeric_format() { | |
211 | let mut h: GnuHeader = unsafe { mem::zeroed() }; | |
a1dfa0c6 XL |
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]); | |
ff7c6d11 XL |
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); | |
a1dfa0c6 XL |
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); | |
ff7c6d11 XL |
227 | h.uid = [0x80, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78]; |
228 | assert_eq!(h.as_header().uid().unwrap(), 0x12345678); | |
a1dfa0c6 XL |
229 | |
230 | h.mtime = [ | |
231 | 0x80, 0, 0, 0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, | |
232 | ]; | |
ff7c6d11 XL |
233 | assert_eq!(h.as_header().mtime().unwrap(), 0x0123456789abcdef); |
234 | } | |
83c7162d XL |
235 | |
236 | #[test] | |
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 | } |