1 /* $NetBSD: cd9660.c,v 1.19 2007/04/07 17:14:58 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 5 * Perez-Rathke and Ram Vedam. All rights reserved. 6 * 7 * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 8 * Alan Perez-Rathke and Ram Vedam. 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 21 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 25 * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 28 * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 32 * OF SUCH DAMAGE. 33 */ 34 /* 35 * Copyright (c) 2001 Wasabi Systems, Inc. 36 * All rights reserved. 37 * 38 * Written by Luke Mewburn for Wasabi Systems, Inc. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed for the NetBSD Project by 51 * Wasabi Systems, Inc. 52 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 53 * or promote products derived from this software without specific prior 54 * written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 58 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 59 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 60 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 61 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 62 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 63 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 64 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 65 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 66 * POSSIBILITY OF SUCH DAMAGE. 67 */ 68 /* 69 * Copyright (c) 1982, 1986, 1989, 1993 70 * The Regents of the University of California. All rights reserved. 71 * 72 * Redistribution and use in source and binary forms, with or without 73 * modification, are permitted provided that the following conditions 74 * are met: 75 * 1. Redistributions of source code must retain the above copyright 76 * notice, this list of conditions and the following disclaimer. 77 * 2. Redistributions in binary form must reproduce the above copyright 78 * notice, this list of conditions and the following disclaimer in the 79 * documentation and/or other materials provided with the distribution. 80 * 3. Neither the name of the University nor the names of its contributors 81 * may be used to endorse or promote products derived from this software 82 * without specific prior written permission. 83 * 84 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 87 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 94 * SUCH DAMAGE. 95 * 96 */ 97 98 #if HAVE_NBTOOL_CONFIG_H 99 #include "nbtool_config.h" 100 #else 101 #include <sys/mount.h> 102 #endif 103 104 #include <sys/cdefs.h> 105 #if defined(__RCSID) && !defined(__lint) 106 __RCSID("$NetBSD: cd9660.c,v 1.19 2007/04/07 17:14:58 christos Exp $"); 107 #endif /* !__lint */ 108 109 #include <string.h> 110 #include <ctype.h> 111 #include <sys/param.h> 112 #include <sys/queue.h> 113 114 #include "makefs.h" 115 #include "cd9660.h" 116 #include "cd9660/iso9660_rrip.h" 117 118 /* 119 * Global variables 120 */ 121 iso9660_disk diskStructure; 122 123 static void cd9660_finalize_PVD(void); 124 static cd9660node *cd9660_allocate_cd9660node(void); 125 static void cd9660_set_defaults(void); 126 static int cd9660_arguments_set_string(const char *, const char *, int, 127 char, char *); 128 static void cd9660_populate_iso_dir_record( 129 struct _iso_directory_record_cd9660 *, u_char, u_char, u_char, 130 const char *); 131 static void cd9660_setup_root_node(void); 132 static int cd9660_setup_volume_descriptors(void); 133 #if 0 134 static int cd9660_fill_extended_attribute_record(cd9660node *); 135 #endif 136 static void cd9660_sort_nodes(cd9660node *); 137 static int cd9960_translate_node_common(cd9660node *); 138 static int cd9660_translate_node(fsnode *, cd9660node *); 139 static int cd9660_compare_filename(const char *, const char *); 140 static void cd9660_sorted_child_insert(cd9660node *, cd9660node *); 141 static int cd9660_handle_collisions(cd9660node *, int); 142 static cd9660node *cd9660_rename_filename(cd9660node *, int, int); 143 static void cd9660_copy_filenames(cd9660node *); 144 static void cd9660_sorting_nodes(cd9660node *); 145 static int cd9660_count_collisions(cd9660node *); 146 static cd9660node *cd9660_rrip_move_directory(cd9660node *); 147 static int cd9660_add_dot_records(cd9660node *); 148 149 static void cd9660_convert_structure(fsnode *, cd9660node *, int, 150 int *, int *); 151 static void cd9660_free_structure(cd9660node *); 152 static int cd9660_generate_path_table(void); 153 static int cd9660_level1_convert_filename(const char *, char *, int); 154 static int cd9660_level2_convert_filename(const char *, char *, int); 155 #if 0 156 static int cd9660_joliet_convert_filename(const char *, char *, int); 157 #endif 158 static int cd9660_convert_filename(const char *, char *, int); 159 static void cd9660_populate_dot_records(cd9660node *); 160 static int cd9660_compute_offsets(cd9660node *, int); 161 #if 0 162 static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int); 163 #endif 164 static cd9660node *cd9660_create_virtual_entry(const char *, cd9660node *, int, 165 int); 166 static cd9660node *cd9660_create_file(const char *, cd9660node *, cd9660node *); 167 static cd9660node *cd9660_create_directory(const char *, cd9660node *, 168 cd9660node *); 169 static cd9660node *cd9660_create_special_directory(u_char, cd9660node *); 170 171 172 /* 173 * Allocate and initalize a cd9660node 174 * @returns struct cd9660node * Pointer to new node, or NULL on error 175 */ 176 static cd9660node * 177 cd9660_allocate_cd9660node(void) 178 { 179 cd9660node *temp; 180 181 if ((temp = calloc(1, sizeof(cd9660node))) == NULL) 182 err(EXIT_FAILURE, "%s: calloc", __func__); 183 TAILQ_INIT(&temp->cn_children); 184 temp->parent = temp->dot_record = temp->dot_dot_record = NULL; 185 temp->ptnext = temp->ptprev = temp->ptlast = NULL; 186 temp->node = NULL; 187 temp->isoDirRecord = NULL; 188 temp->isoExtAttributes = NULL; 189 temp->rr_real_parent = temp->rr_relocated = NULL; 190 return temp; 191 } 192 193 int cd9660_defaults_set = 0; 194 195 /** 196 * Set default values for cd9660 extension to makefs 197 */ 198 static void 199 cd9660_set_defaults(void) 200 { 201 /*Fix the sector size for now, though the spec allows for other sizes*/ 202 diskStructure.sectorSize = 2048; 203 204 /* Set up defaults in our own structure */ 205 diskStructure.verbose_level = 0; 206 diskStructure.keep_bad_images = 0; 207 diskStructure.follow_sym_links = 0; 208 diskStructure.isoLevel = 2; 209 210 diskStructure.rock_ridge_enabled = 0; 211 diskStructure.rock_ridge_renamed_dir_name = 0; 212 diskStructure.rock_ridge_move_count = 0; 213 diskStructure.rr_moved_dir = 0; 214 215 diskStructure.include_padding_areas = 1; 216 217 /* Spec breaking functionality */ 218 diskStructure.allow_deep_trees = 219 diskStructure.allow_start_dot = 220 diskStructure.allow_max_name = 221 diskStructure.allow_illegal_chars = 222 diskStructure.allow_lowercase = 223 diskStructure.allow_multidot = 224 diskStructure.omit_trailing_period = 0; 225 226 /* Make sure the PVD is clear */ 227 memset(&diskStructure.primaryDescriptor, 0, 2048); 228 229 memset(diskStructure.primaryDescriptor.volume_set_id, 0x20,32); 230 memset(diskStructure.primaryDescriptor.publisher_id, 0x20,128); 231 memset(diskStructure.primaryDescriptor.preparer_id, 0x20,128); 232 memset(diskStructure.primaryDescriptor.application_id, 0x20,128); 233 memset(diskStructure.primaryDescriptor.copyright_file_id, 0x20,128); 234 memset(diskStructure.primaryDescriptor.abstract_file_id, 0x20,128); 235 memset(diskStructure.primaryDescriptor.bibliographic_file_id, 0x20,128); 236 237 strcpy(diskStructure.primaryDescriptor.system_id,"NetBSD"); 238 239 cd9660_defaults_set = 1; 240 241 /* Boot support: Initially disabled */ 242 diskStructure.boot_image_directory = 0; 243 /*memset(diskStructure.boot_descriptor, 0, 2048);*/ 244 245 diskStructure.is_bootable = 0; 246 TAILQ_INIT(&diskStructure.boot_images); 247 LIST_INIT(&diskStructure.boot_entries); 248 } 249 250 void 251 cd9660_prep_opts(fsinfo_t *fsopts __unused) 252 { 253 cd9660_set_defaults(); 254 } 255 256 void 257 cd9660_cleanup_opts(fsinfo_t *fsopts __unused) 258 { 259 260 } 261 262 static int 263 cd9660_arguments_set_string(const char *val, const char *fieldtitle, int length, 264 char testmode, char * dest) 265 { 266 int len, test; 267 268 if (val == NULL) 269 warnx("error: The %s requires a string argument", fieldtitle); 270 else if ((len = strlen(val)) <= length) { 271 if (testmode == 'd') 272 test = cd9660_valid_d_chars(val); 273 else 274 test = cd9660_valid_a_chars(val); 275 if (test) { 276 memcpy(dest, val, len); 277 if (test == 2) 278 cd9660_uppercase_characters(dest, len); 279 return 1; 280 } else 281 warnx("error: The %s must be composed of " 282 "%c-characters", fieldtitle, testmode); 283 } else 284 warnx("error: The %s must be at most 32 characters long", 285 fieldtitle); 286 return 0; 287 } 288 289 /* 290 * Command-line parsing function 291 */ 292 293 int 294 cd9660_parse_opts(const char *option, fsinfo_t *fsopts) 295 { 296 char *var, *val; 297 int rv; 298 /* Set up allowed options - integer options ONLY */ 299 option_t cd9660_options[] = { 300 { "l", &diskStructure.isoLevel, 1, 3, "ISO Level" }, 301 { "isolevel", &diskStructure.isoLevel, 1, 3, "ISO Level" }, 302 { "verbose", &diskStructure.verbose_level, 0, 2, 303 "Turns on verbose output" }, 304 { "v", &diskStructure.verbose_level, 0 , 2, 305 "Turns on verbose output"}, 306 { .name = NULL } 307 }; 308 309 if (cd9660_defaults_set == 0) 310 cd9660_set_defaults(); 311 312 /* 313 * Todo : finish implementing this, and make a function that 314 * parses them 315 */ 316 /* 317 string_option_t cd9660_string_options[] = { 318 { "L", "Label", &diskStructure.primaryDescriptor.volume_id, 1, 32, "Disk Label", ISO_STRING_FILTER_DCHARS }, 319 { NULL } 320 } 321 */ 322 323 assert(option != NULL); 324 assert(fsopts != NULL); 325 326 if (debug & DEBUG_FS_PARSE_OPTS) 327 printf("cd9660_parse_opts: got `%s'\n", option); 328 329 if ((var = strdup(option)) == NULL) 330 err(1, "allocating memory for copy of option string"); 331 rv = 1; 332 333 val = strchr(var, '='); 334 if (val != NULL) 335 *val++ = '\0'; 336 337 /* First handle options with no parameters */ 338 if (strcmp(var, "h") == 0) { 339 diskStructure.displayHelp = 1; 340 rv = 1; 341 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "S", "follow-symlinks")) { 342 /* this is not handled yet */ 343 diskStructure.follow_sym_links = 1; 344 rv = 1; 345 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "L", "label")) { 346 rv = cd9660_arguments_set_string(val, "Disk Label", 32, 'd', 347 diskStructure.primaryDescriptor.volume_id); 348 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "applicationid")) { 349 rv = cd9660_arguments_set_string(val, "Application Identifier", 128, 'a', 350 diskStructure.primaryDescriptor.application_id); 351 } else if(CD9660_IS_COMMAND_ARG_DUAL(var, "P", "publisher")) { 352 rv = cd9660_arguments_set_string(val, "Publisher Identifier", 353 128, 'a', diskStructure.primaryDescriptor.publisher_id); 354 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "p", "preparer")) { 355 rv = cd9660_arguments_set_string(val, "Preparer Identifier", 356 128, 'a', diskStructure.primaryDescriptor.preparer_id); 357 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "V", "volumeid")) { 358 rv = cd9660_arguments_set_string(val, "Volume Set Identifier", 359 128, 'a', diskStructure.primaryDescriptor.volume_set_id); 360 /* Boot options */ 361 } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "B", "bootimage")) { 362 if (val == NULL) 363 warnx("error: The Boot Image parameter requires a valid boot information string"); 364 else 365 rv = cd9660_add_boot_disk(val); 366 } else if (CD9660_IS_COMMAND_ARG(var, "bootimagedir")) { 367 /* 368 * XXXfvdl this is unused. 369 */ 370 if (val == NULL) 371 errx(1, "error: The Boot Image Directory parameter" 372 " requires a directory name\n"); 373 else { 374 if ((diskStructure.boot_image_directory = 375 malloc(strlen(val) + 1)) == NULL) { 376 CD9660_MEM_ALLOC_ERROR("cd9660_parse_opts"); 377 exit(1); 378 } 379 380 /* BIG TODO: Add the max length function here */ 381 cd9660_arguments_set_string(val, "Boot Image Directory", 382 12 , 'd', diskStructure.boot_image_directory); 383 } 384 } else if (CD9660_IS_COMMAND_ARG(var, "no-trailing-padding")) 385 diskStructure.include_padding_areas = 0; 386 /* RRIP */ 387 else if (CD9660_IS_COMMAND_ARG_DUAL(var, "R", "rockridge")) 388 diskStructure.rock_ridge_enabled = 1; 389 else if (CD9660_IS_COMMAND_ARG_DUAL(var, "K", "keep-bad-images")) 390 diskStructure.keep_bad_images = 1; 391 else if (CD9660_IS_COMMAND_ARG(var, "allow-deep-trees")) 392 diskStructure.allow_deep_trees = 1; 393 else if (CD9660_IS_COMMAND_ARG(var, "allow-max-name")) 394 diskStructure.allow_max_name = 1; 395 else if (CD9660_IS_COMMAND_ARG(var, "allow-illegal-chars")) 396 diskStructure.allow_illegal_chars = 1; 397 else if (CD9660_IS_COMMAND_ARG(var, "allow-lowercase")) 398 diskStructure.allow_lowercase = 1; 399 else if (CD9660_IS_COMMAND_ARG(var,"allow-multidot")) 400 diskStructure.allow_multidot = 1; 401 else if (CD9660_IS_COMMAND_ARG(var, "omit-trailing-period")) 402 diskStructure.omit_trailing_period = 1; 403 else if (CD9660_IS_COMMAND_ARG(var, "no-emul-boot") || 404 CD9660_IS_COMMAND_ARG(var, "no-boot") || 405 CD9660_IS_COMMAND_ARG(var, "hard-disk-boot")) { 406 cd9660_eltorito_add_boot_option(var, 0); 407 408 /* End of flag variables */ 409 } else if (CD9660_IS_COMMAND_ARG(var, "boot-load-segment")) { 410 if (val == NULL) { 411 warnx("Option `%s' doesn't contain a value", var); 412 rv = 0; 413 } else { 414 cd9660_eltorito_add_boot_option(var, val); 415 } 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 /* 956 * first will either be 0, the . or the .. 957 * if . or .., this means no other entry may be written before first 958 * if 0, the new node may be inserted at the head 959 */ 960 961 TAILQ_FOREACH(cn, head, cn_next_child) { 962 /* 963 * Dont insert a node twice - 964 * that would cause an infinite loop 965 */ 966 if (cn_new == cn) 967 return; 968 969 compare = cd9660_compare_filename(cn_new->isoDirRecord->name, 970 cn->isoDirRecord->name); 971 972 if (compare == 0) 973 compare = cd9660_compare_filename(cn_new->node->name, 974 cn->node->name); 975 976 if (compare < 0) 977 break; 978 } 979 if (cn == NULL) 980 TAILQ_INSERT_TAIL(head, cn_new, cn_next_child); 981 else 982 TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child); 983 } 984 985 /* 986 * Called After cd9660_sorted_child_insert 987 * handles file collisions by suffixing each filname with ~n 988 * where n represents the files respective place in the ordering 989 */ 990 static int 991 cd9660_handle_collisions(cd9660node *colliding, int past) 992 { 993 cd9660node *iter, *next, *prev; 994 int skip; 995 int delete_chars = 0; 996 int temp_past = past; 997 int temp_skip; 998 int flag = 0; 999 cd9660node *end_of_range; 1000 1001 for (iter = TAILQ_FIRST(&colliding->cn_children); 1002 iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) { 1003 if (strcmp(iter->isoDirRecord->name, 1004 next->isoDirRecord->name) != 0) { 1005 iter = TAILQ_NEXT(iter, cn_next_child); 1006 continue; 1007 } 1008 flag = 1; 1009 temp_skip = skip = cd9660_count_collisions(iter); 1010 end_of_range = iter; 1011 while (temp_skip > 0) { 1012 temp_skip--; 1013 end_of_range = TAILQ_NEXT(end_of_range, cn_next_child); 1014 } 1015 temp_past = past; 1016 while (temp_past > 0) { 1017 if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL) 1018 end_of_range = next; 1019 else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL) 1020 iter = prev; 1021 else 1022 delete_chars++; 1023 temp_past--; 1024 } 1025 skip += past; 1026 iter = cd9660_rename_filename(iter, skip, delete_chars); 1027 } 1028 return flag; 1029 } 1030 1031 1032 static cd9660node * 1033 cd9660_rename_filename(cd9660node *iter, int num, int delete_chars) 1034 { 1035 int i = 0; 1036 int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; 1037 char *naming; 1038 int maxlength; 1039 char *tmp; 1040 1041 if (diskStructure.verbose_level > 0) 1042 printf("Rename_filename called\n"); 1043 1044 /* TODO : A LOT of chanes regarding 8.3 filenames */ 1045 if (diskStructure.isoLevel == 1) 1046 maxlength = 8; 1047 else if (diskStructure.isoLevel == 2) 1048 maxlength = 31; 1049 else 1050 maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION; 1051 1052 tmp = malloc(maxlength + 1); 1053 1054 while (i < num) { 1055 powers = 1; 1056 count = 0; 1057 digits = 1; 1058 multiplier = 1; 1059 while (((int)(i / powers) ) >= 10) { 1060 digits++; 1061 powers = powers * 10; 1062 } 1063 1064 naming = iter->o_name; 1065 1066 /* 1067 while ((*naming != '.') && (*naming != ';')) { 1068 naming++; 1069 count++; 1070 } 1071 */ 1072 1073 dot = -1; 1074 semi = -1; 1075 while (count < maxlength) { 1076 if (*naming == '.') 1077 dot = count; 1078 else if (*naming == ';') { 1079 semi = count; 1080 break; 1081 } 1082 naming++; 1083 count++; 1084 } 1085 1086 if ((count + digits) < maxlength) 1087 numbts = count; 1088 else 1089 numbts = maxlength - (digits); 1090 numbts -= delete_chars; 1091 1092 /* 8.3 rules - keep the extension, add before the dot */ 1093 1094 /* 1095 * This code makes a bunch of assumptions. 1096 * See if you can spot them all :) 1097 */ 1098 1099 /* 1100 if (diskStructure.isoLevel == 1) { 1101 numbts = 8 - digits - delete_chars; 1102 if (dot < 0) { 1103 1104 } else { 1105 if (dot < 8) { 1106 memmove(&tmp[numbts],&tmp[dot],4); 1107 } 1108 } 1109 } 1110 */ 1111 1112 /* (copying just the filename before the '.' */ 1113 memcpy(tmp, (iter->o_name), numbts); 1114 1115 /* adding the appropriate number following the name */ 1116 temp = i; 1117 while (digits > 0) { 1118 digit = (int)(temp / powers); 1119 temp = temp - digit * powers; 1120 sprintf(&tmp[numbts] , "%d", digit); 1121 digits--; 1122 numbts++; 1123 powers = powers / 10; 1124 } 1125 1126 while ((*naming != ';') && (numbts < maxlength)) { 1127 tmp[numbts] = (*naming); 1128 naming++; 1129 numbts++; 1130 } 1131 1132 tmp[numbts] = ';'; 1133 tmp[numbts+1] = '1'; 1134 1135 /* 1136 * now tmp has exactly the identifier 1137 * we want so we'll copy it back to record 1138 */ 1139 memcpy((iter->isoDirRecord->name), tmp, numbts + 2); 1140 1141 iter = TAILQ_NEXT(iter, cn_next_child); 1142 i++; 1143 } 1144 1145 free(tmp); 1146 return iter; 1147 } 1148 1149 /* Todo: Figure out why these functions are nec. */ 1150 static void 1151 cd9660_copy_filenames(cd9660node *node) 1152 { 1153 cd9660node *cn; 1154 1155 if (TAILQ_EMPTY(&node->cn_children)) 1156 return; 1157 1158 if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) { 1159 debug_print_tree(diskStructure.rootNode, 0); 1160 exit(1); 1161 } 1162 1163 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 1164 cd9660_copy_filenames(cn); 1165 memcpy(cn->o_name, cn->isoDirRecord->name, 1166 ISO_FILENAME_MAXLENGTH_WITH_PADDING); 1167 } 1168 } 1169 1170 static void 1171 cd9660_sorting_nodes(cd9660node *node) 1172 { 1173 cd9660node *cn; 1174 1175 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) 1176 cd9660_sorting_nodes(cn); 1177 cd9660_sort_nodes(node); 1178 } 1179 1180 /* XXX Bubble sort. */ 1181 static void 1182 cd9660_sort_nodes(cd9660node *node) 1183 { 1184 cd9660node *cn, *next; 1185 1186 do { 1187 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 1188 if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL) 1189 return; 1190 else if (strcmp(next->isoDirRecord->name, 1191 cn->isoDirRecord->name) >= 0) 1192 continue; 1193 TAILQ_REMOVE(&node->cn_children, next, cn_next_child); 1194 TAILQ_INSERT_BEFORE(cn, next, cn_next_child); 1195 break; 1196 } 1197 } while (cn != NULL); 1198 } 1199 1200 static int 1201 cd9660_count_collisions(cd9660node *copy) 1202 { 1203 int count = 0; 1204 cd9660node *iter, *next; 1205 1206 for (iter = copy; 1207 (next = TAILQ_NEXT(iter, cn_next_child)) != NULL; 1208 iter = next) { 1209 if (cd9660_compare_filename(iter->isoDirRecord->name, 1210 next->isoDirRecord->name) == 0) 1211 count++; 1212 else 1213 return count; 1214 } 1215 #if 0 1216 if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) { 1217 printf("cd9660_recurse_on_collision: count is %i \n", count); 1218 compare = cd9660_compare_filename(iter->isoDirRecord->name, 1219 next->isoDirRecord->name); 1220 if (compare == 0) { 1221 count++; 1222 return cd9660_recurse_on_collision(next, count); 1223 } else 1224 return count; 1225 } 1226 #endif 1227 return count; 1228 } 1229 1230 static cd9660node * 1231 cd9660_rrip_move_directory(cd9660node *dir) 1232 { 1233 char newname[9]; 1234 cd9660node *tfile; 1235 1236 /* 1237 * This function needs to: 1238 * 1) Create an empty virtual file in place of the old directory 1239 * 2) Point the virtual file to the new directory 1240 * 3) Point the relocated directory to its old parent 1241 * 4) Move the directory specified by dir into rr_moved_dir, 1242 * and rename it to "diskStructure.rock_ridge_move_count" (as a string) 1243 */ 1244 1245 /* First see if the moved directory even exists */ 1246 if (diskStructure.rr_moved_dir == NULL) { 1247 diskStructure.rr_moved_dir = 1248 cd9660_create_directory(ISO_RRIP_DEFAULT_MOVE_DIR_NAME, 1249 diskStructure.rootNode, dir); 1250 if (diskStructure.rr_moved_dir == NULL) 1251 return 0; 1252 } 1253 1254 /* Create a file with the same ORIGINAL name */ 1255 tfile = cd9660_create_file(dir->node->name, dir->parent, dir); 1256 if (tfile == NULL) 1257 return NULL; 1258 1259 diskStructure.rock_ridge_move_count++; 1260 snprintf(newname, sizeof(newname), "%08i", 1261 diskStructure.rock_ridge_move_count); 1262 1263 /* Point to old parent */ 1264 dir->rr_real_parent = dir->parent; 1265 1266 /* Place the placeholder file */ 1267 if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) { 1268 TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile, 1269 cn_next_child); 1270 } else { 1271 cd9660_sorted_child_insert(dir->rr_real_parent, tfile); 1272 } 1273 1274 /* Point to new parent */ 1275 dir->parent = diskStructure.rr_moved_dir; 1276 1277 /* Point the file to the moved directory */ 1278 tfile->rr_relocated = dir; 1279 1280 /* Actually move the directory */ 1281 cd9660_sorted_child_insert(diskStructure.rr_moved_dir, dir); 1282 1283 /* TODO: Inherit permissions / ownership (basically the entire inode) */ 1284 1285 /* Set the new name */ 1286 memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); 1287 strncpy(dir->isoDirRecord->name, newname, 8); 1288 1289 return dir; 1290 } 1291 1292 static int 1293 cd9660_add_dot_records(cd9660node *root) 1294 { 1295 struct cd9660_children_head *head = &root->cn_children; 1296 cd9660node *cn; 1297 1298 TAILQ_FOREACH(cn, head, cn_next_child) { 1299 if ((cn->type & CD9660_TYPE_DIR) == 0) 1300 continue; 1301 /* Recursion first */ 1302 cd9660_add_dot_records(cn); 1303 } 1304 cd9660_create_special_directory(CD9660_TYPE_DOT, root); 1305 cd9660_create_special_directory(CD9660_TYPE_DOTDOT, root); 1306 return 1; 1307 } 1308 1309 /* 1310 * Convert node to cd9660 structure 1311 * This function is designed to be called recursively on the root node of 1312 * the filesystem 1313 * Lots of recursion going on here, want to make sure it is efficient 1314 * @param struct fsnode * The root node to be converted 1315 * @param struct cd9660* The parent node (should not be NULL) 1316 * @param int Current directory depth 1317 * @param int* Running count of the number of directories that are being created 1318 */ 1319 static void 1320 cd9660_convert_structure(fsnode *root, cd9660node *parent_node, int level, 1321 int *numDirectories, int *error) 1322 { 1323 fsnode *iterator = root; 1324 cd9660node *this_node; 1325 int working_level; 1326 int add; 1327 int flag = 0; 1328 int counter = 0; 1329 1330 /* 1331 * Newer, more efficient method, reduces recursion depth 1332 */ 1333 if (root == NULL) { 1334 warnx("%s: root is null\n", __func__); 1335 return; 1336 } 1337 1338 /* Test for an empty directory - makefs still gives us the . record */ 1339 if ((S_ISDIR(root->type)) && (root->name[0] == '.') 1340 && (root->name[1] == '\0')) { 1341 root = root->next; 1342 if (root == NULL) 1343 return; 1344 } 1345 if ((this_node = cd9660_allocate_cd9660node()) == NULL) { 1346 CD9660_MEM_ALLOC_ERROR(__func__); 1347 } 1348 1349 /* 1350 * To reduce the number of recursive calls, we will iterate over 1351 * the next pointers to the right. 1352 */ 1353 while (iterator != NULL) { 1354 add = 1; 1355 /* 1356 * Increment the directory count if this is a directory 1357 * Ignore "." entries. We will generate them later 1358 */ 1359 if (!S_ISDIR(iterator->type) || 1360 strcmp(iterator->name, ".") != 0) { 1361 1362 /* Translate the node, including its filename */ 1363 this_node->parent = parent_node; 1364 cd9660_translate_node(iterator, this_node); 1365 this_node->level = level; 1366 1367 if (S_ISDIR(iterator->type)) { 1368 (*numDirectories)++; 1369 this_node->type = CD9660_TYPE_DIR; 1370 working_level = level + 1; 1371 1372 /* 1373 * If at level 8, directory would be at 8 1374 * and have children at 9 which is not 1375 * allowed as per ISO spec 1376 */ 1377 if (level == 8) { 1378 if ((!diskStructure.allow_deep_trees) && 1379 (!diskStructure.rock_ridge_enabled)) { 1380 warnx("error: found entry " 1381 "with depth greater " 1382 "than 8."); 1383 (*error) = 1; 1384 return; 1385 } else if (diskStructure. 1386 rock_ridge_enabled) { 1387 working_level = 3; 1388 /* 1389 * Moved directory is actually 1390 * at level 2. 1391 */ 1392 this_node->level = 1393 working_level - 1; 1394 if (cd9660_rrip_move_directory( 1395 this_node) == 0) { 1396 warnx("Failure in " 1397 "cd9660_rrip_" 1398 "move_directory" 1399 ); 1400 (*error) = 1; 1401 return; 1402 } 1403 add = 0; 1404 } 1405 } 1406 1407 /* Do the recursive call on the children */ 1408 if (iterator->child != 0) { 1409 cd9660_convert_structure( 1410 iterator->child, this_node, 1411 working_level, 1412 numDirectories, error); 1413 1414 if ((*error) == 1) { 1415 warnx("%s: Error on recursive " 1416 "call", __func__); 1417 return; 1418 } 1419 } 1420 1421 } else { 1422 /* Only directories should have children */ 1423 assert(iterator->child == NULL); 1424 1425 this_node->type = CD9660_TYPE_FILE; 1426 } 1427 1428 /* 1429 * Finally, do a sorted insert 1430 */ 1431 if (add) { 1432 cd9660_sorted_child_insert( 1433 parent_node, this_node); 1434 } 1435 1436 /*Allocate new temp_node */ 1437 if (iterator->next != 0) { 1438 this_node = cd9660_allocate_cd9660node(); 1439 if (this_node == NULL) 1440 CD9660_MEM_ALLOC_ERROR(__func__); 1441 } 1442 } 1443 iterator = iterator->next; 1444 } 1445 1446 /* cd9660_handle_collisions(first_node); */ 1447 1448 /* TODO: need cleanup */ 1449 cd9660_copy_filenames(parent_node); 1450 1451 do { 1452 flag = cd9660_handle_collisions(parent_node, counter); 1453 counter++; 1454 cd9660_sorting_nodes(parent_node); 1455 } while ((flag == 1) && (counter < 100)); 1456 } 1457 1458 /* 1459 * Clean up the cd9660node tree 1460 * This is designed to be called recursively on the root node 1461 * @param struct cd9660node *root The node to free 1462 * @returns void 1463 */ 1464 static void 1465 cd9660_free_structure(cd9660node *root) 1466 { 1467 cd9660node *cn; 1468 1469 while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) { 1470 TAILQ_REMOVE(&root->cn_children, cn, cn_next_child); 1471 cd9660_free_structure(cn); 1472 } 1473 free(root); 1474 } 1475 1476 /* 1477 * Be a little more memory conservative: 1478 * instead of having the TAILQ_ENTRY as part of the cd9660node, 1479 * just create a temporary structure 1480 */ 1481 struct ptq_entry 1482 { 1483 TAILQ_ENTRY(ptq_entry) ptq; 1484 cd9660node *node; 1485 } *n; 1486 1487 #define PTQUEUE_NEW(n,s,r,t){\ 1488 n = malloc(sizeof(struct s)); \ 1489 if (n == NULL) \ 1490 return r; \ 1491 n->node = t;\ 1492 } 1493 1494 /* 1495 * Generate the path tables 1496 * The specific implementation of this function is left as an exercise to the 1497 * programmer. It could be done recursively. Make sure you read how the path 1498 * table has to be laid out, it has levels. 1499 * @param struct iso9660_disk *disk The disk image 1500 * @returns int The number of built path tables (between 1 and 4), 0 on failure 1501 */ 1502 static int 1503 cd9660_generate_path_table(void) 1504 { 1505 cd9660node *cn, *dirNode = diskStructure.rootNode; 1506 cd9660node *last = dirNode; 1507 int pathTableSize = 0; /* computed as we go */ 1508 int counter = 1; /* root gets a count of 0 */ 1509 int parentRecNum = 0; /* root's parent is '0' */ 1510 1511 TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head; 1512 TAILQ_INIT(&pt_head); 1513 1514 PTQUEUE_NEW(n, ptq_entry, -1, diskStructure.rootNode); 1515 1516 /* Push the root node */ 1517 TAILQ_INSERT_HEAD(&pt_head, n, ptq); 1518 1519 /* Breadth-first traversal of file structure */ 1520 while (pt_head.tqh_first != 0) { 1521 n = pt_head.tqh_first; 1522 dirNode = n->node; 1523 TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq); 1524 free(n); 1525 1526 /* Update the size */ 1527 pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE 1528 + dirNode->isoDirRecord->name_len[0]+ 1529 (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1); 1530 /* includes the padding bit */ 1531 1532 dirNode->ptnumber=counter; 1533 if (dirNode != last) { 1534 last->ptnext = dirNode; 1535 dirNode->ptprev = last; 1536 } 1537 last = dirNode; 1538 1539 parentRecNum = 1; 1540 if (dirNode->parent != 0) 1541 parentRecNum = dirNode->parent->ptnumber; 1542 1543 /* Push children onto queue */ 1544 TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) { 1545 /* 1546 * Dont add the DOT and DOTDOT types to the path 1547 * table. 1548 */ 1549 if ((cn->type != CD9660_TYPE_DOT) 1550 && (cn->type != CD9660_TYPE_DOTDOT)) { 1551 1552 if (S_ISDIR(cn->node->type)) { 1553 PTQUEUE_NEW(n, ptq_entry, -1, cn); 1554 TAILQ_INSERT_TAIL(&pt_head, n, ptq); 1555 } 1556 } 1557 } 1558 counter++; 1559 } 1560 return pathTableSize; 1561 } 1562 1563 void 1564 cd9660_compute_full_filename(cd9660node *node, char *buf, int level) 1565 { 1566 cd9660node *parent; 1567 1568 parent = (node->rr_real_parent == NULL ? 1569 node->parent : node->rr_real_parent); 1570 if (parent != NULL) { 1571 cd9660_compute_full_filename(parent, buf, level + 1); 1572 strcat(buf, node->node->name); 1573 } else { 1574 /* We are at the root */ 1575 strcat(buf, diskStructure.rootFilesystemPath); 1576 if (buf[strlen(buf) - 1] == '/') 1577 buf[strlen(buf) - 1] = '\0'; 1578 } 1579 1580 if (level != 0) 1581 strcat(buf, "/"); 1582 } 1583 1584 /* NEW filename conversion method */ 1585 typedef int(*cd9660_filename_conversion_functor)(const char *, char *, int); 1586 1587 1588 /* 1589 * TODO: These two functions are almost identical. 1590 * Some code cleanup is possible here 1591 * 1592 * XXX bounds checking! 1593 */ 1594 static int 1595 cd9660_level1_convert_filename(const char *oldname, char *newname, int is_file) 1596 { 1597 /* 1598 * ISO 9660 : 10.1 1599 * File Name shall not contain more than 8 d or d1 characters 1600 * File Name Extension shall not contain more than 3 d or d1 characters 1601 * Directory Identifier shall not contain more than 8 d or d1 characters 1602 */ 1603 int namelen = 0; 1604 int extlen = 0; 1605 int found_ext = 0; 1606 1607 while (*oldname != '\0') { 1608 /* Handle period first, as it is special */ 1609 if (*oldname == '.') { 1610 if (found_ext) { 1611 *newname++ = '_'; 1612 extlen ++; 1613 } 1614 else { 1615 *newname++ = '.'; 1616 found_ext = 1; 1617 } 1618 } else { 1619 /* Enforce 12.3 / 8 */ 1620 if (((namelen == 8) && !found_ext) || 1621 (found_ext && extlen == 3)) { 1622 break; 1623 } 1624 1625 if (islower((unsigned char)*oldname)) 1626 *newname++ = toupper((unsigned char)*oldname); 1627 else if (isupper((unsigned char)*oldname) 1628 || isdigit((unsigned char)*oldname)) 1629 *newname++ = *oldname; 1630 else 1631 *newname++ = '_'; 1632 1633 if (found_ext) 1634 extlen++; 1635 else 1636 namelen++; 1637 } 1638 oldname ++; 1639 } 1640 if (is_file) { 1641 if (!found_ext && !diskStructure.omit_trailing_period) 1642 *newname++ = '.'; 1643 /* Add version */ 1644 sprintf(newname, ";%i", 1); 1645 } 1646 return namelen + extlen + found_ext; 1647 } 1648 1649 /* XXX bounds checking! */ 1650 static int 1651 cd9660_level2_convert_filename(const char *oldname, char *newname, int is_file) 1652 { 1653 /* 1654 * ISO 9660 : 7.5.1 1655 * File name : 0+ d or d1 characters 1656 * separator 1 (.) 1657 * File name extension : 0+ d or d1 characters 1658 * separator 2 (;) 1659 * File version number (5 characters, 1-32767) 1660 * 1 <= Sum of File name and File name extension <= 30 1661 */ 1662 int namelen = 0; 1663 int extlen = 0; 1664 int found_ext = 0; 1665 1666 while (*oldname != '\0') { 1667 /* Handle period first, as it is special */ 1668 if (*oldname == '.') { 1669 if (found_ext) { 1670 *newname++ = '_'; 1671 extlen ++; 1672 } 1673 else { 1674 *newname++ = '.'; 1675 found_ext = 1; 1676 } 1677 } else { 1678 if ((namelen + extlen) == 30) 1679 break; 1680 1681 if (islower((unsigned char)*oldname)) 1682 *newname++ = toupper((unsigned char)*oldname); 1683 else if (isupper((unsigned char)*oldname) || 1684 isdigit((unsigned char)*oldname)) 1685 *newname++ = *oldname; 1686 else 1687 *newname++ = '_'; 1688 1689 if (found_ext) 1690 extlen++; 1691 else 1692 namelen++; 1693 } 1694 oldname ++; 1695 } 1696 if (is_file) { 1697 if (!found_ext && !diskStructure.omit_trailing_period) 1698 *newname++ = '.'; 1699 /* Add version */ 1700 sprintf(newname, ";%i", 1); 1701 } 1702 return namelen + extlen + found_ext; 1703 } 1704 1705 #if 0 1706 static int 1707 cd9660_joliet_convert_filename(const char *oldname, char *newname, int is_file) 1708 { 1709 /* TODO: implement later, move to cd9660_joliet.c ?? */ 1710 } 1711 #endif 1712 1713 1714 /* 1715 * Convert a file name to ISO compliant file name 1716 * @param char * oldname The original filename 1717 * @param char ** newname The new file name, in the appropriate character 1718 * set and of appropriate length 1719 * @param int 1 if file, 0 if directory 1720 * @returns int The length of the new string 1721 */ 1722 static int 1723 cd9660_convert_filename(const char *oldname, char *newname, int is_file) 1724 { 1725 /* NEW */ 1726 cd9660_filename_conversion_functor conversion_function = 0; 1727 if (diskStructure.isoLevel == 1) 1728 conversion_function = &cd9660_level1_convert_filename; 1729 else if (diskStructure.isoLevel == 2) 1730 conversion_function = &cd9660_level2_convert_filename; 1731 return (*conversion_function)(oldname, newname, is_file); 1732 } 1733 1734 int 1735 cd9660_compute_record_size(cd9660node *node) 1736 { 1737 int size = node->isoDirRecord->length[0]; 1738 1739 if (diskStructure.rock_ridge_enabled) 1740 size += node->susp_entry_size; 1741 return size; 1742 } 1743 1744 static void 1745 cd9660_populate_dot_records(cd9660node *node) 1746 { 1747 node->dot_record->fileDataSector = node->fileDataSector; 1748 memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34); 1749 node->dot_record->isoDirRecord->name_len[0] = 1; 1750 node->dot_record->isoDirRecord->name[0] = 0; 1751 node->dot_record->isoDirRecord->name[1] = 0; 1752 node->dot_record->isoDirRecord->length[0] = 34; 1753 node->dot_record->fileRecordSize = 1754 cd9660_compute_record_size(node->dot_record); 1755 1756 if (node == diskStructure.rootNode) { 1757 node->dot_dot_record->fileDataSector = node->fileDataSector; 1758 memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord, 1759 34); 1760 } else { 1761 node->dot_dot_record->fileDataSector = 1762 node->parent->fileDataSector; 1763 memcpy(node->dot_dot_record->isoDirRecord, 1764 node->parent->isoDirRecord,34); 1765 } 1766 node->dot_dot_record->isoDirRecord->name_len[0] = 1; 1767 node->dot_dot_record->isoDirRecord->name[0] = 1; 1768 node->dot_dot_record->isoDirRecord->name[1] = 0; 1769 node->dot_dot_record->isoDirRecord->length[0] = 34; 1770 node->dot_dot_record->fileRecordSize = 1771 cd9660_compute_record_size(node->dot_dot_record); 1772 } 1773 1774 /* 1775 * @param struct cd9660node *node The node 1776 * @param int The offset (in bytes) - SHOULD align to the beginning of a sector 1777 * @returns int The total size of files and directory entries (should be 1778 * a multiple of sector size) 1779 */ 1780 static int 1781 cd9660_compute_offsets(cd9660node *node, int startOffset) 1782 { 1783 /* 1784 * This function needs to compute the size of directory records and 1785 * runs, file lengths, and set the appropriate variables both in 1786 * cd9660node and isoDirEntry 1787 */ 1788 int used_bytes = 0; 1789 int current_sector_usage = 0; 1790 cd9660node *child; 1791 fsinode *inode; 1792 int r; 1793 1794 assert(node != NULL); 1795 1796 1797 /* 1798 * NOTE : There needs to be some special case detection for 1799 * the "real root" node, since for it, node->node is undefined 1800 */ 1801 1802 node->fileDataSector = -1; 1803 1804 if (node->type & CD9660_TYPE_DIR) { 1805 node->fileRecordSize = cd9660_compute_record_size(node); 1806 /*Set what sector this directory starts in*/ 1807 node->fileDataSector = 1808 CD9660_BLOCKS(diskStructure.sectorSize,startOffset); 1809 1810 cd9660_bothendian_dword(node->fileDataSector, 1811 node->isoDirRecord->extent); 1812 1813 /* 1814 * First loop over children, need to know the size of 1815 * their directory records 1816 */ 1817 node->fileSectorsUsed = 1; 1818 TAILQ_FOREACH(child, &node->cn_children, cn_next_child) { 1819 node->fileDataLength += 1820 cd9660_compute_record_size(child); 1821 if ((cd9660_compute_record_size(child) + 1822 current_sector_usage) >= 1823 diskStructure.sectorSize) { 1824 current_sector_usage = 0; 1825 node->fileSectorsUsed++; 1826 } 1827 1828 current_sector_usage += 1829 cd9660_compute_record_size(child); 1830 } 1831 1832 cd9660_bothendian_dword(node->fileSectorsUsed * 1833 diskStructure.sectorSize,node->isoDirRecord->size); 1834 1835 /* 1836 * This should point to the sector after the directory 1837 * record (or, the first byte in that sector) 1838 */ 1839 used_bytes += node->fileSectorsUsed * diskStructure.sectorSize; 1840 1841 for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 1842 child != NULL; child = TAILQ_NEXT(child, cn_next_child)) { 1843 /* Directories need recursive call */ 1844 if (S_ISDIR(child->node->type)) { 1845 r = cd9660_compute_offsets(child, 1846 used_bytes + startOffset); 1847 1848 if (r != -1) 1849 used_bytes += r; 1850 else 1851 return -1; 1852 } 1853 } 1854 1855 /* Explicitly set the . and .. records */ 1856 cd9660_populate_dot_records(node); 1857 1858 /* Finally, do another iteration to write the file data*/ 1859 for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 1860 child != NULL; 1861 child = TAILQ_NEXT(child, cn_next_child)) { 1862 /* Files need extent set */ 1863 if (S_ISDIR(child->node->type)) 1864 continue; 1865 child->fileRecordSize = 1866 cd9660_compute_record_size(child); 1867 1868 child->fileSectorsUsed = 1869 CD9660_BLOCKS(diskStructure.sectorSize, 1870 child->fileDataLength); 1871 1872 inode = child->node->inode; 1873 if ((inode->flags & FI_ALLOCATED) == 0) { 1874 inode->ino = 1875 CD9660_BLOCKS(diskStructure.sectorSize, 1876 used_bytes + startOffset); 1877 inode->flags |= FI_ALLOCATED; 1878 used_bytes += child->fileSectorsUsed * 1879 diskStructure.sectorSize; 1880 } else { 1881 INODE_WARNX(("%s: already allocated inode %d " 1882 "data sectors at %" PRIu32, __func__, 1883 (int)inode->st.st_ino, inode->ino)); 1884 } 1885 child->fileDataSector = inode->ino; 1886 cd9660_bothendian_dword(child->fileDataSector, 1887 child->isoDirRecord->extent); 1888 } 1889 } 1890 1891 return used_bytes; 1892 } 1893 1894 #if 0 1895 /* Might get rid of this func */ 1896 static int 1897 cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file) 1898 { 1899 to->node->inode->st.st_dev = 0; 1900 to->node->inode->st.st_ino = 0; 1901 to->node->inode->st.st_size = 0; 1902 to->node->inode->st.st_blksize = from->node->inode->st.st_blksize; 1903 to->node->inode->st.st_atime = from->node->inode->st.st_atime; 1904 to->node->inode->st.st_mtime = from->node->inode->st.st_mtime; 1905 to->node->inode->st.st_ctime = from->node->inode->st.st_ctime; 1906 to->node->inode->st.st_uid = from->node->inode->st.st_uid; 1907 to->node->inode->st.st_gid = from->node->inode->st.st_gid; 1908 to->node->inode->st.st_mode = from->node->inode->st.st_mode; 1909 /* Clear out type */ 1910 to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT); 1911 if (file) 1912 to->node->inode->st.st_mode |= S_IFREG; 1913 else 1914 to->node->inode->st.st_mode |= S_IFDIR; 1915 return 1; 1916 } 1917 #endif 1918 1919 static cd9660node * 1920 cd9660_create_virtual_entry(const char *name, cd9660node *parent, int file, 1921 int insert) 1922 { 1923 cd9660node *temp; 1924 fsnode * tfsnode; 1925 1926 assert(parent != NULL); 1927 1928 temp = cd9660_allocate_cd9660node(); 1929 if (temp == NULL) 1930 return NULL; 1931 1932 if ((tfsnode = malloc(sizeof(fsnode))) == NULL) { 1933 CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry"); 1934 return NULL; 1935 } 1936 1937 /* Assume for now name is a valid length */ 1938 if ((tfsnode->name = malloc(strlen(name) + 1)) == NULL) { 1939 CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry"); 1940 return NULL; 1941 } 1942 1943 if ((temp->isoDirRecord = 1944 malloc(sizeof(iso_directory_record_cd9660))) == NULL) { 1945 CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry"); 1946 return NULL; 1947 } 1948 1949 strcpy(tfsnode->name, name); 1950 1951 cd9660_convert_filename(tfsnode->name, temp->isoDirRecord->name, file); 1952 1953 temp->node = tfsnode; 1954 temp->parent = parent; 1955 1956 if (insert) { 1957 if (temp->parent != NULL) { 1958 temp->level = temp->parent->level + 1; 1959 if (!TAILQ_EMPTY(&temp->parent->cn_children)) 1960 cd9660_sorted_child_insert(temp->parent, temp); 1961 else 1962 TAILQ_INSERT_HEAD(&temp->parent->cn_children, 1963 temp, cn_next_child); 1964 } 1965 } 1966 1967 if (parent->node != NULL) { 1968 tfsnode->type = parent->node->type; 1969 } 1970 1971 /* Clear out file type bits */ 1972 tfsnode->type &= ~(S_IFMT); 1973 if (file) 1974 tfsnode->type |= S_IFREG; 1975 else 1976 tfsnode->type |= S_IFDIR; 1977 1978 /* Indicate that there is no spec entry (inode) */ 1979 tfsnode->flags &= ~(FSNODE_F_HASSPEC); 1980 #if 0 1981 cd9660_copy_stat_info(parent, temp, file); 1982 #endif 1983 return temp; 1984 } 1985 1986 static cd9660node * 1987 cd9660_create_file(const char * name, cd9660node *parent, cd9660node *me) 1988 { 1989 cd9660node *temp; 1990 1991 temp = cd9660_create_virtual_entry(name,parent,1,1); 1992 if (temp == NULL) 1993 return NULL; 1994 1995 temp->fileDataLength = 0; 1996 1997 temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL; 1998 1999 if ((temp->node->inode = calloc(1, sizeof(fsinode))) == NULL) 2000 return NULL; 2001 *temp->node->inode = *me->node->inode; 2002 2003 if (cd9960_translate_node_common(temp) == 0) 2004 return NULL; 2005 return temp; 2006 } 2007 2008 /* 2009 * Create a new directory which does not exist on disk 2010 * @param const char * name The name to assign to the directory 2011 * @param const char * parent Pointer to the parent directory 2012 * @returns cd9660node * Pointer to the new directory 2013 */ 2014 static cd9660node * 2015 cd9660_create_directory(const char *name, cd9660node *parent, cd9660node *me) 2016 { 2017 cd9660node *temp; 2018 2019 temp = cd9660_create_virtual_entry(name,parent,0,1); 2020 if (temp == NULL) 2021 return NULL; 2022 temp->node->type |= S_IFDIR; 2023 2024 temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL; 2025 2026 if ((temp->node->inode = calloc(1, sizeof(fsinode))) == NULL) 2027 return NULL; 2028 *temp->node->inode = *me->node->inode; 2029 2030 if (cd9960_translate_node_common(temp) == 0) 2031 return NULL; 2032 return temp; 2033 } 2034 2035 static cd9660node * 2036 cd9660_create_special_directory(u_char type, cd9660node *parent) 2037 { 2038 cd9660node *temp, *first; 2039 char na[2]; 2040 2041 assert(parent != NULL); 2042 2043 if (type == CD9660_TYPE_DOT) 2044 na[0] = 0; 2045 else if (type == CD9660_TYPE_DOTDOT) 2046 na[0] = 1; 2047 else 2048 return 0; 2049 2050 na[1] = 0; 2051 if ((temp = cd9660_create_virtual_entry(na, parent, 0, 0)) == NULL) 2052 return NULL; 2053 2054 temp->parent = parent; 2055 temp->type = type; 2056 temp->isoDirRecord->length[0] = 34; 2057 /* Dot record is always first */ 2058 if (type == CD9660_TYPE_DOT) { 2059 parent->dot_record = temp; 2060 TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child); 2061 /* DotDot should be second */ 2062 } else if (type == CD9660_TYPE_DOTDOT) { 2063 parent->dot_dot_record = temp; 2064 /* 2065 * If the first child is the dot record, insert 2066 * this second. Otherwise, insert it at the head. 2067 */ 2068 if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL || 2069 (first->type & CD9660_TYPE_DOT) == 0) { 2070 TAILQ_INSERT_HEAD(&parent->cn_children, temp, 2071 cn_next_child); 2072 } else { 2073 TAILQ_INSERT_AFTER(&parent->cn_children, first, temp, 2074 cn_next_child); 2075 } 2076 } 2077 2078 return temp; 2079 } 2080 2081