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