1 /*-
2  * Copyright (c) 2010 Michihiro NAKAJIMA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 #include "test.h"
26 __FBSDID("$FreeBSD");
27 
28 /*
29 Execute the following command to rebuild the data for this program:
30    tail -n +44 test_read_format_cab.c | /bin/sh
31 And following works are:
32 1. Move /tmp/cab/cab.zip to Windows PC
33 2. Extract cab.zip
34 3. Open command prompt and change current directory where you extracted cab.zip
35 4. Execute cab.bat
36 5. Then you will see that there is a cabinet file, test.cab
37 6. Move test.cab to posix platform
38 7. Extract test.cab with this version of bsdtar
39 8. Execute the following command to make uuencoded files.
40  uuencode test_read_format_cab_1.cab test_read_format_cab_1.cab > test_read_format_cab_1.cab.uu
41  uuencode test_read_format_cab_2.cab test_read_format_cab_2.cab > test_read_format_cab_2.cab.uu
42  uuencode test_read_format_cab_3.cab test_read_format_cab_3.cab > test_read_format_cab_3.cab.uu
43 
44 #!/bin/sh
45 #
46 # How to make test data.
47 #
48 # Temporary directory.
49 base=/tmp/cab
50 # Owner id
51 owner=1001
52 # Group id
53 group=1001
54 #
55 # Make contents of a cabinet file.
56 #
57 rm -rf ${base}
58 mkdir ${base}
59 mkdir ${base}/dir1
60 mkdir ${base}/dir2
61 #
62 touch ${base}/empty
63 cat > ${base}/dir1/file1 << END
64                           file 1 contents
65 hello
66 hello
67 hello
68 END
69 #
70 cat > ${base}/dir2/file2 << END
71                           file 2 contents
72 hello
73 hello
74 hello
75 hello
76 hello
77 hello
78 END
79 #
80 dd if=/dev/zero of=${base}/zero bs=1 count=33000 > /dev/null 2>&1
81 #
82 cab1=test_read_format_cab_1.cab
83 cab2=test_read_format_cab_2.cab
84 cab3=test_read_format_cab_3.cab
85 #
86 #
87 cat > ${base}/mkcab1 << END
88 .Set Compress=OFF
89 .Set DiskDirectory1=.
90 .Set InfDate=1980-01-02
91 .Set InfTime=00:00:00
92 .Set CabinetName1=${cab1}
93 empty
94 .Set DestinationDir=dir1
95 dir1/file1
96 .Set DestinationDir=dir2
97 dir2/file2
98 END
99 #
100 cat > ${base}/mkcab2 << END
101 .Set CompressionType=MSZIP
102 .Set DiskDirectory1=.
103 .Set InfDate=1980-01-02
104 .Set InfTime=00:00:00
105 .Set CabinetName1=${cab2}
106 empty
107 zero
108 .Set DestinationDir=dir1
109 dir1/file1
110 .Set DestinationDir=dir2
111 dir2/file2
112 END
113 #
114 cat > ${base}/mkcab3 << END
115 .Set CompressionType=LZX
116 .Set DiskDirectory1=.
117 .Set InfDate=1980-01-02
118 .Set InfTime=00:00:00
119 .Set CabinetName1=${cab3}
120 empty
121 zero
122 .Set DestinationDir=dir1
123 dir1/file1
124 .Set DestinationDir=dir2
125 dir2/file2
126 END
127 #
128 cat > ${base}/mkcab4 << END
129 .Set CompressionType=MSZIP
130 .Set DiskDirectory1=.
131 .Set CabinetName1=test.cab
132 ${cab1}
133 ${cab2}
134 ${cab3}
135 END
136 #
137 cat > ${base}/cab.bat << END
138 makecab.exe /F mkcab1
139 makecab.exe /F mkcab2
140 makecab.exe /F mkcab3
141 makecab.exe /F mkcab4
142 del setup.inf setup.rpt
143 del empty zero dir1\file1 dir2\file2 mkcab1 mkcab2 mkcab3 mkcab4
144 del ${cab1} ${cab2} ${cab3}
145 rmdir dir1 dir2
146 END
147 #
148 f=cab.zip
149 (cd ${base}; zip -q -c $f empty zero dir1/file1 dir2/file2 mkcab1 mkcab2 mkcab3 mkcab4 cab.bat)
150 #
151 exit 1
152 */
153 
154 static const char file1[] = {
155 "                          file 1 contents\n"
156 "hello\n"
157 "hello\n"
158 "hello\n"
159 };
160 #define file1_size (sizeof(file1)-1)
161 static const char file2[] = {
162 "                          file 2 contents\n"
163 "hello\n"
164 "hello\n"
165 "hello\n"
166 "hello\n"
167 "hello\n"
168 "hello\n"
169 };
170 #define file2_size (sizeof(file2)-1)
171 
172 enum comp_type {
173 	STORE = 0,
174 	MSZIP,
175 	LZX
176 };
177 static void
178 verify(const char *refname, enum comp_type comp)
179 {
180 	struct archive_entry *ae;
181 	struct archive *a;
182 	char buff[128];
183 	char zero[128];
184 	size_t s;
185 
186 	memset(zero, 0, sizeof(zero));
187 	extract_reference_file(refname);
188 	assert((a = archive_read_new()) != NULL);
189 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
190 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
191 	assertEqualIntA(a, ARCHIVE_OK,
192 	    archive_read_open_filename(a, refname, 10240));
193 
194 	/* Verify regular empty. */
195 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
196 	assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
197 	assertEqualString("empty", archive_entry_pathname(ae));
198 	assertEqualInt(0, archive_entry_uid(ae));
199 	assertEqualInt(0, archive_entry_gid(ae));
200 	assertEqualInt(0, archive_entry_size(ae));
201 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
202 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
203 
204 	if (comp != STORE) {
205 		/* Verify regular zero.
206 		 * Maximum CFDATA size is 32768, so we need over 32768 bytes
207 		 * file to check if we properly handle multiple CFDATA.
208 		 */
209 		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
210 		assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
211 		assertEqualString("zero", archive_entry_pathname(ae));
212 		assertEqualInt(0, archive_entry_uid(ae));
213 		assertEqualInt(0, archive_entry_gid(ae));
214 		assertEqualInt(archive_entry_is_encrypted(ae), 0);
215 		assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
216 		assertEqualInt(33000, archive_entry_size(ae));
217 		for (s = 0; s + sizeof(buff) < 33000; s+= sizeof(buff)) {
218 			ssize_t rsize = archive_read_data(a, buff, sizeof(buff));
219 			if (comp == MSZIP && rsize == ARCHIVE_FATAL && archive_zlib_version() == NULL) {
220 				skipping("Skipping CAB format(MSZIP) check: %s",
221 				    archive_error_string(a));
222 				goto finish;
223 			}
224 			assertEqualInt(sizeof(buff), rsize);
225 			assertEqualMem(buff, zero, sizeof(buff));
226 		}
227 		assertEqualInt(33000 - s, archive_read_data(a, buff, 33000 - s));
228 		assertEqualMem(buff, zero, 33000 - s);
229 	}
230 
231 	/* Verify regular file1. */
232 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
233 	assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
234 	assertEqualString("dir1/file1", archive_entry_pathname(ae));
235 	assertEqualInt(0, archive_entry_uid(ae));
236 	assertEqualInt(0, archive_entry_gid(ae));
237 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
238 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
239 	assertEqualInt(file1_size, archive_entry_size(ae));
240 	assertEqualInt(file1_size, archive_read_data(a, buff, file1_size));
241 	assertEqualMem(buff, file1, file1_size);
242 
243 	/* Verify regular file2. */
244 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
245 	assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
246 	assertEqualString("dir2/file2", archive_entry_pathname(ae));
247 	assertEqualInt(0, archive_entry_uid(ae));
248 	assertEqualInt(0, archive_entry_gid(ae));
249 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
250 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
251 	assertEqualInt(file2_size, archive_entry_size(ae));
252 	assertEqualInt(file2_size, archive_read_data(a, buff, file2_size));
253 	assertEqualMem(buff, file2, file2_size);
254 
255 	/* End of archive. */
256 	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
257 
258 	if (comp != STORE) {
259 		assertEqualInt(4, archive_file_count(a));
260 	} else {
261 		assertEqualInt(3, archive_file_count(a));
262 	}
263 
264 	/* Verify archive format. */
265 	assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
266 	assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a));
267 
268 	/* Close the archive. */
269 finish:
270 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
271 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
272 }
273 
274 /*
275  * Skip beginning files and Read the last file.
276  */
277 static void
278 verify2(const char *refname, enum comp_type comp)
279 {
280 	struct archive_entry *ae;
281 	struct archive *a;
282 	char buff[128];
283 	char zero[128];
284 
285 	if (comp == MSZIP && archive_zlib_version() == NULL) {
286 		skipping("Skipping CAB format(MSZIP) check for %s",
287 		  refname);
288 		return;
289 	}
290 	memset(zero, 0, sizeof(zero));
291 	extract_reference_file(refname);
292 	assert((a = archive_read_new()) != NULL);
293 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
294 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
295 	assertEqualIntA(a, ARCHIVE_OK,
296 	    archive_read_open_filename(a, refname, 10240));
297 
298 	/* Verify regular empty. */
299 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
300 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
301 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
302 	if (comp != STORE) {
303 		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
304 		assertEqualInt(archive_entry_is_encrypted(ae), 0);
305 		assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
306 	}
307 	/* Verify regular file1. */
308 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
309 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
310 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
311 
312 	/* Verify regular file2. */
313 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
314 	assertEqualInt((AE_IFREG | 0666), archive_entry_mode(ae));
315 	assertEqualString("dir2/file2", archive_entry_pathname(ae));
316 	assertEqualInt(0, archive_entry_uid(ae));
317 	assertEqualInt(0, archive_entry_gid(ae));
318 	assertEqualInt(file2_size, archive_entry_size(ae));
319 	assertEqualInt(file2_size, archive_read_data(a, buff, file2_size));
320 	assertEqualMem(buff, file2, file2_size);
321 
322 	/* End of archive. */
323 	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
324 
325 	if (comp != STORE) {
326 		assertEqualInt(4, archive_file_count(a));
327 	} else {
328 		assertEqualInt(3, archive_file_count(a));
329 	}
330 
331 	/* Verify archive format. */
332 	assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
333 	assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a));
334 
335 	/* Close the archive. */
336 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
337 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
338 }
339 
340 /*
341  * Skip all file like 'bsdtar tvf foo.cab'.
342  */
343 static void
344 verify3(const char *refname, enum comp_type comp)
345 {
346 	struct archive_entry *ae;
347 	struct archive *a;
348 	char zero[128];
349 
350 	memset(zero, 0, sizeof(zero));
351 	extract_reference_file(refname);
352 	assert((a = archive_read_new()) != NULL);
353 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
354 	assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
355 	assertEqualIntA(a, ARCHIVE_OK,
356 	    archive_read_open_filename(a, refname, 10240));
357 
358 	/* Verify regular empty. */
359 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
360 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
361 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
362 	if (comp != STORE) {
363 		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
364 		assertEqualInt(archive_entry_is_encrypted(ae), 0);
365 		assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
366 	}
367 	/* Verify regular file1. */
368 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
369 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
370 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
371 
372 	/* Verify regular file2. */
373 	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
374 	assertEqualInt(archive_entry_is_encrypted(ae), 0);
375 	assertEqualIntA(a, archive_read_has_encrypted_entries(a), ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED);
376 
377 	/* End of archive. */
378 	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
379 
380 	if (comp != STORE) {
381 		assertEqualInt(4, archive_file_count(a));
382 	} else {
383 		assertEqualInt(3, archive_file_count(a));
384 	}
385 
386 	/* Verify archive format. */
387 	assertEqualIntA(a, ARCHIVE_FILTER_NONE, archive_filter_code(a, 0));
388 	assertEqualIntA(a, ARCHIVE_FORMAT_CAB, archive_format(a));
389 
390 	/* Close the archive. */
391 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
392 	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
393 }
394 
395 DEFINE_TEST(test_read_format_cab)
396 {
397 	/* Verify Cabinet file in no compression. */
398 	verify("test_read_format_cab_1.cab", STORE);
399 	verify2("test_read_format_cab_1.cab", STORE);
400 	verify3("test_read_format_cab_1.cab", STORE);
401 	/* Verify Cabinet file in MSZIP. */
402 	verify("test_read_format_cab_2.cab", MSZIP);
403 	verify2("test_read_format_cab_2.cab", MSZIP);
404 	verify3("test_read_format_cab_2.cab", MSZIP);
405 	/* Verify Cabinet file in LZX. */
406 	verify("test_read_format_cab_3.cab", LZX);
407 	verify2("test_read_format_cab_3.cab", LZX);
408 	verify3("test_read_format_cab_3.cab", LZX);
409 }
410 
411