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