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