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