1 /* $OpenBSD: cd9660.c,v 1.23 2022/01/11 05:34:32 jsg Exp $ */ 2 /* $NetBSD: cd9660.c,v 1.53 2016/11/25 23:02:44 christos Exp $ */ 3 4 /* 5 * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 6 * Perez-Rathke and Ram Vedam. All rights reserved. 7 * 8 * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 9 * Alan Perez-Rathke and Ram Vedam. 10 * 11 * Redistribution and use in source and binary forms, with or 12 * without modification, are permitted provided that the following 13 * conditions are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer in the documentation and/or other materials provided 19 * with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 22 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 26 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 29 * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 33 * OF SUCH DAMAGE. 34 */ 35 /* 36 * Copyright (c) 2001 Wasabi Systems, Inc. 37 * All rights reserved. 38 * 39 * Written by Luke Mewburn for Wasabi Systems, Inc. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed for the NetBSD Project by 52 * Wasabi Systems, Inc. 53 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 54 * or promote products derived from this software without specific prior 55 * written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 60 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 61 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 62 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 63 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 64 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 65 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 66 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 67 * POSSIBILITY OF SUCH DAMAGE. 68 */ 69 /* 70 * Copyright (c) 1982, 1986, 1989, 1993 71 * The Regents of the University of California. All rights reserved. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 1. Redistributions of source code must retain the above copyright 77 * notice, this list of conditions and the following disclaimer. 78 * 2. Redistributions in binary form must reproduce the above copyright 79 * notice, this list of conditions and the following disclaimer in the 80 * documentation and/or other materials provided with the distribution. 81 * 3. Neither the name of the University nor the names of its contributors 82 * may be used to endorse or promote products derived from this software 83 * without specific prior written permission. 84 * 85 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 86 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 87 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 88 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 89 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 90 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 91 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 92 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 93 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 94 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 95 * SUCH DAMAGE. 96 * 97 */ 98 99 #include <sys/queue.h> 100 101 #include <string.h> 102 #include <ctype.h> 103 #include <inttypes.h> 104 #include <limits.h> 105 106 #include "makefs.h" 107 #include "cd9660.h" 108 #include "cd9660/iso9660_rrip.h" 109 110 /* 111 * Global variables 112 */ 113 114 static void cd9660_finalize_PVD(iso9660_disk *); 115 static cd9660node *cd9660_allocate_cd9660node(void); 116 static void cd9660_set_defaults(iso9660_disk *); 117 static int cd9660_arguments_set_string(const char *, const char *, size_t, 118 char, char *); 119 static void cd9660_populate_iso_dir_record( 120 struct _iso_directory_record_cd9660 *, u_char, u_char, u_char, 121 const char *); 122 static void cd9660_setup_root_node(iso9660_disk *); 123 static int cd9660_setup_volume_descriptors(iso9660_disk *); 124 #if 0 125 static int cd9660_fill_extended_attribute_record(cd9660node *); 126 #endif 127 static void cd9660_sort_nodes(cd9660node *); 128 static int cd9660_translate_node_common(iso9660_disk *, cd9660node *); 129 static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *); 130 static int cd9660_compare_filename(const char *, const char *); 131 static void cd9660_sorted_child_insert(cd9660node *, cd9660node *); 132 static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int); 133 static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int, 134 int); 135 static void cd9660_copy_filenames(iso9660_disk *, cd9660node *); 136 static void cd9660_sorting_nodes(cd9660node *); 137 static int cd9660_count_collisions(cd9660node *); 138 static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *); 139 static int cd9660_add_dot_records(iso9660_disk *, cd9660node *); 140 141 static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int, 142 int *, int *); 143 static void cd9660_free_structure(cd9660node *); 144 static int cd9660_generate_path_table(iso9660_disk *); 145 static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *, 146 size_t, int); 147 static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *, 148 size_t, int); 149 static int cd9660_convert_filename(iso9660_disk *, const char *, char *, size_t, int); 150 static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *); 151 static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t); 152 #if 0 153 static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int); 154 #endif 155 static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *, 156 cd9660node *, int, int); 157 static cd9660node *cd9660_create_file(iso9660_disk *, const char *, 158 cd9660node *, cd9660node *); 159 static cd9660node *cd9660_create_directory(iso9660_disk *, const char *, 160 cd9660node *, cd9660node *); 161 static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char, 162 cd9660node *); 163 static int cd9660_add_generic_bootimage(iso9660_disk *, const char *); 164 165 166 /* 167 * Allocate and initialize a cd9660node 168 * @returns struct cd9660node * Pointer to new node, or NULL on error 169 */ 170 static cd9660node * 171 cd9660_allocate_cd9660node(void) 172 { 173 cd9660node *temp = ecalloc(1, sizeof(*temp)); 174 TAILQ_INIT(&temp->cn_children); 175 temp->parent = temp->dot_record = temp->dot_dot_record = NULL; 176 temp->ptnext = temp->ptprev = temp->ptlast = NULL; 177 temp->node = NULL; 178 temp->isoDirRecord = NULL; 179 temp->isoExtAttributes = NULL; 180 temp->rr_real_parent = temp->rr_relocated = NULL; 181 temp->su_tail_data = NULL; 182 return temp; 183 } 184 185 int cd9660_defaults_set = 0; 186 187 /** 188 * Set default values for cd9660 extension to makefs 189 */ 190 static void 191 cd9660_set_defaults(iso9660_disk *diskStructure) 192 { 193 /*Fix the sector size for now, though the spec allows for other sizes*/ 194 diskStructure->sectorSize = 2048; 195 196 /* Set up defaults in our own structure */ 197 diskStructure->isoLevel = 2; 198 199 diskStructure->rock_ridge_enabled = 0; 200 diskStructure->rock_ridge_renamed_dir_name = 0; 201 diskStructure->rock_ridge_move_count = 0; 202 diskStructure->rr_moved_dir = 0; 203 204 diskStructure->include_padding_areas = 1; 205 206 /* Spec breaking functionality */ 207 diskStructure->allow_deep_trees = 208 diskStructure->allow_multidot = 209 diskStructure->omit_trailing_period = 0; 210 211 /* Make sure the PVD is clear */ 212 memset(&diskStructure->primaryDescriptor, 0, 2048); 213 214 memset(diskStructure->primaryDescriptor.publisher_id, 0x20,128); 215 memset(diskStructure->primaryDescriptor.preparer_id, 0x20,128); 216 memset(diskStructure->primaryDescriptor.application_id, 0x20,128); 217 memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37); 218 memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37); 219 memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37); 220 221 strlcpy(diskStructure->primaryDescriptor.system_id,"NetBSD", sizeof(diskStructure->primaryDescriptor.system_id)); 222 223 cd9660_defaults_set = 1; 224 225 /* Boot support: Initially disabled */ 226 diskStructure->has_generic_bootimage = 0; 227 diskStructure->generic_bootimage = NULL; 228 229 /*memset(diskStructure->boot_descriptor, 0, 2048);*/ 230 231 diskStructure->is_bootable = 0; 232 TAILQ_INIT(&diskStructure->boot_images); 233 LIST_INIT(&diskStructure->boot_entries); 234 } 235 236 void 237 cd9660_prep_opts(fsinfo_t *fsopts) 238 { 239 iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure)); 240 241 #define OPT_STR(name) \ 242 { name, NULL, OPT_STRBUF, 0, 0 } 243 244 #define OPT_NUM(name, field, min, max) \ 245 { name, &diskStructure->field, \ 246 sizeof(diskStructure->field) == 8 ? OPT_INT64 : \ 247 (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \ 248 (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \ 249 min, max } 250 251 #define OPT_BOOL(name, field) \ 252 { name, &diskStructure->field, OPT_BOOL } 253 254 const option_t cd9660_options[] = { 255 OPT_BOOL("allow-deep-trees", allow_deep_trees), 256 OPT_BOOL("allow-multidot", allow_multidot), 257 OPT_STR("applicationid"), 258 OPT_STR("boot-load-segment"), 259 OPT_STR("bootimage"), 260 OPT_STR("generic-bootimage"), 261 OPT_STR("hard-disk-boot"), 262 OPT_NUM("isolevel", isoLevel, 1, 3), 263 OPT_STR("label"), 264 OPT_STR("no-boot"), 265 OPT_STR("no-emul-boot"), 266 OPT_BOOL("no-trailing-padding", include_padding_areas), 267 OPT_BOOL("omit-trailing-period", omit_trailing_period), 268 OPT_STR("preparer"), 269 OPT_STR("publisher"), 270 OPT_BOOL("rockridge", rock_ridge_enabled), 271 OPT_STR("volumeid"), 272 { .name = NULL } 273 }; 274 275 fsopts->fs_specific = diskStructure; 276 fsopts->fs_options = copy_opts(cd9660_options); 277 278 cd9660_set_defaults(diskStructure); 279 } 280 281 void 282 cd9660_cleanup_opts(fsinfo_t *fsopts) 283 { 284 free(fsopts->fs_specific); 285 free(fsopts->fs_options); 286 } 287 288 static int 289 cd9660_arguments_set_string(const char *val, const char *fieldtitle, 290 size_t length, char testmode, char * dest) 291 { 292 size_t len; 293 int test; 294 295 if (val == NULL) 296 warnx("error: '%s' requires a string argument", fieldtitle); 297 else if ((len = strlen(val)) <= length) { 298 if (testmode == 'd') 299 test = cd9660_valid_d_chars(val); 300 else 301 test = cd9660_valid_a_chars(val); 302 if (test) { 303 memcpy(dest, val, len); 304 if (test == 2) 305 cd9660_uppercase_characters(dest, len); 306 return 1; 307 } else 308 warnx("error: '%s' must be composed of %c-characters", 309 fieldtitle, testmode); 310 } else 311 warnx("error: '%s' must be at most 32 characters long", 312 fieldtitle); 313 return 0; 314 } 315 316 /* 317 * Command-line parsing function 318 */ 319 320 int 321 cd9660_parse_opts(const char *option, fsinfo_t *fsopts) 322 { 323 int rv, i; 324 iso9660_disk *diskStructure = fsopts->fs_specific; 325 option_t *cd9660_options = fsopts->fs_options; 326 char buf[1024]; 327 const char *name; 328 329 assert(option != NULL); 330 331 i = set_option(cd9660_options, option, buf, sizeof(buf)); 332 if (i == -1) 333 return 0; 334 335 if (cd9660_options[i].name == NULL) 336 abort(); 337 338 339 name = cd9660_options[i].name; 340 341 if (strcmp(name, "applicationid") == 0) { 342 rv = cd9660_arguments_set_string(buf, name, 128, 'a', 343 diskStructure->primaryDescriptor.application_id); 344 } else if (strcmp(name, "boot-load-segment") == 0) { 345 if (buf[0] == '\0') { 346 warnx("Option `%s' doesn't contain a value", 347 name); 348 rv = 0; 349 } else { 350 cd9660_eltorito_add_boot_option(diskStructure, 351 name, buf); 352 rv = 1; 353 } 354 } else if (strcmp(name, "bootimage") == 0) { 355 if (buf[0] == '\0') { 356 warnx("The Boot Image parameter requires a valid boot" 357 " information string"); 358 rv = 0; 359 } else 360 rv = cd9660_add_boot_disk(diskStructure, buf); 361 } else if (strcmp(name, "generic-bootimage") == 0) { 362 if (buf[0] == '\0') { 363 warnx("The Generic Boot Image parameter requires a" 364 " valid boot information string"); 365 rv = 0; 366 } else 367 rv = cd9660_add_generic_bootimage(diskStructure, buf); 368 } else if (strcmp(name, "label") == 0) { 369 rv = cd9660_arguments_set_string(buf, name, 32, 'd', 370 diskStructure->primaryDescriptor.volume_id); 371 } else if (strcmp(name, "preparer") == 0) { 372 rv = cd9660_arguments_set_string(buf, name, 128, 'a', 373 diskStructure->primaryDescriptor.preparer_id); 374 } else if (strcmp(name, "publisher") == 0) { 375 rv = cd9660_arguments_set_string(buf, name, 128, 'a', 376 diskStructure->primaryDescriptor.publisher_id); 377 } else if (strcmp(name, "volumeid") == 0) { 378 rv = cd9660_arguments_set_string(buf, name, 128, 'a', 379 diskStructure->primaryDescriptor.volume_set_id); 380 } else if (strcmp(name, "hard-disk-boot") == 0 || 381 strcmp(name, "no-boot") == 0 || 382 strcmp(name, "no-emul-boot") == 0) { 383 /* RRIP */ 384 cd9660_eltorito_add_boot_option(diskStructure, name, 0); 385 rv = 1; 386 } else 387 rv = 1; 388 389 return rv; 390 } 391 392 /* 393 * Main function for cd9660_makefs 394 * Builds the ISO image file 395 * @param const char *image The image filename to create 396 * @param const char *dir The directory that is being read 397 * @param struct fsnode *root The root node of the filesystem tree 398 * @param struct fsinfo_t *fsopts Any options 399 */ 400 void 401 cd9660_makefs(const char *image, const char *dir, fsnode *root, 402 fsinfo_t *fsopts) 403 { 404 int64_t startoffset; 405 int ret, numDirectories; 406 uint64_t pathTableSectors; 407 int64_t firstAvailableSector; 408 int64_t totalSpace; 409 int error; 410 cd9660node *real_root; 411 iso9660_disk *diskStructure = fsopts->fs_specific; 412 413 if (diskStructure->isoLevel < 2 && 414 diskStructure->allow_multidot) 415 errx(1, "allow-multidot requires iso level of 2"); 416 417 assert(image != NULL); 418 assert(dir != NULL); 419 assert(root != NULL); 420 421 /* Set up some constants. Later, these will be defined with options */ 422 423 /* Counter needed for path tables */ 424 numDirectories = 0; 425 426 /* Convert tree to our own format */ 427 /* Actually, we now need to add the REAL root node, at level 0 */ 428 429 real_root = cd9660_allocate_cd9660node(); 430 real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord)); 431 /* Leave filename blank for root */ 432 memset(real_root->isoDirRecord->name, 0, 433 ISO_FILENAME_MAXLENGTH_WITH_PADDING); 434 435 real_root->level = 0; 436 diskStructure->rootNode = real_root; 437 real_root->type = CD9660_TYPE_DIR; 438 error = 0; 439 real_root->node = root; 440 cd9660_convert_structure(diskStructure, root, real_root, 1, 441 &numDirectories, &error); 442 443 if (TAILQ_EMPTY(&real_root->cn_children)) { 444 errx(1, "%s: converted directory is empty. " 445 "Tree conversion failed", __func__); 446 } else if (error != 0) { 447 errx(1, "%s: tree conversion failed", __func__); 448 } 449 450 /* Add the dot and dot dot records */ 451 cd9660_add_dot_records(diskStructure, real_root); 452 453 cd9660_setup_root_node(diskStructure); 454 455 /* Rock ridge / SUSP init pass */ 456 if (diskStructure->rock_ridge_enabled) { 457 cd9660_susp_initialize(diskStructure, diskStructure->rootNode, 458 diskStructure->rootNode, NULL); 459 } 460 461 /* Build path table structure */ 462 diskStructure->pathTableLength = cd9660_generate_path_table( 463 diskStructure); 464 465 pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize, 466 diskStructure->pathTableLength); 467 468 firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure); 469 if (diskStructure->is_bootable) { 470 firstAvailableSector = cd9660_setup_boot(diskStructure, 471 firstAvailableSector); 472 if (firstAvailableSector < 0) 473 errx(1, "setup_boot failed"); 474 } 475 /* LE first, then BE */ 476 diskStructure->primaryLittleEndianTableSector = firstAvailableSector; 477 diskStructure->primaryBigEndianTableSector = 478 diskStructure->primaryLittleEndianTableSector + pathTableSectors; 479 480 /* Set the secondary ones to -1, not going to use them for now */ 481 diskStructure->secondaryBigEndianTableSector = -1; 482 diskStructure->secondaryLittleEndianTableSector = -1; 483 484 diskStructure->dataFirstSector = 485 diskStructure->primaryBigEndianTableSector + pathTableSectors; 486 487 startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector; 488 489 totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset); 490 491 diskStructure->totalSectors = diskStructure->dataFirstSector + 492 CD9660_BLOCKS(diskStructure->sectorSize, totalSpace); 493 494 /* Disabled until pass 1 is done */ 495 if (diskStructure->rock_ridge_enabled) { 496 diskStructure->susp_continuation_area_start_sector = 497 diskStructure->totalSectors; 498 diskStructure->totalSectors += 499 CD9660_BLOCKS(diskStructure->sectorSize, 500 diskStructure->susp_continuation_area_size); 501 cd9660_susp_finalize(diskStructure, diskStructure->rootNode); 502 } 503 504 505 cd9660_finalize_PVD(diskStructure); 506 507 /* Add padding sectors, just for testing purposes right now */ 508 /* diskStructure->totalSectors+=150; */ 509 510 /* 511 * Add padding sectors at the end 512 * TODO: Clean this up and separate padding 513 */ 514 if (diskStructure->include_padding_areas) 515 diskStructure->totalSectors += 150; 516 517 ret = cd9660_write_image(diskStructure, image); 518 519 /* Clean up data structures */ 520 cd9660_free_structure(real_root); 521 522 if (ret == 0) /* cd9660_write_image() failed */ 523 exit(1); 524 } 525 526 /* Generic function pointer - implement later */ 527 typedef int (*cd9660node_func)(cd9660node *); 528 529 static void 530 cd9660_finalize_PVD(iso9660_disk *diskStructure) 531 { 532 time_t tstamp = Tflag ? stampts : time(NULL); 533 534 /* root should be a fixed size of 34 bytes since it has no name */ 535 memcpy(diskStructure->primaryDescriptor.root_directory_record, 536 diskStructure->rootNode->dot_record->isoDirRecord, 34); 537 538 /* In RRIP, this might be longer than 34 */ 539 diskStructure->primaryDescriptor.root_directory_record[0] = 34; 540 541 /* Set up all the important numbers in the PVD */ 542 cd9660_bothendian_dword(diskStructure->totalSectors, 543 (unsigned char *)diskStructure->primaryDescriptor.volume_space_size); 544 cd9660_bothendian_word(1, 545 (unsigned char *)diskStructure->primaryDescriptor.volume_set_size); 546 cd9660_bothendian_word(1, 547 (unsigned char *) 548 diskStructure->primaryDescriptor.volume_sequence_number); 549 cd9660_bothendian_word(diskStructure->sectorSize, 550 (unsigned char *) 551 diskStructure->primaryDescriptor.logical_block_size); 552 cd9660_bothendian_dword(diskStructure->pathTableLength, 553 (unsigned char *)diskStructure->primaryDescriptor.path_table_size); 554 555 cd9660_731(diskStructure->primaryLittleEndianTableSector, 556 (u_char *)diskStructure->primaryDescriptor.type_l_path_table); 557 cd9660_732(diskStructure->primaryBigEndianTableSector, 558 (u_char *)diskStructure->primaryDescriptor.type_m_path_table); 559 560 diskStructure->primaryDescriptor.file_structure_version[0] = 1; 561 562 /* Pad all strings with spaces instead of nulls */ 563 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32); 564 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32); 565 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id, 566 128); 567 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id, 568 128); 569 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id, 570 128); 571 cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id, 572 128); 573 cd9660_pad_string_spaces( 574 diskStructure->primaryDescriptor.copyright_file_id, 37); 575 cd9660_pad_string_spaces( 576 diskStructure->primaryDescriptor.abstract_file_id, 37); 577 cd9660_pad_string_spaces( 578 diskStructure->primaryDescriptor.bibliographic_file_id, 37); 579 580 /* Setup dates */ 581 cd9660_time_8426( 582 (unsigned char *)diskStructure->primaryDescriptor.creation_date, 583 tstamp); 584 cd9660_time_8426( 585 (unsigned char *)diskStructure->primaryDescriptor.modification_date, 586 tstamp); 587 588 #if 0 589 cd9660_set_date(diskStructure->primaryDescriptor.expiration_date, 590 tstamp); 591 #endif 592 memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16); 593 diskStructure->primaryDescriptor.expiration_date[16] = 0; 594 595 cd9660_time_8426( 596 (unsigned char *)diskStructure->primaryDescriptor.effective_date, 597 tstamp); 598 } 599 600 static void 601 cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record, 602 u_char ext_attr_length, u_char flags, 603 u_char name_len, const char * name) 604 { 605 record->ext_attr_length[0] = ext_attr_length; 606 record->flags[0] = ISO_FLAG_CLEAR | flags; 607 record->file_unit_size[0] = 0; 608 record->interleave[0] = 0; 609 cd9660_bothendian_word(1, record->volume_sequence_number); 610 record->name_len[0] = name_len; 611 memset(record->name, '\0', sizeof (record->name)); 612 memcpy(record->name, name, name_len); 613 record->length[0] = 33 + name_len; 614 615 /* Todo : better rounding */ 616 record->length[0] += (record->length[0] & 1) ? 1 : 0; 617 } 618 619 static void 620 cd9660_setup_root_node(iso9660_disk *diskStructure) 621 { 622 cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord, 623 0, ISO_FLAG_DIRECTORY, 1, "\0"); 624 625 } 626 627 /*********** SUPPORT FUNCTIONS ***********/ 628 static int 629 cd9660_setup_volume_descriptors(iso9660_disk *diskStructure) 630 { 631 /* Boot volume descriptor should come second */ 632 int sector = 16; 633 /* For now, a fixed 2 : PVD and terminator */ 634 volume_descriptor *temp, *t; 635 636 /* Set up the PVD */ 637 temp = emalloc(sizeof(*temp)); 638 temp->volumeDescriptorData = 639 (unsigned char *)&diskStructure->primaryDescriptor; 640 temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD; 641 temp->volumeDescriptorData[6] = 1; 642 temp->sector = sector; 643 memcpy(temp->volumeDescriptorData + 1, 644 ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 645 diskStructure->firstVolumeDescriptor = temp; 646 647 sector++; 648 /* Set up boot support if enabled. BVD must reside in sector 17 */ 649 if (diskStructure->is_bootable) { 650 t = emalloc(sizeof(*t)); 651 t->volumeDescriptorData = ecalloc(1, 2048); 652 temp->next = t; 653 temp = t; 654 t->sector = 17; 655 cd9660_setup_boot_volume_descriptor(diskStructure, t); 656 sector++; 657 } 658 659 /* Set up the terminator */ 660 t = emalloc(sizeof(*t)); 661 t->volumeDescriptorData = ecalloc(1, 2048); 662 temp->next = t; 663 t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR; 664 t->next = 0; 665 t->volumeDescriptorData[6] = 1; 666 t->sector = sector; 667 memcpy(t->volumeDescriptorData + 1, 668 ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 669 670 sector++; 671 return sector; 672 } 673 674 #if 0 675 /* 676 * Populate EAR at some point. Not required, but is used by NetBSD's 677 * cd9660 support 678 */ 679 static int 680 cd9660_fill_extended_attribute_record(cd9660node *node) 681 { 682 node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes)); 683 return 1; 684 } 685 #endif 686 687 static int 688 cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode) 689 { 690 time_t tstamp = Tflag ? stampts : time(NULL); 691 u_char flag; 692 char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING]; 693 694 /* Now populate the isoDirRecord structure */ 695 memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); 696 697 (void)cd9660_convert_filename(diskStructure, newnode->node->name, 698 temp, sizeof temp, !(S_ISDIR(newnode->node->type))); 699 700 flag = ISO_FLAG_CLEAR; 701 if (S_ISDIR(newnode->node->type)) 702 flag |= ISO_FLAG_DIRECTORY; 703 704 cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0, 705 flag, strlen(temp), temp); 706 707 /* Set the various dates */ 708 709 /* If we want to use the current date and time */ 710 711 cd9660_time_915(newnode->isoDirRecord->date, tstamp); 712 713 cd9660_bothendian_dword(newnode->fileDataLength, 714 newnode->isoDirRecord->size); 715 /* If the file is a link, we want to set the size to 0 */ 716 if (S_ISLNK(newnode->node->type)) 717 newnode->fileDataLength = 0; 718 719 return 1; 720 } 721 722 /* 723 * Translate fsnode to cd9660node 724 * Translate filenames and other metadata, including dates, sizes, 725 * permissions, etc 726 * @param struct fsnode * The node generated by makefs 727 * @param struct cd9660node * The intermediate node to be written to 728 * @returns int 0 on failure, 1 on success 729 */ 730 static int 731 cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node, 732 cd9660node *newnode) 733 { 734 if (node == NULL) 735 return 0; 736 737 newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord)); 738 /* Set the node pointer */ 739 newnode->node = node; 740 741 /* Set the size */ 742 if (!(S_ISDIR(node->type))) 743 newnode->fileDataLength = node->inode->st.st_size; 744 745 if (cd9660_translate_node_common(diskStructure, newnode) == 0) 746 return 0; 747 748 /* Finally, overwrite some of the values that are set by default */ 749 cd9660_time_915(newnode->isoDirRecord->date, 750 Tflag ? stampts : node->inode->st.st_mtime); 751 752 return 1; 753 } 754 755 /* 756 * Compares two ISO filenames 757 * @param const char * The first file name 758 * @param const char * The second file name 759 * @returns : -1 if first is less than second, 0 if they are the same, 1 if 760 * the second is greater than the first 761 */ 762 static int 763 cd9660_compare_filename(const char *first, const char *second) 764 { 765 /* 766 * This can be made more optimal once it has been tested 767 * (the extra character, for example, is for testing) 768 */ 769 770 int p1 = 0; 771 int p2 = 0; 772 char c1, c2; 773 /* First, on the filename */ 774 775 while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1 776 && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) { 777 c1 = first[p1]; 778 c2 = second[p2]; 779 if (c1 == '.' && c2 =='.') 780 break; 781 else if (c1 == '.') { 782 p2++; 783 c1 = ' '; 784 } else if (c2 == '.') { 785 p1++; 786 c2 = ' '; 787 } else { 788 p1++; 789 p2++; 790 } 791 792 if (c1 < c2) 793 return -1; 794 else if (c1 > c2) { 795 return 1; 796 } 797 } 798 799 if (first[p1] == '.' && second[p2] == '.') { 800 p1++; 801 p2++; 802 while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1 803 && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) { 804 c1 = first[p1]; 805 c2 = second[p2]; 806 if (c1 == ';' && c2 == ';') 807 break; 808 else if (c1 == ';') { 809 p2++; 810 c1 = ' '; 811 } else if (c2 == ';') { 812 p1++; 813 c2 = ' '; 814 } else { 815 p1++; 816 p2++; 817 } 818 819 if (c1 < c2) 820 return -1; 821 else if (c1 > c2) 822 return 1; 823 } 824 } 825 return 0; 826 } 827 828 /* 829 * Insert a node into list with ISO sorting rules 830 * @param cd9660node * The head node of the list 831 * @param cd9660node * The node to be inserted 832 */ 833 static void 834 cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new) 835 { 836 int compare; 837 cd9660node *cn; 838 struct cd9660_children_head *head = &parent->cn_children; 839 840 /* TODO: Optimize? */ 841 cn_new->parent = parent; 842 843 /* 844 * first will either be 0, the . or the .. 845 * if . or .., this means no other entry may be written before first 846 * if 0, the new node may be inserted at the head 847 */ 848 849 TAILQ_FOREACH(cn, head, cn_next_child) { 850 /* 851 * Dont insert a node twice - 852 * that would cause an infinite loop 853 */ 854 if (cn_new == cn) 855 return; 856 857 compare = cd9660_compare_filename(cn_new->isoDirRecord->name, 858 cn->isoDirRecord->name); 859 860 if (compare == 0) 861 compare = cd9660_compare_filename(cn_new->node->name, 862 cn->node->name); 863 864 if (compare < 0) 865 break; 866 } 867 if (cn == NULL) 868 TAILQ_INSERT_TAIL(head, cn_new, cn_next_child); 869 else 870 TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child); 871 } 872 873 /* 874 * Called After cd9660_sorted_child_insert 875 * handles file collisions by suffixing each filename with ~n 876 * where n represents the files respective place in the ordering 877 */ 878 static int 879 cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding, 880 int past) 881 { 882 cd9660node *iter, *next, *prev; 883 int skip; 884 int delete_chars = 0; 885 int temp_past = past; 886 int temp_skip; 887 int flag = 0; 888 cd9660node *end_of_range; 889 890 for (iter = TAILQ_FIRST(&colliding->cn_children); 891 iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) { 892 if (strcmp(iter->isoDirRecord->name, 893 next->isoDirRecord->name) != 0) { 894 iter = TAILQ_NEXT(iter, cn_next_child); 895 continue; 896 } 897 flag = 1; 898 temp_skip = skip = cd9660_count_collisions(iter); 899 end_of_range = iter; 900 while (temp_skip > 0) { 901 temp_skip--; 902 end_of_range = TAILQ_NEXT(end_of_range, cn_next_child); 903 } 904 temp_past = past; 905 while (temp_past > 0) { 906 if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL) 907 end_of_range = next; 908 else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL) 909 iter = prev; 910 else 911 delete_chars++; 912 temp_past--; 913 } 914 skip += past; 915 iter = cd9660_rename_filename(diskStructure, iter, skip, 916 delete_chars); 917 } 918 return flag; 919 } 920 921 922 static cd9660node * 923 cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num, 924 int delete_chars) 925 { 926 int i = 0; 927 int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; 928 char *naming; 929 int maxlength; 930 char *tmp; 931 932 /* TODO : A LOT of chanes regarding 8.3 filenames */ 933 if (diskStructure->isoLevel == 1) 934 maxlength = 8; 935 else if (diskStructure->isoLevel == 2) 936 maxlength = 31; 937 else 938 maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION; 939 940 tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING); 941 942 while (i < num && iter) { 943 powers = 1; 944 count = 0; 945 digits = 1; 946 multiplier = 1; 947 while (((int)(i / powers) ) >= 10) { 948 digits++; 949 powers = powers * 10; 950 } 951 952 naming = iter->o_name; 953 954 /* 955 while ((*naming != '.') && (*naming != ';')) { 956 naming++; 957 count++; 958 } 959 */ 960 961 dot = -1; 962 semi = -1; 963 while (count < maxlength) { 964 if (*naming == '.') 965 dot = count; 966 else if (*naming == ';') { 967 semi = count; 968 break; 969 } 970 naming++; 971 count++; 972 } 973 974 if ((count + digits) < maxlength) 975 numbts = count; 976 else 977 numbts = maxlength - (digits); 978 numbts -= delete_chars; 979 980 /* 8.3 rules - keep the extension, add before the dot */ 981 982 /* 983 * This code makes a bunch of assumptions. 984 * See if you can spot them all :) 985 */ 986 987 #if 0 988 if (diskStructure->isoLevel == 1) { 989 numbts = 8 - digits - delete_chars; 990 if (dot < 0) { 991 992 } else { 993 if (dot < 8) { 994 memmove(&tmp[numbts],&tmp[dot],4); 995 } 996 } 997 } 998 #else 999 (void)dot; 1000 (void)semi; 1001 (void)multiplier; 1002 #endif 1003 1004 /* (copying just the filename before the '.' */ 1005 memcpy(tmp, (iter->o_name), numbts); 1006 1007 /* adding the appropriate number following the name */ 1008 temp = i; 1009 while (digits > 0) { 1010 digit = (int)(temp / powers); 1011 temp = temp - digit * powers; 1012 snprintf(&tmp[numbts] , ISO_FILENAME_MAXLENGTH_WITH_PADDING - numbts, "%d", digit); 1013 digits--; 1014 numbts++; 1015 powers = powers / 10; 1016 } 1017 1018 while ((*naming != ';') && (numbts < maxlength)) { 1019 tmp[numbts] = (*naming); 1020 naming++; 1021 numbts++; 1022 } 1023 1024 tmp[numbts] = ';'; 1025 tmp[numbts+1] = '1'; 1026 tmp[numbts+2] = '\0'; 1027 1028 /* 1029 * now tmp has exactly the identifier 1030 * we want so we'll copy it back to record 1031 */ 1032 memcpy((iter->isoDirRecord->name), tmp, numbts + 3); 1033 1034 iter = TAILQ_NEXT(iter, cn_next_child); 1035 i++; 1036 } 1037 1038 free(tmp); 1039 return iter; 1040 } 1041 1042 /* Todo: Figure out why these functions are nec. */ 1043 static void 1044 cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node) 1045 { 1046 cd9660node *cn; 1047 1048 if (TAILQ_EMPTY(&node->cn_children)) 1049 return; 1050 1051 if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) { 1052 debug_print_tree(diskStructure, diskStructure->rootNode, 0); 1053 exit(1); 1054 } 1055 1056 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 1057 cd9660_copy_filenames(diskStructure, cn); 1058 memcpy(cn->o_name, cn->isoDirRecord->name, 1059 ISO_FILENAME_MAXLENGTH_WITH_PADDING); 1060 } 1061 } 1062 1063 static void 1064 cd9660_sorting_nodes(cd9660node *node) 1065 { 1066 cd9660node *cn; 1067 1068 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) 1069 cd9660_sorting_nodes(cn); 1070 cd9660_sort_nodes(node); 1071 } 1072 1073 /* XXX Bubble sort. */ 1074 static void 1075 cd9660_sort_nodes(cd9660node *node) 1076 { 1077 cd9660node *cn, *next; 1078 1079 do { 1080 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 1081 if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL) 1082 return; 1083 else if (strcmp(next->isoDirRecord->name, 1084 cn->isoDirRecord->name) >= 0) 1085 continue; 1086 TAILQ_REMOVE(&node->cn_children, next, cn_next_child); 1087 TAILQ_INSERT_BEFORE(cn, next, cn_next_child); 1088 break; 1089 } 1090 } while (cn != NULL); 1091 } 1092 1093 static int 1094 cd9660_count_collisions(cd9660node *copy) 1095 { 1096 int count = 0; 1097 cd9660node *iter, *next; 1098 1099 for (iter = copy; 1100 (next = TAILQ_NEXT(iter, cn_next_child)) != NULL; 1101 iter = next) { 1102 if (cd9660_compare_filename(iter->isoDirRecord->name, 1103 next->isoDirRecord->name) == 0) 1104 count++; 1105 else 1106 return count; 1107 } 1108 #if 0 1109 if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) { 1110 printf("%s: count is %i \n", __func__, count); 1111 compare = cd9660_compare_filename(iter->isoDirRecord->name, 1112 next->isoDirRecord->name); 1113 if (compare == 0) { 1114 count++; 1115 return cd9660_recurse_on_collision(next, count); 1116 } else 1117 return count; 1118 } 1119 #endif 1120 return count; 1121 } 1122 1123 static cd9660node * 1124 cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir) 1125 { 1126 char newname[9]; 1127 cd9660node *tfile; 1128 1129 /* 1130 * This function needs to: 1131 * 1) Create an empty virtual file in place of the old directory 1132 * 2) Point the virtual file to the new directory 1133 * 3) Point the relocated directory to its old parent 1134 * 4) Move the directory specified by dir into rr_moved_dir, 1135 * and rename it to "diskStructure->rock_ridge_move_count" (as a string) 1136 */ 1137 1138 /* First see if the moved directory even exists */ 1139 if (diskStructure->rr_moved_dir == NULL) { 1140 diskStructure->rr_moved_dir = cd9660_create_directory( 1141 diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME, 1142 diskStructure->rootNode, dir); 1143 if (diskStructure->rr_moved_dir == NULL) 1144 return 0; 1145 cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date, 1146 Tflag ? stampts : start_time.tv_sec); 1147 } 1148 1149 /* Create a file with the same ORIGINAL name */ 1150 tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent, 1151 dir); 1152 if (tfile == NULL) 1153 return NULL; 1154 1155 diskStructure->rock_ridge_move_count++; 1156 snprintf(newname, sizeof(newname), "%08i", 1157 diskStructure->rock_ridge_move_count); 1158 1159 /* Point to old parent */ 1160 dir->rr_real_parent = dir->parent; 1161 1162 /* Place the placeholder file */ 1163 if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) { 1164 TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile, 1165 cn_next_child); 1166 } else { 1167 cd9660_sorted_child_insert(dir->rr_real_parent, tfile); 1168 } 1169 1170 /* Point to new parent */ 1171 dir->parent = diskStructure->rr_moved_dir; 1172 1173 /* Point the file to the moved directory */ 1174 tfile->rr_relocated = dir; 1175 1176 /* Actually move the directory */ 1177 cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir); 1178 1179 /* TODO: Inherit permissions / ownership (basically the entire inode) */ 1180 1181 /* Set the new name */ 1182 memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); 1183 strncpy(dir->isoDirRecord->name, newname, 8); 1184 dir->isoDirRecord->length[0] = 34 + 8; 1185 dir->isoDirRecord->name_len[0] = 8; 1186 1187 return dir; 1188 } 1189 1190 static int 1191 cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root) 1192 { 1193 struct cd9660_children_head *head = &root->cn_children; 1194 cd9660node *cn; 1195 1196 TAILQ_FOREACH(cn, head, cn_next_child) { 1197 if ((cn->type & CD9660_TYPE_DIR) == 0) 1198 continue; 1199 /* Recursion first */ 1200 cd9660_add_dot_records(diskStructure, cn); 1201 } 1202 cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root); 1203 cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT, 1204 root); 1205 return 1; 1206 } 1207 1208 /* 1209 * Convert node to cd9660 structure 1210 * This function is designed to be called recursively on the root node of 1211 * the filesystem 1212 * Lots of recursion going on here, want to make sure it is efficient 1213 * @param struct fsnode * The root node to be converted 1214 * @param struct cd9660* The parent node (should not be NULL) 1215 * @param int Current directory depth 1216 * @param int* Running count of the number of directories that are being created 1217 */ 1218 static void 1219 cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root, 1220 cd9660node *parent_node, int level, int *numDirectories, int *error) 1221 { 1222 fsnode *iterator = root; 1223 cd9660node *this_node; 1224 int working_level; 1225 int add; 1226 int flag = 0; 1227 int counter = 0; 1228 1229 /* 1230 * Newer, more efficient method, reduces recursion depth 1231 */ 1232 if (root == NULL) { 1233 warnx("%s: root is null", __func__); 1234 return; 1235 } 1236 1237 /* Test for an empty directory - makefs still gives us the . record */ 1238 if ((S_ISDIR(root->type)) && (root->name[0] == '.') 1239 && (root->name[1] == '\0')) { 1240 root = root->next; 1241 if (root == NULL) 1242 return; 1243 } 1244 if ((this_node = cd9660_allocate_cd9660node()) == NULL) { 1245 CD9660_MEM_ALLOC_ERROR(__func__); 1246 } 1247 1248 /* 1249 * To reduce the number of recursive calls, we will iterate over 1250 * the next pointers to the right. 1251 */ 1252 while (iterator != NULL) { 1253 add = 1; 1254 /* 1255 * Increment the directory count if this is a directory 1256 * Ignore "." entries. We will generate them later 1257 */ 1258 if (!S_ISDIR(iterator->type) || 1259 strcmp(iterator->name, ".") != 0) { 1260 1261 /* Translate the node, including its filename */ 1262 this_node->parent = parent_node; 1263 cd9660_translate_node(diskStructure, iterator, 1264 this_node); 1265 this_node->level = level; 1266 1267 if (S_ISDIR(iterator->type)) { 1268 (*numDirectories)++; 1269 this_node->type = CD9660_TYPE_DIR; 1270 working_level = level + 1; 1271 1272 /* 1273 * If at level 8, directory would be at 8 1274 * and have children at 9 which is not 1275 * allowed as per ISO spec 1276 */ 1277 if (level == 8) { 1278 if ((!diskStructure->allow_deep_trees) && 1279 (!diskStructure->rock_ridge_enabled)) { 1280 warnx("error: found entry " 1281 "with depth greater " 1282 "than 8."); 1283 (*error) = 1; 1284 return; 1285 } else if (diskStructure-> 1286 rock_ridge_enabled) { 1287 working_level = 3; 1288 /* 1289 * Moved directory is actually 1290 * at level 2. 1291 */ 1292 this_node->level = 1293 working_level - 1; 1294 if (cd9660_rrip_move_directory( 1295 diskStructure, 1296 this_node) == 0) { 1297 warnx("Failure in " 1298 "cd9660_rrip_" 1299 "move_directory" 1300 ); 1301 (*error) = 1; 1302 return; 1303 } 1304 add = 0; 1305 } 1306 } 1307 1308 /* Do the recursive call on the children */ 1309 if (iterator->child != 0) { 1310 cd9660_convert_structure(diskStructure, 1311 iterator->child, this_node, 1312 working_level, 1313 numDirectories, error); 1314 1315 if ((*error) == 1) { 1316 warnx("%s: Error on recursive " 1317 "call", __func__); 1318 return; 1319 } 1320 } 1321 1322 } else { 1323 /* Only directories should have children */ 1324 assert(iterator->child == NULL); 1325 1326 this_node->type = CD9660_TYPE_FILE; 1327 } 1328 1329 /* 1330 * Finally, do a sorted insert 1331 */ 1332 if (add) { 1333 cd9660_sorted_child_insert( 1334 parent_node, this_node); 1335 } 1336 1337 /*Allocate new temp_node */ 1338 if (iterator->next != 0) { 1339 this_node = cd9660_allocate_cd9660node(); 1340 if (this_node == NULL) 1341 CD9660_MEM_ALLOC_ERROR(__func__); 1342 } 1343 } 1344 iterator = iterator->next; 1345 } 1346 1347 /* cd9660_handle_collisions(first_node); */ 1348 1349 /* TODO: need cleanup */ 1350 cd9660_copy_filenames(diskStructure, parent_node); 1351 1352 do { 1353 flag = cd9660_handle_collisions(diskStructure, parent_node, 1354 counter); 1355 counter++; 1356 cd9660_sorting_nodes(parent_node); 1357 } while ((flag == 1) && (counter < 100)); 1358 } 1359 1360 /* 1361 * Clean up the cd9660node tree 1362 * This is designed to be called recursively on the root node 1363 * @param struct cd9660node *root The node to free 1364 * @returns void 1365 */ 1366 static void 1367 cd9660_free_structure(cd9660node *root) 1368 { 1369 cd9660node *cn; 1370 1371 while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) { 1372 TAILQ_REMOVE(&root->cn_children, cn, cn_next_child); 1373 cd9660_free_structure(cn); 1374 } 1375 free(root); 1376 } 1377 1378 /* 1379 * Be a little more memory conservative: 1380 * instead of having the TAILQ_ENTRY as part of the cd9660node, 1381 * just create a temporary structure 1382 */ 1383 struct ptq_entry 1384 { 1385 TAILQ_ENTRY(ptq_entry) ptq; 1386 cd9660node *node; 1387 } *n; 1388 1389 #define PTQUEUE_NEW(n,s,r,t){\ 1390 n = emalloc(sizeof(struct s)); \ 1391 if (n == NULL) \ 1392 return r; \ 1393 n->node = t;\ 1394 } 1395 1396 /* 1397 * Generate the path tables 1398 * The specific implementation of this function is left as an exercise to the 1399 * programmer. It could be done recursively. Make sure you read how the path 1400 * table has to be laid out, it has levels. 1401 * @param struct iso9660_disk *disk The disk image 1402 * @returns int The number of built path tables (between 1 and 4), 0 on failure 1403 */ 1404 static int 1405 cd9660_generate_path_table(iso9660_disk *diskStructure) 1406 { 1407 cd9660node *cn, *dirNode = diskStructure->rootNode; 1408 cd9660node *last = dirNode; 1409 int pathTableSize = 0; /* computed as we go */ 1410 int counter = 1; /* root gets a count of 0 */ 1411 1412 TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head; 1413 TAILQ_INIT(&pt_head); 1414 1415 PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode); 1416 1417 /* Push the root node */ 1418 TAILQ_INSERT_HEAD(&pt_head, n, ptq); 1419 1420 /* Breadth-first traversal of file structure */ 1421 while (pt_head.tqh_first != 0) { 1422 n = pt_head.tqh_first; 1423 dirNode = n->node; 1424 TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq); 1425 free(n); 1426 1427 /* Update the size */ 1428 pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE 1429 + dirNode->isoDirRecord->name_len[0]+ 1430 (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1); 1431 /* includes the padding bit */ 1432 1433 dirNode->ptnumber=counter; 1434 if (dirNode != last) { 1435 last->ptnext = dirNode; 1436 dirNode->ptprev = last; 1437 } 1438 last = dirNode; 1439 1440 /* Push children onto queue */ 1441 TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) { 1442 /* 1443 * Dont add the DOT and DOTDOT types to the path 1444 * table. 1445 */ 1446 if ((cn->type != CD9660_TYPE_DOT) 1447 && (cn->type != CD9660_TYPE_DOTDOT)) { 1448 1449 if (S_ISDIR(cn->node->type)) { 1450 PTQUEUE_NEW(n, ptq_entry, -1, cn); 1451 TAILQ_INSERT_TAIL(&pt_head, n, ptq); 1452 } 1453 } 1454 } 1455 counter++; 1456 } 1457 return pathTableSize; 1458 } 1459 1460 char * 1461 cd9660_compute_full_filename(cd9660node *node) 1462 { 1463 static char buf[PATH_MAX]; 1464 int len; 1465 1466 len = snprintf(buf, PATH_MAX, "%s/%s/%s", node->node->root, 1467 node->node->path, node->node->name); 1468 if (len < 0) { 1469 warn(NULL); 1470 return NULL; 1471 } else if (len >= PATH_MAX) { 1472 warnc(ENAMETOOLONG, NULL); 1473 return NULL; 1474 } 1475 return buf; 1476 } 1477 1478 /* 1479 * TODO: These two functions are almost identical. 1480 * Some code cleanup is possible here 1481 * 1482 * XXX bounds checking! 1483 */ 1484 static int 1485 cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1486 char *newname, size_t newnamelen, int is_file) 1487 { 1488 /* 1489 * ISO 9660 : 10.1 1490 * File Name shall not contain more than 8 d or d1 characters 1491 * File Name Extension shall not contain more than 3 d or d1 characters 1492 * Directory Identifier shall not contain more than 8 d or d1 characters 1493 */ 1494 int namelen = 0; 1495 int extlen = 0; 1496 int found_ext = 0; 1497 char *orignewname = newname; 1498 1499 while (*oldname != '\0' && extlen < 3) { 1500 /* Handle period first, as it is special */ 1501 if (*oldname == '.') { 1502 if (found_ext) { 1503 *newname++ = '_'; 1504 extlen ++; 1505 } 1506 else { 1507 *newname++ = '.'; 1508 found_ext = 1; 1509 } 1510 } else { 1511 /* Enforce 12.3 / 8 */ 1512 if (namelen == 8 && !found_ext) 1513 break; 1514 1515 if (islower((unsigned char)*oldname)) 1516 *newname++ = toupper((unsigned char)*oldname); 1517 else if (isupper((unsigned char)*oldname) 1518 || isdigit((unsigned char)*oldname)) 1519 *newname++ = *oldname; 1520 else 1521 *newname++ = '_'; 1522 1523 if (found_ext) 1524 extlen++; 1525 else 1526 namelen++; 1527 } 1528 oldname++; 1529 } 1530 if (is_file) { 1531 if (!found_ext && !diskStructure->omit_trailing_period) 1532 *newname++ = '.'; 1533 /* Add version */ 1534 snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); 1535 } 1536 return namelen + extlen + found_ext; 1537 } 1538 1539 /* XXX bounds checking! */ 1540 static int 1541 cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1542 char *newname, size_t newnamelen, int is_file) 1543 { 1544 /* 1545 * ISO 9660 : 7.5.1 1546 * File name : 0+ d or d1 characters 1547 * separator 1 (.) 1548 * File name extension : 0+ d or d1 characters 1549 * separator 2 (;) 1550 * File version number (5 characters, 1-32767) 1551 * 1 <= Sum of File name and File name extension <= 30 1552 */ 1553 int namelen = 0; 1554 int extlen = 0; 1555 int found_ext = 0; 1556 char *orignewname = newname; 1557 1558 while (*oldname != '\0' && namelen + extlen < 30) { 1559 /* Handle period first, as it is special */ 1560 if (*oldname == '.') { 1561 if (found_ext) { 1562 if (diskStructure->allow_multidot) { 1563 *newname++ = '.'; 1564 } else { 1565 *newname++ = '_'; 1566 } 1567 extlen ++; 1568 } 1569 else { 1570 *newname++ = '.'; 1571 found_ext = 1; 1572 } 1573 } else { 1574 if (islower((unsigned char)*oldname)) 1575 *newname++ = toupper((unsigned char)*oldname); 1576 else if (isupper((unsigned char)*oldname) || 1577 isdigit((unsigned char)*oldname)) 1578 *newname++ = *oldname; 1579 else if (diskStructure->allow_multidot && 1580 *oldname == '.') { 1581 *newname++ = '.'; 1582 } else { 1583 *newname++ = '_'; 1584 } 1585 1586 if (found_ext) 1587 extlen++; 1588 else 1589 namelen++; 1590 } 1591 oldname ++; 1592 } 1593 if (is_file) { 1594 if (!found_ext && !diskStructure->omit_trailing_period) 1595 *newname++ = '.'; 1596 /* Add version */ 1597 snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); 1598 } 1599 return namelen + extlen + found_ext; 1600 } 1601 1602 /* 1603 * Convert a file name to ISO compliant file name 1604 * @param char * oldname The original filename 1605 * @param char ** newname The new file name, in the appropriate character 1606 * set and of appropriate length 1607 * @param int 1 if file, 0 if directory 1608 * @returns int The length of the new string 1609 */ 1610 static int 1611 cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1612 char *newname, size_t newnamelen, int is_file) 1613 { 1614 if (diskStructure->isoLevel == 1) 1615 return cd9660_level1_convert_filename(diskStructure, 1616 oldname, newname, newnamelen, is_file); 1617 else if (diskStructure->isoLevel == 2) 1618 return cd9660_level2_convert_filename(diskStructure, 1619 oldname, newname, newnamelen, is_file); 1620 abort(); 1621 } 1622 1623 int 1624 cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node) 1625 { 1626 int size = node->isoDirRecord->length[0]; 1627 1628 if (diskStructure->rock_ridge_enabled) 1629 size += node->susp_entry_size; 1630 size += node->su_tail_size; 1631 size += size & 1; /* Ensure length of record is even. */ 1632 assert(size <= 254); 1633 return size; 1634 } 1635 1636 static void 1637 cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node) 1638 { 1639 node->dot_record->fileDataSector = node->fileDataSector; 1640 memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34); 1641 node->dot_record->isoDirRecord->name_len[0] = 1; 1642 node->dot_record->isoDirRecord->name[0] = 0; 1643 node->dot_record->isoDirRecord->name[1] = 0; 1644 node->dot_record->isoDirRecord->length[0] = 34; 1645 node->dot_record->fileRecordSize = 1646 cd9660_compute_record_size(diskStructure, node->dot_record); 1647 1648 if (node == diskStructure->rootNode) { 1649 node->dot_dot_record->fileDataSector = node->fileDataSector; 1650 memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord, 1651 34); 1652 } else { 1653 node->dot_dot_record->fileDataSector = 1654 node->parent->fileDataSector; 1655 memcpy(node->dot_dot_record->isoDirRecord, 1656 node->parent->isoDirRecord,34); 1657 } 1658 node->dot_dot_record->isoDirRecord->name_len[0] = 1; 1659 node->dot_dot_record->isoDirRecord->name[0] = 1; 1660 node->dot_dot_record->isoDirRecord->name[1] = 0; 1661 node->dot_dot_record->isoDirRecord->length[0] = 34; 1662 node->dot_dot_record->fileRecordSize = 1663 cd9660_compute_record_size(diskStructure, node->dot_dot_record); 1664 } 1665 1666 /* 1667 * @param struct cd9660node *node The node 1668 * @param int The offset (in bytes) - SHOULD align to the beginning of a sector 1669 * @returns int The total size of files and directory entries (should be 1670 * a multiple of sector size) 1671 */ 1672 static int64_t 1673 cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node, 1674 int64_t startOffset) 1675 { 1676 /* 1677 * This function needs to compute the size of directory records and 1678 * runs, file lengths, and set the appropriate variables both in 1679 * cd9660node and isoDirEntry 1680 */ 1681 int64_t used_bytes = 0; 1682 int64_t current_sector_usage = 0; 1683 cd9660node *child; 1684 fsinode *inode; 1685 int64_t r; 1686 1687 assert(node != NULL); 1688 1689 1690 /* 1691 * NOTE : There needs to be some special case detection for 1692 * the "real root" node, since for it, node->node is undefined 1693 */ 1694 1695 node->fileDataSector = -1; 1696 1697 if (node->type & CD9660_TYPE_DIR) { 1698 node->fileRecordSize = cd9660_compute_record_size( 1699 diskStructure, node); 1700 /*Set what sector this directory starts in*/ 1701 node->fileDataSector = 1702 CD9660_BLOCKS(diskStructure->sectorSize,startOffset); 1703 1704 cd9660_bothendian_dword(node->fileDataSector, 1705 node->isoDirRecord->extent); 1706 1707 /* 1708 * First loop over children, need to know the size of 1709 * their directory records 1710 */ 1711 node->fileSectorsUsed = 1; 1712 TAILQ_FOREACH(child, &node->cn_children, cn_next_child) { 1713 node->fileDataLength += 1714 cd9660_compute_record_size(diskStructure, child); 1715 if ((cd9660_compute_record_size(diskStructure, child) + 1716 current_sector_usage) >= 1717 diskStructure->sectorSize) { 1718 current_sector_usage = 0; 1719 node->fileSectorsUsed++; 1720 } 1721 1722 current_sector_usage += 1723 cd9660_compute_record_size(diskStructure, child); 1724 } 1725 1726 cd9660_bothendian_dword(node->fileSectorsUsed * 1727 diskStructure->sectorSize,node->isoDirRecord->size); 1728 1729 /* 1730 * This should point to the sector after the directory 1731 * record (or, the first byte in that sector) 1732 */ 1733 used_bytes += node->fileSectorsUsed * diskStructure->sectorSize; 1734 1735 for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 1736 child != NULL; child = TAILQ_NEXT(child, cn_next_child)) { 1737 /* Directories need recursive call */ 1738 if (S_ISDIR(child->node->type)) { 1739 r = cd9660_compute_offsets(diskStructure, child, 1740 used_bytes + startOffset); 1741 1742 if (r != -1) 1743 used_bytes += r; 1744 else 1745 return -1; 1746 } 1747 } 1748 1749 /* Explicitly set the . and .. records */ 1750 cd9660_populate_dot_records(diskStructure, node); 1751 1752 /* Finally, do another iteration to write the file data*/ 1753 for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 1754 child != NULL; 1755 child = TAILQ_NEXT(child, cn_next_child)) { 1756 /* Files need extent set */ 1757 if (S_ISDIR(child->node->type)) 1758 continue; 1759 child->fileRecordSize = 1760 cd9660_compute_record_size(diskStructure, child); 1761 1762 child->fileSectorsUsed = 1763 CD9660_BLOCKS(diskStructure->sectorSize, 1764 child->fileDataLength); 1765 1766 inode = child->node->inode; 1767 if ((inode->flags & FI_ALLOCATED) == 0) { 1768 inode->ino = 1769 CD9660_BLOCKS(diskStructure->sectorSize, 1770 used_bytes + startOffset); 1771 inode->flags |= FI_ALLOCATED; 1772 used_bytes += child->fileSectorsUsed * 1773 diskStructure->sectorSize; 1774 } else { 1775 INODE_WARNX(("%s: already allocated inode %d " 1776 "data sectors at %" PRIu32, __func__, 1777 (int)inode->st.st_ino, inode->ino)); 1778 } 1779 child->fileDataSector = inode->ino; 1780 cd9660_bothendian_dword(child->fileDataSector, 1781 child->isoDirRecord->extent); 1782 } 1783 } 1784 1785 return used_bytes; 1786 } 1787 1788 #if 0 1789 /* Might get rid of this func */ 1790 static int 1791 cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file) 1792 { 1793 to->node->inode->st.st_dev = 0; 1794 to->node->inode->st.st_ino = 0; 1795 to->node->inode->st.st_size = 0; 1796 to->node->inode->st.st_blksize = from->node->inode->st.st_blksize; 1797 to->node->inode->st.st_atime = from->node->inode->st.st_atime; 1798 to->node->inode->st.st_mtime = from->node->inode->st.st_mtime; 1799 to->node->inode->st.st_ctime = from->node->inode->st.st_ctime; 1800 to->node->inode->st.st_uid = from->node->inode->st.st_uid; 1801 to->node->inode->st.st_gid = from->node->inode->st.st_gid; 1802 to->node->inode->st.st_mode = from->node->inode->st.st_mode; 1803 /* Clear out type */ 1804 to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT); 1805 if (file) 1806 to->node->inode->st.st_mode |= S_IFREG; 1807 else 1808 to->node->inode->st.st_mode |= S_IFDIR; 1809 return 1; 1810 } 1811 #endif 1812 1813 static cd9660node * 1814 cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name, 1815 cd9660node *parent, int file, int insert) 1816 { 1817 cd9660node *temp; 1818 fsnode * tfsnode; 1819 1820 assert(parent != NULL); 1821 1822 temp = cd9660_allocate_cd9660node(); 1823 if (temp == NULL) 1824 return NULL; 1825 1826 tfsnode = emalloc(sizeof(*tfsnode)); 1827 tfsnode->name = estrdup(name); 1828 temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord)); 1829 1830 cd9660_convert_filename(diskStructure, tfsnode->name, 1831 temp->isoDirRecord->name, sizeof temp->isoDirRecord->name, file); 1832 1833 temp->node = tfsnode; 1834 temp->parent = parent; 1835 1836 if (insert) { 1837 if (temp->parent != NULL) { 1838 temp->level = temp->parent->level + 1; 1839 if (!TAILQ_EMPTY(&temp->parent->cn_children)) 1840 cd9660_sorted_child_insert(temp->parent, temp); 1841 else 1842 TAILQ_INSERT_HEAD(&temp->parent->cn_children, 1843 temp, cn_next_child); 1844 } 1845 } 1846 1847 if (parent->node != NULL) { 1848 tfsnode->type = parent->node->type; 1849 } 1850 1851 /* Clear out file type bits */ 1852 tfsnode->type &= ~(S_IFMT); 1853 if (file) 1854 tfsnode->type |= S_IFREG; 1855 else 1856 tfsnode->type |= S_IFDIR; 1857 1858 /* Indicate that there is no spec entry (inode) */ 1859 tfsnode->flags &= ~(FSNODE_F_HASSPEC); 1860 #if 0 1861 cd9660_copy_stat_info(parent, temp, file); 1862 #endif 1863 return temp; 1864 } 1865 1866 static cd9660node * 1867 cd9660_create_file(iso9660_disk *diskStructure, const char *name, 1868 cd9660node *parent, cd9660node *me) 1869 { 1870 cd9660node *temp; 1871 1872 temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1); 1873 if (temp == NULL) 1874 return NULL; 1875 1876 temp->fileDataLength = 0; 1877 1878 temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL; 1879 1880 temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); 1881 *temp->node->inode = *me->node->inode; 1882 1883 if (cd9660_translate_node_common(diskStructure, temp) == 0) 1884 return NULL; 1885 return temp; 1886 } 1887 1888 /* 1889 * Create a new directory which does not exist on disk 1890 * @param const char * name The name to assign to the directory 1891 * @param const char * parent Pointer to the parent directory 1892 * @returns cd9660node * Pointer to the new directory 1893 */ 1894 static cd9660node * 1895 cd9660_create_directory(iso9660_disk *diskStructure, const char *name, 1896 cd9660node *parent, cd9660node *me) 1897 { 1898 cd9660node *temp; 1899 1900 temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1); 1901 if (temp == NULL) 1902 return NULL; 1903 temp->node->type |= S_IFDIR; 1904 1905 temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL; 1906 1907 temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); 1908 *temp->node->inode = *me->node->inode; 1909 1910 if (cd9660_translate_node_common(diskStructure, temp) == 0) 1911 return NULL; 1912 return temp; 1913 } 1914 1915 static cd9660node * 1916 cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type, 1917 cd9660node *parent) 1918 { 1919 cd9660node *temp, *first; 1920 char na[2]; 1921 1922 assert(parent != NULL); 1923 1924 if (type == CD9660_TYPE_DOT) 1925 na[0] = 0; 1926 else if (type == CD9660_TYPE_DOTDOT) 1927 na[0] = 1; 1928 else 1929 return 0; 1930 1931 na[1] = 0; 1932 if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent, 1933 0, 0)) == NULL) 1934 return NULL; 1935 1936 temp->parent = parent; 1937 temp->type = type; 1938 temp->isoDirRecord->length[0] = 34; 1939 /* Dot record is always first */ 1940 if (type == CD9660_TYPE_DOT) { 1941 parent->dot_record = temp; 1942 TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child); 1943 /* DotDot should be second */ 1944 } else if (type == CD9660_TYPE_DOTDOT) { 1945 parent->dot_dot_record = temp; 1946 /* 1947 * If the first child is the dot record, insert 1948 * this second. Otherwise, insert it at the head. 1949 */ 1950 if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL || 1951 (first->type & CD9660_TYPE_DOT) == 0) { 1952 TAILQ_INSERT_HEAD(&parent->cn_children, temp, 1953 cn_next_child); 1954 } else { 1955 TAILQ_INSERT_AFTER(&parent->cn_children, first, temp, 1956 cn_next_child); 1957 } 1958 } 1959 1960 return temp; 1961 } 1962 1963 static int 1964 cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage) 1965 { 1966 struct stat stbuf; 1967 1968 assert(bootimage != NULL); 1969 1970 if (*bootimage == '\0') { 1971 warnx("Error: Boot image must be a filename"); 1972 return 0; 1973 } 1974 1975 diskStructure->generic_bootimage = estrdup(bootimage); 1976 1977 if (unveil(diskStructure->generic_bootimage, "r") == -1) 1978 err(1, "unveil %s", diskStructure->generic_bootimage); 1979 /* Get information about the file */ 1980 if (lstat(diskStructure->generic_bootimage, &stbuf) == -1) 1981 err(1, "%s: lstat(\"%s\")", __func__, 1982 diskStructure->generic_bootimage); 1983 1984 if (stbuf.st_size > 32768) { 1985 warnx("Error: Boot image must be no greater than 32768 bytes"); 1986 return 0; 1987 } 1988 1989 diskStructure->has_generic_bootimage = 1; 1990 return 1; 1991 } 1992