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