1*493aa139Smillert /* $OpenBSD: cd9660.c,v 1.24 2024/08/03 22:23:32 millert Exp $ */ 24e4cca72Snatano /* $NetBSD: cd9660.c,v 1.53 2016/11/25 23:02:44 christos Exp $ */ 36163fc9cSnatano 46163fc9cSnatano /* 56163fc9cSnatano * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan 66163fc9cSnatano * Perez-Rathke and Ram Vedam. All rights reserved. 76163fc9cSnatano * 86163fc9cSnatano * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys, 96163fc9cSnatano * Alan Perez-Rathke and Ram Vedam. 106163fc9cSnatano * 116163fc9cSnatano * Redistribution and use in source and binary forms, with or 126163fc9cSnatano * without modification, are permitted provided that the following 136163fc9cSnatano * conditions are met: 146163fc9cSnatano * 1. Redistributions of source code must retain the above copyright 156163fc9cSnatano * notice, this list of conditions and the following disclaimer. 166163fc9cSnatano * 2. Redistributions in binary form must reproduce the above 176163fc9cSnatano * copyright notice, this list of conditions and the following 186163fc9cSnatano * disclaimer in the documentation and/or other materials provided 196163fc9cSnatano * with the distribution. 206163fc9cSnatano * 216163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN 226163fc9cSnatano * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR 236163fc9cSnatano * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 246163fc9cSnatano * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 256163fc9cSnatano * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN 266163fc9cSnatano * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT, 276163fc9cSnatano * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 286163fc9cSnatano * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 296163fc9cSnatano * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 306163fc9cSnatano * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 316163fc9cSnatano * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 326163fc9cSnatano * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 336163fc9cSnatano * OF SUCH DAMAGE. 346163fc9cSnatano */ 356163fc9cSnatano /* 366163fc9cSnatano * Copyright (c) 2001 Wasabi Systems, Inc. 376163fc9cSnatano * All rights reserved. 386163fc9cSnatano * 396163fc9cSnatano * Written by Luke Mewburn for Wasabi Systems, Inc. 406163fc9cSnatano * 416163fc9cSnatano * Redistribution and use in source and binary forms, with or without 426163fc9cSnatano * modification, are permitted provided that the following conditions 436163fc9cSnatano * are met: 446163fc9cSnatano * 1. Redistributions of source code must retain the above copyright 456163fc9cSnatano * notice, this list of conditions and the following disclaimer. 466163fc9cSnatano * 2. Redistributions in binary form must reproduce the above copyright 476163fc9cSnatano * notice, this list of conditions and the following disclaimer in the 486163fc9cSnatano * documentation and/or other materials provided with the distribution. 496163fc9cSnatano * 3. All advertising materials mentioning features or use of this software 506163fc9cSnatano * must display the following acknowledgement: 516163fc9cSnatano * This product includes software developed for the NetBSD Project by 526163fc9cSnatano * Wasabi Systems, Inc. 536163fc9cSnatano * 4. The name of Wasabi Systems, Inc. may not be used to endorse 546163fc9cSnatano * or promote products derived from this software without specific prior 556163fc9cSnatano * written permission. 566163fc9cSnatano * 576163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 586163fc9cSnatano * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 596163fc9cSnatano * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 606163fc9cSnatano * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 616163fc9cSnatano * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 626163fc9cSnatano * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 636163fc9cSnatano * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 646163fc9cSnatano * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 656163fc9cSnatano * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 666163fc9cSnatano * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 676163fc9cSnatano * POSSIBILITY OF SUCH DAMAGE. 686163fc9cSnatano */ 696163fc9cSnatano /* 706163fc9cSnatano * Copyright (c) 1982, 1986, 1989, 1993 716163fc9cSnatano * The Regents of the University of California. All rights reserved. 726163fc9cSnatano * 736163fc9cSnatano * Redistribution and use in source and binary forms, with or without 746163fc9cSnatano * modification, are permitted provided that the following conditions 756163fc9cSnatano * are met: 766163fc9cSnatano * 1. Redistributions of source code must retain the above copyright 776163fc9cSnatano * notice, this list of conditions and the following disclaimer. 786163fc9cSnatano * 2. Redistributions in binary form must reproduce the above copyright 796163fc9cSnatano * notice, this list of conditions and the following disclaimer in the 806163fc9cSnatano * documentation and/or other materials provided with the distribution. 816163fc9cSnatano * 3. Neither the name of the University nor the names of its contributors 826163fc9cSnatano * may be used to endorse or promote products derived from this software 836163fc9cSnatano * without specific prior written permission. 846163fc9cSnatano * 856163fc9cSnatano * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 866163fc9cSnatano * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 876163fc9cSnatano * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 886163fc9cSnatano * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 896163fc9cSnatano * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 906163fc9cSnatano * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 916163fc9cSnatano * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 926163fc9cSnatano * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 936163fc9cSnatano * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 946163fc9cSnatano * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 956163fc9cSnatano * SUCH DAMAGE. 966163fc9cSnatano * 976163fc9cSnatano */ 986163fc9cSnatano 996163fc9cSnatano #include <sys/queue.h> 1006163fc9cSnatano 1016163fc9cSnatano #include <string.h> 1026163fc9cSnatano #include <ctype.h> 1036163fc9cSnatano #include <inttypes.h> 104299d8950Snatano #include <limits.h> 1056163fc9cSnatano 1066163fc9cSnatano #include "makefs.h" 1076163fc9cSnatano #include "cd9660.h" 1086163fc9cSnatano #include "cd9660/iso9660_rrip.h" 1096163fc9cSnatano 1106163fc9cSnatano /* 1116163fc9cSnatano * Global variables 1126163fc9cSnatano */ 1136163fc9cSnatano 1146163fc9cSnatano static void cd9660_finalize_PVD(iso9660_disk *); 1156163fc9cSnatano static cd9660node *cd9660_allocate_cd9660node(void); 1166163fc9cSnatano static void cd9660_set_defaults(iso9660_disk *); 1176163fc9cSnatano static int cd9660_arguments_set_string(const char *, const char *, size_t, 1186163fc9cSnatano char, char *); 1196163fc9cSnatano static void cd9660_populate_iso_dir_record( 1206163fc9cSnatano struct _iso_directory_record_cd9660 *, u_char, u_char, u_char, 1216163fc9cSnatano const char *); 1226163fc9cSnatano static void cd9660_setup_root_node(iso9660_disk *); 1236163fc9cSnatano static int cd9660_setup_volume_descriptors(iso9660_disk *); 1246163fc9cSnatano #if 0 1256163fc9cSnatano static int cd9660_fill_extended_attribute_record(cd9660node *); 1266163fc9cSnatano #endif 1276163fc9cSnatano static void cd9660_sort_nodes(cd9660node *); 1286163fc9cSnatano static int cd9660_translate_node_common(iso9660_disk *, cd9660node *); 1296163fc9cSnatano static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *); 1306163fc9cSnatano static int cd9660_compare_filename(const char *, const char *); 1316163fc9cSnatano static void cd9660_sorted_child_insert(cd9660node *, cd9660node *); 1326163fc9cSnatano static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int); 1336163fc9cSnatano static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int, 1346163fc9cSnatano int); 1356163fc9cSnatano static void cd9660_copy_filenames(iso9660_disk *, cd9660node *); 1366163fc9cSnatano static void cd9660_sorting_nodes(cd9660node *); 1376163fc9cSnatano static int cd9660_count_collisions(cd9660node *); 1386163fc9cSnatano static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *); 1396163fc9cSnatano static int cd9660_add_dot_records(iso9660_disk *, cd9660node *); 1406163fc9cSnatano 1416163fc9cSnatano static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int, 1426163fc9cSnatano int *, int *); 1436163fc9cSnatano static void cd9660_free_structure(cd9660node *); 1446163fc9cSnatano static int cd9660_generate_path_table(iso9660_disk *); 1456163fc9cSnatano static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *, 146d95291fdStedu size_t, int); 1476163fc9cSnatano static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *, 148d95291fdStedu size_t, int); 149d95291fdStedu static int cd9660_convert_filename(iso9660_disk *, const char *, char *, size_t, int); 1506163fc9cSnatano static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *); 1516163fc9cSnatano static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t); 1526163fc9cSnatano #if 0 1536163fc9cSnatano static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int); 1546163fc9cSnatano #endif 1556163fc9cSnatano static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *, 1566163fc9cSnatano cd9660node *, int, int); 1576163fc9cSnatano static cd9660node *cd9660_create_file(iso9660_disk *, const char *, 1586163fc9cSnatano cd9660node *, cd9660node *); 1596163fc9cSnatano static cd9660node *cd9660_create_directory(iso9660_disk *, const char *, 1606163fc9cSnatano cd9660node *, cd9660node *); 1616163fc9cSnatano static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char, 1626163fc9cSnatano cd9660node *); 1636163fc9cSnatano static int cd9660_add_generic_bootimage(iso9660_disk *, const char *); 1646163fc9cSnatano 1656163fc9cSnatano 1666163fc9cSnatano /* 1678e544e80Sjsg * Allocate and initialize a cd9660node 1686163fc9cSnatano * @returns struct cd9660node * Pointer to new node, or NULL on error 1696163fc9cSnatano */ 1706163fc9cSnatano static cd9660node * 1716163fc9cSnatano cd9660_allocate_cd9660node(void) 1726163fc9cSnatano { 1736163fc9cSnatano cd9660node *temp = ecalloc(1, sizeof(*temp)); 1746163fc9cSnatano TAILQ_INIT(&temp->cn_children); 1756163fc9cSnatano temp->parent = temp->dot_record = temp->dot_dot_record = NULL; 1766163fc9cSnatano temp->ptnext = temp->ptprev = temp->ptlast = NULL; 1776163fc9cSnatano temp->node = NULL; 1786163fc9cSnatano temp->isoDirRecord = NULL; 1796163fc9cSnatano temp->isoExtAttributes = NULL; 1806163fc9cSnatano temp->rr_real_parent = temp->rr_relocated = NULL; 1816163fc9cSnatano temp->su_tail_data = NULL; 1826163fc9cSnatano return temp; 1836163fc9cSnatano } 1846163fc9cSnatano 1856163fc9cSnatano int cd9660_defaults_set = 0; 1866163fc9cSnatano 1876163fc9cSnatano /** 1886163fc9cSnatano * Set default values for cd9660 extension to makefs 1896163fc9cSnatano */ 1906163fc9cSnatano static void 1916163fc9cSnatano cd9660_set_defaults(iso9660_disk *diskStructure) 1926163fc9cSnatano { 1936163fc9cSnatano /*Fix the sector size for now, though the spec allows for other sizes*/ 1946163fc9cSnatano diskStructure->sectorSize = 2048; 1956163fc9cSnatano 1966163fc9cSnatano /* Set up defaults in our own structure */ 1976163fc9cSnatano diskStructure->isoLevel = 2; 1986163fc9cSnatano 1996163fc9cSnatano diskStructure->rock_ridge_enabled = 0; 2006163fc9cSnatano diskStructure->rock_ridge_renamed_dir_name = 0; 2016163fc9cSnatano diskStructure->rock_ridge_move_count = 0; 2026163fc9cSnatano diskStructure->rr_moved_dir = 0; 2036163fc9cSnatano 2046163fc9cSnatano diskStructure->include_padding_areas = 1; 2056163fc9cSnatano 2066163fc9cSnatano /* Spec breaking functionality */ 2076163fc9cSnatano diskStructure->allow_deep_trees = 2086163fc9cSnatano diskStructure->allow_multidot = 2096163fc9cSnatano diskStructure->omit_trailing_period = 0; 2106163fc9cSnatano 2116163fc9cSnatano /* Make sure the PVD is clear */ 2126163fc9cSnatano memset(&diskStructure->primaryDescriptor, 0, 2048); 2136163fc9cSnatano 2146163fc9cSnatano memset(diskStructure->primaryDescriptor.publisher_id, 0x20,128); 2156163fc9cSnatano memset(diskStructure->primaryDescriptor.preparer_id, 0x20,128); 2166163fc9cSnatano memset(diskStructure->primaryDescriptor.application_id, 0x20,128); 2176163fc9cSnatano memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37); 2186163fc9cSnatano memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37); 2196163fc9cSnatano memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37); 2206163fc9cSnatano 221*493aa139Smillert strlcpy(diskStructure->primaryDescriptor.system_id,"OpenBSD", sizeof(diskStructure->primaryDescriptor.system_id)); 2226163fc9cSnatano 2236163fc9cSnatano cd9660_defaults_set = 1; 2246163fc9cSnatano 2256163fc9cSnatano /* Boot support: Initially disabled */ 2266163fc9cSnatano diskStructure->has_generic_bootimage = 0; 2276163fc9cSnatano diskStructure->generic_bootimage = NULL; 2286163fc9cSnatano 2296163fc9cSnatano /*memset(diskStructure->boot_descriptor, 0, 2048);*/ 2306163fc9cSnatano 2316163fc9cSnatano diskStructure->is_bootable = 0; 2326163fc9cSnatano TAILQ_INIT(&diskStructure->boot_images); 2336163fc9cSnatano LIST_INIT(&diskStructure->boot_entries); 2346163fc9cSnatano } 2356163fc9cSnatano 2366163fc9cSnatano void 2376163fc9cSnatano cd9660_prep_opts(fsinfo_t *fsopts) 2386163fc9cSnatano { 2396163fc9cSnatano iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure)); 2406163fc9cSnatano 24140854474Snatano #define OPT_STR(name) \ 24240854474Snatano { name, NULL, OPT_STRBUF, 0, 0 } 2436163fc9cSnatano 24440854474Snatano #define OPT_NUM(name, field, min, max) \ 24513b03f79Snatano { name, &diskStructure->field, \ 2466163fc9cSnatano sizeof(diskStructure->field) == 8 ? OPT_INT64 : \ 2476163fc9cSnatano (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \ 2486163fc9cSnatano (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \ 24940854474Snatano min, max } 2506163fc9cSnatano 25140854474Snatano #define OPT_BOOL(name, field) \ 252e1a25d74Snatano { name, &diskStructure->field, OPT_BOOL } 2536163fc9cSnatano 2546163fc9cSnatano const option_t cd9660_options[] = { 25540854474Snatano OPT_BOOL("allow-deep-trees", allow_deep_trees), 25640854474Snatano OPT_BOOL("allow-multidot", allow_multidot), 25740854474Snatano OPT_STR("applicationid"), 25840854474Snatano OPT_STR("boot-load-segment"), 25940854474Snatano OPT_STR("bootimage"), 26040854474Snatano OPT_STR("generic-bootimage"), 26140854474Snatano OPT_STR("hard-disk-boot"), 26240854474Snatano OPT_NUM("isolevel", isoLevel, 1, 3), 26340854474Snatano OPT_STR("label"), 26440854474Snatano OPT_STR("no-boot"), 26540854474Snatano OPT_STR("no-emul-boot"), 26640854474Snatano OPT_BOOL("no-trailing-padding", include_padding_areas), 26740854474Snatano OPT_BOOL("omit-trailing-period", omit_trailing_period), 26840854474Snatano OPT_STR("preparer"), 26940854474Snatano OPT_STR("publisher"), 27040854474Snatano OPT_BOOL("rockridge", rock_ridge_enabled), 27140854474Snatano OPT_STR("volumeid"), 2726163fc9cSnatano { .name = NULL } 2736163fc9cSnatano }; 2746163fc9cSnatano 2756163fc9cSnatano fsopts->fs_specific = diskStructure; 2766163fc9cSnatano fsopts->fs_options = copy_opts(cd9660_options); 2776163fc9cSnatano 2786163fc9cSnatano cd9660_set_defaults(diskStructure); 2796163fc9cSnatano } 2806163fc9cSnatano 2816163fc9cSnatano void 2826163fc9cSnatano cd9660_cleanup_opts(fsinfo_t *fsopts) 2836163fc9cSnatano { 2846163fc9cSnatano free(fsopts->fs_specific); 2856163fc9cSnatano free(fsopts->fs_options); 2866163fc9cSnatano } 2876163fc9cSnatano 2886163fc9cSnatano static int 2896163fc9cSnatano cd9660_arguments_set_string(const char *val, const char *fieldtitle, 2906163fc9cSnatano size_t length, char testmode, char * dest) 2916163fc9cSnatano { 2926163fc9cSnatano size_t len; 2936163fc9cSnatano int test; 2946163fc9cSnatano 2956163fc9cSnatano if (val == NULL) 29640854474Snatano warnx("error: '%s' requires a string argument", fieldtitle); 2976163fc9cSnatano else if ((len = strlen(val)) <= length) { 2986163fc9cSnatano if (testmode == 'd') 2996163fc9cSnatano test = cd9660_valid_d_chars(val); 3006163fc9cSnatano else 3016163fc9cSnatano test = cd9660_valid_a_chars(val); 3026163fc9cSnatano if (test) { 3036163fc9cSnatano memcpy(dest, val, len); 3046163fc9cSnatano if (test == 2) 3056163fc9cSnatano cd9660_uppercase_characters(dest, len); 3066163fc9cSnatano return 1; 3076163fc9cSnatano } else 30840854474Snatano warnx("error: '%s' must be composed of %c-characters", 30940854474Snatano fieldtitle, testmode); 3106163fc9cSnatano } else 31140854474Snatano warnx("error: '%s' must be at most 32 characters long", 3126163fc9cSnatano fieldtitle); 3136163fc9cSnatano return 0; 3146163fc9cSnatano } 3156163fc9cSnatano 3166163fc9cSnatano /* 3176163fc9cSnatano * Command-line parsing function 3186163fc9cSnatano */ 3196163fc9cSnatano 3206163fc9cSnatano int 3216163fc9cSnatano cd9660_parse_opts(const char *option, fsinfo_t *fsopts) 3226163fc9cSnatano { 3236163fc9cSnatano int rv, i; 3246163fc9cSnatano iso9660_disk *diskStructure = fsopts->fs_specific; 3256163fc9cSnatano option_t *cd9660_options = fsopts->fs_options; 3266163fc9cSnatano char buf[1024]; 32740854474Snatano const char *name; 3286163fc9cSnatano 3296163fc9cSnatano assert(option != NULL); 3306163fc9cSnatano 3316163fc9cSnatano i = set_option(cd9660_options, option, buf, sizeof(buf)); 3326163fc9cSnatano if (i == -1) 3336163fc9cSnatano return 0; 3346163fc9cSnatano 3356163fc9cSnatano if (cd9660_options[i].name == NULL) 3366163fc9cSnatano abort(); 3376163fc9cSnatano 3386163fc9cSnatano 3396163fc9cSnatano name = cd9660_options[i].name; 34013b03f79Snatano 34113b03f79Snatano if (strcmp(name, "applicationid") == 0) { 34240854474Snatano rv = cd9660_arguments_set_string(buf, name, 128, 'a', 3436163fc9cSnatano diskStructure->primaryDescriptor.application_id); 34413b03f79Snatano } else if (strcmp(name, "boot-load-segment") == 0) { 34513b03f79Snatano if (buf[0] == '\0') { 34613b03f79Snatano warnx("Option `%s' doesn't contain a value", 34713b03f79Snatano name); 34813b03f79Snatano rv = 0; 34913b03f79Snatano } else { 35013b03f79Snatano cd9660_eltorito_add_boot_option(diskStructure, 35113b03f79Snatano name, buf); 35213b03f79Snatano rv = 1; 35313b03f79Snatano } 35413b03f79Snatano } else if (strcmp(name, "bootimage") == 0) { 3556163fc9cSnatano if (buf[0] == '\0') { 3566163fc9cSnatano warnx("The Boot Image parameter requires a valid boot" 3576163fc9cSnatano " information string"); 3586163fc9cSnatano rv = 0; 3596163fc9cSnatano } else 3606163fc9cSnatano rv = cd9660_add_boot_disk(diskStructure, buf); 36113b03f79Snatano } else if (strcmp(name, "generic-bootimage") == 0) { 36213b03f79Snatano if (buf[0] == '\0') { 36313b03f79Snatano warnx("The Generic Boot Image parameter requires a" 36413b03f79Snatano " valid boot information string"); 36513b03f79Snatano rv = 0; 36613b03f79Snatano } else 36713b03f79Snatano rv = cd9660_add_generic_bootimage(diskStructure, buf); 36813b03f79Snatano } else if (strcmp(name, "label") == 0) { 36940854474Snatano rv = cd9660_arguments_set_string(buf, name, 32, 'd', 37013b03f79Snatano diskStructure->primaryDescriptor.volume_id); 37113b03f79Snatano } else if (strcmp(name, "preparer") == 0) { 37240854474Snatano rv = cd9660_arguments_set_string(buf, name, 128, 'a', 37313b03f79Snatano diskStructure->primaryDescriptor.preparer_id); 37413b03f79Snatano } else if (strcmp(name, "publisher") == 0) { 37540854474Snatano rv = cd9660_arguments_set_string(buf, name, 128, 'a', 37613b03f79Snatano diskStructure->primaryDescriptor.publisher_id); 37713b03f79Snatano } else if (strcmp(name, "volumeid") == 0) { 37840854474Snatano rv = cd9660_arguments_set_string(buf, name, 128, 'a', 37913b03f79Snatano diskStructure->primaryDescriptor.volume_set_id); 38013b03f79Snatano } else if (strcmp(name, "hard-disk-boot") == 0 || 3816163fc9cSnatano strcmp(name, "no-boot") == 0 || 38213b03f79Snatano strcmp(name, "no-emul-boot") == 0) { 3836163fc9cSnatano /* RRIP */ 3846163fc9cSnatano cd9660_eltorito_add_boot_option(diskStructure, name, 0); 3856163fc9cSnatano rv = 1; 3866163fc9cSnatano } else 3876163fc9cSnatano rv = 1; 38813b03f79Snatano 3896163fc9cSnatano return rv; 3906163fc9cSnatano } 3916163fc9cSnatano 3926163fc9cSnatano /* 3936163fc9cSnatano * Main function for cd9660_makefs 3946163fc9cSnatano * Builds the ISO image file 3956163fc9cSnatano * @param const char *image The image filename to create 3966163fc9cSnatano * @param const char *dir The directory that is being read 3976163fc9cSnatano * @param struct fsnode *root The root node of the filesystem tree 3986163fc9cSnatano * @param struct fsinfo_t *fsopts Any options 3996163fc9cSnatano */ 4006163fc9cSnatano void 4016163fc9cSnatano cd9660_makefs(const char *image, const char *dir, fsnode *root, 4026163fc9cSnatano fsinfo_t *fsopts) 4036163fc9cSnatano { 4046163fc9cSnatano int64_t startoffset; 405c8f48d9bSyasuoka int ret, numDirectories; 4066163fc9cSnatano uint64_t pathTableSectors; 4076163fc9cSnatano int64_t firstAvailableSector; 4086163fc9cSnatano int64_t totalSpace; 4096163fc9cSnatano int error; 4106163fc9cSnatano cd9660node *real_root; 4116163fc9cSnatano iso9660_disk *diskStructure = fsopts->fs_specific; 4126163fc9cSnatano 4136163fc9cSnatano if (diskStructure->isoLevel < 2 && 4146163fc9cSnatano diskStructure->allow_multidot) 415944eabd5Snatano errx(1, "allow-multidot requires iso level of 2"); 4166163fc9cSnatano 4176163fc9cSnatano assert(image != NULL); 4186163fc9cSnatano assert(dir != NULL); 4196163fc9cSnatano assert(root != NULL); 4206163fc9cSnatano 4216163fc9cSnatano /* Set up some constants. Later, these will be defined with options */ 4226163fc9cSnatano 4236163fc9cSnatano /* Counter needed for path tables */ 4246163fc9cSnatano numDirectories = 0; 4256163fc9cSnatano 4266163fc9cSnatano /* Convert tree to our own format */ 4276163fc9cSnatano /* Actually, we now need to add the REAL root node, at level 0 */ 4286163fc9cSnatano 4296163fc9cSnatano real_root = cd9660_allocate_cd9660node(); 4306163fc9cSnatano real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord)); 4316163fc9cSnatano /* Leave filename blank for root */ 4326163fc9cSnatano memset(real_root->isoDirRecord->name, 0, 4336163fc9cSnatano ISO_FILENAME_MAXLENGTH_WITH_PADDING); 4346163fc9cSnatano 4356163fc9cSnatano real_root->level = 0; 4366163fc9cSnatano diskStructure->rootNode = real_root; 4376163fc9cSnatano real_root->type = CD9660_TYPE_DIR; 4386163fc9cSnatano error = 0; 4396163fc9cSnatano real_root->node = root; 4406163fc9cSnatano cd9660_convert_structure(diskStructure, root, real_root, 1, 4416163fc9cSnatano &numDirectories, &error); 4426163fc9cSnatano 4436163fc9cSnatano if (TAILQ_EMPTY(&real_root->cn_children)) { 444944eabd5Snatano errx(1, "%s: converted directory is empty. " 4456163fc9cSnatano "Tree conversion failed", __func__); 4466163fc9cSnatano } else if (error != 0) { 447944eabd5Snatano errx(1, "%s: tree conversion failed", __func__); 4486163fc9cSnatano } 4496163fc9cSnatano 4506163fc9cSnatano /* Add the dot and dot dot records */ 4516163fc9cSnatano cd9660_add_dot_records(diskStructure, real_root); 4526163fc9cSnatano 4536163fc9cSnatano cd9660_setup_root_node(diskStructure); 4546163fc9cSnatano 4556163fc9cSnatano /* Rock ridge / SUSP init pass */ 4566163fc9cSnatano if (diskStructure->rock_ridge_enabled) { 4576163fc9cSnatano cd9660_susp_initialize(diskStructure, diskStructure->rootNode, 4586163fc9cSnatano diskStructure->rootNode, NULL); 4596163fc9cSnatano } 4606163fc9cSnatano 4616163fc9cSnatano /* Build path table structure */ 4626163fc9cSnatano diskStructure->pathTableLength = cd9660_generate_path_table( 4636163fc9cSnatano diskStructure); 4646163fc9cSnatano 4656163fc9cSnatano pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize, 4666163fc9cSnatano diskStructure->pathTableLength); 4676163fc9cSnatano 4686163fc9cSnatano firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure); 4696163fc9cSnatano if (diskStructure->is_bootable) { 4706163fc9cSnatano firstAvailableSector = cd9660_setup_boot(diskStructure, 4716163fc9cSnatano firstAvailableSector); 4726163fc9cSnatano if (firstAvailableSector < 0) 473944eabd5Snatano errx(1, "setup_boot failed"); 4746163fc9cSnatano } 4756163fc9cSnatano /* LE first, then BE */ 4766163fc9cSnatano diskStructure->primaryLittleEndianTableSector = firstAvailableSector; 4776163fc9cSnatano diskStructure->primaryBigEndianTableSector = 4786163fc9cSnatano diskStructure->primaryLittleEndianTableSector + pathTableSectors; 4796163fc9cSnatano 4806163fc9cSnatano /* Set the secondary ones to -1, not going to use them for now */ 4816163fc9cSnatano diskStructure->secondaryBigEndianTableSector = -1; 4826163fc9cSnatano diskStructure->secondaryLittleEndianTableSector = -1; 4836163fc9cSnatano 4846163fc9cSnatano diskStructure->dataFirstSector = 4856163fc9cSnatano diskStructure->primaryBigEndianTableSector + pathTableSectors; 4866163fc9cSnatano 4876163fc9cSnatano startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector; 4886163fc9cSnatano 4896163fc9cSnatano totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset); 4906163fc9cSnatano 4916163fc9cSnatano diskStructure->totalSectors = diskStructure->dataFirstSector + 4926163fc9cSnatano CD9660_BLOCKS(diskStructure->sectorSize, totalSpace); 4936163fc9cSnatano 4946163fc9cSnatano /* Disabled until pass 1 is done */ 4956163fc9cSnatano if (diskStructure->rock_ridge_enabled) { 4966163fc9cSnatano diskStructure->susp_continuation_area_start_sector = 4976163fc9cSnatano diskStructure->totalSectors; 4986163fc9cSnatano diskStructure->totalSectors += 4996163fc9cSnatano CD9660_BLOCKS(diskStructure->sectorSize, 5006163fc9cSnatano diskStructure->susp_continuation_area_size); 5016163fc9cSnatano cd9660_susp_finalize(diskStructure, diskStructure->rootNode); 5026163fc9cSnatano } 5036163fc9cSnatano 5046163fc9cSnatano 5056163fc9cSnatano cd9660_finalize_PVD(diskStructure); 5066163fc9cSnatano 5076163fc9cSnatano /* Add padding sectors, just for testing purposes right now */ 5086163fc9cSnatano /* diskStructure->totalSectors+=150; */ 5096163fc9cSnatano 5106163fc9cSnatano /* 5116163fc9cSnatano * Add padding sectors at the end 5126163fc9cSnatano * TODO: Clean this up and separate padding 5136163fc9cSnatano */ 5146163fc9cSnatano if (diskStructure->include_padding_areas) 5156163fc9cSnatano diskStructure->totalSectors += 150; 5166163fc9cSnatano 517c8f48d9bSyasuoka ret = cd9660_write_image(diskStructure, image); 5186163fc9cSnatano 5196163fc9cSnatano /* Clean up data structures */ 5206163fc9cSnatano cd9660_free_structure(real_root); 521c8f48d9bSyasuoka 522c8f48d9bSyasuoka if (ret == 0) /* cd9660_write_image() failed */ 523c8f48d9bSyasuoka exit(1); 5246163fc9cSnatano } 5256163fc9cSnatano 5266163fc9cSnatano /* Generic function pointer - implement later */ 5276163fc9cSnatano typedef int (*cd9660node_func)(cd9660node *); 5286163fc9cSnatano 5296163fc9cSnatano static void 5306163fc9cSnatano cd9660_finalize_PVD(iso9660_disk *diskStructure) 5316163fc9cSnatano { 532bc67c994Snatano time_t tstamp = Tflag ? stampts : time(NULL); 5336163fc9cSnatano 5346163fc9cSnatano /* root should be a fixed size of 34 bytes since it has no name */ 5356163fc9cSnatano memcpy(diskStructure->primaryDescriptor.root_directory_record, 5366163fc9cSnatano diskStructure->rootNode->dot_record->isoDirRecord, 34); 5376163fc9cSnatano 5386163fc9cSnatano /* In RRIP, this might be longer than 34 */ 5396163fc9cSnatano diskStructure->primaryDescriptor.root_directory_record[0] = 34; 5406163fc9cSnatano 5416163fc9cSnatano /* Set up all the important numbers in the PVD */ 5426163fc9cSnatano cd9660_bothendian_dword(diskStructure->totalSectors, 5436163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.volume_space_size); 5446163fc9cSnatano cd9660_bothendian_word(1, 5456163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.volume_set_size); 5466163fc9cSnatano cd9660_bothendian_word(1, 5476163fc9cSnatano (unsigned char *) 5486163fc9cSnatano diskStructure->primaryDescriptor.volume_sequence_number); 5496163fc9cSnatano cd9660_bothendian_word(diskStructure->sectorSize, 5506163fc9cSnatano (unsigned char *) 5516163fc9cSnatano diskStructure->primaryDescriptor.logical_block_size); 5526163fc9cSnatano cd9660_bothendian_dword(diskStructure->pathTableLength, 5536163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.path_table_size); 5546163fc9cSnatano 5556163fc9cSnatano cd9660_731(diskStructure->primaryLittleEndianTableSector, 5566163fc9cSnatano (u_char *)diskStructure->primaryDescriptor.type_l_path_table); 5576163fc9cSnatano cd9660_732(diskStructure->primaryBigEndianTableSector, 5586163fc9cSnatano (u_char *)diskStructure->primaryDescriptor.type_m_path_table); 5596163fc9cSnatano 5606163fc9cSnatano diskStructure->primaryDescriptor.file_structure_version[0] = 1; 5616163fc9cSnatano 5626163fc9cSnatano /* Pad all strings with spaces instead of nulls */ 5636163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32); 5646163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32); 5656163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id, 5666163fc9cSnatano 128); 5676163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id, 5686163fc9cSnatano 128); 5696163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id, 5706163fc9cSnatano 128); 5716163fc9cSnatano cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id, 5726163fc9cSnatano 128); 5736163fc9cSnatano cd9660_pad_string_spaces( 5746163fc9cSnatano diskStructure->primaryDescriptor.copyright_file_id, 37); 5756163fc9cSnatano cd9660_pad_string_spaces( 5766163fc9cSnatano diskStructure->primaryDescriptor.abstract_file_id, 37); 5776163fc9cSnatano cd9660_pad_string_spaces( 5786163fc9cSnatano diskStructure->primaryDescriptor.bibliographic_file_id, 37); 5796163fc9cSnatano 5806163fc9cSnatano /* Setup dates */ 5816163fc9cSnatano cd9660_time_8426( 5826163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.creation_date, 5836163fc9cSnatano tstamp); 5846163fc9cSnatano cd9660_time_8426( 5856163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.modification_date, 5866163fc9cSnatano tstamp); 5876163fc9cSnatano 5886163fc9cSnatano #if 0 5896163fc9cSnatano cd9660_set_date(diskStructure->primaryDescriptor.expiration_date, 5906163fc9cSnatano tstamp); 5916163fc9cSnatano #endif 5926163fc9cSnatano memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16); 5936163fc9cSnatano diskStructure->primaryDescriptor.expiration_date[16] = 0; 5946163fc9cSnatano 5956163fc9cSnatano cd9660_time_8426( 5966163fc9cSnatano (unsigned char *)diskStructure->primaryDescriptor.effective_date, 5976163fc9cSnatano tstamp); 5986163fc9cSnatano } 5996163fc9cSnatano 6006163fc9cSnatano static void 6016163fc9cSnatano cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record, 6026163fc9cSnatano u_char ext_attr_length, u_char flags, 6036163fc9cSnatano u_char name_len, const char * name) 6046163fc9cSnatano { 6056163fc9cSnatano record->ext_attr_length[0] = ext_attr_length; 6066163fc9cSnatano record->flags[0] = ISO_FLAG_CLEAR | flags; 6076163fc9cSnatano record->file_unit_size[0] = 0; 6086163fc9cSnatano record->interleave[0] = 0; 6096163fc9cSnatano cd9660_bothendian_word(1, record->volume_sequence_number); 6106163fc9cSnatano record->name_len[0] = name_len; 6116163fc9cSnatano memset(record->name, '\0', sizeof (record->name)); 6126163fc9cSnatano memcpy(record->name, name, name_len); 6136163fc9cSnatano record->length[0] = 33 + name_len; 6146163fc9cSnatano 6156163fc9cSnatano /* Todo : better rounding */ 6166163fc9cSnatano record->length[0] += (record->length[0] & 1) ? 1 : 0; 6176163fc9cSnatano } 6186163fc9cSnatano 6196163fc9cSnatano static void 6206163fc9cSnatano cd9660_setup_root_node(iso9660_disk *diskStructure) 6216163fc9cSnatano { 6226163fc9cSnatano cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord, 6236163fc9cSnatano 0, ISO_FLAG_DIRECTORY, 1, "\0"); 6246163fc9cSnatano 6256163fc9cSnatano } 6266163fc9cSnatano 6276163fc9cSnatano /*********** SUPPORT FUNCTIONS ***********/ 6286163fc9cSnatano static int 6296163fc9cSnatano cd9660_setup_volume_descriptors(iso9660_disk *diskStructure) 6306163fc9cSnatano { 6316163fc9cSnatano /* Boot volume descriptor should come second */ 6326163fc9cSnatano int sector = 16; 6336163fc9cSnatano /* For now, a fixed 2 : PVD and terminator */ 6346163fc9cSnatano volume_descriptor *temp, *t; 6356163fc9cSnatano 6366163fc9cSnatano /* Set up the PVD */ 6376163fc9cSnatano temp = emalloc(sizeof(*temp)); 6386163fc9cSnatano temp->volumeDescriptorData = 6396163fc9cSnatano (unsigned char *)&diskStructure->primaryDescriptor; 6406163fc9cSnatano temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD; 6416163fc9cSnatano temp->volumeDescriptorData[6] = 1; 6426163fc9cSnatano temp->sector = sector; 6436163fc9cSnatano memcpy(temp->volumeDescriptorData + 1, 6446163fc9cSnatano ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 6456163fc9cSnatano diskStructure->firstVolumeDescriptor = temp; 6466163fc9cSnatano 6476163fc9cSnatano sector++; 6486163fc9cSnatano /* Set up boot support if enabled. BVD must reside in sector 17 */ 6496163fc9cSnatano if (diskStructure->is_bootable) { 6506163fc9cSnatano t = emalloc(sizeof(*t)); 6516163fc9cSnatano t->volumeDescriptorData = ecalloc(1, 2048); 6526163fc9cSnatano temp->next = t; 6536163fc9cSnatano temp = t; 6546163fc9cSnatano t->sector = 17; 6556163fc9cSnatano cd9660_setup_boot_volume_descriptor(diskStructure, t); 6566163fc9cSnatano sector++; 6576163fc9cSnatano } 6586163fc9cSnatano 6596163fc9cSnatano /* Set up the terminator */ 6606163fc9cSnatano t = emalloc(sizeof(*t)); 6616163fc9cSnatano t->volumeDescriptorData = ecalloc(1, 2048); 6626163fc9cSnatano temp->next = t; 6636163fc9cSnatano t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR; 6646163fc9cSnatano t->next = 0; 6656163fc9cSnatano t->volumeDescriptorData[6] = 1; 6666163fc9cSnatano t->sector = sector; 6676163fc9cSnatano memcpy(t->volumeDescriptorData + 1, 6686163fc9cSnatano ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5); 6696163fc9cSnatano 6706163fc9cSnatano sector++; 6716163fc9cSnatano return sector; 6726163fc9cSnatano } 6736163fc9cSnatano 6746163fc9cSnatano #if 0 6756163fc9cSnatano /* 6766163fc9cSnatano * Populate EAR at some point. Not required, but is used by NetBSD's 6776163fc9cSnatano * cd9660 support 6786163fc9cSnatano */ 6796163fc9cSnatano static int 6806163fc9cSnatano cd9660_fill_extended_attribute_record(cd9660node *node) 6816163fc9cSnatano { 6826163fc9cSnatano node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes)); 6836163fc9cSnatano return 1; 6846163fc9cSnatano } 6856163fc9cSnatano #endif 6866163fc9cSnatano 6876163fc9cSnatano static int 6886163fc9cSnatano cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode) 6896163fc9cSnatano { 690bc67c994Snatano time_t tstamp = Tflag ? stampts : time(NULL); 6916163fc9cSnatano u_char flag; 6926163fc9cSnatano char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING]; 6936163fc9cSnatano 6946163fc9cSnatano /* Now populate the isoDirRecord structure */ 6956163fc9cSnatano memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); 6966163fc9cSnatano 6976163fc9cSnatano (void)cd9660_convert_filename(diskStructure, newnode->node->name, 698d95291fdStedu temp, sizeof temp, !(S_ISDIR(newnode->node->type))); 6996163fc9cSnatano 7006163fc9cSnatano flag = ISO_FLAG_CLEAR; 7016163fc9cSnatano if (S_ISDIR(newnode->node->type)) 7026163fc9cSnatano flag |= ISO_FLAG_DIRECTORY; 7036163fc9cSnatano 7046163fc9cSnatano cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0, 7056163fc9cSnatano flag, strlen(temp), temp); 7066163fc9cSnatano 7076163fc9cSnatano /* Set the various dates */ 7086163fc9cSnatano 7096163fc9cSnatano /* If we want to use the current date and time */ 7106163fc9cSnatano 7116163fc9cSnatano cd9660_time_915(newnode->isoDirRecord->date, tstamp); 7126163fc9cSnatano 7136163fc9cSnatano cd9660_bothendian_dword(newnode->fileDataLength, 7146163fc9cSnatano newnode->isoDirRecord->size); 7156163fc9cSnatano /* If the file is a link, we want to set the size to 0 */ 7166163fc9cSnatano if (S_ISLNK(newnode->node->type)) 7176163fc9cSnatano newnode->fileDataLength = 0; 7186163fc9cSnatano 7196163fc9cSnatano return 1; 7206163fc9cSnatano } 7216163fc9cSnatano 7226163fc9cSnatano /* 7236163fc9cSnatano * Translate fsnode to cd9660node 7246163fc9cSnatano * Translate filenames and other metadata, including dates, sizes, 7256163fc9cSnatano * permissions, etc 7266163fc9cSnatano * @param struct fsnode * The node generated by makefs 7276163fc9cSnatano * @param struct cd9660node * The intermediate node to be written to 7286163fc9cSnatano * @returns int 0 on failure, 1 on success 7296163fc9cSnatano */ 7306163fc9cSnatano static int 7316163fc9cSnatano cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node, 7326163fc9cSnatano cd9660node *newnode) 7336163fc9cSnatano { 73477bbe232Snatano if (node == NULL) 7356163fc9cSnatano return 0; 73677bbe232Snatano 7376163fc9cSnatano newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord)); 7386163fc9cSnatano /* Set the node pointer */ 7396163fc9cSnatano newnode->node = node; 7406163fc9cSnatano 7416163fc9cSnatano /* Set the size */ 7426163fc9cSnatano if (!(S_ISDIR(node->type))) 7436163fc9cSnatano newnode->fileDataLength = node->inode->st.st_size; 7446163fc9cSnatano 7456163fc9cSnatano if (cd9660_translate_node_common(diskStructure, newnode) == 0) 7466163fc9cSnatano return 0; 7476163fc9cSnatano 7486163fc9cSnatano /* Finally, overwrite some of the values that are set by default */ 7496163fc9cSnatano cd9660_time_915(newnode->isoDirRecord->date, 750bc67c994Snatano Tflag ? stampts : node->inode->st.st_mtime); 7516163fc9cSnatano 7526163fc9cSnatano return 1; 7536163fc9cSnatano } 7546163fc9cSnatano 7556163fc9cSnatano /* 7566163fc9cSnatano * Compares two ISO filenames 7576163fc9cSnatano * @param const char * The first file name 7586163fc9cSnatano * @param const char * The second file name 7596163fc9cSnatano * @returns : -1 if first is less than second, 0 if they are the same, 1 if 7606163fc9cSnatano * the second is greater than the first 7616163fc9cSnatano */ 7626163fc9cSnatano static int 7636163fc9cSnatano cd9660_compare_filename(const char *first, const char *second) 7646163fc9cSnatano { 7656163fc9cSnatano /* 7666163fc9cSnatano * This can be made more optimal once it has been tested 7676163fc9cSnatano * (the extra character, for example, is for testing) 7686163fc9cSnatano */ 7696163fc9cSnatano 7706163fc9cSnatano int p1 = 0; 7716163fc9cSnatano int p2 = 0; 7726163fc9cSnatano char c1, c2; 7736163fc9cSnatano /* First, on the filename */ 7746163fc9cSnatano 7756163fc9cSnatano while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1 7766163fc9cSnatano && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) { 7776163fc9cSnatano c1 = first[p1]; 7786163fc9cSnatano c2 = second[p2]; 7796163fc9cSnatano if (c1 == '.' && c2 =='.') 7806163fc9cSnatano break; 7816163fc9cSnatano else if (c1 == '.') { 7826163fc9cSnatano p2++; 7836163fc9cSnatano c1 = ' '; 7846163fc9cSnatano } else if (c2 == '.') { 7856163fc9cSnatano p1++; 7866163fc9cSnatano c2 = ' '; 7876163fc9cSnatano } else { 7886163fc9cSnatano p1++; 7896163fc9cSnatano p2++; 7906163fc9cSnatano } 7916163fc9cSnatano 7926163fc9cSnatano if (c1 < c2) 7936163fc9cSnatano return -1; 7946163fc9cSnatano else if (c1 > c2) { 7956163fc9cSnatano return 1; 7966163fc9cSnatano } 7976163fc9cSnatano } 7986163fc9cSnatano 7996163fc9cSnatano if (first[p1] == '.' && second[p2] == '.') { 8006163fc9cSnatano p1++; 8016163fc9cSnatano p2++; 8026163fc9cSnatano while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1 8036163fc9cSnatano && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) { 8046163fc9cSnatano c1 = first[p1]; 8056163fc9cSnatano c2 = second[p2]; 8066163fc9cSnatano if (c1 == ';' && c2 == ';') 8076163fc9cSnatano break; 8086163fc9cSnatano else if (c1 == ';') { 8096163fc9cSnatano p2++; 8106163fc9cSnatano c1 = ' '; 8116163fc9cSnatano } else if (c2 == ';') { 8126163fc9cSnatano p1++; 8136163fc9cSnatano c2 = ' '; 8146163fc9cSnatano } else { 8156163fc9cSnatano p1++; 8166163fc9cSnatano p2++; 8176163fc9cSnatano } 8186163fc9cSnatano 8196163fc9cSnatano if (c1 < c2) 8206163fc9cSnatano return -1; 8216163fc9cSnatano else if (c1 > c2) 8226163fc9cSnatano return 1; 8236163fc9cSnatano } 8246163fc9cSnatano } 8256163fc9cSnatano return 0; 8266163fc9cSnatano } 8276163fc9cSnatano 8286163fc9cSnatano /* 8296163fc9cSnatano * Insert a node into list with ISO sorting rules 8306163fc9cSnatano * @param cd9660node * The head node of the list 8316163fc9cSnatano * @param cd9660node * The node to be inserted 8326163fc9cSnatano */ 8336163fc9cSnatano static void 8346163fc9cSnatano cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new) 8356163fc9cSnatano { 8366163fc9cSnatano int compare; 8376163fc9cSnatano cd9660node *cn; 8386163fc9cSnatano struct cd9660_children_head *head = &parent->cn_children; 8396163fc9cSnatano 8406163fc9cSnatano /* TODO: Optimize? */ 8416163fc9cSnatano cn_new->parent = parent; 8426163fc9cSnatano 8436163fc9cSnatano /* 8446163fc9cSnatano * first will either be 0, the . or the .. 8456163fc9cSnatano * if . or .., this means no other entry may be written before first 8466163fc9cSnatano * if 0, the new node may be inserted at the head 8476163fc9cSnatano */ 8486163fc9cSnatano 8496163fc9cSnatano TAILQ_FOREACH(cn, head, cn_next_child) { 8506163fc9cSnatano /* 8516163fc9cSnatano * Dont insert a node twice - 8526163fc9cSnatano * that would cause an infinite loop 8536163fc9cSnatano */ 8546163fc9cSnatano if (cn_new == cn) 8556163fc9cSnatano return; 8566163fc9cSnatano 8576163fc9cSnatano compare = cd9660_compare_filename(cn_new->isoDirRecord->name, 8586163fc9cSnatano cn->isoDirRecord->name); 8596163fc9cSnatano 8606163fc9cSnatano if (compare == 0) 8616163fc9cSnatano compare = cd9660_compare_filename(cn_new->node->name, 8626163fc9cSnatano cn->node->name); 8636163fc9cSnatano 8646163fc9cSnatano if (compare < 0) 8656163fc9cSnatano break; 8666163fc9cSnatano } 8676163fc9cSnatano if (cn == NULL) 8686163fc9cSnatano TAILQ_INSERT_TAIL(head, cn_new, cn_next_child); 8696163fc9cSnatano else 8706163fc9cSnatano TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child); 8716163fc9cSnatano } 8726163fc9cSnatano 8736163fc9cSnatano /* 8746163fc9cSnatano * Called After cd9660_sorted_child_insert 8758e544e80Sjsg * handles file collisions by suffixing each filename with ~n 8766163fc9cSnatano * where n represents the files respective place in the ordering 8776163fc9cSnatano */ 8786163fc9cSnatano static int 8796163fc9cSnatano cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding, 8806163fc9cSnatano int past) 8816163fc9cSnatano { 8826163fc9cSnatano cd9660node *iter, *next, *prev; 8836163fc9cSnatano int skip; 8846163fc9cSnatano int delete_chars = 0; 8856163fc9cSnatano int temp_past = past; 8866163fc9cSnatano int temp_skip; 8876163fc9cSnatano int flag = 0; 8886163fc9cSnatano cd9660node *end_of_range; 8896163fc9cSnatano 8906163fc9cSnatano for (iter = TAILQ_FIRST(&colliding->cn_children); 8916163fc9cSnatano iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) { 8926163fc9cSnatano if (strcmp(iter->isoDirRecord->name, 8936163fc9cSnatano next->isoDirRecord->name) != 0) { 8946163fc9cSnatano iter = TAILQ_NEXT(iter, cn_next_child); 8956163fc9cSnatano continue; 8966163fc9cSnatano } 8976163fc9cSnatano flag = 1; 8986163fc9cSnatano temp_skip = skip = cd9660_count_collisions(iter); 8996163fc9cSnatano end_of_range = iter; 9006163fc9cSnatano while (temp_skip > 0) { 9016163fc9cSnatano temp_skip--; 9026163fc9cSnatano end_of_range = TAILQ_NEXT(end_of_range, cn_next_child); 9036163fc9cSnatano } 9046163fc9cSnatano temp_past = past; 9056163fc9cSnatano while (temp_past > 0) { 9066163fc9cSnatano if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL) 9076163fc9cSnatano end_of_range = next; 9086163fc9cSnatano else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL) 9096163fc9cSnatano iter = prev; 9106163fc9cSnatano else 9116163fc9cSnatano delete_chars++; 9126163fc9cSnatano temp_past--; 9136163fc9cSnatano } 9146163fc9cSnatano skip += past; 9156163fc9cSnatano iter = cd9660_rename_filename(diskStructure, iter, skip, 9166163fc9cSnatano delete_chars); 9176163fc9cSnatano } 9186163fc9cSnatano return flag; 9196163fc9cSnatano } 9206163fc9cSnatano 9216163fc9cSnatano 9226163fc9cSnatano static cd9660node * 9236163fc9cSnatano cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num, 9246163fc9cSnatano int delete_chars) 9256163fc9cSnatano { 9266163fc9cSnatano int i = 0; 9276163fc9cSnatano int numbts, dot, semi, digit, digits, temp, powers, multiplier, count; 9286163fc9cSnatano char *naming; 9296163fc9cSnatano int maxlength; 9306163fc9cSnatano char *tmp; 9316163fc9cSnatano 9326163fc9cSnatano /* TODO : A LOT of chanes regarding 8.3 filenames */ 9336163fc9cSnatano if (diskStructure->isoLevel == 1) 9346163fc9cSnatano maxlength = 8; 9356163fc9cSnatano else if (diskStructure->isoLevel == 2) 9366163fc9cSnatano maxlength = 31; 9376163fc9cSnatano else 9386163fc9cSnatano maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION; 9396163fc9cSnatano 9406163fc9cSnatano tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING); 9416163fc9cSnatano 9424e4cca72Snatano while (i < num && iter) { 9436163fc9cSnatano powers = 1; 9446163fc9cSnatano count = 0; 9456163fc9cSnatano digits = 1; 9466163fc9cSnatano multiplier = 1; 9476163fc9cSnatano while (((int)(i / powers) ) >= 10) { 9486163fc9cSnatano digits++; 9496163fc9cSnatano powers = powers * 10; 9506163fc9cSnatano } 9516163fc9cSnatano 9526163fc9cSnatano naming = iter->o_name; 9536163fc9cSnatano 9546163fc9cSnatano /* 9556163fc9cSnatano while ((*naming != '.') && (*naming != ';')) { 9566163fc9cSnatano naming++; 9576163fc9cSnatano count++; 9586163fc9cSnatano } 9596163fc9cSnatano */ 9606163fc9cSnatano 9616163fc9cSnatano dot = -1; 9626163fc9cSnatano semi = -1; 9636163fc9cSnatano while (count < maxlength) { 9646163fc9cSnatano if (*naming == '.') 9656163fc9cSnatano dot = count; 9666163fc9cSnatano else if (*naming == ';') { 9676163fc9cSnatano semi = count; 9686163fc9cSnatano break; 9696163fc9cSnatano } 9706163fc9cSnatano naming++; 9716163fc9cSnatano count++; 9726163fc9cSnatano } 9736163fc9cSnatano 9746163fc9cSnatano if ((count + digits) < maxlength) 9756163fc9cSnatano numbts = count; 9766163fc9cSnatano else 9776163fc9cSnatano numbts = maxlength - (digits); 9786163fc9cSnatano numbts -= delete_chars; 9796163fc9cSnatano 9806163fc9cSnatano /* 8.3 rules - keep the extension, add before the dot */ 9816163fc9cSnatano 9826163fc9cSnatano /* 9836163fc9cSnatano * This code makes a bunch of assumptions. 9846163fc9cSnatano * See if you can spot them all :) 9856163fc9cSnatano */ 9866163fc9cSnatano 9876163fc9cSnatano #if 0 9886163fc9cSnatano if (diskStructure->isoLevel == 1) { 9896163fc9cSnatano numbts = 8 - digits - delete_chars; 9906163fc9cSnatano if (dot < 0) { 9916163fc9cSnatano 9926163fc9cSnatano } else { 9936163fc9cSnatano if (dot < 8) { 9946163fc9cSnatano memmove(&tmp[numbts],&tmp[dot],4); 9956163fc9cSnatano } 9966163fc9cSnatano } 9976163fc9cSnatano } 9986163fc9cSnatano #else 9996163fc9cSnatano (void)dot; 10006163fc9cSnatano (void)semi; 10016163fc9cSnatano (void)multiplier; 10026163fc9cSnatano #endif 10036163fc9cSnatano 10046163fc9cSnatano /* (copying just the filename before the '.' */ 10056163fc9cSnatano memcpy(tmp, (iter->o_name), numbts); 10066163fc9cSnatano 10076163fc9cSnatano /* adding the appropriate number following the name */ 10086163fc9cSnatano temp = i; 10096163fc9cSnatano while (digits > 0) { 10106163fc9cSnatano digit = (int)(temp / powers); 10116163fc9cSnatano temp = temp - digit * powers; 1012d95291fdStedu snprintf(&tmp[numbts] , ISO_FILENAME_MAXLENGTH_WITH_PADDING - numbts, "%d", digit); 10136163fc9cSnatano digits--; 10146163fc9cSnatano numbts++; 10156163fc9cSnatano powers = powers / 10; 10166163fc9cSnatano } 10176163fc9cSnatano 10186163fc9cSnatano while ((*naming != ';') && (numbts < maxlength)) { 10196163fc9cSnatano tmp[numbts] = (*naming); 10206163fc9cSnatano naming++; 10216163fc9cSnatano numbts++; 10226163fc9cSnatano } 10236163fc9cSnatano 10246163fc9cSnatano tmp[numbts] = ';'; 10256163fc9cSnatano tmp[numbts+1] = '1'; 10266163fc9cSnatano tmp[numbts+2] = '\0'; 10276163fc9cSnatano 10286163fc9cSnatano /* 10296163fc9cSnatano * now tmp has exactly the identifier 10306163fc9cSnatano * we want so we'll copy it back to record 10316163fc9cSnatano */ 10326163fc9cSnatano memcpy((iter->isoDirRecord->name), tmp, numbts + 3); 10336163fc9cSnatano 10346163fc9cSnatano iter = TAILQ_NEXT(iter, cn_next_child); 10356163fc9cSnatano i++; 10366163fc9cSnatano } 10376163fc9cSnatano 10386163fc9cSnatano free(tmp); 10396163fc9cSnatano return iter; 10406163fc9cSnatano } 10416163fc9cSnatano 10426163fc9cSnatano /* Todo: Figure out why these functions are nec. */ 10436163fc9cSnatano static void 10446163fc9cSnatano cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node) 10456163fc9cSnatano { 10466163fc9cSnatano cd9660node *cn; 10476163fc9cSnatano 10486163fc9cSnatano if (TAILQ_EMPTY(&node->cn_children)) 10496163fc9cSnatano return; 10506163fc9cSnatano 10516163fc9cSnatano if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) { 10526163fc9cSnatano debug_print_tree(diskStructure, diskStructure->rootNode, 0); 10536163fc9cSnatano exit(1); 10546163fc9cSnatano } 10556163fc9cSnatano 10566163fc9cSnatano TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 10576163fc9cSnatano cd9660_copy_filenames(diskStructure, cn); 10586163fc9cSnatano memcpy(cn->o_name, cn->isoDirRecord->name, 10596163fc9cSnatano ISO_FILENAME_MAXLENGTH_WITH_PADDING); 10606163fc9cSnatano } 10616163fc9cSnatano } 10626163fc9cSnatano 10636163fc9cSnatano static void 10646163fc9cSnatano cd9660_sorting_nodes(cd9660node *node) 10656163fc9cSnatano { 10666163fc9cSnatano cd9660node *cn; 10676163fc9cSnatano 10686163fc9cSnatano TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) 10696163fc9cSnatano cd9660_sorting_nodes(cn); 10706163fc9cSnatano cd9660_sort_nodes(node); 10716163fc9cSnatano } 10726163fc9cSnatano 10736163fc9cSnatano /* XXX Bubble sort. */ 10746163fc9cSnatano static void 10756163fc9cSnatano cd9660_sort_nodes(cd9660node *node) 10766163fc9cSnatano { 10776163fc9cSnatano cd9660node *cn, *next; 10786163fc9cSnatano 10796163fc9cSnatano do { 10806163fc9cSnatano TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) { 10816163fc9cSnatano if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL) 10826163fc9cSnatano return; 10836163fc9cSnatano else if (strcmp(next->isoDirRecord->name, 10846163fc9cSnatano cn->isoDirRecord->name) >= 0) 10856163fc9cSnatano continue; 10866163fc9cSnatano TAILQ_REMOVE(&node->cn_children, next, cn_next_child); 10876163fc9cSnatano TAILQ_INSERT_BEFORE(cn, next, cn_next_child); 10886163fc9cSnatano break; 10896163fc9cSnatano } 10906163fc9cSnatano } while (cn != NULL); 10916163fc9cSnatano } 10926163fc9cSnatano 10936163fc9cSnatano static int 10946163fc9cSnatano cd9660_count_collisions(cd9660node *copy) 10956163fc9cSnatano { 10966163fc9cSnatano int count = 0; 10976163fc9cSnatano cd9660node *iter, *next; 10986163fc9cSnatano 10996163fc9cSnatano for (iter = copy; 11006163fc9cSnatano (next = TAILQ_NEXT(iter, cn_next_child)) != NULL; 11016163fc9cSnatano iter = next) { 11026163fc9cSnatano if (cd9660_compare_filename(iter->isoDirRecord->name, 11036163fc9cSnatano next->isoDirRecord->name) == 0) 11046163fc9cSnatano count++; 11056163fc9cSnatano else 11066163fc9cSnatano return count; 11076163fc9cSnatano } 11086163fc9cSnatano #if 0 11096163fc9cSnatano if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) { 11106163fc9cSnatano printf("%s: count is %i \n", __func__, count); 11116163fc9cSnatano compare = cd9660_compare_filename(iter->isoDirRecord->name, 11126163fc9cSnatano next->isoDirRecord->name); 11136163fc9cSnatano if (compare == 0) { 11146163fc9cSnatano count++; 11156163fc9cSnatano return cd9660_recurse_on_collision(next, count); 11166163fc9cSnatano } else 11176163fc9cSnatano return count; 11186163fc9cSnatano } 11196163fc9cSnatano #endif 11206163fc9cSnatano return count; 11216163fc9cSnatano } 11226163fc9cSnatano 11236163fc9cSnatano static cd9660node * 11246163fc9cSnatano cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir) 11256163fc9cSnatano { 11266163fc9cSnatano char newname[9]; 11276163fc9cSnatano cd9660node *tfile; 11286163fc9cSnatano 11296163fc9cSnatano /* 11306163fc9cSnatano * This function needs to: 11316163fc9cSnatano * 1) Create an empty virtual file in place of the old directory 11326163fc9cSnatano * 2) Point the virtual file to the new directory 11336163fc9cSnatano * 3) Point the relocated directory to its old parent 11346163fc9cSnatano * 4) Move the directory specified by dir into rr_moved_dir, 11356163fc9cSnatano * and rename it to "diskStructure->rock_ridge_move_count" (as a string) 11366163fc9cSnatano */ 11376163fc9cSnatano 11386163fc9cSnatano /* First see if the moved directory even exists */ 11396163fc9cSnatano if (diskStructure->rr_moved_dir == NULL) { 11406163fc9cSnatano diskStructure->rr_moved_dir = cd9660_create_directory( 11416163fc9cSnatano diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME, 11426163fc9cSnatano diskStructure->rootNode, dir); 11436163fc9cSnatano if (diskStructure->rr_moved_dir == NULL) 11446163fc9cSnatano return 0; 11456163fc9cSnatano cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date, 1146bc67c994Snatano Tflag ? stampts : start_time.tv_sec); 11476163fc9cSnatano } 11486163fc9cSnatano 11496163fc9cSnatano /* Create a file with the same ORIGINAL name */ 11506163fc9cSnatano tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent, 11516163fc9cSnatano dir); 11526163fc9cSnatano if (tfile == NULL) 11536163fc9cSnatano return NULL; 11546163fc9cSnatano 11556163fc9cSnatano diskStructure->rock_ridge_move_count++; 11566163fc9cSnatano snprintf(newname, sizeof(newname), "%08i", 11576163fc9cSnatano diskStructure->rock_ridge_move_count); 11586163fc9cSnatano 11596163fc9cSnatano /* Point to old parent */ 11606163fc9cSnatano dir->rr_real_parent = dir->parent; 11616163fc9cSnatano 11626163fc9cSnatano /* Place the placeholder file */ 11636163fc9cSnatano if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) { 11646163fc9cSnatano TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile, 11656163fc9cSnatano cn_next_child); 11666163fc9cSnatano } else { 11676163fc9cSnatano cd9660_sorted_child_insert(dir->rr_real_parent, tfile); 11686163fc9cSnatano } 11696163fc9cSnatano 11706163fc9cSnatano /* Point to new parent */ 11716163fc9cSnatano dir->parent = diskStructure->rr_moved_dir; 11726163fc9cSnatano 11736163fc9cSnatano /* Point the file to the moved directory */ 11746163fc9cSnatano tfile->rr_relocated = dir; 11756163fc9cSnatano 11766163fc9cSnatano /* Actually move the directory */ 11776163fc9cSnatano cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir); 11786163fc9cSnatano 11796163fc9cSnatano /* TODO: Inherit permissions / ownership (basically the entire inode) */ 11806163fc9cSnatano 11816163fc9cSnatano /* Set the new name */ 11826163fc9cSnatano memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING); 11836163fc9cSnatano strncpy(dir->isoDirRecord->name, newname, 8); 11846163fc9cSnatano dir->isoDirRecord->length[0] = 34 + 8; 11856163fc9cSnatano dir->isoDirRecord->name_len[0] = 8; 11866163fc9cSnatano 11876163fc9cSnatano return dir; 11886163fc9cSnatano } 11896163fc9cSnatano 11906163fc9cSnatano static int 11916163fc9cSnatano cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root) 11926163fc9cSnatano { 11936163fc9cSnatano struct cd9660_children_head *head = &root->cn_children; 11946163fc9cSnatano cd9660node *cn; 11956163fc9cSnatano 11966163fc9cSnatano TAILQ_FOREACH(cn, head, cn_next_child) { 11976163fc9cSnatano if ((cn->type & CD9660_TYPE_DIR) == 0) 11986163fc9cSnatano continue; 11996163fc9cSnatano /* Recursion first */ 12006163fc9cSnatano cd9660_add_dot_records(diskStructure, cn); 12016163fc9cSnatano } 12026163fc9cSnatano cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root); 12036163fc9cSnatano cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT, 12046163fc9cSnatano root); 12056163fc9cSnatano return 1; 12066163fc9cSnatano } 12076163fc9cSnatano 12086163fc9cSnatano /* 12096163fc9cSnatano * Convert node to cd9660 structure 12106163fc9cSnatano * This function is designed to be called recursively on the root node of 12116163fc9cSnatano * the filesystem 12126163fc9cSnatano * Lots of recursion going on here, want to make sure it is efficient 12136163fc9cSnatano * @param struct fsnode * The root node to be converted 12146163fc9cSnatano * @param struct cd9660* The parent node (should not be NULL) 12156163fc9cSnatano * @param int Current directory depth 12166163fc9cSnatano * @param int* Running count of the number of directories that are being created 12176163fc9cSnatano */ 12186163fc9cSnatano static void 12196163fc9cSnatano cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root, 12206163fc9cSnatano cd9660node *parent_node, int level, int *numDirectories, int *error) 12216163fc9cSnatano { 12226163fc9cSnatano fsnode *iterator = root; 12236163fc9cSnatano cd9660node *this_node; 12246163fc9cSnatano int working_level; 12256163fc9cSnatano int add; 12266163fc9cSnatano int flag = 0; 12276163fc9cSnatano int counter = 0; 12286163fc9cSnatano 12296163fc9cSnatano /* 12306163fc9cSnatano * Newer, more efficient method, reduces recursion depth 12316163fc9cSnatano */ 12326163fc9cSnatano if (root == NULL) { 12336163fc9cSnatano warnx("%s: root is null", __func__); 12346163fc9cSnatano return; 12356163fc9cSnatano } 12366163fc9cSnatano 12376163fc9cSnatano /* Test for an empty directory - makefs still gives us the . record */ 12386163fc9cSnatano if ((S_ISDIR(root->type)) && (root->name[0] == '.') 12396163fc9cSnatano && (root->name[1] == '\0')) { 12406163fc9cSnatano root = root->next; 12416163fc9cSnatano if (root == NULL) 12426163fc9cSnatano return; 12436163fc9cSnatano } 12446163fc9cSnatano if ((this_node = cd9660_allocate_cd9660node()) == NULL) { 12456163fc9cSnatano CD9660_MEM_ALLOC_ERROR(__func__); 12466163fc9cSnatano } 12476163fc9cSnatano 12486163fc9cSnatano /* 12496163fc9cSnatano * To reduce the number of recursive calls, we will iterate over 12506163fc9cSnatano * the next pointers to the right. 12516163fc9cSnatano */ 12526163fc9cSnatano while (iterator != NULL) { 12536163fc9cSnatano add = 1; 12546163fc9cSnatano /* 12556163fc9cSnatano * Increment the directory count if this is a directory 12566163fc9cSnatano * Ignore "." entries. We will generate them later 12576163fc9cSnatano */ 12586163fc9cSnatano if (!S_ISDIR(iterator->type) || 12596163fc9cSnatano strcmp(iterator->name, ".") != 0) { 12606163fc9cSnatano 12616163fc9cSnatano /* Translate the node, including its filename */ 12626163fc9cSnatano this_node->parent = parent_node; 12636163fc9cSnatano cd9660_translate_node(diskStructure, iterator, 12646163fc9cSnatano this_node); 12656163fc9cSnatano this_node->level = level; 12666163fc9cSnatano 12676163fc9cSnatano if (S_ISDIR(iterator->type)) { 12686163fc9cSnatano (*numDirectories)++; 12696163fc9cSnatano this_node->type = CD9660_TYPE_DIR; 12706163fc9cSnatano working_level = level + 1; 12716163fc9cSnatano 12726163fc9cSnatano /* 12736163fc9cSnatano * If at level 8, directory would be at 8 12746163fc9cSnatano * and have children at 9 which is not 12756163fc9cSnatano * allowed as per ISO spec 12766163fc9cSnatano */ 12776163fc9cSnatano if (level == 8) { 12786163fc9cSnatano if ((!diskStructure->allow_deep_trees) && 12796163fc9cSnatano (!diskStructure->rock_ridge_enabled)) { 12806163fc9cSnatano warnx("error: found entry " 12816163fc9cSnatano "with depth greater " 12826163fc9cSnatano "than 8."); 12836163fc9cSnatano (*error) = 1; 12846163fc9cSnatano return; 12856163fc9cSnatano } else if (diskStructure-> 12866163fc9cSnatano rock_ridge_enabled) { 12876163fc9cSnatano working_level = 3; 12886163fc9cSnatano /* 12896163fc9cSnatano * Moved directory is actually 12906163fc9cSnatano * at level 2. 12916163fc9cSnatano */ 12926163fc9cSnatano this_node->level = 12936163fc9cSnatano working_level - 1; 12946163fc9cSnatano if (cd9660_rrip_move_directory( 12956163fc9cSnatano diskStructure, 12966163fc9cSnatano this_node) == 0) { 12976163fc9cSnatano warnx("Failure in " 12986163fc9cSnatano "cd9660_rrip_" 12996163fc9cSnatano "move_directory" 13006163fc9cSnatano ); 13016163fc9cSnatano (*error) = 1; 13026163fc9cSnatano return; 13036163fc9cSnatano } 13046163fc9cSnatano add = 0; 13056163fc9cSnatano } 13066163fc9cSnatano } 13076163fc9cSnatano 13086163fc9cSnatano /* Do the recursive call on the children */ 13096163fc9cSnatano if (iterator->child != 0) { 13106163fc9cSnatano cd9660_convert_structure(diskStructure, 13116163fc9cSnatano iterator->child, this_node, 13126163fc9cSnatano working_level, 13136163fc9cSnatano numDirectories, error); 13146163fc9cSnatano 13156163fc9cSnatano if ((*error) == 1) { 13166163fc9cSnatano warnx("%s: Error on recursive " 13176163fc9cSnatano "call", __func__); 13186163fc9cSnatano return; 13196163fc9cSnatano } 13206163fc9cSnatano } 13216163fc9cSnatano 13226163fc9cSnatano } else { 13236163fc9cSnatano /* Only directories should have children */ 13246163fc9cSnatano assert(iterator->child == NULL); 13256163fc9cSnatano 13266163fc9cSnatano this_node->type = CD9660_TYPE_FILE; 13276163fc9cSnatano } 13286163fc9cSnatano 13296163fc9cSnatano /* 13306163fc9cSnatano * Finally, do a sorted insert 13316163fc9cSnatano */ 13326163fc9cSnatano if (add) { 13336163fc9cSnatano cd9660_sorted_child_insert( 13346163fc9cSnatano parent_node, this_node); 13356163fc9cSnatano } 13366163fc9cSnatano 13376163fc9cSnatano /*Allocate new temp_node */ 13386163fc9cSnatano if (iterator->next != 0) { 13396163fc9cSnatano this_node = cd9660_allocate_cd9660node(); 13406163fc9cSnatano if (this_node == NULL) 13416163fc9cSnatano CD9660_MEM_ALLOC_ERROR(__func__); 13426163fc9cSnatano } 13436163fc9cSnatano } 13446163fc9cSnatano iterator = iterator->next; 13456163fc9cSnatano } 13466163fc9cSnatano 13476163fc9cSnatano /* cd9660_handle_collisions(first_node); */ 13486163fc9cSnatano 13496163fc9cSnatano /* TODO: need cleanup */ 13506163fc9cSnatano cd9660_copy_filenames(diskStructure, parent_node); 13516163fc9cSnatano 13526163fc9cSnatano do { 13536163fc9cSnatano flag = cd9660_handle_collisions(diskStructure, parent_node, 13546163fc9cSnatano counter); 13556163fc9cSnatano counter++; 13566163fc9cSnatano cd9660_sorting_nodes(parent_node); 13576163fc9cSnatano } while ((flag == 1) && (counter < 100)); 13586163fc9cSnatano } 13596163fc9cSnatano 13606163fc9cSnatano /* 13616163fc9cSnatano * Clean up the cd9660node tree 13626163fc9cSnatano * This is designed to be called recursively on the root node 13636163fc9cSnatano * @param struct cd9660node *root The node to free 13646163fc9cSnatano * @returns void 13656163fc9cSnatano */ 13666163fc9cSnatano static void 13676163fc9cSnatano cd9660_free_structure(cd9660node *root) 13686163fc9cSnatano { 13696163fc9cSnatano cd9660node *cn; 13706163fc9cSnatano 13716163fc9cSnatano while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) { 13726163fc9cSnatano TAILQ_REMOVE(&root->cn_children, cn, cn_next_child); 13736163fc9cSnatano cd9660_free_structure(cn); 13746163fc9cSnatano } 13756163fc9cSnatano free(root); 13766163fc9cSnatano } 13776163fc9cSnatano 13786163fc9cSnatano /* 13796163fc9cSnatano * Be a little more memory conservative: 13806163fc9cSnatano * instead of having the TAILQ_ENTRY as part of the cd9660node, 13816163fc9cSnatano * just create a temporary structure 13826163fc9cSnatano */ 13836163fc9cSnatano struct ptq_entry 13846163fc9cSnatano { 13856163fc9cSnatano TAILQ_ENTRY(ptq_entry) ptq; 13866163fc9cSnatano cd9660node *node; 13876163fc9cSnatano } *n; 13886163fc9cSnatano 13896163fc9cSnatano #define PTQUEUE_NEW(n,s,r,t){\ 13906163fc9cSnatano n = emalloc(sizeof(struct s)); \ 13916163fc9cSnatano if (n == NULL) \ 13926163fc9cSnatano return r; \ 13936163fc9cSnatano n->node = t;\ 13946163fc9cSnatano } 13956163fc9cSnatano 13966163fc9cSnatano /* 13976163fc9cSnatano * Generate the path tables 13986163fc9cSnatano * The specific implementation of this function is left as an exercise to the 13996163fc9cSnatano * programmer. It could be done recursively. Make sure you read how the path 14006163fc9cSnatano * table has to be laid out, it has levels. 14016163fc9cSnatano * @param struct iso9660_disk *disk The disk image 14026163fc9cSnatano * @returns int The number of built path tables (between 1 and 4), 0 on failure 14036163fc9cSnatano */ 14046163fc9cSnatano static int 14056163fc9cSnatano cd9660_generate_path_table(iso9660_disk *diskStructure) 14066163fc9cSnatano { 14076163fc9cSnatano cd9660node *cn, *dirNode = diskStructure->rootNode; 14086163fc9cSnatano cd9660node *last = dirNode; 14096163fc9cSnatano int pathTableSize = 0; /* computed as we go */ 14106163fc9cSnatano int counter = 1; /* root gets a count of 0 */ 14116163fc9cSnatano 14126163fc9cSnatano TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head; 14136163fc9cSnatano TAILQ_INIT(&pt_head); 14146163fc9cSnatano 14156163fc9cSnatano PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode); 14166163fc9cSnatano 14176163fc9cSnatano /* Push the root node */ 14186163fc9cSnatano TAILQ_INSERT_HEAD(&pt_head, n, ptq); 14196163fc9cSnatano 14206163fc9cSnatano /* Breadth-first traversal of file structure */ 14216163fc9cSnatano while (pt_head.tqh_first != 0) { 14226163fc9cSnatano n = pt_head.tqh_first; 14236163fc9cSnatano dirNode = n->node; 14246163fc9cSnatano TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq); 14256163fc9cSnatano free(n); 14266163fc9cSnatano 14276163fc9cSnatano /* Update the size */ 14286163fc9cSnatano pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE 14296163fc9cSnatano + dirNode->isoDirRecord->name_len[0]+ 14306163fc9cSnatano (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1); 14316163fc9cSnatano /* includes the padding bit */ 14326163fc9cSnatano 14336163fc9cSnatano dirNode->ptnumber=counter; 14346163fc9cSnatano if (dirNode != last) { 14356163fc9cSnatano last->ptnext = dirNode; 14366163fc9cSnatano dirNode->ptprev = last; 14376163fc9cSnatano } 14386163fc9cSnatano last = dirNode; 14396163fc9cSnatano 14406163fc9cSnatano /* Push children onto queue */ 14416163fc9cSnatano TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) { 14426163fc9cSnatano /* 14436163fc9cSnatano * Dont add the DOT and DOTDOT types to the path 14446163fc9cSnatano * table. 14456163fc9cSnatano */ 14466163fc9cSnatano if ((cn->type != CD9660_TYPE_DOT) 14476163fc9cSnatano && (cn->type != CD9660_TYPE_DOTDOT)) { 14486163fc9cSnatano 14496163fc9cSnatano if (S_ISDIR(cn->node->type)) { 14506163fc9cSnatano PTQUEUE_NEW(n, ptq_entry, -1, cn); 14516163fc9cSnatano TAILQ_INSERT_TAIL(&pt_head, n, ptq); 14526163fc9cSnatano } 14536163fc9cSnatano } 14546163fc9cSnatano } 14556163fc9cSnatano counter++; 14566163fc9cSnatano } 14576163fc9cSnatano return pathTableSize; 14586163fc9cSnatano } 14596163fc9cSnatano 1460299d8950Snatano char * 1461299d8950Snatano cd9660_compute_full_filename(cd9660node *node) 14626163fc9cSnatano { 1463299d8950Snatano static char buf[PATH_MAX]; 14646163fc9cSnatano int len; 14656163fc9cSnatano 1466299d8950Snatano len = snprintf(buf, PATH_MAX, "%s/%s/%s", node->node->root, 14676163fc9cSnatano node->node->path, node->node->name); 1468299d8950Snatano if (len < 0) { 1469299d8950Snatano warn(NULL); 1470299d8950Snatano return NULL; 1471299d8950Snatano } else if (len >= PATH_MAX) { 1472299d8950Snatano warnc(ENAMETOOLONG, NULL); 1473299d8950Snatano return NULL; 1474299d8950Snatano } 1475299d8950Snatano return buf; 14766163fc9cSnatano } 14776163fc9cSnatano 14786163fc9cSnatano /* 14796163fc9cSnatano * TODO: These two functions are almost identical. 14806163fc9cSnatano * Some code cleanup is possible here 14816163fc9cSnatano * 14826163fc9cSnatano * XXX bounds checking! 14836163fc9cSnatano */ 14846163fc9cSnatano static int 14856163fc9cSnatano cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1486d95291fdStedu char *newname, size_t newnamelen, int is_file) 14876163fc9cSnatano { 14886163fc9cSnatano /* 14896163fc9cSnatano * ISO 9660 : 10.1 14906163fc9cSnatano * File Name shall not contain more than 8 d or d1 characters 14916163fc9cSnatano * File Name Extension shall not contain more than 3 d or d1 characters 14926163fc9cSnatano * Directory Identifier shall not contain more than 8 d or d1 characters 14936163fc9cSnatano */ 14946163fc9cSnatano int namelen = 0; 14956163fc9cSnatano int extlen = 0; 14966163fc9cSnatano int found_ext = 0; 1497d95291fdStedu char *orignewname = newname; 14986163fc9cSnatano 14996163fc9cSnatano while (*oldname != '\0' && extlen < 3) { 15006163fc9cSnatano /* Handle period first, as it is special */ 15016163fc9cSnatano if (*oldname == '.') { 15026163fc9cSnatano if (found_ext) { 15036163fc9cSnatano *newname++ = '_'; 15046163fc9cSnatano extlen ++; 15056163fc9cSnatano } 15066163fc9cSnatano else { 15076163fc9cSnatano *newname++ = '.'; 15086163fc9cSnatano found_ext = 1; 15096163fc9cSnatano } 15106163fc9cSnatano } else { 15116163fc9cSnatano /* Enforce 12.3 / 8 */ 15126163fc9cSnatano if (namelen == 8 && !found_ext) 15136163fc9cSnatano break; 15146163fc9cSnatano 15156163fc9cSnatano if (islower((unsigned char)*oldname)) 15166163fc9cSnatano *newname++ = toupper((unsigned char)*oldname); 15176163fc9cSnatano else if (isupper((unsigned char)*oldname) 15186163fc9cSnatano || isdigit((unsigned char)*oldname)) 15196163fc9cSnatano *newname++ = *oldname; 15206163fc9cSnatano else 15216163fc9cSnatano *newname++ = '_'; 15226163fc9cSnatano 15236163fc9cSnatano if (found_ext) 15246163fc9cSnatano extlen++; 15256163fc9cSnatano else 15266163fc9cSnatano namelen++; 15276163fc9cSnatano } 15286163fc9cSnatano oldname++; 15296163fc9cSnatano } 15306163fc9cSnatano if (is_file) { 15316163fc9cSnatano if (!found_ext && !diskStructure->omit_trailing_period) 15326163fc9cSnatano *newname++ = '.'; 15336163fc9cSnatano /* Add version */ 1534d95291fdStedu snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); 15356163fc9cSnatano } 15366163fc9cSnatano return namelen + extlen + found_ext; 15376163fc9cSnatano } 15386163fc9cSnatano 15396163fc9cSnatano /* XXX bounds checking! */ 15406163fc9cSnatano static int 15416163fc9cSnatano cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1542d95291fdStedu char *newname, size_t newnamelen, int is_file) 15436163fc9cSnatano { 15446163fc9cSnatano /* 15456163fc9cSnatano * ISO 9660 : 7.5.1 15466163fc9cSnatano * File name : 0+ d or d1 characters 15476163fc9cSnatano * separator 1 (.) 15486163fc9cSnatano * File name extension : 0+ d or d1 characters 15496163fc9cSnatano * separator 2 (;) 15506163fc9cSnatano * File version number (5 characters, 1-32767) 15516163fc9cSnatano * 1 <= Sum of File name and File name extension <= 30 15526163fc9cSnatano */ 15536163fc9cSnatano int namelen = 0; 15546163fc9cSnatano int extlen = 0; 15556163fc9cSnatano int found_ext = 0; 1556d95291fdStedu char *orignewname = newname; 15576163fc9cSnatano 15586163fc9cSnatano while (*oldname != '\0' && namelen + extlen < 30) { 15596163fc9cSnatano /* Handle period first, as it is special */ 15606163fc9cSnatano if (*oldname == '.') { 15616163fc9cSnatano if (found_ext) { 15626163fc9cSnatano if (diskStructure->allow_multidot) { 15636163fc9cSnatano *newname++ = '.'; 15646163fc9cSnatano } else { 15656163fc9cSnatano *newname++ = '_'; 15666163fc9cSnatano } 15676163fc9cSnatano extlen ++; 15686163fc9cSnatano } 15696163fc9cSnatano else { 15706163fc9cSnatano *newname++ = '.'; 15716163fc9cSnatano found_ext = 1; 15726163fc9cSnatano } 15736163fc9cSnatano } else { 15746163fc9cSnatano if (islower((unsigned char)*oldname)) 15756163fc9cSnatano *newname++ = toupper((unsigned char)*oldname); 15766163fc9cSnatano else if (isupper((unsigned char)*oldname) || 15776163fc9cSnatano isdigit((unsigned char)*oldname)) 15786163fc9cSnatano *newname++ = *oldname; 15796163fc9cSnatano else if (diskStructure->allow_multidot && 15806163fc9cSnatano *oldname == '.') { 15816163fc9cSnatano *newname++ = '.'; 15826163fc9cSnatano } else { 15836163fc9cSnatano *newname++ = '_'; 15846163fc9cSnatano } 15856163fc9cSnatano 15866163fc9cSnatano if (found_ext) 15876163fc9cSnatano extlen++; 15886163fc9cSnatano else 15896163fc9cSnatano namelen++; 15906163fc9cSnatano } 15916163fc9cSnatano oldname ++; 15926163fc9cSnatano } 15936163fc9cSnatano if (is_file) { 15946163fc9cSnatano if (!found_ext && !diskStructure->omit_trailing_period) 15956163fc9cSnatano *newname++ = '.'; 15966163fc9cSnatano /* Add version */ 1597d95291fdStedu snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1); 15986163fc9cSnatano } 15996163fc9cSnatano return namelen + extlen + found_ext; 16006163fc9cSnatano } 16016163fc9cSnatano 16026163fc9cSnatano /* 16036163fc9cSnatano * Convert a file name to ISO compliant file name 16046163fc9cSnatano * @param char * oldname The original filename 16056163fc9cSnatano * @param char ** newname The new file name, in the appropriate character 16066163fc9cSnatano * set and of appropriate length 16076163fc9cSnatano * @param int 1 if file, 0 if directory 16086163fc9cSnatano * @returns int The length of the new string 16096163fc9cSnatano */ 16106163fc9cSnatano static int 16116163fc9cSnatano cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname, 1612d95291fdStedu char *newname, size_t newnamelen, int is_file) 16136163fc9cSnatano { 16146163fc9cSnatano if (diskStructure->isoLevel == 1) 16154095a2e0Stedu return cd9660_level1_convert_filename(diskStructure, 16164095a2e0Stedu oldname, newname, newnamelen, is_file); 16176163fc9cSnatano else if (diskStructure->isoLevel == 2) 16184095a2e0Stedu return cd9660_level2_convert_filename(diskStructure, 16194095a2e0Stedu oldname, newname, newnamelen, is_file); 16204095a2e0Stedu abort(); 16216163fc9cSnatano } 16226163fc9cSnatano 16236163fc9cSnatano int 16246163fc9cSnatano cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node) 16256163fc9cSnatano { 16266163fc9cSnatano int size = node->isoDirRecord->length[0]; 16276163fc9cSnatano 16286163fc9cSnatano if (diskStructure->rock_ridge_enabled) 16296163fc9cSnatano size += node->susp_entry_size; 16306163fc9cSnatano size += node->su_tail_size; 16316163fc9cSnatano size += size & 1; /* Ensure length of record is even. */ 16326163fc9cSnatano assert(size <= 254); 16336163fc9cSnatano return size; 16346163fc9cSnatano } 16356163fc9cSnatano 16366163fc9cSnatano static void 16376163fc9cSnatano cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node) 16386163fc9cSnatano { 16396163fc9cSnatano node->dot_record->fileDataSector = node->fileDataSector; 16406163fc9cSnatano memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34); 16416163fc9cSnatano node->dot_record->isoDirRecord->name_len[0] = 1; 16426163fc9cSnatano node->dot_record->isoDirRecord->name[0] = 0; 16436163fc9cSnatano node->dot_record->isoDirRecord->name[1] = 0; 16446163fc9cSnatano node->dot_record->isoDirRecord->length[0] = 34; 16456163fc9cSnatano node->dot_record->fileRecordSize = 16466163fc9cSnatano cd9660_compute_record_size(diskStructure, node->dot_record); 16476163fc9cSnatano 16486163fc9cSnatano if (node == diskStructure->rootNode) { 16496163fc9cSnatano node->dot_dot_record->fileDataSector = node->fileDataSector; 16506163fc9cSnatano memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord, 16516163fc9cSnatano 34); 16526163fc9cSnatano } else { 16536163fc9cSnatano node->dot_dot_record->fileDataSector = 16546163fc9cSnatano node->parent->fileDataSector; 16556163fc9cSnatano memcpy(node->dot_dot_record->isoDirRecord, 16566163fc9cSnatano node->parent->isoDirRecord,34); 16576163fc9cSnatano } 16586163fc9cSnatano node->dot_dot_record->isoDirRecord->name_len[0] = 1; 16596163fc9cSnatano node->dot_dot_record->isoDirRecord->name[0] = 1; 16606163fc9cSnatano node->dot_dot_record->isoDirRecord->name[1] = 0; 16616163fc9cSnatano node->dot_dot_record->isoDirRecord->length[0] = 34; 16626163fc9cSnatano node->dot_dot_record->fileRecordSize = 16636163fc9cSnatano cd9660_compute_record_size(diskStructure, node->dot_dot_record); 16646163fc9cSnatano } 16656163fc9cSnatano 16666163fc9cSnatano /* 16676163fc9cSnatano * @param struct cd9660node *node The node 16686163fc9cSnatano * @param int The offset (in bytes) - SHOULD align to the beginning of a sector 16696163fc9cSnatano * @returns int The total size of files and directory entries (should be 16706163fc9cSnatano * a multiple of sector size) 16716163fc9cSnatano */ 16726163fc9cSnatano static int64_t 16736163fc9cSnatano cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node, 16746163fc9cSnatano int64_t startOffset) 16756163fc9cSnatano { 16766163fc9cSnatano /* 16776163fc9cSnatano * This function needs to compute the size of directory records and 16786163fc9cSnatano * runs, file lengths, and set the appropriate variables both in 16796163fc9cSnatano * cd9660node and isoDirEntry 16806163fc9cSnatano */ 16816163fc9cSnatano int64_t used_bytes = 0; 16826163fc9cSnatano int64_t current_sector_usage = 0; 16836163fc9cSnatano cd9660node *child; 16846163fc9cSnatano fsinode *inode; 16856163fc9cSnatano int64_t r; 16866163fc9cSnatano 16876163fc9cSnatano assert(node != NULL); 16886163fc9cSnatano 16896163fc9cSnatano 16906163fc9cSnatano /* 16916163fc9cSnatano * NOTE : There needs to be some special case detection for 16926163fc9cSnatano * the "real root" node, since for it, node->node is undefined 16936163fc9cSnatano */ 16946163fc9cSnatano 16956163fc9cSnatano node->fileDataSector = -1; 16966163fc9cSnatano 16976163fc9cSnatano if (node->type & CD9660_TYPE_DIR) { 16986163fc9cSnatano node->fileRecordSize = cd9660_compute_record_size( 16996163fc9cSnatano diskStructure, node); 17006163fc9cSnatano /*Set what sector this directory starts in*/ 17016163fc9cSnatano node->fileDataSector = 17026163fc9cSnatano CD9660_BLOCKS(diskStructure->sectorSize,startOffset); 17036163fc9cSnatano 17046163fc9cSnatano cd9660_bothendian_dword(node->fileDataSector, 17056163fc9cSnatano node->isoDirRecord->extent); 17066163fc9cSnatano 17076163fc9cSnatano /* 17086163fc9cSnatano * First loop over children, need to know the size of 17096163fc9cSnatano * their directory records 17106163fc9cSnatano */ 17116163fc9cSnatano node->fileSectorsUsed = 1; 17126163fc9cSnatano TAILQ_FOREACH(child, &node->cn_children, cn_next_child) { 17136163fc9cSnatano node->fileDataLength += 17146163fc9cSnatano cd9660_compute_record_size(diskStructure, child); 17156163fc9cSnatano if ((cd9660_compute_record_size(diskStructure, child) + 17166163fc9cSnatano current_sector_usage) >= 17176163fc9cSnatano diskStructure->sectorSize) { 17186163fc9cSnatano current_sector_usage = 0; 17196163fc9cSnatano node->fileSectorsUsed++; 17206163fc9cSnatano } 17216163fc9cSnatano 17226163fc9cSnatano current_sector_usage += 17236163fc9cSnatano cd9660_compute_record_size(diskStructure, child); 17246163fc9cSnatano } 17256163fc9cSnatano 17266163fc9cSnatano cd9660_bothendian_dword(node->fileSectorsUsed * 17276163fc9cSnatano diskStructure->sectorSize,node->isoDirRecord->size); 17286163fc9cSnatano 17296163fc9cSnatano /* 17306163fc9cSnatano * This should point to the sector after the directory 17316163fc9cSnatano * record (or, the first byte in that sector) 17326163fc9cSnatano */ 17336163fc9cSnatano used_bytes += node->fileSectorsUsed * diskStructure->sectorSize; 17346163fc9cSnatano 17356163fc9cSnatano for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 17366163fc9cSnatano child != NULL; child = TAILQ_NEXT(child, cn_next_child)) { 17376163fc9cSnatano /* Directories need recursive call */ 17386163fc9cSnatano if (S_ISDIR(child->node->type)) { 17396163fc9cSnatano r = cd9660_compute_offsets(diskStructure, child, 17406163fc9cSnatano used_bytes + startOffset); 17416163fc9cSnatano 17426163fc9cSnatano if (r != -1) 17436163fc9cSnatano used_bytes += r; 17446163fc9cSnatano else 17456163fc9cSnatano return -1; 17466163fc9cSnatano } 17476163fc9cSnatano } 17486163fc9cSnatano 17496163fc9cSnatano /* Explicitly set the . and .. records */ 17506163fc9cSnatano cd9660_populate_dot_records(diskStructure, node); 17516163fc9cSnatano 17526163fc9cSnatano /* Finally, do another iteration to write the file data*/ 17536163fc9cSnatano for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child); 17546163fc9cSnatano child != NULL; 17556163fc9cSnatano child = TAILQ_NEXT(child, cn_next_child)) { 17566163fc9cSnatano /* Files need extent set */ 17576163fc9cSnatano if (S_ISDIR(child->node->type)) 17586163fc9cSnatano continue; 17596163fc9cSnatano child->fileRecordSize = 17606163fc9cSnatano cd9660_compute_record_size(diskStructure, child); 17616163fc9cSnatano 17626163fc9cSnatano child->fileSectorsUsed = 17636163fc9cSnatano CD9660_BLOCKS(diskStructure->sectorSize, 17646163fc9cSnatano child->fileDataLength); 17656163fc9cSnatano 17666163fc9cSnatano inode = child->node->inode; 17676163fc9cSnatano if ((inode->flags & FI_ALLOCATED) == 0) { 17686163fc9cSnatano inode->ino = 17696163fc9cSnatano CD9660_BLOCKS(diskStructure->sectorSize, 17706163fc9cSnatano used_bytes + startOffset); 17716163fc9cSnatano inode->flags |= FI_ALLOCATED; 17726163fc9cSnatano used_bytes += child->fileSectorsUsed * 17736163fc9cSnatano diskStructure->sectorSize; 17746163fc9cSnatano } else { 17756163fc9cSnatano INODE_WARNX(("%s: already allocated inode %d " 17766163fc9cSnatano "data sectors at %" PRIu32, __func__, 17776163fc9cSnatano (int)inode->st.st_ino, inode->ino)); 17786163fc9cSnatano } 17796163fc9cSnatano child->fileDataSector = inode->ino; 17806163fc9cSnatano cd9660_bothendian_dword(child->fileDataSector, 17816163fc9cSnatano child->isoDirRecord->extent); 17826163fc9cSnatano } 17836163fc9cSnatano } 17846163fc9cSnatano 17856163fc9cSnatano return used_bytes; 17866163fc9cSnatano } 17876163fc9cSnatano 17886163fc9cSnatano #if 0 17896163fc9cSnatano /* Might get rid of this func */ 17906163fc9cSnatano static int 17916163fc9cSnatano cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file) 17926163fc9cSnatano { 17936163fc9cSnatano to->node->inode->st.st_dev = 0; 17946163fc9cSnatano to->node->inode->st.st_ino = 0; 17956163fc9cSnatano to->node->inode->st.st_size = 0; 17966163fc9cSnatano to->node->inode->st.st_blksize = from->node->inode->st.st_blksize; 17976163fc9cSnatano to->node->inode->st.st_atime = from->node->inode->st.st_atime; 17986163fc9cSnatano to->node->inode->st.st_mtime = from->node->inode->st.st_mtime; 17996163fc9cSnatano to->node->inode->st.st_ctime = from->node->inode->st.st_ctime; 18006163fc9cSnatano to->node->inode->st.st_uid = from->node->inode->st.st_uid; 18016163fc9cSnatano to->node->inode->st.st_gid = from->node->inode->st.st_gid; 18026163fc9cSnatano to->node->inode->st.st_mode = from->node->inode->st.st_mode; 18036163fc9cSnatano /* Clear out type */ 18046163fc9cSnatano to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT); 18056163fc9cSnatano if (file) 18066163fc9cSnatano to->node->inode->st.st_mode |= S_IFREG; 18076163fc9cSnatano else 18086163fc9cSnatano to->node->inode->st.st_mode |= S_IFDIR; 18096163fc9cSnatano return 1; 18106163fc9cSnatano } 18116163fc9cSnatano #endif 18126163fc9cSnatano 18136163fc9cSnatano static cd9660node * 18146163fc9cSnatano cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name, 18156163fc9cSnatano cd9660node *parent, int file, int insert) 18166163fc9cSnatano { 18176163fc9cSnatano cd9660node *temp; 18186163fc9cSnatano fsnode * tfsnode; 18196163fc9cSnatano 18206163fc9cSnatano assert(parent != NULL); 18216163fc9cSnatano 18226163fc9cSnatano temp = cd9660_allocate_cd9660node(); 18236163fc9cSnatano if (temp == NULL) 18246163fc9cSnatano return NULL; 18256163fc9cSnatano 18266163fc9cSnatano tfsnode = emalloc(sizeof(*tfsnode)); 18276163fc9cSnatano tfsnode->name = estrdup(name); 18286163fc9cSnatano temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord)); 18296163fc9cSnatano 18306163fc9cSnatano cd9660_convert_filename(diskStructure, tfsnode->name, 1831d95291fdStedu temp->isoDirRecord->name, sizeof temp->isoDirRecord->name, file); 18326163fc9cSnatano 18336163fc9cSnatano temp->node = tfsnode; 18346163fc9cSnatano temp->parent = parent; 18356163fc9cSnatano 18366163fc9cSnatano if (insert) { 18376163fc9cSnatano if (temp->parent != NULL) { 18386163fc9cSnatano temp->level = temp->parent->level + 1; 18396163fc9cSnatano if (!TAILQ_EMPTY(&temp->parent->cn_children)) 18406163fc9cSnatano cd9660_sorted_child_insert(temp->parent, temp); 18416163fc9cSnatano else 18426163fc9cSnatano TAILQ_INSERT_HEAD(&temp->parent->cn_children, 18436163fc9cSnatano temp, cn_next_child); 18446163fc9cSnatano } 18456163fc9cSnatano } 18466163fc9cSnatano 18476163fc9cSnatano if (parent->node != NULL) { 18486163fc9cSnatano tfsnode->type = parent->node->type; 18496163fc9cSnatano } 18506163fc9cSnatano 18516163fc9cSnatano /* Clear out file type bits */ 18526163fc9cSnatano tfsnode->type &= ~(S_IFMT); 18536163fc9cSnatano if (file) 18546163fc9cSnatano tfsnode->type |= S_IFREG; 18556163fc9cSnatano else 18566163fc9cSnatano tfsnode->type |= S_IFDIR; 18576163fc9cSnatano 18586163fc9cSnatano /* Indicate that there is no spec entry (inode) */ 18596163fc9cSnatano tfsnode->flags &= ~(FSNODE_F_HASSPEC); 18606163fc9cSnatano #if 0 18616163fc9cSnatano cd9660_copy_stat_info(parent, temp, file); 18626163fc9cSnatano #endif 18636163fc9cSnatano return temp; 18646163fc9cSnatano } 18656163fc9cSnatano 18666163fc9cSnatano static cd9660node * 18676163fc9cSnatano cd9660_create_file(iso9660_disk *diskStructure, const char *name, 18686163fc9cSnatano cd9660node *parent, cd9660node *me) 18696163fc9cSnatano { 18706163fc9cSnatano cd9660node *temp; 18716163fc9cSnatano 18726163fc9cSnatano temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1); 18736163fc9cSnatano if (temp == NULL) 18746163fc9cSnatano return NULL; 18756163fc9cSnatano 18766163fc9cSnatano temp->fileDataLength = 0; 18776163fc9cSnatano 18786163fc9cSnatano temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL; 18796163fc9cSnatano 18806163fc9cSnatano temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); 18816163fc9cSnatano *temp->node->inode = *me->node->inode; 18826163fc9cSnatano 18836163fc9cSnatano if (cd9660_translate_node_common(diskStructure, temp) == 0) 18846163fc9cSnatano return NULL; 18856163fc9cSnatano return temp; 18866163fc9cSnatano } 18876163fc9cSnatano 18886163fc9cSnatano /* 18896163fc9cSnatano * Create a new directory which does not exist on disk 18906163fc9cSnatano * @param const char * name The name to assign to the directory 18916163fc9cSnatano * @param const char * parent Pointer to the parent directory 18926163fc9cSnatano * @returns cd9660node * Pointer to the new directory 18936163fc9cSnatano */ 18946163fc9cSnatano static cd9660node * 18956163fc9cSnatano cd9660_create_directory(iso9660_disk *diskStructure, const char *name, 18966163fc9cSnatano cd9660node *parent, cd9660node *me) 18976163fc9cSnatano { 18986163fc9cSnatano cd9660node *temp; 18996163fc9cSnatano 19006163fc9cSnatano temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1); 19016163fc9cSnatano if (temp == NULL) 19026163fc9cSnatano return NULL; 19036163fc9cSnatano temp->node->type |= S_IFDIR; 19046163fc9cSnatano 19056163fc9cSnatano temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL; 19066163fc9cSnatano 19076163fc9cSnatano temp->node->inode = ecalloc(1, sizeof(*temp->node->inode)); 19086163fc9cSnatano *temp->node->inode = *me->node->inode; 19096163fc9cSnatano 19106163fc9cSnatano if (cd9660_translate_node_common(diskStructure, temp) == 0) 19116163fc9cSnatano return NULL; 19126163fc9cSnatano return temp; 19136163fc9cSnatano } 19146163fc9cSnatano 19156163fc9cSnatano static cd9660node * 19166163fc9cSnatano cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type, 19176163fc9cSnatano cd9660node *parent) 19186163fc9cSnatano { 19196163fc9cSnatano cd9660node *temp, *first; 19206163fc9cSnatano char na[2]; 19216163fc9cSnatano 19226163fc9cSnatano assert(parent != NULL); 19236163fc9cSnatano 19246163fc9cSnatano if (type == CD9660_TYPE_DOT) 19256163fc9cSnatano na[0] = 0; 19266163fc9cSnatano else if (type == CD9660_TYPE_DOTDOT) 19276163fc9cSnatano na[0] = 1; 19286163fc9cSnatano else 19296163fc9cSnatano return 0; 19306163fc9cSnatano 19316163fc9cSnatano na[1] = 0; 19326163fc9cSnatano if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent, 19336163fc9cSnatano 0, 0)) == NULL) 19346163fc9cSnatano return NULL; 19356163fc9cSnatano 19366163fc9cSnatano temp->parent = parent; 19376163fc9cSnatano temp->type = type; 19386163fc9cSnatano temp->isoDirRecord->length[0] = 34; 19396163fc9cSnatano /* Dot record is always first */ 19406163fc9cSnatano if (type == CD9660_TYPE_DOT) { 19416163fc9cSnatano parent->dot_record = temp; 19426163fc9cSnatano TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child); 19436163fc9cSnatano /* DotDot should be second */ 19446163fc9cSnatano } else if (type == CD9660_TYPE_DOTDOT) { 19456163fc9cSnatano parent->dot_dot_record = temp; 19466163fc9cSnatano /* 19476163fc9cSnatano * If the first child is the dot record, insert 19486163fc9cSnatano * this second. Otherwise, insert it at the head. 19496163fc9cSnatano */ 19506163fc9cSnatano if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL || 19516163fc9cSnatano (first->type & CD9660_TYPE_DOT) == 0) { 19526163fc9cSnatano TAILQ_INSERT_HEAD(&parent->cn_children, temp, 19536163fc9cSnatano cn_next_child); 19546163fc9cSnatano } else { 19556163fc9cSnatano TAILQ_INSERT_AFTER(&parent->cn_children, first, temp, 19566163fc9cSnatano cn_next_child); 19576163fc9cSnatano } 19586163fc9cSnatano } 19596163fc9cSnatano 19606163fc9cSnatano return temp; 19616163fc9cSnatano } 19626163fc9cSnatano 19636163fc9cSnatano static int 19646163fc9cSnatano cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage) 19656163fc9cSnatano { 19666163fc9cSnatano struct stat stbuf; 19676163fc9cSnatano 19686163fc9cSnatano assert(bootimage != NULL); 19696163fc9cSnatano 19706163fc9cSnatano if (*bootimage == '\0') { 19716163fc9cSnatano warnx("Error: Boot image must be a filename"); 19726163fc9cSnatano return 0; 19736163fc9cSnatano } 19746163fc9cSnatano 19756163fc9cSnatano diskStructure->generic_bootimage = estrdup(bootimage); 19766163fc9cSnatano 1977c8f48d9bSyasuoka if (unveil(diskStructure->generic_bootimage, "r") == -1) 1978bc5a8259Sbeck err(1, "unveil %s", diskStructure->generic_bootimage); 19796163fc9cSnatano /* Get information about the file */ 19806163fc9cSnatano if (lstat(diskStructure->generic_bootimage, &stbuf) == -1) 1981944eabd5Snatano err(1, "%s: lstat(\"%s\")", __func__, 19826163fc9cSnatano diskStructure->generic_bootimage); 19836163fc9cSnatano 19846163fc9cSnatano if (stbuf.st_size > 32768) { 19856163fc9cSnatano warnx("Error: Boot image must be no greater than 32768 bytes"); 19866163fc9cSnatano return 0; 19876163fc9cSnatano } 19886163fc9cSnatano 19896163fc9cSnatano diskStructure->has_generic_bootimage = 1; 19906163fc9cSnatano return 1; 19916163fc9cSnatano } 1992