1 /*-
2 * Copyright (c) 2009,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
27 /*
28 * Check that an ISO 9660 image is correctly created.
29 */
30 static void
add_entry(struct archive * a,const char * fname,const char * sym)31 add_entry(struct archive *a, const char *fname, const char *sym)
32 {
33 struct archive_entry *ae;
34
35 assert((ae = archive_entry_new()) != NULL);
36 archive_entry_set_birthtime(ae, 2, 20);
37 archive_entry_set_atime(ae, 3, 30);
38 archive_entry_set_ctime(ae, 4, 40);
39 archive_entry_set_mtime(ae, 5, 50);
40 archive_entry_copy_pathname(ae, fname);
41 if (sym != NULL)
42 archive_entry_set_symlink(ae, sym);
43 archive_entry_set_mode(ae, S_IFREG | 0555);
44 archive_entry_set_size(ae, 0);
45 assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
46 archive_entry_free(ae);
47 }
48
49 struct fns {
50 size_t maxlen;
51 size_t longest_len;
52 size_t maxflen;
53 size_t maxelen;
54 size_t alloc;
55 int cnt;
56 char **names;
57 int opt;
58 #define UPPER_CASE_ONLY 0x00001
59 #define ONE_DOT 0x00002
60 #define ALLOW_LDOT 0x00004
61 };
62
63 enum vtype {
64 ROCKRIDGE,
65 JOLIET,
66 ISO9660
67 };
68
69 /*
70 * Verify file
71 */
72 static void
verify_file(struct archive * a,enum vtype type,struct fns * fns)73 verify_file(struct archive *a, enum vtype type, struct fns *fns)
74 {
75 struct archive_entry *ae;
76 int i;
77
78 assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
79 if (type == ROCKRIDGE) {
80 assertEqualInt(2, archive_entry_birthtime(ae));
81 assertEqualInt(3, archive_entry_atime(ae));
82 assertEqualInt(4, archive_entry_ctime(ae));
83 } else {
84 assertEqualInt(0, archive_entry_birthtime_is_set(ae));
85 assertEqualInt(5, archive_entry_atime(ae));
86 assertEqualInt(5, archive_entry_ctime(ae));
87 }
88 assertEqualInt(5, archive_entry_mtime(ae));
89 if (type == ROCKRIDGE)
90 assert((S_IFREG | 0555) == archive_entry_mode(ae));
91 else
92 assert((S_IFREG | 0400) == archive_entry_mode(ae));
93 assertEqualInt(0, archive_entry_size(ae));
94
95 /*
96 * Check if the same filename does not appear.
97 */
98 for (i = 0; i < fns->cnt; i++) {
99 const char *p;
100 const char *pathname = archive_entry_pathname(ae);
101 const char *symlinkname = archive_entry_symlink(ae);
102 size_t length;
103
104 if (symlinkname != NULL) {
105 length = strlen(symlinkname);
106 assert(length == 1 || length == 128 || length == 255);
107 assertEqualInt(symlinkname[length-1], 'x');
108 }
109 failure("Found duplicate for %s", pathname);
110 assert(strcmp(fns->names[i], pathname) != 0);
111 assert((length = strlen(pathname)) <= fns->maxlen);
112 if (length > fns->longest_len)
113 fns->longest_len = length;
114 p = strrchr(pathname, '.');
115 if (p != NULL) {
116 /* Check a length of file name. */
117 assert((size_t)(p - pathname) <= fns->maxflen);
118 /* Check a length of file extension. */
119 assert(strlen(p+1) <= fns->maxelen);
120 if (fns->opt & ONE_DOT) {
121 /* Do not have multi dot. */
122 assert(strchr(pathname, '.') == p);
123 }
124 }
125 for (p = pathname; *p; p++) {
126 if (fns->opt & UPPER_CASE_ONLY) {
127 /* Do not have any lower-case character. */
128 assert(*p < 'a' || *p > 'z');
129 } else
130 break;
131 }
132 if ((fns->opt & ALLOW_LDOT) == 0)
133 /* Do not have a dot at the first position. */
134 assert(*pathname != '.');
135 }
136 /* Save the filename which is appeared to use above next time. */
137 fns->names[fns->cnt++] = strdup(archive_entry_pathname(ae));
138 }
139
140 static void
verify(unsigned char * buff,size_t used,enum vtype type,struct fns * fns)141 verify(unsigned char *buff, size_t used, enum vtype type, struct fns *fns)
142 {
143 struct archive *a;
144 struct archive_entry *ae;
145 size_t i;
146
147 /*
148 * Read ISO image.
149 */
150 assert((a = archive_read_new()) != NULL);
151 assertEqualIntA(a, 0, archive_read_support_format_all(a));
152 assertEqualIntA(a, 0, archive_read_support_filter_all(a));
153 if (type >= 1)
154 assertA(0 == archive_read_set_option(a, NULL, "rockridge",
155 NULL));
156 if (type >= 2)
157 assertA(0 == archive_read_set_option(a, NULL, "joliet",
158 NULL));
159 assertEqualIntA(a, 0, archive_read_open_memory(a, buff, used));
160
161 /*
162 * Read Root Directory
163 * Root Directory entry must be in ISO image.
164 */
165 assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
166 assertEqualInt(archive_entry_atime(ae), archive_entry_ctime(ae));
167 assertEqualInt(archive_entry_atime(ae), archive_entry_mtime(ae));
168 assertEqualString(".", archive_entry_pathname(ae));
169 switch (type) {
170 case ROCKRIDGE:
171 assert((S_IFDIR | 0555) == archive_entry_mode(ae));
172 break;
173 case JOLIET:
174 assert((S_IFDIR | 0700) == archive_entry_mode(ae));
175 break;
176 case ISO9660:
177 assert((S_IFDIR | 0700) == archive_entry_mode(ae));
178 break;
179 }
180
181 /*
182 * Verify file status.
183 */
184 memset(fns->names, 0, sizeof(char *) * fns->alloc);
185 fns->cnt = 0;
186 for (i = 0; i < fns->alloc; i++)
187 verify_file(a, type, fns);
188 for (i = 0; i < fns->alloc; i++)
189 free(fns->names[i]);
190 assertEqualInt((int)fns->longest_len, (int)fns->maxlen);
191
192 /*
193 * Verify the end of the archive.
194 */
195 assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
196 assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
197 assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a));
198 }
199
200 static int
create_iso_image(unsigned char * buff,size_t buffsize,size_t * used,const char * opt)201 create_iso_image(unsigned char *buff, size_t buffsize, size_t *used,
202 const char *opt)
203 {
204 struct archive *a;
205 int i, l, fcnt;
206 const int lens[] = {
207 0, 1, 3, 5, 7, 8, 9, 29, 30, 31, 32,
208 62, 63, 64, 65, 101, 102, 103, 104,
209 191, 192, 193, 194, 204, 205, 206, 207, 208,
210 252, 253, 254, 255,
211 -1 };
212 char fname1[256];
213 char fname2[256];
214 char sym1[2];
215 char sym128[129];
216 char sym255[256];
217
218 /* ISO9660 format: Create a new archive in memory. */
219 assert((a = archive_write_new()) != NULL);
220 assertA(0 == archive_write_set_format_iso9660(a));
221 assertA(0 == archive_write_add_filter_none(a));
222 assertA(0 == archive_write_set_option(a, NULL, "pad", NULL));
223 if (opt)
224 assertA(0 == archive_write_set_options(a, opt));
225 assertA(0 == archive_write_set_bytes_per_block(a, 1));
226 assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
227 assertA(0 == archive_write_open_memory(a, buff, buffsize, used));
228
229 sym1[0] = 'x';
230 sym1[1] = '\0';
231 for (i = 0; i < (int)sizeof(sym128)-2; i++)
232 sym128[i] = 'a';
233 sym128[sizeof(sym128)-2] = 'x';
234 sym128[sizeof(sym128)-1] = '\0';
235 for (i = 0; i < (int)sizeof(sym255)-2; i++)
236 sym255[i] = 'a';
237 sym255[sizeof(sym255)-2] = 'x';
238 sym255[sizeof(sym255)-1] = '\0';
239
240 fcnt = 0;
241 for (i = 0; lens[i] >= 0; i++) {
242 for (l = 0; l < lens[i]; l++) {
243 fname1[l] = 'a';
244 fname2[l] = 'A';
245 }
246 if (l > 0) {
247 fname1[l] = '\0';
248 fname2[l] = '\0';
249 add_entry(a, fname1, NULL);
250 add_entry(a, fname2, sym1);
251 fcnt += 2;
252 }
253 if (l < 254) {
254 fname1[l] = '.';
255 fname1[l+1] = 'c';
256 fname1[l+2] = '\0';
257 fname2[l] = '.';
258 fname2[l+1] = 'C';
259 fname2[l+2] = '\0';
260 add_entry(a, fname1, sym128);
261 add_entry(a, fname2, sym255);
262 fcnt += 2;
263 }
264 if (l < 252) {
265 fname1[l] = '.';
266 fname1[l+1] = 'p';
267 fname1[l+2] = 'n';
268 fname1[l+3] = 'g';
269 fname1[l+4] = '\0';
270 fname2[l] = '.';
271 fname2[l+1] = 'P';
272 fname2[l+2] = 'N';
273 fname2[l+3] = 'G';
274 fname2[l+4] = '\0';
275 add_entry(a, fname1, NULL);
276 add_entry(a, fname2, sym1);
277 fcnt += 2;
278 }
279 if (l < 251) {
280 fname1[l] = '.';
281 fname1[l+1] = 'j';
282 fname1[l+2] = 'p';
283 fname1[l+3] = 'e';
284 fname1[l+4] = 'g';
285 fname1[l+5] = '\0';
286 fname2[l] = '.';
287 fname2[l+1] = 'J';
288 fname2[l+2] = 'P';
289 fname2[l+3] = 'E';
290 fname2[l+4] = 'G';
291 fname2[l+5] = '\0';
292 add_entry(a, fname1, sym128);
293 add_entry(a, fname2, sym255);
294 fcnt += 2;
295 }
296 }
297
298 /* Close out the archive. */
299 assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
300 assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a));
301
302 return (fcnt);
303 }
304
DEFINE_TEST(test_write_format_iso9660_filename)305 DEFINE_TEST(test_write_format_iso9660_filename)
306 {
307 unsigned char *buff;
308 size_t buffsize = 120 * 2048;
309 size_t used;
310 int fcnt;
311 struct fns fns;
312
313 buff = malloc(buffsize);
314 assert(buff != NULL);
315 if (buff == NULL)
316 return;
317 memset(&fns, 0, sizeof(fns));
318
319 /*
320 * Create ISO image with no option.
321 */
322 fcnt = create_iso_image(buff, buffsize, &used, NULL);
323
324 fns.names = malloc(sizeof(char *) * fcnt);
325 assert(fns.names != NULL);
326 if (fns.names == NULL) {
327 free(buff);
328 return;
329 }
330 fns.alloc = fcnt;
331
332 /* Verify rockridge filenames. */
333 fns.longest_len = 0;
334 fns.maxlen = fns.maxflen = fns.maxelen = 255;
335 fns.opt = ALLOW_LDOT;
336 verify(buff, used, ROCKRIDGE, &fns);
337
338 /* Verify joliet filenames. */
339 fns.longest_len = 0;
340 fns.maxlen = fns.maxflen = fns.maxelen = 64;
341 fns.opt = ALLOW_LDOT;
342 verify(buff, used, JOLIET, &fns);
343
344 /* Verify ISO9660 filenames. */
345 fns.longest_len = 0;
346 fns.maxlen = 8+3+1;
347 fns.maxflen = 8;
348 fns.maxelen = 3;
349 fns.opt = UPPER_CASE_ONLY | ONE_DOT;
350 verify(buff, used, ISO9660, &fns);
351
352 /*
353 * Create ISO image with iso-level=2.
354 */
355 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used,
356 "iso-level=2"));
357
358 /* Verify rockridge filenames. */
359 fns.longest_len = 0;
360 fns.maxlen = fns.maxflen = fns.maxelen = 255;
361 fns.opt = ALLOW_LDOT;
362 verify(buff, used, ROCKRIDGE, &fns);
363
364 /* Verify joliet filenames. */
365 fns.longest_len = 0;
366 fns.maxlen = fns.maxflen = fns.maxelen = 64;
367 fns.opt = ALLOW_LDOT;
368 verify(buff, used, JOLIET, &fns);
369
370 /* Verify ISO9660 filenames. */
371 fns.longest_len = 0;
372 fns.maxlen = 31;
373 fns.maxflen = 30;
374 fns.maxelen = 30;
375 fns.opt = UPPER_CASE_ONLY | ONE_DOT;
376 verify(buff, used, ISO9660, &fns);
377
378 /*
379 * Create ISO image with iso-level=3.
380 */
381 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used,
382 "iso-level=3"));
383
384 /* Verify rockridge filenames. */
385 fns.longest_len = 0;
386 fns.maxlen = fns.maxflen = fns.maxelen = 255;
387 fns.opt = ALLOW_LDOT;
388 verify(buff, used, ROCKRIDGE, &fns);
389
390 /* Verify joliet filenames. */
391 fns.longest_len = 0;
392 fns.maxlen = fns.maxflen = fns.maxelen = 64;
393 fns.opt = ALLOW_LDOT;
394 verify(buff, used, JOLIET, &fns);
395
396 /* Verify ISO9660 filenames. */
397 fns.longest_len = 0;
398 fns.maxlen = 31;
399 fns.maxflen = 30;
400 fns.maxelen = 30;
401 fns.opt = UPPER_CASE_ONLY | ONE_DOT;
402 verify(buff, used, ISO9660, &fns);
403
404 /*
405 * Create ISO image with iso-level=4.
406 */
407 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used,
408 "iso-level=4"));
409
410 /* Verify rockridge filenames. */
411 fns.longest_len = 0;
412 fns.maxlen = fns.maxflen = fns.maxelen = 255;
413 fns.opt = ALLOW_LDOT;
414 verify(buff, used, ROCKRIDGE, &fns);
415
416 /* Verify joliet filenames. */
417 fns.longest_len = 0;
418 fns.maxlen = fns.maxflen = fns.maxelen = 64;
419 fns.opt = ALLOW_LDOT;
420 verify(buff, used, JOLIET, &fns);
421
422 /* Verify ISO9660 filenames. */
423 fns.longest_len = 0;
424 fns.maxlen = fns.maxflen = fns.maxelen = 193;
425 fns.opt = ALLOW_LDOT;
426 verify(buff, used, ISO9660, &fns);
427
428 /*
429 * Create ISO image with iso-level=4 and !rockridge.
430 */
431 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used,
432 "iso-level=4,!rockridge"));
433
434 /* Verify joliet filenames. */
435 fns.longest_len = 0;
436 fns.maxlen = fns.maxflen = fns.maxelen = 64;
437 fns.opt = ALLOW_LDOT;
438 verify(buff, used, JOLIET, &fns);
439
440 /* Verify ISO9660 filenames. */
441 fns.longest_len = 0;
442 fns.maxlen = fns.maxflen = fns.maxelen = 207;
443 fns.opt = ALLOW_LDOT;
444 verify(buff, used, ISO9660, &fns);
445
446 /*
447 * Create ISO image with joliet=long.
448 */
449 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used,
450 "joliet=long"));
451
452 /* Verify rockridge filenames. */
453 fns.longest_len = 0;
454 fns.maxlen = fns.maxflen = fns.maxelen = 255;
455 fns.opt = ALLOW_LDOT;
456 verify(buff, used, ROCKRIDGE, &fns);
457
458 /* Verify joliet filenames. */
459 fns.longest_len = 0;
460 fns.maxlen = fns.maxflen = fns.maxelen = 103;
461 fns.opt = ALLOW_LDOT;
462 verify(buff, used, JOLIET, &fns);
463
464 /* Verify ISO9660 filenames. */
465 fns.longest_len = 0;
466 fns.maxlen = 8+3+1;
467 fns.maxflen = 8;
468 fns.maxelen = 3;
469 fns.opt = UPPER_CASE_ONLY | ONE_DOT;
470 verify(buff, used, ISO9660, &fns);
471
472 free(fns.names);
473 free(buff);
474 }
475