1 /* $OpenBSD: cd9660.c,v 1.24 2024/08/03 22:23:32 millert 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 *
cd9660_allocate_cd9660node(void)171 cd9660_allocate_cd9660node(void)
172 {
173 cd9660node *temp = ecalloc(1, sizeof(*temp));
174 TAILQ_INIT(&temp->cn_children);
175 temp->parent = temp->dot_record = temp->dot_dot_record = NULL;
176 temp->ptnext = temp->ptprev = temp->ptlast = NULL;
177 temp->node = NULL;
178 temp->isoDirRecord = NULL;
179 temp->isoExtAttributes = NULL;
180 temp->rr_real_parent = temp->rr_relocated = NULL;
181 temp->su_tail_data = NULL;
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
cd9660_set_defaults(iso9660_disk * diskStructure)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,"OpenBSD", 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;
228
229 /*memset(diskStructure->boot_descriptor, 0, 2048);*/
230
231 diskStructure->is_bootable = 0;
232 TAILQ_INIT(&diskStructure->boot_images);
233 LIST_INIT(&diskStructure->boot_entries);
234 }
235
236 void
cd9660_prep_opts(fsinfo_t * fsopts)237 cd9660_prep_opts(fsinfo_t *fsopts)
238 {
239 iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure));
240
241 #define OPT_STR(name) \
242 { name, NULL, OPT_STRBUF, 0, 0 }
243
244 #define OPT_NUM(name, field, 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) \
252 { name, &diskStructure->field, OPT_BOOL }
253
254 const option_t cd9660_options[] = {
255 OPT_BOOL("allow-deep-trees", allow_deep_trees),
256 OPT_BOOL("allow-multidot", allow_multidot),
257 OPT_STR("applicationid"),
258 OPT_STR("boot-load-segment"),
259 OPT_STR("bootimage"),
260 OPT_STR("generic-bootimage"),
261 OPT_STR("hard-disk-boot"),
262 OPT_NUM("isolevel", isoLevel, 1, 3),
263 OPT_STR("label"),
264 OPT_STR("no-boot"),
265 OPT_STR("no-emul-boot"),
266 OPT_BOOL("no-trailing-padding", include_padding_areas),
267 OPT_BOOL("omit-trailing-period", omit_trailing_period),
268 OPT_STR("preparer"),
269 OPT_STR("publisher"),
270 OPT_BOOL("rockridge", rock_ridge_enabled),
271 OPT_STR("volumeid"),
272 { .name = NULL }
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
cd9660_cleanup_opts(fsinfo_t * fsopts)282 cd9660_cleanup_opts(fsinfo_t *fsopts)
283 {
284 free(fsopts->fs_specific);
285 free(fsopts->fs_options);
286 }
287
288 static int
cd9660_arguments_set_string(const char * val,const char * fieldtitle,size_t length,char testmode,char * dest)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)
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
cd9660_parse_opts(const char * option,fsinfo_t * fsopts)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);
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)
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
cd9660_makefs(const char * image,const char * dir,fsnode * root,fsinfo_t * fsopts)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);
418 assert(dir != NULL);
419 assert(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_PADDING);
434
435 real_root->level = 0;
436 diskStructure->rootNode = real_root;
437 real_root->type = CD9660_TYPE_DIR;
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)) {
444 errx(1, "%s: converted directory is empty. "
445 "Tree conversion failed", __func__);
446 } else if (error != 0) {
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);
459 }
460
461 /* Build path table structure */
462 diskStructure->pathTableLength = cd9660_generate_path_table(
463 diskStructure);
464
465 pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize,
466 diskStructure->pathTableLength);
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);
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,
500 diskStructure->susp_continuation_area_size);
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
cd9660_finalize_PVD(iso9660_disk * diskStructure)530 cd9660_finalize_PVD(iso9660_disk *diskStructure)
531 {
532 time_t tstamp = Tflag ? stampts : time(NULL);
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
cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 * record,u_char ext_attr_length,u_char flags,u_char name_len,const char * name)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_CLEAR | 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
cd9660_setup_root_node(iso9660_disk * diskStructure)620 cd9660_setup_root_node(iso9660_disk *diskStructure)
621 {
622 cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord,
623 0, ISO_FLAG_DIRECTORY, 1, "\0");
624
625 }
626
627 /*********** SUPPORT FUNCTIONS ***********/
628 static int
cd9660_setup_volume_descriptors(iso9660_disk * diskStructure)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_PVD;
641 temp->volumeDescriptorData[6] = 1;
642 temp->sector = sector;
643 memcpy(temp->volumeDescriptorData + 1,
644 ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 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_TERMINATOR;
664 t->next = 0;
665 t->volumeDescriptorData[6] = 1;
666 t->sector = sector;
667 memcpy(t->volumeDescriptorData + 1,
668 ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 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
cd9660_translate_node_common(iso9660_disk * diskStructure,cd9660node * newnode)688 cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode)
689 {
690 time_t tstamp = Tflag ? stampts : time(NULL);
691 u_char flag;
692 char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
693
694 /* Now populate the isoDirRecord structure */
695 memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
696
697 (void)cd9660_convert_filename(diskStructure, newnode->node->name,
698 temp, sizeof temp, !(S_ISDIR(newnode->node->type)));
699
700 flag = ISO_FLAG_CLEAR;
701 if (S_ISDIR(newnode->node->type))
702 flag |= ISO_FLAG_DIRECTORY;
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))
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
cd9660_translate_node(iso9660_disk * diskStructure,fsnode * node,cd9660node * newnode)731 cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node,
732 cd9660node *newnode)
733 {
734 if (node == NULL)
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)))
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_mtime);
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
cd9660_compare_filename(const char * first,const char * second)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_VERSION-1
776 && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-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_VERSION - 1
803 && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 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
cd9660_sorted_child_insert(cd9660node * parent,cd9660node * cn_new)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) {
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)
868 TAILQ_INSERT_TAIL(head, cn_new, cn_next_child);
869 else
870 TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child);
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
cd9660_handle_collisions(iso9660_disk * diskStructure,cd9660node * colliding,int past)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);
891 iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) {
892 if (strcmp(iter->isoDirRecord->name,
893 next->isoDirRecord->name) != 0) {
894 iter = TAILQ_NEXT(iter, cn_next_child);
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);
903 }
904 temp_past = past;
905 while (temp_past > 0) {
906 if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL)
907 end_of_range = next;
908 else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL)
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 *
cd9660_rename_filename(iso9660_disk * diskStructure,cd9660node * iter,int num,int delete_chars)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_VERSION;
939
940 tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING);
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_PADDING - 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);
1035 i++;
1036 }
1037
1038 free(tmp);
1039 return iter;
1040 }
1041
1042 /* Todo: Figure out why these functions are nec. */
1043 static void
cd9660_copy_filenames(iso9660_disk * diskStructure,cd9660node * node)1044 cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node)
1045 {
1046 cd9660node *cn;
1047
1048 if (TAILQ_EMPTY(&node->cn_children))
1049 return;
1050
1051 if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) {
1052 debug_print_tree(diskStructure, diskStructure->rootNode, 0);
1053 exit(1);
1054 }
1055
1056 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1057 cd9660_copy_filenames(diskStructure, cn);
1058 memcpy(cn->o_name, cn->isoDirRecord->name,
1059 ISO_FILENAME_MAXLENGTH_WITH_PADDING);
1060 }
1061 }
1062
1063 static void
cd9660_sorting_nodes(cd9660node * node)1064 cd9660_sorting_nodes(cd9660node *node)
1065 {
1066 cd9660node *cn;
1067
1068 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
1069 cd9660_sorting_nodes(cn);
1070 cd9660_sort_nodes(node);
1071 }
1072
1073 /* XXX Bubble sort. */
1074 static void
cd9660_sort_nodes(cd9660node * node)1075 cd9660_sort_nodes(cd9660node *node)
1076 {
1077 cd9660node *cn, *next;
1078
1079 do {
1080 TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
1081 if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL)
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);
1087 TAILQ_INSERT_BEFORE(cn, next, cn_next_child);
1088 break;
1089 }
1090 } while (cn != NULL);
1091 }
1092
1093 static int
cd9660_count_collisions(cd9660node * copy)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)) != NULL;
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)) != NULL) {
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 *
cd9660_rrip_move_directory(iso9660_disk * diskStructure,cd9660node * dir)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) {
1140 diskStructure->rr_moved_dir = cd9660_create_directory(
1141 diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME,
1142 diskStructure->rootNode, dir);
1143 if (diskStructure->rr_moved_dir == NULL)
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)
1153 return NULL;
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)) {
1164 TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,
1165 cn_next_child);
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_PADDING);
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
cd9660_add_dot_records(iso9660_disk * diskStructure,cd9660node * root)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) {
1197 if ((cn->type & CD9660_TYPE_DIR) == 0)
1198 continue;
1199 /* Recursion first */
1200 cd9660_add_dot_records(diskStructure, cn);
1201 }
1202 cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root);
1203 cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT,
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
cd9660_convert_structure(iso9660_disk * diskStructure,fsnode * root,cd9660node * parent_node,int level,int * numDirectories,int * error)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) {
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->name[0] == '.')
1239 && (root->name[1] == '\0')) {
1240 root = root->next;
1241 if (root == NULL)
1242 return;
1243 }
1244 if ((this_node = cd9660_allocate_cd9660node()) == NULL) {
1245 CD9660_MEM_ALLOC_ERROR(__func__);
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) {
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) ||
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)) {
1268 (*numDirectories)++;
1269 this_node->type = CD9660_TYPE_DIR;
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);
1325
1326 this_node->type = CD9660_TYPE_FILE;
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)
1341 CD9660_MEM_ALLOC_ERROR(__func__);
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
cd9660_free_structure(cd9660node * root)1367 cd9660_free_structure(cd9660node *root)
1368 {
1369 cd9660node *cn;
1370
1371 while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) {
1372 TAILQ_REMOVE(&root->cn_children, cn, cn_next_child);
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) ptq;
1386 cd9660node *node;
1387 } *n;
1388
1389 #define PTQUEUE_NEW(n,s,r,t){\
1390 n = emalloc(sizeof(struct s)); \
1391 if (n == NULL) \
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
cd9660_generate_path_table(iso9660_disk * diskStructure)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) pt_head;
1413 TAILQ_INIT(&pt_head);
1414
1415 PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode);
1416
1417 /* Push the root node */
1418 TAILQ_INSERT_HEAD(&pt_head, n, ptq);
1419
1420 /* Breadth-first traversal of file structure */
1421 while (pt_head.tqh_first != 0) {
1422 n = pt_head.tqh_first;
1423 dirNode = n->node;
1424 TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq);
1425 free(n);
1426
1427 /* Update the size */
1428 pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE
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 != last) {
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) {
1442 /*
1443 * Dont add the DOT and DOTDOT types to the path
1444 * table.
1445 */
1446 if ((cn->type != CD9660_TYPE_DOT)
1447 && (cn->type != CD9660_TYPE_DOTDOT)) {
1448
1449 if (S_ISDIR(cn->node->type)) {
1450 PTQUEUE_NEW(n, ptq_entry, -1, cn);
1451 TAILQ_INSERT_TAIL(&pt_head, n, ptq);
1452 }
1453 }
1454 }
1455 counter++;
1456 }
1457 return pathTableSize;
1458 }
1459
1460 char *
cd9660_compute_full_filename(cd9660node * node)1461 cd9660_compute_full_filename(cd9660node *node)
1462 {
1463 static char buf[PATH_MAX];
1464 int len;
1465
1466 len = snprintf(buf, PATH_MAX, "%s/%s/%s", node->node->root,
1467 node->node->path, node->node->name);
1468 if (len < 0) {
1469 warn(NULL);
1470 return NULL;
1471 } else if (len >= PATH_MAX) {
1472 warnc(ENAMETOOLONG, NULL);
1473 return NULL;
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
cd9660_level1_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)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
cd9660_level2_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)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
cd9660_convert_filename(iso9660_disk * diskStructure,const char * oldname,char * newname,size_t newnamelen,int is_file)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
cd9660_compute_record_size(iso9660_disk * diskStructure,cd9660node * node)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);
1633 return size;
1634 }
1635
1636 static void
cd9660_populate_dot_records(iso9660_disk * diskStructure,cd9660node * node)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
cd9660_compute_offsets(iso9660_disk * diskStructure,cd9660node * node,int64_t startOffset)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);
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_DIR) {
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);
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) {
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);
1736 child != NULL; child = TAILQ_NEXT(child, cn_next_child)) {
1737 /* Directories need recursive call */
1738 if (S_ISDIR(child->node->type)) {
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);
1754 child != NULL;
1755 child = TAILQ_NEXT(child, cn_next_child)) {
1756 /* Files need extent set */
1757 if (S_ISDIR(child->node->type))
1758 continue;
1759 child->fileRecordSize =
1760 cd9660_compute_record_size(diskStructure, child);
1761
1762 child->fileSectorsUsed =
1763 CD9660_BLOCKS(diskStructure->sectorSize,
1764 child->fileDataLength);
1765
1766 inode = child->node->inode;
1767 if ((inode->flags & FI_ALLOCATED) == 0) {
1768 inode->ino =
1769 CD9660_BLOCKS(diskStructure->sectorSize,
1770 used_bytes + startOffset);
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_atime = from->node->inode->st.st_atime;
1798 to->node->inode->st.st_mtime = from->node->inode->st.st_mtime;
1799 to->node->inode->st.st_ctime = from->node->inode->st.st_ctime;
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_IFMT);
1805 if (file)
1806 to->node->inode->st.st_mode |= S_IFREG;
1807 else
1808 to->node->inode->st.st_mode |= S_IFDIR;
1809 return 1;
1810 }
1811 #endif
1812
1813 static cd9660node *
cd9660_create_virtual_entry(iso9660_disk * diskStructure,const char * name,cd9660node * parent,int file,int insert)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);
1821
1822 temp = cd9660_allocate_cd9660node();
1823 if (temp == NULL)
1824 return NULL;
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) {
1838 temp->level = temp->parent->level + 1;
1839 if (!TAILQ_EMPTY(&temp->parent->cn_children))
1840 cd9660_sorted_child_insert(temp->parent, temp);
1841 else
1842 TAILQ_INSERT_HEAD(&temp->parent->cn_children,
1843 temp, cn_next_child);
1844 }
1845 }
1846
1847 if (parent->node != NULL) {
1848 tfsnode->type = parent->node->type;
1849 }
1850
1851 /* Clear out file type bits */
1852 tfsnode->type &= ~(S_IFMT);
1853 if (file)
1854 tfsnode->type |= S_IFREG;
1855 else
1856 tfsnode->type |= S_IFDIR;
1857
1858 /* Indicate that there is no spec entry (inode) */
1859 tfsnode->flags &= ~(FSNODE_F_HASSPEC);
1860 #if 0
1861 cd9660_copy_stat_info(parent, temp, file);
1862 #endif
1863 return temp;
1864 }
1865
1866 static cd9660node *
cd9660_create_file(iso9660_disk * diskStructure,const char * name,cd9660node * parent,cd9660node * me)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)
1874 return NULL;
1875
1876 temp->fileDataLength = 0;
1877
1878 temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL;
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;
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 *
cd9660_create_directory(iso9660_disk * diskStructure,const char * name,cd9660node * parent,cd9660node * me)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)
1902 return NULL;
1903 temp->node->type |= S_IFDIR;
1904
1905 temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL;
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;
1912 return temp;
1913 }
1914
1915 static cd9660node *
cd9660_create_special_directory(iso9660_disk * diskStructure,u_char type,cd9660node * parent)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);
1923
1924 if (type == CD9660_TYPE_DOT)
1925 na[0] = 0;
1926 else if (type == CD9660_TYPE_DOTDOT)
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)
1934 return NULL;
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_DOT) {
1941 parent->dot_record = temp;
1942 TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child);
1943 /* DotDot should be second */
1944 } else if (type == CD9660_TYPE_DOTDOT) {
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)) == NULL ||
1951 (first->type & CD9660_TYPE_DOT) == 0) {
1952 TAILQ_INSERT_HEAD(&parent->cn_children, temp,
1953 cn_next_child);
1954 } else {
1955 TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,
1956 cn_next_child);
1957 }
1958 }
1959
1960 return temp;
1961 }
1962
1963 static int
cd9660_add_generic_bootimage(iso9660_disk * diskStructure,const char * bootimage)1964 cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage)
1965 {
1966 struct stat stbuf;
1967
1968 assert(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 }
1992