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