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