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