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