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