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