test_write_format_iso9660_filename.c revision 231200
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 */ 30static void 31add_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 49struct 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 63enum vtype { 64 ROCKRIDGE, 65 JOLIET, 66 ISO9660 67}; 68 69/* 70 * Verify file 71 */ 72static void 73verify_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 *symlink = archive_entry_symlink(ae); 102 size_t length; 103 104 if (symlink != NULL) { 105 length = strlen(symlink); 106 assert(length == 1 || length == 128 || length == 255); 107 assertEqualInt(symlink[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 140static void 141verify(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 200static int 201create_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_set_compression_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 < 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 < 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 305DEFINE_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 memset(&fns, 0, sizeof(fns)); 316 317 /* 318 * Create ISO image with no option. 319 */ 320 fcnt = create_iso_image(buff, buffsize, &used, NULL); 321 322 fns.names = (char **)malloc(sizeof(char *) * fcnt); 323 assert(fns.names != NULL); 324 fns.alloc = fcnt; 325 326 /* Verify rockridge filenames. */ 327 fns.longest_len = 0; 328 fns.maxlen = fns.maxflen = fns.maxelen = 255; 329 fns.opt = ALLOW_LDOT; 330 verify(buff, used, ROCKRIDGE, &fns); 331 332 /* Verify joliet filenames. */ 333 fns.longest_len = 0; 334 fns.maxlen = fns.maxflen = fns.maxelen = 64; 335 fns.opt = ALLOW_LDOT; 336 verify(buff, used, JOLIET, &fns); 337 338 /* Verify ISO9660 filenames. */ 339 fns.longest_len = 0; 340 fns.maxlen = 8+3+1; 341 fns.maxflen = 8; 342 fns.maxelen = 3; 343 fns.opt = UPPER_CASE_ONLY | ONE_DOT; 344 verify(buff, used, ISO9660, &fns); 345 346 /* 347 * Create ISO image with iso-level=2. 348 */ 349 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used, 350 "iso-level=2")); 351 352 /* Verify rockridge filenames. */ 353 fns.longest_len = 0; 354 fns.maxlen = fns.maxflen = fns.maxelen = 255; 355 fns.opt = ALLOW_LDOT; 356 verify(buff, used, ROCKRIDGE, &fns); 357 358 /* Verify joliet filenames. */ 359 fns.longest_len = 0; 360 fns.maxlen = fns.maxflen = fns.maxelen = 64; 361 fns.opt = ALLOW_LDOT; 362 verify(buff, used, JOLIET, &fns); 363 364 /* Verify ISO9660 filenames. */ 365 fns.longest_len = 0; 366 fns.maxlen = 31; 367 fns.maxflen = 30; 368 fns.maxelen = 30; 369 fns.opt = UPPER_CASE_ONLY | ONE_DOT; 370 verify(buff, used, ISO9660, &fns); 371 372 /* 373 * Create ISO image with iso-level=3. 374 */ 375 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used, 376 "iso-level=3")); 377 378 /* Verify rockridge filenames. */ 379 fns.longest_len = 0; 380 fns.maxlen = fns.maxflen = fns.maxelen = 255; 381 fns.opt = ALLOW_LDOT; 382 verify(buff, used, ROCKRIDGE, &fns); 383 384 /* Verify joliet filenames. */ 385 fns.longest_len = 0; 386 fns.maxlen = fns.maxflen = fns.maxelen = 64; 387 fns.opt = ALLOW_LDOT; 388 verify(buff, used, JOLIET, &fns); 389 390 /* Verify ISO9660 filenames. */ 391 fns.longest_len = 0; 392 fns.maxlen = 31; 393 fns.maxflen = 30; 394 fns.maxelen = 30; 395 fns.opt = UPPER_CASE_ONLY | ONE_DOT; 396 verify(buff, used, ISO9660, &fns); 397 398 /* 399 * Create ISO image with iso-level=4. 400 */ 401 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used, 402 "iso-level=4")); 403 404 /* Verify rockridge filenames. */ 405 fns.longest_len = 0; 406 fns.maxlen = fns.maxflen = fns.maxelen = 255; 407 fns.opt = ALLOW_LDOT; 408 verify(buff, used, ROCKRIDGE, &fns); 409 410 /* Verify joliet filenames. */ 411 fns.longest_len = 0; 412 fns.maxlen = fns.maxflen = fns.maxelen = 64; 413 fns.opt = ALLOW_LDOT; 414 verify(buff, used, JOLIET, &fns); 415 416 /* Verify ISO9660 filenames. */ 417 fns.longest_len = 0; 418 fns.maxlen = fns.maxflen = fns.maxelen = 193; 419 fns.opt = ALLOW_LDOT; 420 verify(buff, used, ISO9660, &fns); 421 422 /* 423 * Create ISO image with iso-level=4 and !rockridge. 424 */ 425 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used, 426 "iso-level=4,!rockridge")); 427 428 /* Verify joliet filenames. */ 429 fns.longest_len = 0; 430 fns.maxlen = fns.maxflen = fns.maxelen = 64; 431 fns.opt = ALLOW_LDOT; 432 verify(buff, used, JOLIET, &fns); 433 434 /* Verify ISO9660 filenames. */ 435 fns.longest_len = 0; 436 fns.maxlen = fns.maxflen = fns.maxelen = 207; 437 fns.opt = ALLOW_LDOT; 438 verify(buff, used, ISO9660, &fns); 439 440 /* 441 * Create ISO image with joliet=long. 442 */ 443 assertEqualInt(fcnt, create_iso_image(buff, buffsize, &used, 444 "joliet=long")); 445 446 /* Verify rockridge filenames. */ 447 fns.longest_len = 0; 448 fns.maxlen = fns.maxflen = fns.maxelen = 255; 449 fns.opt = ALLOW_LDOT; 450 verify(buff, used, ROCKRIDGE, &fns); 451 452 /* Verify joliet filenames. */ 453 fns.longest_len = 0; 454 fns.maxlen = fns.maxflen = fns.maxelen = 103; 455 fns.opt = ALLOW_LDOT; 456 verify(buff, used, JOLIET, &fns); 457 458 /* Verify ISO9660 filenames. */ 459 fns.longest_len = 0; 460 fns.maxlen = 8+3+1; 461 fns.maxflen = 8; 462 fns.maxelen = 3; 463 fns.opt = UPPER_CASE_ONLY | ONE_DOT; 464 verify(buff, used, ISO9660, &fns); 465 466 free(fns.names); 467 free(buff); 468} 469