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