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