xref: /openbsd-src/usr.sbin/makefs/cd9660.c (revision 493aa139460d27930d60a92380691ef4e2dde0bd)
1*493aa139Smillert /*	$OpenBSD: cd9660.c,v 1.24 2024/08/03 22:23:32 millert Exp $	*/
24e4cca72Snatano /*	$NetBSD: cd9660.c,v 1.53 2016/11/25 23:02:44 christos Exp $	*/
36163fc9cSnatano 
46163fc9cSnatano /*
56163fc9cSnatano  * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
66163fc9cSnatano  * Perez-Rathke and Ram Vedam.  All rights reserved.
76163fc9cSnatano  *
86163fc9cSnatano  * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
96163fc9cSnatano  * Alan Perez-Rathke and Ram Vedam.
106163fc9cSnatano  *
116163fc9cSnatano  * Redistribution and use in source and binary forms, with or
126163fc9cSnatano  * without modification, are permitted provided that the following
136163fc9cSnatano  * conditions are met:
146163fc9cSnatano  * 1. Redistributions of source code must retain the above copyright
156163fc9cSnatano  *    notice, this list of conditions and the following disclaimer.
166163fc9cSnatano  * 2. Redistributions in binary form must reproduce the above
176163fc9cSnatano  *    copyright notice, this list of conditions and the following
186163fc9cSnatano  *    disclaimer in the documentation and/or other materials provided
196163fc9cSnatano  *    with the distribution.
206163fc9cSnatano  *
216163fc9cSnatano  * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
226163fc9cSnatano  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
236163fc9cSnatano  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
246163fc9cSnatano  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
256163fc9cSnatano  * DISCLAIMED.  IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
266163fc9cSnatano  * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
276163fc9cSnatano  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
286163fc9cSnatano  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
296163fc9cSnatano  * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
306163fc9cSnatano  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
316163fc9cSnatano  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
326163fc9cSnatano  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
336163fc9cSnatano  * OF SUCH DAMAGE.
346163fc9cSnatano  */
356163fc9cSnatano /*
366163fc9cSnatano  * Copyright (c) 2001 Wasabi Systems, Inc.
376163fc9cSnatano  * All rights reserved.
386163fc9cSnatano  *
396163fc9cSnatano  * Written by Luke Mewburn for Wasabi Systems, Inc.
406163fc9cSnatano  *
416163fc9cSnatano  * Redistribution and use in source and binary forms, with or without
426163fc9cSnatano  * modification, are permitted provided that the following conditions
436163fc9cSnatano  * are met:
446163fc9cSnatano  * 1. Redistributions of source code must retain the above copyright
456163fc9cSnatano  *    notice, this list of conditions and the following disclaimer.
466163fc9cSnatano  * 2. Redistributions in binary form must reproduce the above copyright
476163fc9cSnatano  *    notice, this list of conditions and the following disclaimer in the
486163fc9cSnatano  *    documentation and/or other materials provided with the distribution.
496163fc9cSnatano  * 3. All advertising materials mentioning features or use of this software
506163fc9cSnatano  *    must display the following acknowledgement:
516163fc9cSnatano  *      This product includes software developed for the NetBSD Project by
526163fc9cSnatano  *      Wasabi Systems, Inc.
536163fc9cSnatano  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
546163fc9cSnatano  *    or promote products derived from this software without specific prior
556163fc9cSnatano  *    written permission.
566163fc9cSnatano  *
576163fc9cSnatano  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
586163fc9cSnatano  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
596163fc9cSnatano  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
606163fc9cSnatano  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
616163fc9cSnatano  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
626163fc9cSnatano  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
636163fc9cSnatano  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
646163fc9cSnatano  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
656163fc9cSnatano  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
666163fc9cSnatano  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
676163fc9cSnatano  * POSSIBILITY OF SUCH DAMAGE.
686163fc9cSnatano  */
696163fc9cSnatano /*
706163fc9cSnatano  * Copyright (c) 1982, 1986, 1989, 1993
716163fc9cSnatano  *	The Regents of the University of California.  All rights reserved.
726163fc9cSnatano  *
736163fc9cSnatano  * Redistribution and use in source and binary forms, with or without
746163fc9cSnatano  * modification, are permitted provided that the following conditions
756163fc9cSnatano  * are met:
766163fc9cSnatano  * 1. Redistributions of source code must retain the above copyright
776163fc9cSnatano  *    notice, this list of conditions and the following disclaimer.
786163fc9cSnatano  * 2. Redistributions in binary form must reproduce the above copyright
796163fc9cSnatano  *    notice, this list of conditions and the following disclaimer in the
806163fc9cSnatano  *    documentation and/or other materials provided with the distribution.
816163fc9cSnatano  * 3. Neither the name of the University nor the names of its contributors
826163fc9cSnatano  *    may be used to endorse or promote products derived from this software
836163fc9cSnatano  *    without specific prior written permission.
846163fc9cSnatano  *
856163fc9cSnatano  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
866163fc9cSnatano  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
876163fc9cSnatano  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
886163fc9cSnatano  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
896163fc9cSnatano  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
906163fc9cSnatano  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
916163fc9cSnatano  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
926163fc9cSnatano  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
936163fc9cSnatano  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
946163fc9cSnatano  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
956163fc9cSnatano  * SUCH DAMAGE.
966163fc9cSnatano  *
976163fc9cSnatano   */
986163fc9cSnatano 
996163fc9cSnatano #include <sys/queue.h>
1006163fc9cSnatano 
1016163fc9cSnatano #include <string.h>
1026163fc9cSnatano #include <ctype.h>
1036163fc9cSnatano #include <inttypes.h>
104299d8950Snatano #include <limits.h>
1056163fc9cSnatano 
1066163fc9cSnatano #include "makefs.h"
1076163fc9cSnatano #include "cd9660.h"
1086163fc9cSnatano #include "cd9660/iso9660_rrip.h"
1096163fc9cSnatano 
1106163fc9cSnatano /*
1116163fc9cSnatano  * Global variables
1126163fc9cSnatano  */
1136163fc9cSnatano 
1146163fc9cSnatano static void cd9660_finalize_PVD(iso9660_disk *);
1156163fc9cSnatano static cd9660node *cd9660_allocate_cd9660node(void);
1166163fc9cSnatano static void cd9660_set_defaults(iso9660_disk *);
1176163fc9cSnatano static int cd9660_arguments_set_string(const char *, const char *, size_t,
1186163fc9cSnatano     char, char *);
1196163fc9cSnatano static void cd9660_populate_iso_dir_record(
1206163fc9cSnatano     struct _iso_directory_record_cd9660 *, u_char, u_char, u_char,
1216163fc9cSnatano     const char *);
1226163fc9cSnatano static void cd9660_setup_root_node(iso9660_disk *);
1236163fc9cSnatano static int cd9660_setup_volume_descriptors(iso9660_disk *);
1246163fc9cSnatano #if 0
1256163fc9cSnatano static int cd9660_fill_extended_attribute_record(cd9660node *);
1266163fc9cSnatano #endif
1276163fc9cSnatano static void cd9660_sort_nodes(cd9660node *);
1286163fc9cSnatano static int cd9660_translate_node_common(iso9660_disk *, cd9660node *);
1296163fc9cSnatano static int cd9660_translate_node(iso9660_disk *, fsnode *, cd9660node *);
1306163fc9cSnatano static int cd9660_compare_filename(const char *, const char *);
1316163fc9cSnatano static void cd9660_sorted_child_insert(cd9660node *, cd9660node *);
1326163fc9cSnatano static int cd9660_handle_collisions(iso9660_disk *, cd9660node *, int);
1336163fc9cSnatano static cd9660node *cd9660_rename_filename(iso9660_disk *, cd9660node *, int,
1346163fc9cSnatano     int);
1356163fc9cSnatano static void cd9660_copy_filenames(iso9660_disk *, cd9660node *);
1366163fc9cSnatano static void cd9660_sorting_nodes(cd9660node *);
1376163fc9cSnatano static int cd9660_count_collisions(cd9660node *);
1386163fc9cSnatano static cd9660node *cd9660_rrip_move_directory(iso9660_disk *, cd9660node *);
1396163fc9cSnatano static int cd9660_add_dot_records(iso9660_disk *, cd9660node *);
1406163fc9cSnatano 
1416163fc9cSnatano static void cd9660_convert_structure(iso9660_disk *, fsnode *, cd9660node *, int,
1426163fc9cSnatano     int *, int *);
1436163fc9cSnatano static void cd9660_free_structure(cd9660node *);
1446163fc9cSnatano static int cd9660_generate_path_table(iso9660_disk *);
1456163fc9cSnatano static int cd9660_level1_convert_filename(iso9660_disk *, const char *, char *,
146d95291fdStedu     size_t, int);
1476163fc9cSnatano static int cd9660_level2_convert_filename(iso9660_disk *, const char *, char *,
148d95291fdStedu     size_t, int);
149d95291fdStedu static int cd9660_convert_filename(iso9660_disk *, const char *, char *, size_t, int);
1506163fc9cSnatano static void cd9660_populate_dot_records(iso9660_disk *, cd9660node *);
1516163fc9cSnatano static int64_t cd9660_compute_offsets(iso9660_disk *, cd9660node *, int64_t);
1526163fc9cSnatano #if 0
1536163fc9cSnatano static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int);
1546163fc9cSnatano #endif
1556163fc9cSnatano static cd9660node *cd9660_create_virtual_entry(iso9660_disk *, const char *,
1566163fc9cSnatano     cd9660node *, int, int);
1576163fc9cSnatano static cd9660node *cd9660_create_file(iso9660_disk *, const char *,
1586163fc9cSnatano     cd9660node *, cd9660node *);
1596163fc9cSnatano static cd9660node *cd9660_create_directory(iso9660_disk *, const char *,
1606163fc9cSnatano     cd9660node *, cd9660node *);
1616163fc9cSnatano static cd9660node *cd9660_create_special_directory(iso9660_disk *, u_char,
1626163fc9cSnatano     cd9660node *);
1636163fc9cSnatano static int  cd9660_add_generic_bootimage(iso9660_disk *, const char *);
1646163fc9cSnatano 
1656163fc9cSnatano 
1666163fc9cSnatano /*
1678e544e80Sjsg  * Allocate and initialize a cd9660node
1686163fc9cSnatano  * @returns struct cd9660node * Pointer to new node, or NULL on error
1696163fc9cSnatano  */
1706163fc9cSnatano static cd9660node *
1716163fc9cSnatano cd9660_allocate_cd9660node(void)
1726163fc9cSnatano {
1736163fc9cSnatano 	cd9660node *temp = ecalloc(1, sizeof(*temp));
1746163fc9cSnatano 	TAILQ_INIT(&temp->cn_children);
1756163fc9cSnatano 	temp->parent = temp->dot_record = temp->dot_dot_record = NULL;
1766163fc9cSnatano 	temp->ptnext = temp->ptprev = temp->ptlast = NULL;
1776163fc9cSnatano 	temp->node = NULL;
1786163fc9cSnatano 	temp->isoDirRecord = NULL;
1796163fc9cSnatano 	temp->isoExtAttributes = NULL;
1806163fc9cSnatano 	temp->rr_real_parent = temp->rr_relocated = NULL;
1816163fc9cSnatano 	temp->su_tail_data = NULL;
1826163fc9cSnatano 	return temp;
1836163fc9cSnatano }
1846163fc9cSnatano 
1856163fc9cSnatano int cd9660_defaults_set = 0;
1866163fc9cSnatano 
1876163fc9cSnatano /**
1886163fc9cSnatano * Set default values for cd9660 extension to makefs
1896163fc9cSnatano */
1906163fc9cSnatano static void
1916163fc9cSnatano cd9660_set_defaults(iso9660_disk *diskStructure)
1926163fc9cSnatano {
1936163fc9cSnatano 	/*Fix the sector size for now, though the spec allows for other sizes*/
1946163fc9cSnatano 	diskStructure->sectorSize = 2048;
1956163fc9cSnatano 
1966163fc9cSnatano 	/* Set up defaults in our own structure */
1976163fc9cSnatano 	diskStructure->isoLevel = 2;
1986163fc9cSnatano 
1996163fc9cSnatano 	diskStructure->rock_ridge_enabled = 0;
2006163fc9cSnatano 	diskStructure->rock_ridge_renamed_dir_name = 0;
2016163fc9cSnatano 	diskStructure->rock_ridge_move_count = 0;
2026163fc9cSnatano 	diskStructure->rr_moved_dir = 0;
2036163fc9cSnatano 
2046163fc9cSnatano 	diskStructure->include_padding_areas = 1;
2056163fc9cSnatano 
2066163fc9cSnatano 	/* Spec breaking functionality */
2076163fc9cSnatano 	diskStructure->allow_deep_trees =
2086163fc9cSnatano 	    diskStructure->allow_multidot =
2096163fc9cSnatano 	    diskStructure->omit_trailing_period = 0;
2106163fc9cSnatano 
2116163fc9cSnatano 	/* Make sure the PVD is clear */
2126163fc9cSnatano 	memset(&diskStructure->primaryDescriptor, 0, 2048);
2136163fc9cSnatano 
2146163fc9cSnatano 	memset(diskStructure->primaryDescriptor.publisher_id,	0x20,128);
2156163fc9cSnatano 	memset(diskStructure->primaryDescriptor.preparer_id,	0x20,128);
2166163fc9cSnatano 	memset(diskStructure->primaryDescriptor.application_id,	0x20,128);
2176163fc9cSnatano 	memset(diskStructure->primaryDescriptor.copyright_file_id, 0x20,37);
2186163fc9cSnatano 	memset(diskStructure->primaryDescriptor.abstract_file_id, 0x20,37);
2196163fc9cSnatano 	memset(diskStructure->primaryDescriptor.bibliographic_file_id, 0x20,37);
2206163fc9cSnatano 
221*493aa139Smillert 	strlcpy(diskStructure->primaryDescriptor.system_id,"OpenBSD", sizeof(diskStructure->primaryDescriptor.system_id));
2226163fc9cSnatano 
2236163fc9cSnatano 	cd9660_defaults_set = 1;
2246163fc9cSnatano 
2256163fc9cSnatano 	/* Boot support: Initially disabled */
2266163fc9cSnatano 	diskStructure->has_generic_bootimage = 0;
2276163fc9cSnatano 	diskStructure->generic_bootimage = NULL;
2286163fc9cSnatano 
2296163fc9cSnatano 	/*memset(diskStructure->boot_descriptor, 0, 2048);*/
2306163fc9cSnatano 
2316163fc9cSnatano 	diskStructure->is_bootable = 0;
2326163fc9cSnatano 	TAILQ_INIT(&diskStructure->boot_images);
2336163fc9cSnatano 	LIST_INIT(&diskStructure->boot_entries);
2346163fc9cSnatano }
2356163fc9cSnatano 
2366163fc9cSnatano void
2376163fc9cSnatano cd9660_prep_opts(fsinfo_t *fsopts)
2386163fc9cSnatano {
2396163fc9cSnatano 	iso9660_disk *diskStructure = ecalloc(1, sizeof(*diskStructure));
2406163fc9cSnatano 
24140854474Snatano #define OPT_STR(name)  \
24240854474Snatano 	{ name, NULL, OPT_STRBUF, 0, 0 }
2436163fc9cSnatano 
24440854474Snatano #define OPT_NUM(name, field, min, max) \
24513b03f79Snatano 	{ name, &diskStructure->field, \
2466163fc9cSnatano 	  sizeof(diskStructure->field) == 8 ? OPT_INT64 : \
2476163fc9cSnatano 	  (sizeof(diskStructure->field) == 4 ? OPT_INT32 : \
2486163fc9cSnatano 	  (sizeof(diskStructure->field) == 2 ? OPT_INT16 : OPT_INT8)), \
24940854474Snatano 	  min, max }
2506163fc9cSnatano 
25140854474Snatano #define OPT_BOOL(name, field) \
252e1a25d74Snatano 	{ name, &diskStructure->field, OPT_BOOL }
2536163fc9cSnatano 
2546163fc9cSnatano 	const option_t cd9660_options[] = {
25540854474Snatano 	        OPT_BOOL("allow-deep-trees", allow_deep_trees),
25640854474Snatano 	        OPT_BOOL("allow-multidot", allow_multidot),
25740854474Snatano 		OPT_STR("applicationid"),
25840854474Snatano 		OPT_STR("boot-load-segment"),
25940854474Snatano 		OPT_STR("bootimage"),
26040854474Snatano 		OPT_STR("generic-bootimage"),
26140854474Snatano 		OPT_STR("hard-disk-boot"),
26240854474Snatano 		OPT_NUM("isolevel", isoLevel, 1, 3),
26340854474Snatano 		OPT_STR("label"),
26440854474Snatano 		OPT_STR("no-boot"),
26540854474Snatano 		OPT_STR("no-emul-boot"),
26640854474Snatano 		OPT_BOOL("no-trailing-padding", include_padding_areas),
26740854474Snatano 	        OPT_BOOL("omit-trailing-period", omit_trailing_period),
26840854474Snatano 		OPT_STR("preparer"),
26940854474Snatano 		OPT_STR("publisher"),
27040854474Snatano 	        OPT_BOOL("rockridge", rock_ridge_enabled),
27140854474Snatano 		OPT_STR("volumeid"),
2726163fc9cSnatano 		{ .name = NULL }
2736163fc9cSnatano 	};
2746163fc9cSnatano 
2756163fc9cSnatano 	fsopts->fs_specific = diskStructure;
2766163fc9cSnatano 	fsopts->fs_options = copy_opts(cd9660_options);
2776163fc9cSnatano 
2786163fc9cSnatano 	cd9660_set_defaults(diskStructure);
2796163fc9cSnatano }
2806163fc9cSnatano 
2816163fc9cSnatano void
2826163fc9cSnatano cd9660_cleanup_opts(fsinfo_t *fsopts)
2836163fc9cSnatano {
2846163fc9cSnatano 	free(fsopts->fs_specific);
2856163fc9cSnatano 	free(fsopts->fs_options);
2866163fc9cSnatano }
2876163fc9cSnatano 
2886163fc9cSnatano static int
2896163fc9cSnatano cd9660_arguments_set_string(const char *val, const char *fieldtitle,
2906163fc9cSnatano     size_t length, char testmode, char * dest)
2916163fc9cSnatano {
2926163fc9cSnatano 	size_t len;
2936163fc9cSnatano 	int test;
2946163fc9cSnatano 
2956163fc9cSnatano 	if (val == NULL)
29640854474Snatano 		warnx("error: '%s' requires a string argument", fieldtitle);
2976163fc9cSnatano 	else if ((len = strlen(val)) <= length) {
2986163fc9cSnatano 		if (testmode == 'd')
2996163fc9cSnatano 			test = cd9660_valid_d_chars(val);
3006163fc9cSnatano 		else
3016163fc9cSnatano 			test = cd9660_valid_a_chars(val);
3026163fc9cSnatano 		if (test) {
3036163fc9cSnatano 			memcpy(dest, val, len);
3046163fc9cSnatano 			if (test == 2)
3056163fc9cSnatano 				cd9660_uppercase_characters(dest, len);
3066163fc9cSnatano 			return 1;
3076163fc9cSnatano 		} else
30840854474Snatano 			warnx("error: '%s' must be composed of %c-characters",
30940854474Snatano 			    fieldtitle, testmode);
3106163fc9cSnatano 	} else
31140854474Snatano 		warnx("error: '%s' must be at most 32 characters long",
3126163fc9cSnatano 		    fieldtitle);
3136163fc9cSnatano 	return 0;
3146163fc9cSnatano }
3156163fc9cSnatano 
3166163fc9cSnatano /*
3176163fc9cSnatano  * Command-line parsing function
3186163fc9cSnatano  */
3196163fc9cSnatano 
3206163fc9cSnatano int
3216163fc9cSnatano cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
3226163fc9cSnatano {
3236163fc9cSnatano 	int	rv, i;
3246163fc9cSnatano 	iso9660_disk *diskStructure = fsopts->fs_specific;
3256163fc9cSnatano 	option_t *cd9660_options = fsopts->fs_options;
3266163fc9cSnatano 	char buf[1024];
32740854474Snatano 	const char *name;
3286163fc9cSnatano 
3296163fc9cSnatano 	assert(option != NULL);
3306163fc9cSnatano 
3316163fc9cSnatano 	i = set_option(cd9660_options, option, buf, sizeof(buf));
3326163fc9cSnatano 	if (i == -1)
3336163fc9cSnatano 		return 0;
3346163fc9cSnatano 
3356163fc9cSnatano 	if (cd9660_options[i].name == NULL)
3366163fc9cSnatano 		abort();
3376163fc9cSnatano 
3386163fc9cSnatano 
3396163fc9cSnatano 	name = cd9660_options[i].name;
34013b03f79Snatano 
34113b03f79Snatano 	if (strcmp(name, "applicationid") == 0) {
34240854474Snatano 		rv = cd9660_arguments_set_string(buf, name, 128, 'a',
3436163fc9cSnatano 		    diskStructure->primaryDescriptor.application_id);
34413b03f79Snatano 	} else if (strcmp(name, "boot-load-segment") == 0) {
34513b03f79Snatano 		if (buf[0] == '\0') {
34613b03f79Snatano 			warnx("Option `%s' doesn't contain a value",
34713b03f79Snatano 			    name);
34813b03f79Snatano 			rv = 0;
34913b03f79Snatano 		} else {
35013b03f79Snatano 			cd9660_eltorito_add_boot_option(diskStructure,
35113b03f79Snatano 			    name, buf);
35213b03f79Snatano 			rv = 1;
35313b03f79Snatano 		}
35413b03f79Snatano 	} else if (strcmp(name, "bootimage") == 0) {
3556163fc9cSnatano 		if (buf[0] == '\0') {
3566163fc9cSnatano 			warnx("The Boot Image parameter requires a valid boot"
3576163fc9cSnatano 			" information string");
3586163fc9cSnatano 			rv = 0;
3596163fc9cSnatano 		} else
3606163fc9cSnatano 			rv = cd9660_add_boot_disk(diskStructure, buf);
36113b03f79Snatano 	} else if (strcmp(name, "generic-bootimage") == 0) {
36213b03f79Snatano 		if (buf[0] == '\0') {
36313b03f79Snatano 			warnx("The Generic Boot Image parameter requires a"
36413b03f79Snatano 			    " valid boot information string");
36513b03f79Snatano 			rv = 0;
36613b03f79Snatano 		} else
36713b03f79Snatano 			rv = cd9660_add_generic_bootimage(diskStructure, buf);
36813b03f79Snatano 	} else if (strcmp(name, "label") == 0) {
36940854474Snatano 		rv = cd9660_arguments_set_string(buf, name, 32, 'd',
37013b03f79Snatano 		    diskStructure->primaryDescriptor.volume_id);
37113b03f79Snatano 	} else if (strcmp(name, "preparer") == 0) {
37240854474Snatano 		rv = cd9660_arguments_set_string(buf, name, 128, 'a',
37313b03f79Snatano 		    diskStructure->primaryDescriptor.preparer_id);
37413b03f79Snatano 	} else if (strcmp(name, "publisher") == 0) {
37540854474Snatano 		rv = cd9660_arguments_set_string(buf, name, 128, 'a',
37613b03f79Snatano 		    diskStructure->primaryDescriptor.publisher_id);
37713b03f79Snatano 	} else if (strcmp(name, "volumeid") == 0) {
37840854474Snatano 		rv = cd9660_arguments_set_string(buf, name, 128, 'a',
37913b03f79Snatano 		    diskStructure->primaryDescriptor.volume_set_id);
38013b03f79Snatano 	} else if (strcmp(name, "hard-disk-boot") == 0 ||
3816163fc9cSnatano 	    strcmp(name, "no-boot") == 0 ||
38213b03f79Snatano 	    strcmp(name, "no-emul-boot") == 0) {
3836163fc9cSnatano 		/* RRIP */
3846163fc9cSnatano 		cd9660_eltorito_add_boot_option(diskStructure, name, 0);
3856163fc9cSnatano 		rv = 1;
3866163fc9cSnatano 	} else
3876163fc9cSnatano 		rv = 1;
38813b03f79Snatano 
3896163fc9cSnatano 	return rv;
3906163fc9cSnatano }
3916163fc9cSnatano 
3926163fc9cSnatano /*
3936163fc9cSnatano  * Main function for cd9660_makefs
3946163fc9cSnatano  * Builds the ISO image file
3956163fc9cSnatano  * @param const char *image The image filename to create
3966163fc9cSnatano  * @param const char *dir The directory that is being read
3976163fc9cSnatano  * @param struct fsnode *root The root node of the filesystem tree
3986163fc9cSnatano  * @param struct fsinfo_t *fsopts Any options
3996163fc9cSnatano  */
4006163fc9cSnatano void
4016163fc9cSnatano cd9660_makefs(const char *image, const char *dir, fsnode *root,
4026163fc9cSnatano     fsinfo_t *fsopts)
4036163fc9cSnatano {
4046163fc9cSnatano 	int64_t startoffset;
405c8f48d9bSyasuoka 	int ret, numDirectories;
4066163fc9cSnatano 	uint64_t pathTableSectors;
4076163fc9cSnatano 	int64_t firstAvailableSector;
4086163fc9cSnatano 	int64_t totalSpace;
4096163fc9cSnatano 	int error;
4106163fc9cSnatano 	cd9660node *real_root;
4116163fc9cSnatano 	iso9660_disk *diskStructure = fsopts->fs_specific;
4126163fc9cSnatano 
4136163fc9cSnatano 	if (diskStructure->isoLevel < 2 &&
4146163fc9cSnatano 	    diskStructure->allow_multidot)
415944eabd5Snatano 		errx(1, "allow-multidot requires iso level of 2");
4166163fc9cSnatano 
4176163fc9cSnatano 	assert(image != NULL);
4186163fc9cSnatano 	assert(dir != NULL);
4196163fc9cSnatano 	assert(root != NULL);
4206163fc9cSnatano 
4216163fc9cSnatano 	/* Set up some constants. Later, these will be defined with options */
4226163fc9cSnatano 
4236163fc9cSnatano 	/* Counter needed for path tables */
4246163fc9cSnatano 	numDirectories = 0;
4256163fc9cSnatano 
4266163fc9cSnatano 	/* Convert tree to our own format */
4276163fc9cSnatano 	/* Actually, we now need to add the REAL root node, at level 0 */
4286163fc9cSnatano 
4296163fc9cSnatano 	real_root = cd9660_allocate_cd9660node();
4306163fc9cSnatano 	real_root->isoDirRecord = emalloc(sizeof(*real_root->isoDirRecord));
4316163fc9cSnatano 	/* Leave filename blank for root */
4326163fc9cSnatano 	memset(real_root->isoDirRecord->name, 0,
4336163fc9cSnatano 	    ISO_FILENAME_MAXLENGTH_WITH_PADDING);
4346163fc9cSnatano 
4356163fc9cSnatano 	real_root->level = 0;
4366163fc9cSnatano 	diskStructure->rootNode = real_root;
4376163fc9cSnatano 	real_root->type = CD9660_TYPE_DIR;
4386163fc9cSnatano 	error = 0;
4396163fc9cSnatano 	real_root->node = root;
4406163fc9cSnatano 	cd9660_convert_structure(diskStructure, root, real_root, 1,
4416163fc9cSnatano 	    &numDirectories, &error);
4426163fc9cSnatano 
4436163fc9cSnatano 	if (TAILQ_EMPTY(&real_root->cn_children)) {
444944eabd5Snatano 		errx(1, "%s: converted directory is empty. "
4456163fc9cSnatano 		    "Tree conversion failed", __func__);
4466163fc9cSnatano 	} else if (error != 0) {
447944eabd5Snatano 		errx(1, "%s: tree conversion failed", __func__);
4486163fc9cSnatano 	}
4496163fc9cSnatano 
4506163fc9cSnatano 	/* Add the dot and dot dot records */
4516163fc9cSnatano 	cd9660_add_dot_records(diskStructure, real_root);
4526163fc9cSnatano 
4536163fc9cSnatano 	cd9660_setup_root_node(diskStructure);
4546163fc9cSnatano 
4556163fc9cSnatano 	/* Rock ridge / SUSP init pass */
4566163fc9cSnatano 	if (diskStructure->rock_ridge_enabled) {
4576163fc9cSnatano 		cd9660_susp_initialize(diskStructure, diskStructure->rootNode,
4586163fc9cSnatano 		    diskStructure->rootNode, NULL);
4596163fc9cSnatano 	}
4606163fc9cSnatano 
4616163fc9cSnatano 	/* Build path table structure */
4626163fc9cSnatano 	diskStructure->pathTableLength = cd9660_generate_path_table(
4636163fc9cSnatano 	    diskStructure);
4646163fc9cSnatano 
4656163fc9cSnatano 	pathTableSectors = CD9660_BLOCKS(diskStructure->sectorSize,
4666163fc9cSnatano 		diskStructure->pathTableLength);
4676163fc9cSnatano 
4686163fc9cSnatano 	firstAvailableSector = cd9660_setup_volume_descriptors(diskStructure);
4696163fc9cSnatano 	if (diskStructure->is_bootable) {
4706163fc9cSnatano 		firstAvailableSector = cd9660_setup_boot(diskStructure,
4716163fc9cSnatano 		    firstAvailableSector);
4726163fc9cSnatano 		if (firstAvailableSector < 0)
473944eabd5Snatano 			errx(1, "setup_boot failed");
4746163fc9cSnatano 	}
4756163fc9cSnatano 	/* LE first, then BE */
4766163fc9cSnatano 	diskStructure->primaryLittleEndianTableSector = firstAvailableSector;
4776163fc9cSnatano 	diskStructure->primaryBigEndianTableSector =
4786163fc9cSnatano 		diskStructure->primaryLittleEndianTableSector + pathTableSectors;
4796163fc9cSnatano 
4806163fc9cSnatano 	/* Set the secondary ones to -1, not going to use them for now */
4816163fc9cSnatano 	diskStructure->secondaryBigEndianTableSector = -1;
4826163fc9cSnatano 	diskStructure->secondaryLittleEndianTableSector = -1;
4836163fc9cSnatano 
4846163fc9cSnatano 	diskStructure->dataFirstSector =
4856163fc9cSnatano 	    diskStructure->primaryBigEndianTableSector + pathTableSectors;
4866163fc9cSnatano 
4876163fc9cSnatano 	startoffset = diskStructure->sectorSize*diskStructure->dataFirstSector;
4886163fc9cSnatano 
4896163fc9cSnatano 	totalSpace = cd9660_compute_offsets(diskStructure, real_root, startoffset);
4906163fc9cSnatano 
4916163fc9cSnatano 	diskStructure->totalSectors = diskStructure->dataFirstSector +
4926163fc9cSnatano 		CD9660_BLOCKS(diskStructure->sectorSize, totalSpace);
4936163fc9cSnatano 
4946163fc9cSnatano 	/* Disabled until pass 1 is done */
4956163fc9cSnatano 	if (diskStructure->rock_ridge_enabled) {
4966163fc9cSnatano 		diskStructure->susp_continuation_area_start_sector =
4976163fc9cSnatano 		    diskStructure->totalSectors;
4986163fc9cSnatano 		diskStructure->totalSectors +=
4996163fc9cSnatano 		    CD9660_BLOCKS(diskStructure->sectorSize,
5006163fc9cSnatano 			diskStructure->susp_continuation_area_size);
5016163fc9cSnatano 		cd9660_susp_finalize(diskStructure, diskStructure->rootNode);
5026163fc9cSnatano 	}
5036163fc9cSnatano 
5046163fc9cSnatano 
5056163fc9cSnatano 	cd9660_finalize_PVD(diskStructure);
5066163fc9cSnatano 
5076163fc9cSnatano 	/* Add padding sectors, just for testing purposes right now */
5086163fc9cSnatano 	/* diskStructure->totalSectors+=150; */
5096163fc9cSnatano 
5106163fc9cSnatano 	/*
5116163fc9cSnatano 	 * Add padding sectors at the end
5126163fc9cSnatano 	 * TODO: Clean this up and separate padding
5136163fc9cSnatano 	 */
5146163fc9cSnatano 	if (diskStructure->include_padding_areas)
5156163fc9cSnatano 		diskStructure->totalSectors += 150;
5166163fc9cSnatano 
517c8f48d9bSyasuoka 	ret = cd9660_write_image(diskStructure, image);
5186163fc9cSnatano 
5196163fc9cSnatano 	/* Clean up data structures */
5206163fc9cSnatano 	cd9660_free_structure(real_root);
521c8f48d9bSyasuoka 
522c8f48d9bSyasuoka 	if (ret == 0)	/* cd9660_write_image() failed */
523c8f48d9bSyasuoka 		exit(1);
5246163fc9cSnatano }
5256163fc9cSnatano 
5266163fc9cSnatano /* Generic function pointer - implement later */
5276163fc9cSnatano typedef int (*cd9660node_func)(cd9660node *);
5286163fc9cSnatano 
5296163fc9cSnatano static void
5306163fc9cSnatano cd9660_finalize_PVD(iso9660_disk *diskStructure)
5316163fc9cSnatano {
532bc67c994Snatano 	time_t tstamp = Tflag ? stampts : time(NULL);
5336163fc9cSnatano 
5346163fc9cSnatano 	/* root should be a fixed size of 34 bytes since it has no name */
5356163fc9cSnatano 	memcpy(diskStructure->primaryDescriptor.root_directory_record,
5366163fc9cSnatano 		diskStructure->rootNode->dot_record->isoDirRecord, 34);
5376163fc9cSnatano 
5386163fc9cSnatano 	/* In RRIP, this might be longer than 34 */
5396163fc9cSnatano 	diskStructure->primaryDescriptor.root_directory_record[0] = 34;
5406163fc9cSnatano 
5416163fc9cSnatano 	/* Set up all the important numbers in the PVD */
5426163fc9cSnatano 	cd9660_bothendian_dword(diskStructure->totalSectors,
5436163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.volume_space_size);
5446163fc9cSnatano 	cd9660_bothendian_word(1,
5456163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.volume_set_size);
5466163fc9cSnatano 	cd9660_bothendian_word(1,
5476163fc9cSnatano 	    (unsigned char *)
5486163fc9cSnatano 		diskStructure->primaryDescriptor.volume_sequence_number);
5496163fc9cSnatano 	cd9660_bothendian_word(diskStructure->sectorSize,
5506163fc9cSnatano 	    (unsigned char *)
5516163fc9cSnatano 		diskStructure->primaryDescriptor.logical_block_size);
5526163fc9cSnatano 	cd9660_bothendian_dword(diskStructure->pathTableLength,
5536163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.path_table_size);
5546163fc9cSnatano 
5556163fc9cSnatano 	cd9660_731(diskStructure->primaryLittleEndianTableSector,
5566163fc9cSnatano 		(u_char *)diskStructure->primaryDescriptor.type_l_path_table);
5576163fc9cSnatano 	cd9660_732(diskStructure->primaryBigEndianTableSector,
5586163fc9cSnatano 		(u_char *)diskStructure->primaryDescriptor.type_m_path_table);
5596163fc9cSnatano 
5606163fc9cSnatano 	diskStructure->primaryDescriptor.file_structure_version[0] = 1;
5616163fc9cSnatano 
5626163fc9cSnatano 	/* Pad all strings with spaces instead of nulls */
5636163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_id, 32);
5646163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.system_id, 32);
5656163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.volume_set_id,
5666163fc9cSnatano 	    128);
5676163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.publisher_id,
5686163fc9cSnatano 	    128);
5696163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.preparer_id,
5706163fc9cSnatano 	    128);
5716163fc9cSnatano 	cd9660_pad_string_spaces(diskStructure->primaryDescriptor.application_id,
5726163fc9cSnatano 	    128);
5736163fc9cSnatano 	cd9660_pad_string_spaces(
5746163fc9cSnatano 	    diskStructure->primaryDescriptor.copyright_file_id, 37);
5756163fc9cSnatano 	cd9660_pad_string_spaces(
5766163fc9cSnatano 		diskStructure->primaryDescriptor.abstract_file_id, 37);
5776163fc9cSnatano 	cd9660_pad_string_spaces(
5786163fc9cSnatano 		diskStructure->primaryDescriptor.bibliographic_file_id, 37);
5796163fc9cSnatano 
5806163fc9cSnatano 	/* Setup dates */
5816163fc9cSnatano 	cd9660_time_8426(
5826163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.creation_date,
5836163fc9cSnatano 	    tstamp);
5846163fc9cSnatano 	cd9660_time_8426(
5856163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.modification_date,
5866163fc9cSnatano 	    tstamp);
5876163fc9cSnatano 
5886163fc9cSnatano #if 0
5896163fc9cSnatano 	cd9660_set_date(diskStructure->primaryDescriptor.expiration_date,
5906163fc9cSnatano 	    tstamp);
5916163fc9cSnatano #endif
5926163fc9cSnatano 	memset(diskStructure->primaryDescriptor.expiration_date, '0' ,16);
5936163fc9cSnatano 	diskStructure->primaryDescriptor.expiration_date[16] = 0;
5946163fc9cSnatano 
5956163fc9cSnatano 	cd9660_time_8426(
5966163fc9cSnatano 	    (unsigned char *)diskStructure->primaryDescriptor.effective_date,
5976163fc9cSnatano 	    tstamp);
5986163fc9cSnatano }
5996163fc9cSnatano 
6006163fc9cSnatano static void
6016163fc9cSnatano cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record,
6026163fc9cSnatano 			       u_char ext_attr_length, u_char flags,
6036163fc9cSnatano 			       u_char name_len, const char * name)
6046163fc9cSnatano {
6056163fc9cSnatano 	record->ext_attr_length[0] = ext_attr_length;
6066163fc9cSnatano 	record->flags[0] = ISO_FLAG_CLEAR | flags;
6076163fc9cSnatano 	record->file_unit_size[0] = 0;
6086163fc9cSnatano 	record->interleave[0] = 0;
6096163fc9cSnatano 	cd9660_bothendian_word(1, record->volume_sequence_number);
6106163fc9cSnatano 	record->name_len[0] = name_len;
6116163fc9cSnatano 	memset(record->name, '\0', sizeof (record->name));
6126163fc9cSnatano 	memcpy(record->name, name, name_len);
6136163fc9cSnatano 	record->length[0] = 33 + name_len;
6146163fc9cSnatano 
6156163fc9cSnatano 	/* Todo : better rounding */
6166163fc9cSnatano 	record->length[0] += (record->length[0] & 1) ? 1 : 0;
6176163fc9cSnatano }
6186163fc9cSnatano 
6196163fc9cSnatano static void
6206163fc9cSnatano cd9660_setup_root_node(iso9660_disk *diskStructure)
6216163fc9cSnatano {
6226163fc9cSnatano 	cd9660_populate_iso_dir_record(diskStructure->rootNode->isoDirRecord,
6236163fc9cSnatano 	    0, ISO_FLAG_DIRECTORY, 1, "\0");
6246163fc9cSnatano 
6256163fc9cSnatano }
6266163fc9cSnatano 
6276163fc9cSnatano /*********** SUPPORT FUNCTIONS ***********/
6286163fc9cSnatano static int
6296163fc9cSnatano cd9660_setup_volume_descriptors(iso9660_disk *diskStructure)
6306163fc9cSnatano {
6316163fc9cSnatano 	/* Boot volume descriptor should come second */
6326163fc9cSnatano 	int sector = 16;
6336163fc9cSnatano 	/* For now, a fixed 2 : PVD and terminator */
6346163fc9cSnatano 	volume_descriptor *temp, *t;
6356163fc9cSnatano 
6366163fc9cSnatano 	/* Set up the PVD */
6376163fc9cSnatano 	temp = emalloc(sizeof(*temp));
6386163fc9cSnatano 	temp->volumeDescriptorData =
6396163fc9cSnatano 	   (unsigned char *)&diskStructure->primaryDescriptor;
6406163fc9cSnatano 	temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD;
6416163fc9cSnatano 	temp->volumeDescriptorData[6] = 1;
6426163fc9cSnatano 	temp->sector = sector;
6436163fc9cSnatano 	memcpy(temp->volumeDescriptorData + 1,
6446163fc9cSnatano 	    ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
6456163fc9cSnatano 	diskStructure->firstVolumeDescriptor = temp;
6466163fc9cSnatano 
6476163fc9cSnatano 	sector++;
6486163fc9cSnatano 	/* Set up boot support if enabled. BVD must reside in sector 17 */
6496163fc9cSnatano 	if (diskStructure->is_bootable) {
6506163fc9cSnatano 		t = emalloc(sizeof(*t));
6516163fc9cSnatano 		t->volumeDescriptorData = ecalloc(1, 2048);
6526163fc9cSnatano 		temp->next = t;
6536163fc9cSnatano 		temp = t;
6546163fc9cSnatano 		t->sector = 17;
6556163fc9cSnatano 		cd9660_setup_boot_volume_descriptor(diskStructure, t);
6566163fc9cSnatano 		sector++;
6576163fc9cSnatano 	}
6586163fc9cSnatano 
6596163fc9cSnatano 	/* Set up the terminator */
6606163fc9cSnatano 	t = emalloc(sizeof(*t));
6616163fc9cSnatano 	t->volumeDescriptorData = ecalloc(1, 2048);
6626163fc9cSnatano 	temp->next = t;
6636163fc9cSnatano 	t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR;
6646163fc9cSnatano 	t->next = 0;
6656163fc9cSnatano 	t->volumeDescriptorData[6] = 1;
6666163fc9cSnatano 	t->sector = sector;
6676163fc9cSnatano 	memcpy(t->volumeDescriptorData + 1,
6686163fc9cSnatano 	    ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
6696163fc9cSnatano 
6706163fc9cSnatano 	sector++;
6716163fc9cSnatano 	return sector;
6726163fc9cSnatano }
6736163fc9cSnatano 
6746163fc9cSnatano #if 0
6756163fc9cSnatano /*
6766163fc9cSnatano  * Populate EAR at some point. Not required, but is used by NetBSD's
6776163fc9cSnatano  * cd9660 support
6786163fc9cSnatano  */
6796163fc9cSnatano static int
6806163fc9cSnatano cd9660_fill_extended_attribute_record(cd9660node *node)
6816163fc9cSnatano {
6826163fc9cSnatano 	node->isoExtAttributes = emalloc(sizeof(*node->isoExtAttributes));
6836163fc9cSnatano 	return 1;
6846163fc9cSnatano }
6856163fc9cSnatano #endif
6866163fc9cSnatano 
6876163fc9cSnatano static int
6886163fc9cSnatano cd9660_translate_node_common(iso9660_disk *diskStructure, cd9660node *newnode)
6896163fc9cSnatano {
690bc67c994Snatano 	time_t tstamp = Tflag ? stampts : time(NULL);
6916163fc9cSnatano 	u_char flag;
6926163fc9cSnatano 	char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
6936163fc9cSnatano 
6946163fc9cSnatano 	/* Now populate the isoDirRecord structure */
6956163fc9cSnatano 	memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
6966163fc9cSnatano 
6976163fc9cSnatano 	(void)cd9660_convert_filename(diskStructure, newnode->node->name,
698d95291fdStedu 	    temp, sizeof temp, !(S_ISDIR(newnode->node->type)));
6996163fc9cSnatano 
7006163fc9cSnatano 	flag = ISO_FLAG_CLEAR;
7016163fc9cSnatano 	if (S_ISDIR(newnode->node->type))
7026163fc9cSnatano 		flag |= ISO_FLAG_DIRECTORY;
7036163fc9cSnatano 
7046163fc9cSnatano 	cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0,
7056163fc9cSnatano 	    flag, strlen(temp), temp);
7066163fc9cSnatano 
7076163fc9cSnatano 	/* Set the various dates */
7086163fc9cSnatano 
7096163fc9cSnatano 	/* If we want to use the current date and time */
7106163fc9cSnatano 
7116163fc9cSnatano 	cd9660_time_915(newnode->isoDirRecord->date, tstamp);
7126163fc9cSnatano 
7136163fc9cSnatano 	cd9660_bothendian_dword(newnode->fileDataLength,
7146163fc9cSnatano 	    newnode->isoDirRecord->size);
7156163fc9cSnatano 	/* If the file is a link, we want to set the size to 0 */
7166163fc9cSnatano 	if (S_ISLNK(newnode->node->type))
7176163fc9cSnatano 		newnode->fileDataLength = 0;
7186163fc9cSnatano 
7196163fc9cSnatano 	return 1;
7206163fc9cSnatano }
7216163fc9cSnatano 
7226163fc9cSnatano /*
7236163fc9cSnatano  * Translate fsnode to cd9660node
7246163fc9cSnatano  * Translate filenames and other metadata, including dates, sizes,
7256163fc9cSnatano  * permissions, etc
7266163fc9cSnatano  * @param struct fsnode * The node generated by makefs
7276163fc9cSnatano  * @param struct cd9660node * The intermediate node to be written to
7286163fc9cSnatano  * @returns int 0 on failure, 1 on success
7296163fc9cSnatano  */
7306163fc9cSnatano static int
7316163fc9cSnatano cd9660_translate_node(iso9660_disk *diskStructure, fsnode *node,
7326163fc9cSnatano     cd9660node *newnode)
7336163fc9cSnatano {
73477bbe232Snatano 	if (node == NULL)
7356163fc9cSnatano 		return 0;
73677bbe232Snatano 
7376163fc9cSnatano 	newnode->isoDirRecord = emalloc(sizeof(*newnode->isoDirRecord));
7386163fc9cSnatano 	/* Set the node pointer */
7396163fc9cSnatano 	newnode->node = node;
7406163fc9cSnatano 
7416163fc9cSnatano 	/* Set the size */
7426163fc9cSnatano 	if (!(S_ISDIR(node->type)))
7436163fc9cSnatano 		newnode->fileDataLength = node->inode->st.st_size;
7446163fc9cSnatano 
7456163fc9cSnatano 	if (cd9660_translate_node_common(diskStructure, newnode) == 0)
7466163fc9cSnatano 		return 0;
7476163fc9cSnatano 
7486163fc9cSnatano 	/* Finally, overwrite some of the values that are set by default */
7496163fc9cSnatano 	cd9660_time_915(newnode->isoDirRecord->date,
750bc67c994Snatano 	    Tflag ? stampts : node->inode->st.st_mtime);
7516163fc9cSnatano 
7526163fc9cSnatano 	return 1;
7536163fc9cSnatano }
7546163fc9cSnatano 
7556163fc9cSnatano /*
7566163fc9cSnatano  * Compares two ISO filenames
7576163fc9cSnatano  * @param const char * The first file name
7586163fc9cSnatano  * @param const char * The second file name
7596163fc9cSnatano  * @returns : -1 if first is less than second, 0 if they are the same, 1 if
7606163fc9cSnatano  *	the second is greater than the first
7616163fc9cSnatano  */
7626163fc9cSnatano static int
7636163fc9cSnatano cd9660_compare_filename(const char *first, const char *second)
7646163fc9cSnatano {
7656163fc9cSnatano 	/*
7666163fc9cSnatano 	 * This can be made more optimal once it has been tested
7676163fc9cSnatano 	 * (the extra character, for example, is for testing)
7686163fc9cSnatano 	 */
7696163fc9cSnatano 
7706163fc9cSnatano 	int p1 = 0;
7716163fc9cSnatano 	int p2 = 0;
7726163fc9cSnatano 	char c1, c2;
7736163fc9cSnatano 	/* First, on the filename */
7746163fc9cSnatano 
7756163fc9cSnatano 	while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1
7766163fc9cSnatano 		&& p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) {
7776163fc9cSnatano 		c1 = first[p1];
7786163fc9cSnatano 		c2 = second[p2];
7796163fc9cSnatano 		if (c1 == '.' && c2 =='.')
7806163fc9cSnatano 			break;
7816163fc9cSnatano 		else if (c1 == '.') {
7826163fc9cSnatano 			p2++;
7836163fc9cSnatano 			c1 = ' ';
7846163fc9cSnatano 		} else if (c2 == '.') {
7856163fc9cSnatano 			p1++;
7866163fc9cSnatano 			c2 = ' ';
7876163fc9cSnatano 		} else {
7886163fc9cSnatano 			p1++;
7896163fc9cSnatano 			p2++;
7906163fc9cSnatano 		}
7916163fc9cSnatano 
7926163fc9cSnatano 		if (c1 < c2)
7936163fc9cSnatano 			return -1;
7946163fc9cSnatano 		else if (c1 > c2) {
7956163fc9cSnatano 			return 1;
7966163fc9cSnatano 		}
7976163fc9cSnatano 	}
7986163fc9cSnatano 
7996163fc9cSnatano 	if (first[p1] == '.' && second[p2] == '.') {
8006163fc9cSnatano 		p1++;
8016163fc9cSnatano 		p2++;
8026163fc9cSnatano 		while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1
8036163fc9cSnatano 			&& p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) {
8046163fc9cSnatano 			c1 = first[p1];
8056163fc9cSnatano 			c2 = second[p2];
8066163fc9cSnatano 			if (c1 == ';' && c2 == ';')
8076163fc9cSnatano 				break;
8086163fc9cSnatano 			else if (c1 == ';') {
8096163fc9cSnatano 				p2++;
8106163fc9cSnatano 				c1 = ' ';
8116163fc9cSnatano 			} else if (c2 == ';') {
8126163fc9cSnatano 				p1++;
8136163fc9cSnatano 				c2 = ' ';
8146163fc9cSnatano 			} else {
8156163fc9cSnatano 				p1++;
8166163fc9cSnatano 				p2++;
8176163fc9cSnatano 			}
8186163fc9cSnatano 
8196163fc9cSnatano 			if (c1 < c2)
8206163fc9cSnatano 				return -1;
8216163fc9cSnatano 			else if (c1 > c2)
8226163fc9cSnatano 				return 1;
8236163fc9cSnatano 		}
8246163fc9cSnatano 	}
8256163fc9cSnatano 	return 0;
8266163fc9cSnatano }
8276163fc9cSnatano 
8286163fc9cSnatano /*
8296163fc9cSnatano  * Insert a node into list with ISO sorting rules
8306163fc9cSnatano  * @param cd9660node * The head node of the list
8316163fc9cSnatano  * @param cd9660node * The node to be inserted
8326163fc9cSnatano  */
8336163fc9cSnatano static void
8346163fc9cSnatano cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new)
8356163fc9cSnatano {
8366163fc9cSnatano 	int compare;
8376163fc9cSnatano 	cd9660node *cn;
8386163fc9cSnatano 	struct cd9660_children_head *head = &parent->cn_children;
8396163fc9cSnatano 
8406163fc9cSnatano 	/* TODO: Optimize? */
8416163fc9cSnatano 	cn_new->parent = parent;
8426163fc9cSnatano 
8436163fc9cSnatano 	/*
8446163fc9cSnatano 	 * first will either be 0, the . or the ..
8456163fc9cSnatano 	 * if . or .., this means no other entry may be written before first
8466163fc9cSnatano 	 * if 0, the new node may be inserted at the head
8476163fc9cSnatano 	 */
8486163fc9cSnatano 
8496163fc9cSnatano 	TAILQ_FOREACH(cn, head, cn_next_child) {
8506163fc9cSnatano 		/*
8516163fc9cSnatano 		 * Dont insert a node twice -
8526163fc9cSnatano 		 * that would cause an infinite loop
8536163fc9cSnatano 		 */
8546163fc9cSnatano 		if (cn_new == cn)
8556163fc9cSnatano 			return;
8566163fc9cSnatano 
8576163fc9cSnatano 		compare = cd9660_compare_filename(cn_new->isoDirRecord->name,
8586163fc9cSnatano 			cn->isoDirRecord->name);
8596163fc9cSnatano 
8606163fc9cSnatano 		if (compare == 0)
8616163fc9cSnatano 			compare = cd9660_compare_filename(cn_new->node->name,
8626163fc9cSnatano 				cn->node->name);
8636163fc9cSnatano 
8646163fc9cSnatano 		if (compare < 0)
8656163fc9cSnatano 			break;
8666163fc9cSnatano 	}
8676163fc9cSnatano 	if (cn == NULL)
8686163fc9cSnatano 		TAILQ_INSERT_TAIL(head, cn_new, cn_next_child);
8696163fc9cSnatano 	else
8706163fc9cSnatano 		TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child);
8716163fc9cSnatano }
8726163fc9cSnatano 
8736163fc9cSnatano /*
8746163fc9cSnatano  * Called After cd9660_sorted_child_insert
8758e544e80Sjsg  * handles file collisions by suffixing each filename with ~n
8766163fc9cSnatano  * where n represents the files respective place in the ordering
8776163fc9cSnatano  */
8786163fc9cSnatano static int
8796163fc9cSnatano cd9660_handle_collisions(iso9660_disk *diskStructure, cd9660node *colliding,
8806163fc9cSnatano     int past)
8816163fc9cSnatano {
8826163fc9cSnatano 	cd9660node *iter, *next, *prev;
8836163fc9cSnatano 	int skip;
8846163fc9cSnatano 	int delete_chars = 0;
8856163fc9cSnatano 	int temp_past = past;
8866163fc9cSnatano 	int temp_skip;
8876163fc9cSnatano 	int flag = 0;
8886163fc9cSnatano 	cd9660node *end_of_range;
8896163fc9cSnatano 
8906163fc9cSnatano 	for (iter = TAILQ_FIRST(&colliding->cn_children);
8916163fc9cSnatano 	     iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) {
8926163fc9cSnatano 		if (strcmp(iter->isoDirRecord->name,
8936163fc9cSnatano 		           next->isoDirRecord->name) != 0) {
8946163fc9cSnatano 			iter = TAILQ_NEXT(iter, cn_next_child);
8956163fc9cSnatano 			continue;
8966163fc9cSnatano 		}
8976163fc9cSnatano 		flag = 1;
8986163fc9cSnatano 		temp_skip = skip = cd9660_count_collisions(iter);
8996163fc9cSnatano 		end_of_range = iter;
9006163fc9cSnatano 		while (temp_skip > 0) {
9016163fc9cSnatano 			temp_skip--;
9026163fc9cSnatano 			end_of_range = TAILQ_NEXT(end_of_range, cn_next_child);
9036163fc9cSnatano 		}
9046163fc9cSnatano 		temp_past = past;
9056163fc9cSnatano 		while (temp_past > 0) {
9066163fc9cSnatano 			if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL)
9076163fc9cSnatano 				end_of_range = next;
9086163fc9cSnatano 			else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL)
9096163fc9cSnatano 				iter = prev;
9106163fc9cSnatano 			else
9116163fc9cSnatano 				delete_chars++;
9126163fc9cSnatano 			temp_past--;
9136163fc9cSnatano 		}
9146163fc9cSnatano 		skip += past;
9156163fc9cSnatano 		iter = cd9660_rename_filename(diskStructure, iter, skip,
9166163fc9cSnatano 		    delete_chars);
9176163fc9cSnatano 	}
9186163fc9cSnatano 	return flag;
9196163fc9cSnatano }
9206163fc9cSnatano 
9216163fc9cSnatano 
9226163fc9cSnatano static cd9660node *
9236163fc9cSnatano cd9660_rename_filename(iso9660_disk *diskStructure, cd9660node *iter, int num,
9246163fc9cSnatano     int delete_chars)
9256163fc9cSnatano {
9266163fc9cSnatano 	int i = 0;
9276163fc9cSnatano 	int numbts, dot, semi, digit, digits, temp, powers, multiplier, count;
9286163fc9cSnatano 	char *naming;
9296163fc9cSnatano 	int maxlength;
9306163fc9cSnatano         char *tmp;
9316163fc9cSnatano 
9326163fc9cSnatano 	/* TODO : A LOT of chanes regarding 8.3 filenames */
9336163fc9cSnatano 	if (diskStructure->isoLevel == 1)
9346163fc9cSnatano 		maxlength = 8;
9356163fc9cSnatano 	else if (diskStructure->isoLevel == 2)
9366163fc9cSnatano 		maxlength = 31;
9376163fc9cSnatano 	else
9386163fc9cSnatano 		maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION;
9396163fc9cSnatano 
9406163fc9cSnatano 	tmp = emalloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING);
9416163fc9cSnatano 
9424e4cca72Snatano 	while (i < num && iter) {
9436163fc9cSnatano 		powers = 1;
9446163fc9cSnatano 		count = 0;
9456163fc9cSnatano 		digits = 1;
9466163fc9cSnatano 		multiplier = 1;
9476163fc9cSnatano 		while (((int)(i / powers) ) >= 10) {
9486163fc9cSnatano 			digits++;
9496163fc9cSnatano 			powers = powers * 10;
9506163fc9cSnatano 		}
9516163fc9cSnatano 
9526163fc9cSnatano 		naming = iter->o_name;
9536163fc9cSnatano 
9546163fc9cSnatano 		/*
9556163fc9cSnatano 		while ((*naming != '.') && (*naming != ';')) {
9566163fc9cSnatano 			naming++;
9576163fc9cSnatano 			count++;
9586163fc9cSnatano 		}
9596163fc9cSnatano 		*/
9606163fc9cSnatano 
9616163fc9cSnatano 		dot = -1;
9626163fc9cSnatano 		semi = -1;
9636163fc9cSnatano 		while (count < maxlength) {
9646163fc9cSnatano 			if (*naming == '.')
9656163fc9cSnatano 				dot = count;
9666163fc9cSnatano 			else if (*naming == ';') {
9676163fc9cSnatano 				semi = count;
9686163fc9cSnatano 				break;
9696163fc9cSnatano 			}
9706163fc9cSnatano 			naming++;
9716163fc9cSnatano 			count++;
9726163fc9cSnatano 		}
9736163fc9cSnatano 
9746163fc9cSnatano 		if ((count + digits) < maxlength)
9756163fc9cSnatano 			numbts = count;
9766163fc9cSnatano 		else
9776163fc9cSnatano 			numbts = maxlength - (digits);
9786163fc9cSnatano 		numbts -= delete_chars;
9796163fc9cSnatano 
9806163fc9cSnatano 		/* 8.3 rules - keep the extension, add before the dot */
9816163fc9cSnatano 
9826163fc9cSnatano 		/*
9836163fc9cSnatano 		 * This code makes a bunch of assumptions.
9846163fc9cSnatano 		 * See if you can spot them all :)
9856163fc9cSnatano 		 */
9866163fc9cSnatano 
9876163fc9cSnatano #if 0
9886163fc9cSnatano 		if (diskStructure->isoLevel == 1) {
9896163fc9cSnatano 			numbts = 8 - digits - delete_chars;
9906163fc9cSnatano 			if (dot < 0) {
9916163fc9cSnatano 
9926163fc9cSnatano 			} else {
9936163fc9cSnatano 				if (dot < 8) {
9946163fc9cSnatano 					memmove(&tmp[numbts],&tmp[dot],4);
9956163fc9cSnatano 				}
9966163fc9cSnatano 			}
9976163fc9cSnatano 		}
9986163fc9cSnatano #else
9996163fc9cSnatano 		(void)dot;
10006163fc9cSnatano 		(void)semi;
10016163fc9cSnatano 		(void)multiplier;
10026163fc9cSnatano #endif
10036163fc9cSnatano 
10046163fc9cSnatano 		/* (copying just the filename before the '.' */
10056163fc9cSnatano 		memcpy(tmp, (iter->o_name), numbts);
10066163fc9cSnatano 
10076163fc9cSnatano 		/* adding the appropriate number following the name */
10086163fc9cSnatano 		temp = i;
10096163fc9cSnatano 		while (digits > 0) {
10106163fc9cSnatano 			digit = (int)(temp / powers);
10116163fc9cSnatano 			temp = temp - digit * powers;
1012d95291fdStedu 			snprintf(&tmp[numbts] , ISO_FILENAME_MAXLENGTH_WITH_PADDING - numbts, "%d", digit);
10136163fc9cSnatano 			digits--;
10146163fc9cSnatano 			numbts++;
10156163fc9cSnatano 			powers = powers / 10;
10166163fc9cSnatano 		}
10176163fc9cSnatano 
10186163fc9cSnatano 		while ((*naming != ';')  && (numbts < maxlength)) {
10196163fc9cSnatano 			tmp[numbts] = (*naming);
10206163fc9cSnatano 			naming++;
10216163fc9cSnatano 			numbts++;
10226163fc9cSnatano 		}
10236163fc9cSnatano 
10246163fc9cSnatano 		tmp[numbts] = ';';
10256163fc9cSnatano 		tmp[numbts+1] = '1';
10266163fc9cSnatano 		tmp[numbts+2] = '\0';
10276163fc9cSnatano 
10286163fc9cSnatano 		/*
10296163fc9cSnatano 		 * now tmp has exactly the identifier
10306163fc9cSnatano 		 * we want so we'll copy it back to record
10316163fc9cSnatano 		 */
10326163fc9cSnatano 		memcpy((iter->isoDirRecord->name), tmp, numbts + 3);
10336163fc9cSnatano 
10346163fc9cSnatano 		iter = TAILQ_NEXT(iter, cn_next_child);
10356163fc9cSnatano 		i++;
10366163fc9cSnatano 	}
10376163fc9cSnatano 
10386163fc9cSnatano 	free(tmp);
10396163fc9cSnatano 	return iter;
10406163fc9cSnatano }
10416163fc9cSnatano 
10426163fc9cSnatano /* Todo: Figure out why these functions are nec. */
10436163fc9cSnatano static void
10446163fc9cSnatano cd9660_copy_filenames(iso9660_disk *diskStructure, cd9660node *node)
10456163fc9cSnatano {
10466163fc9cSnatano 	cd9660node *cn;
10476163fc9cSnatano 
10486163fc9cSnatano 	if (TAILQ_EMPTY(&node->cn_children))
10496163fc9cSnatano 		return;
10506163fc9cSnatano 
10516163fc9cSnatano 	if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) {
10526163fc9cSnatano 		debug_print_tree(diskStructure, diskStructure->rootNode, 0);
10536163fc9cSnatano 		exit(1);
10546163fc9cSnatano 	}
10556163fc9cSnatano 
10566163fc9cSnatano 	TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
10576163fc9cSnatano 		cd9660_copy_filenames(diskStructure, cn);
10586163fc9cSnatano 		memcpy(cn->o_name, cn->isoDirRecord->name,
10596163fc9cSnatano 		    ISO_FILENAME_MAXLENGTH_WITH_PADDING);
10606163fc9cSnatano 	}
10616163fc9cSnatano }
10626163fc9cSnatano 
10636163fc9cSnatano static void
10646163fc9cSnatano cd9660_sorting_nodes(cd9660node *node)
10656163fc9cSnatano {
10666163fc9cSnatano 	cd9660node *cn;
10676163fc9cSnatano 
10686163fc9cSnatano 	TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
10696163fc9cSnatano 		cd9660_sorting_nodes(cn);
10706163fc9cSnatano 	cd9660_sort_nodes(node);
10716163fc9cSnatano }
10726163fc9cSnatano 
10736163fc9cSnatano /* XXX Bubble sort. */
10746163fc9cSnatano static void
10756163fc9cSnatano cd9660_sort_nodes(cd9660node *node)
10766163fc9cSnatano {
10776163fc9cSnatano 	cd9660node *cn, *next;
10786163fc9cSnatano 
10796163fc9cSnatano 	do {
10806163fc9cSnatano 		TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
10816163fc9cSnatano 			if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL)
10826163fc9cSnatano 				return;
10836163fc9cSnatano 			else if (strcmp(next->isoDirRecord->name,
10846163fc9cSnatano 				        cn->isoDirRecord->name) >= 0)
10856163fc9cSnatano 				continue;
10866163fc9cSnatano 			TAILQ_REMOVE(&node->cn_children, next, cn_next_child);
10876163fc9cSnatano 			TAILQ_INSERT_BEFORE(cn, next, cn_next_child);
10886163fc9cSnatano 			break;
10896163fc9cSnatano 		}
10906163fc9cSnatano 	} while (cn != NULL);
10916163fc9cSnatano }
10926163fc9cSnatano 
10936163fc9cSnatano static int
10946163fc9cSnatano cd9660_count_collisions(cd9660node *copy)
10956163fc9cSnatano {
10966163fc9cSnatano 	int count = 0;
10976163fc9cSnatano 	cd9660node *iter, *next;
10986163fc9cSnatano 
10996163fc9cSnatano 	for (iter = copy;
11006163fc9cSnatano 	     (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;
11016163fc9cSnatano 	     iter = next) {
11026163fc9cSnatano 		if (cd9660_compare_filename(iter->isoDirRecord->name,
11036163fc9cSnatano 			next->isoDirRecord->name) == 0)
11046163fc9cSnatano 			count++;
11056163fc9cSnatano 		else
11066163fc9cSnatano 			return count;
11076163fc9cSnatano 	}
11086163fc9cSnatano #if 0
11096163fc9cSnatano 	if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) {
11106163fc9cSnatano 		printf("%s: count is %i \n", __func__, count);
11116163fc9cSnatano 		compare = cd9660_compare_filename(iter->isoDirRecord->name,
11126163fc9cSnatano 			next->isoDirRecord->name);
11136163fc9cSnatano 		if (compare == 0) {
11146163fc9cSnatano 			count++;
11156163fc9cSnatano 			return cd9660_recurse_on_collision(next, count);
11166163fc9cSnatano 		} else
11176163fc9cSnatano 			return count;
11186163fc9cSnatano 	}
11196163fc9cSnatano #endif
11206163fc9cSnatano 	return count;
11216163fc9cSnatano }
11226163fc9cSnatano 
11236163fc9cSnatano static cd9660node *
11246163fc9cSnatano cd9660_rrip_move_directory(iso9660_disk *diskStructure, cd9660node *dir)
11256163fc9cSnatano {
11266163fc9cSnatano 	char newname[9];
11276163fc9cSnatano 	cd9660node *tfile;
11286163fc9cSnatano 
11296163fc9cSnatano 	/*
11306163fc9cSnatano 	 * This function needs to:
11316163fc9cSnatano 	 * 1) Create an empty virtual file in place of the old directory
11326163fc9cSnatano 	 * 2) Point the virtual file to the new directory
11336163fc9cSnatano 	 * 3) Point the relocated directory to its old parent
11346163fc9cSnatano 	 * 4) Move the directory specified by dir into rr_moved_dir,
11356163fc9cSnatano 	 * and rename it to "diskStructure->rock_ridge_move_count" (as a string)
11366163fc9cSnatano 	 */
11376163fc9cSnatano 
11386163fc9cSnatano 	/* First see if the moved directory even exists */
11396163fc9cSnatano 	if (diskStructure->rr_moved_dir == NULL) {
11406163fc9cSnatano 		diskStructure->rr_moved_dir = cd9660_create_directory(
11416163fc9cSnatano 		    diskStructure, ISO_RRIP_DEFAULT_MOVE_DIR_NAME,
11426163fc9cSnatano 		    diskStructure->rootNode, dir);
11436163fc9cSnatano 		if (diskStructure->rr_moved_dir == NULL)
11446163fc9cSnatano 			return 0;
11456163fc9cSnatano 		cd9660_time_915(diskStructure->rr_moved_dir->isoDirRecord->date,
1146bc67c994Snatano 		    Tflag ? stampts : start_time.tv_sec);
11476163fc9cSnatano 	}
11486163fc9cSnatano 
11496163fc9cSnatano 	/* Create a file with the same ORIGINAL name */
11506163fc9cSnatano 	tfile = cd9660_create_file(diskStructure, dir->node->name, dir->parent,
11516163fc9cSnatano 	    dir);
11526163fc9cSnatano 	if (tfile == NULL)
11536163fc9cSnatano 		return NULL;
11546163fc9cSnatano 
11556163fc9cSnatano 	diskStructure->rock_ridge_move_count++;
11566163fc9cSnatano 	snprintf(newname, sizeof(newname), "%08i",
11576163fc9cSnatano 	    diskStructure->rock_ridge_move_count);
11586163fc9cSnatano 
11596163fc9cSnatano 	/* Point to old parent */
11606163fc9cSnatano 	dir->rr_real_parent = dir->parent;
11616163fc9cSnatano 
11626163fc9cSnatano 	/* Place the placeholder file */
11636163fc9cSnatano 	if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) {
11646163fc9cSnatano 		TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,
11656163fc9cSnatano 		    cn_next_child);
11666163fc9cSnatano 	} else {
11676163fc9cSnatano 		cd9660_sorted_child_insert(dir->rr_real_parent, tfile);
11686163fc9cSnatano 	}
11696163fc9cSnatano 
11706163fc9cSnatano 	/* Point to new parent */
11716163fc9cSnatano 	dir->parent = diskStructure->rr_moved_dir;
11726163fc9cSnatano 
11736163fc9cSnatano 	/* Point the file to the moved directory */
11746163fc9cSnatano 	tfile->rr_relocated = dir;
11756163fc9cSnatano 
11766163fc9cSnatano 	/* Actually move the directory */
11776163fc9cSnatano 	cd9660_sorted_child_insert(diskStructure->rr_moved_dir, dir);
11786163fc9cSnatano 
11796163fc9cSnatano 	/* TODO: Inherit permissions / ownership (basically the entire inode) */
11806163fc9cSnatano 
11816163fc9cSnatano 	/* Set the new name */
11826163fc9cSnatano 	memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
11836163fc9cSnatano 	strncpy(dir->isoDirRecord->name, newname, 8);
11846163fc9cSnatano 	dir->isoDirRecord->length[0] = 34 + 8;
11856163fc9cSnatano 	dir->isoDirRecord->name_len[0] = 8;
11866163fc9cSnatano 
11876163fc9cSnatano 	return dir;
11886163fc9cSnatano }
11896163fc9cSnatano 
11906163fc9cSnatano static int
11916163fc9cSnatano cd9660_add_dot_records(iso9660_disk *diskStructure, cd9660node *root)
11926163fc9cSnatano {
11936163fc9cSnatano 	struct cd9660_children_head *head = &root->cn_children;
11946163fc9cSnatano 	cd9660node *cn;
11956163fc9cSnatano 
11966163fc9cSnatano 	TAILQ_FOREACH(cn, head, cn_next_child) {
11976163fc9cSnatano 		if ((cn->type & CD9660_TYPE_DIR) == 0)
11986163fc9cSnatano 			continue;
11996163fc9cSnatano 		/* Recursion first */
12006163fc9cSnatano 		cd9660_add_dot_records(diskStructure, cn);
12016163fc9cSnatano 	}
12026163fc9cSnatano 	cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOT, root);
12036163fc9cSnatano 	cd9660_create_special_directory(diskStructure, CD9660_TYPE_DOTDOT,
12046163fc9cSnatano 	    root);
12056163fc9cSnatano 	return 1;
12066163fc9cSnatano }
12076163fc9cSnatano 
12086163fc9cSnatano /*
12096163fc9cSnatano  * Convert node to cd9660 structure
12106163fc9cSnatano  * This function is designed to be called recursively on the root node of
12116163fc9cSnatano  * the filesystem
12126163fc9cSnatano  * Lots of recursion going on here, want to make sure it is efficient
12136163fc9cSnatano  * @param struct fsnode * The root node to be converted
12146163fc9cSnatano  * @param struct cd9660* The parent node (should not be NULL)
12156163fc9cSnatano  * @param int Current directory depth
12166163fc9cSnatano  * @param int* Running count of the number of directories that are being created
12176163fc9cSnatano  */
12186163fc9cSnatano static void
12196163fc9cSnatano cd9660_convert_structure(iso9660_disk *diskStructure, fsnode *root,
12206163fc9cSnatano     cd9660node *parent_node, int level, int *numDirectories, int *error)
12216163fc9cSnatano {
12226163fc9cSnatano 	fsnode *iterator = root;
12236163fc9cSnatano 	cd9660node *this_node;
12246163fc9cSnatano 	int working_level;
12256163fc9cSnatano 	int add;
12266163fc9cSnatano 	int flag = 0;
12276163fc9cSnatano 	int counter = 0;
12286163fc9cSnatano 
12296163fc9cSnatano 	/*
12306163fc9cSnatano 	 * Newer, more efficient method, reduces recursion depth
12316163fc9cSnatano 	 */
12326163fc9cSnatano 	if (root == NULL) {
12336163fc9cSnatano 		warnx("%s: root is null", __func__);
12346163fc9cSnatano 		return;
12356163fc9cSnatano 	}
12366163fc9cSnatano 
12376163fc9cSnatano 	/* Test for an empty directory - makefs still gives us the . record */
12386163fc9cSnatano 	if ((S_ISDIR(root->type)) && (root->name[0] == '.')
12396163fc9cSnatano 		&& (root->name[1] == '\0')) {
12406163fc9cSnatano 		root = root->next;
12416163fc9cSnatano 		if (root == NULL)
12426163fc9cSnatano 			return;
12436163fc9cSnatano 	}
12446163fc9cSnatano 	if ((this_node = cd9660_allocate_cd9660node()) == NULL) {
12456163fc9cSnatano 		CD9660_MEM_ALLOC_ERROR(__func__);
12466163fc9cSnatano 	}
12476163fc9cSnatano 
12486163fc9cSnatano 	/*
12496163fc9cSnatano 	 * To reduce the number of recursive calls, we will iterate over
12506163fc9cSnatano 	 * the next pointers to the right.
12516163fc9cSnatano 	 */
12526163fc9cSnatano 	while (iterator != NULL) {
12536163fc9cSnatano 		add = 1;
12546163fc9cSnatano 		/*
12556163fc9cSnatano 		 * Increment the directory count if this is a directory
12566163fc9cSnatano 		 * Ignore "." entries. We will generate them later
12576163fc9cSnatano 		 */
12586163fc9cSnatano 		if (!S_ISDIR(iterator->type) ||
12596163fc9cSnatano 		    strcmp(iterator->name, ".") != 0) {
12606163fc9cSnatano 
12616163fc9cSnatano 			/* Translate the node, including its filename */
12626163fc9cSnatano 			this_node->parent = parent_node;
12636163fc9cSnatano 			cd9660_translate_node(diskStructure, iterator,
12646163fc9cSnatano 			    this_node);
12656163fc9cSnatano 			this_node->level = level;
12666163fc9cSnatano 
12676163fc9cSnatano 			if (S_ISDIR(iterator->type)) {
12686163fc9cSnatano 				(*numDirectories)++;
12696163fc9cSnatano 				this_node->type = CD9660_TYPE_DIR;
12706163fc9cSnatano 				working_level = level + 1;
12716163fc9cSnatano 
12726163fc9cSnatano 				/*
12736163fc9cSnatano 				 * If at level 8, directory would be at 8
12746163fc9cSnatano 				 * and have children at 9 which is not
12756163fc9cSnatano 				 * allowed as per ISO spec
12766163fc9cSnatano 				 */
12776163fc9cSnatano 				if (level == 8) {
12786163fc9cSnatano 					if ((!diskStructure->allow_deep_trees) &&
12796163fc9cSnatano 					  (!diskStructure->rock_ridge_enabled)) {
12806163fc9cSnatano 						warnx("error: found entry "
12816163fc9cSnatano 						     "with depth greater "
12826163fc9cSnatano 						     "than 8.");
12836163fc9cSnatano 						(*error) = 1;
12846163fc9cSnatano 						return;
12856163fc9cSnatano 					} else if (diskStructure->
12866163fc9cSnatano 						   rock_ridge_enabled) {
12876163fc9cSnatano 						working_level = 3;
12886163fc9cSnatano 						/*
12896163fc9cSnatano 						 * Moved directory is actually
12906163fc9cSnatano 						 * at level 2.
12916163fc9cSnatano 						 */
12926163fc9cSnatano 						this_node->level =
12936163fc9cSnatano 						    working_level - 1;
12946163fc9cSnatano 						if (cd9660_rrip_move_directory(
12956163fc9cSnatano 							diskStructure,
12966163fc9cSnatano 							this_node) == 0) {
12976163fc9cSnatano 							warnx("Failure in "
12986163fc9cSnatano 							      "cd9660_rrip_"
12996163fc9cSnatano 							      "move_directory"
13006163fc9cSnatano 							);
13016163fc9cSnatano 							(*error) = 1;
13026163fc9cSnatano 							return;
13036163fc9cSnatano 						}
13046163fc9cSnatano 						add = 0;
13056163fc9cSnatano 					}
13066163fc9cSnatano 				}
13076163fc9cSnatano 
13086163fc9cSnatano 				/* Do the recursive call on the children */
13096163fc9cSnatano 				if (iterator->child != 0) {
13106163fc9cSnatano 					cd9660_convert_structure(diskStructure,
13116163fc9cSnatano 						iterator->child, this_node,
13126163fc9cSnatano 						working_level,
13136163fc9cSnatano 						numDirectories, error);
13146163fc9cSnatano 
13156163fc9cSnatano 					if ((*error) == 1) {
13166163fc9cSnatano 						warnx("%s: Error on recursive "
13176163fc9cSnatano 						    "call", __func__);
13186163fc9cSnatano 						return;
13196163fc9cSnatano 					}
13206163fc9cSnatano 				}
13216163fc9cSnatano 
13226163fc9cSnatano 			} else {
13236163fc9cSnatano 				/* Only directories should have children */
13246163fc9cSnatano 				assert(iterator->child == NULL);
13256163fc9cSnatano 
13266163fc9cSnatano 				this_node->type = CD9660_TYPE_FILE;
13276163fc9cSnatano 			}
13286163fc9cSnatano 
13296163fc9cSnatano 			/*
13306163fc9cSnatano 			 * Finally, do a sorted insert
13316163fc9cSnatano 			 */
13326163fc9cSnatano 			if (add) {
13336163fc9cSnatano 				cd9660_sorted_child_insert(
13346163fc9cSnatano 				    parent_node, this_node);
13356163fc9cSnatano 			}
13366163fc9cSnatano 
13376163fc9cSnatano 			/*Allocate new temp_node */
13386163fc9cSnatano 			if (iterator->next != 0) {
13396163fc9cSnatano 				this_node = cd9660_allocate_cd9660node();
13406163fc9cSnatano 				if (this_node == NULL)
13416163fc9cSnatano 					CD9660_MEM_ALLOC_ERROR(__func__);
13426163fc9cSnatano 			}
13436163fc9cSnatano 		}
13446163fc9cSnatano 		iterator = iterator->next;
13456163fc9cSnatano 	}
13466163fc9cSnatano 
13476163fc9cSnatano 	/* cd9660_handle_collisions(first_node); */
13486163fc9cSnatano 
13496163fc9cSnatano 	/* TODO: need cleanup */
13506163fc9cSnatano 	cd9660_copy_filenames(diskStructure, parent_node);
13516163fc9cSnatano 
13526163fc9cSnatano 	do {
13536163fc9cSnatano 		flag = cd9660_handle_collisions(diskStructure, parent_node,
13546163fc9cSnatano 		    counter);
13556163fc9cSnatano 		counter++;
13566163fc9cSnatano 		cd9660_sorting_nodes(parent_node);
13576163fc9cSnatano 	} while ((flag == 1) && (counter < 100));
13586163fc9cSnatano }
13596163fc9cSnatano 
13606163fc9cSnatano /*
13616163fc9cSnatano  * Clean up the cd9660node tree
13626163fc9cSnatano  * This is designed to be called recursively on the root node
13636163fc9cSnatano  * @param struct cd9660node *root The node to free
13646163fc9cSnatano  * @returns void
13656163fc9cSnatano  */
13666163fc9cSnatano static void
13676163fc9cSnatano cd9660_free_structure(cd9660node *root)
13686163fc9cSnatano {
13696163fc9cSnatano 	cd9660node *cn;
13706163fc9cSnatano 
13716163fc9cSnatano 	while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) {
13726163fc9cSnatano 		TAILQ_REMOVE(&root->cn_children, cn, cn_next_child);
13736163fc9cSnatano 		cd9660_free_structure(cn);
13746163fc9cSnatano 	}
13756163fc9cSnatano 	free(root);
13766163fc9cSnatano }
13776163fc9cSnatano 
13786163fc9cSnatano /*
13796163fc9cSnatano  * Be a little more memory conservative:
13806163fc9cSnatano  * instead of having the TAILQ_ENTRY as part of the cd9660node,
13816163fc9cSnatano  * just create a temporary structure
13826163fc9cSnatano  */
13836163fc9cSnatano struct ptq_entry
13846163fc9cSnatano {
13856163fc9cSnatano 	TAILQ_ENTRY(ptq_entry) ptq;
13866163fc9cSnatano 	cd9660node *node;
13876163fc9cSnatano } *n;
13886163fc9cSnatano 
13896163fc9cSnatano #define PTQUEUE_NEW(n,s,r,t){\
13906163fc9cSnatano 	n = emalloc(sizeof(struct s));	\
13916163fc9cSnatano 	if (n == NULL)	\
13926163fc9cSnatano 		return r; \
13936163fc9cSnatano 	n->node = t;\
13946163fc9cSnatano }
13956163fc9cSnatano 
13966163fc9cSnatano /*
13976163fc9cSnatano  * Generate the path tables
13986163fc9cSnatano  * The specific implementation of this function is left as an exercise to the
13996163fc9cSnatano  * programmer. It could be done recursively. Make sure you read how the path
14006163fc9cSnatano  * table has to be laid out, it has levels.
14016163fc9cSnatano  * @param struct iso9660_disk *disk The disk image
14026163fc9cSnatano  * @returns int The number of built path tables (between 1 and 4), 0 on failure
14036163fc9cSnatano  */
14046163fc9cSnatano static int
14056163fc9cSnatano cd9660_generate_path_table(iso9660_disk *diskStructure)
14066163fc9cSnatano {
14076163fc9cSnatano 	cd9660node *cn, *dirNode = diskStructure->rootNode;
14086163fc9cSnatano 	cd9660node *last = dirNode;
14096163fc9cSnatano 	int pathTableSize = 0;	/* computed as we go */
14106163fc9cSnatano 	int counter = 1;	/* root gets a count of 0 */
14116163fc9cSnatano 
14126163fc9cSnatano 	TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head;
14136163fc9cSnatano 	TAILQ_INIT(&pt_head);
14146163fc9cSnatano 
14156163fc9cSnatano 	PTQUEUE_NEW(n, ptq_entry, -1, diskStructure->rootNode);
14166163fc9cSnatano 
14176163fc9cSnatano 	/* Push the root node */
14186163fc9cSnatano 	TAILQ_INSERT_HEAD(&pt_head, n, ptq);
14196163fc9cSnatano 
14206163fc9cSnatano 	/* Breadth-first traversal of file structure */
14216163fc9cSnatano 	while (pt_head.tqh_first != 0) {
14226163fc9cSnatano 		n = pt_head.tqh_first;
14236163fc9cSnatano 		dirNode = n->node;
14246163fc9cSnatano 		TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq);
14256163fc9cSnatano 		free(n);
14266163fc9cSnatano 
14276163fc9cSnatano 		/* Update the size */
14286163fc9cSnatano 		pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE
14296163fc9cSnatano 		    + dirNode->isoDirRecord->name_len[0]+
14306163fc9cSnatano 			(dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1);
14316163fc9cSnatano 			/* includes the padding bit */
14326163fc9cSnatano 
14336163fc9cSnatano 		dirNode->ptnumber=counter;
14346163fc9cSnatano 		if (dirNode != last) {
14356163fc9cSnatano 			last->ptnext = dirNode;
14366163fc9cSnatano 			dirNode->ptprev = last;
14376163fc9cSnatano 		}
14386163fc9cSnatano 		last = dirNode;
14396163fc9cSnatano 
14406163fc9cSnatano 		/* Push children onto queue */
14416163fc9cSnatano 		TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) {
14426163fc9cSnatano 			/*
14436163fc9cSnatano 			 * Dont add the DOT and DOTDOT types to the path
14446163fc9cSnatano 			 * table.
14456163fc9cSnatano 			 */
14466163fc9cSnatano 			if ((cn->type != CD9660_TYPE_DOT)
14476163fc9cSnatano 				&& (cn->type != CD9660_TYPE_DOTDOT)) {
14486163fc9cSnatano 
14496163fc9cSnatano 				if (S_ISDIR(cn->node->type)) {
14506163fc9cSnatano 					PTQUEUE_NEW(n, ptq_entry, -1, cn);
14516163fc9cSnatano 					TAILQ_INSERT_TAIL(&pt_head, n, ptq);
14526163fc9cSnatano 				}
14536163fc9cSnatano 			}
14546163fc9cSnatano 		}
14556163fc9cSnatano 		counter++;
14566163fc9cSnatano 	}
14576163fc9cSnatano 	return pathTableSize;
14586163fc9cSnatano }
14596163fc9cSnatano 
1460299d8950Snatano char *
1461299d8950Snatano cd9660_compute_full_filename(cd9660node *node)
14626163fc9cSnatano {
1463299d8950Snatano 	static char buf[PATH_MAX];
14646163fc9cSnatano 	int len;
14656163fc9cSnatano 
1466299d8950Snatano 	len = snprintf(buf, PATH_MAX, "%s/%s/%s", node->node->root,
14676163fc9cSnatano 	    node->node->path, node->node->name);
1468299d8950Snatano 	if (len < 0) {
1469299d8950Snatano 		warn(NULL);
1470299d8950Snatano 		return NULL;
1471299d8950Snatano 	} else if (len >= PATH_MAX) {
1472299d8950Snatano 		warnc(ENAMETOOLONG, NULL);
1473299d8950Snatano 		return NULL;
1474299d8950Snatano 	}
1475299d8950Snatano 	return buf;
14766163fc9cSnatano }
14776163fc9cSnatano 
14786163fc9cSnatano /*
14796163fc9cSnatano  * TODO: These two functions are almost identical.
14806163fc9cSnatano  * Some code cleanup is possible here
14816163fc9cSnatano  *
14826163fc9cSnatano  * XXX bounds checking!
14836163fc9cSnatano  */
14846163fc9cSnatano static int
14856163fc9cSnatano cd9660_level1_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1486d95291fdStedu     char *newname, size_t newnamelen, int is_file)
14876163fc9cSnatano {
14886163fc9cSnatano 	/*
14896163fc9cSnatano 	 * ISO 9660 : 10.1
14906163fc9cSnatano 	 * File Name shall not contain more than 8 d or d1 characters
14916163fc9cSnatano 	 * File Name Extension shall not contain more than 3 d or d1 characters
14926163fc9cSnatano 	 * Directory Identifier shall not contain more than 8 d or d1 characters
14936163fc9cSnatano 	 */
14946163fc9cSnatano 	int namelen = 0;
14956163fc9cSnatano 	int extlen = 0;
14966163fc9cSnatano 	int found_ext = 0;
1497d95291fdStedu 	char *orignewname = newname;
14986163fc9cSnatano 
14996163fc9cSnatano 	while (*oldname != '\0' && extlen < 3) {
15006163fc9cSnatano 		/* Handle period first, as it is special */
15016163fc9cSnatano 		if (*oldname == '.') {
15026163fc9cSnatano 			if (found_ext) {
15036163fc9cSnatano 				*newname++ = '_';
15046163fc9cSnatano 				extlen ++;
15056163fc9cSnatano 			}
15066163fc9cSnatano 			else {
15076163fc9cSnatano 				*newname++ = '.';
15086163fc9cSnatano 				found_ext = 1;
15096163fc9cSnatano 			}
15106163fc9cSnatano 		} else {
15116163fc9cSnatano 			/* Enforce 12.3 / 8 */
15126163fc9cSnatano 			if (namelen == 8 && !found_ext)
15136163fc9cSnatano 				break;
15146163fc9cSnatano 
15156163fc9cSnatano 			if (islower((unsigned char)*oldname))
15166163fc9cSnatano 				*newname++ = toupper((unsigned char)*oldname);
15176163fc9cSnatano 			else if (isupper((unsigned char)*oldname)
15186163fc9cSnatano 			    || isdigit((unsigned char)*oldname))
15196163fc9cSnatano 				*newname++ = *oldname;
15206163fc9cSnatano 			else
15216163fc9cSnatano 				*newname++ = '_';
15226163fc9cSnatano 
15236163fc9cSnatano 			if (found_ext)
15246163fc9cSnatano 				extlen++;
15256163fc9cSnatano 			else
15266163fc9cSnatano 				namelen++;
15276163fc9cSnatano 		}
15286163fc9cSnatano 		oldname++;
15296163fc9cSnatano 	}
15306163fc9cSnatano 	if (is_file) {
15316163fc9cSnatano 		if (!found_ext && !diskStructure->omit_trailing_period)
15326163fc9cSnatano 			*newname++ = '.';
15336163fc9cSnatano 		/* Add version */
1534d95291fdStedu 		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
15356163fc9cSnatano 	}
15366163fc9cSnatano 	return namelen + extlen + found_ext;
15376163fc9cSnatano }
15386163fc9cSnatano 
15396163fc9cSnatano /* XXX bounds checking! */
15406163fc9cSnatano static int
15416163fc9cSnatano cd9660_level2_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1542d95291fdStedu     char *newname, size_t newnamelen, int is_file)
15436163fc9cSnatano {
15446163fc9cSnatano 	/*
15456163fc9cSnatano 	 * ISO 9660 : 7.5.1
15466163fc9cSnatano 	 * File name : 0+ d or d1 characters
15476163fc9cSnatano 	 * separator 1 (.)
15486163fc9cSnatano 	 * File name extension : 0+ d or d1 characters
15496163fc9cSnatano 	 * separator 2 (;)
15506163fc9cSnatano 	 * File version number (5 characters, 1-32767)
15516163fc9cSnatano 	 * 1 <= Sum of File name and File name extension <= 30
15526163fc9cSnatano 	 */
15536163fc9cSnatano 	int namelen = 0;
15546163fc9cSnatano 	int extlen = 0;
15556163fc9cSnatano 	int found_ext = 0;
1556d95291fdStedu 	char *orignewname = newname;
15576163fc9cSnatano 
15586163fc9cSnatano 	while (*oldname != '\0' && namelen + extlen < 30) {
15596163fc9cSnatano 		/* Handle period first, as it is special */
15606163fc9cSnatano 		if (*oldname == '.') {
15616163fc9cSnatano 			if (found_ext) {
15626163fc9cSnatano 				if (diskStructure->allow_multidot) {
15636163fc9cSnatano 					*newname++ = '.';
15646163fc9cSnatano 				} else {
15656163fc9cSnatano 					*newname++ = '_';
15666163fc9cSnatano 				}
15676163fc9cSnatano 				extlen ++;
15686163fc9cSnatano 			}
15696163fc9cSnatano 			else {
15706163fc9cSnatano 				*newname++ = '.';
15716163fc9cSnatano 				found_ext = 1;
15726163fc9cSnatano 			}
15736163fc9cSnatano 		} else {
15746163fc9cSnatano 			if (islower((unsigned char)*oldname))
15756163fc9cSnatano 				*newname++ = toupper((unsigned char)*oldname);
15766163fc9cSnatano 			else if (isupper((unsigned char)*oldname) ||
15776163fc9cSnatano 			    isdigit((unsigned char)*oldname))
15786163fc9cSnatano 				*newname++ = *oldname;
15796163fc9cSnatano 			else if (diskStructure->allow_multidot &&
15806163fc9cSnatano 			    *oldname == '.') {
15816163fc9cSnatano 				*newname++ = '.';
15826163fc9cSnatano 			} else {
15836163fc9cSnatano 				*newname++ = '_';
15846163fc9cSnatano 			}
15856163fc9cSnatano 
15866163fc9cSnatano 			if (found_ext)
15876163fc9cSnatano 				extlen++;
15886163fc9cSnatano 			else
15896163fc9cSnatano 				namelen++;
15906163fc9cSnatano 		}
15916163fc9cSnatano 		oldname ++;
15926163fc9cSnatano 	}
15936163fc9cSnatano 	if (is_file) {
15946163fc9cSnatano 		if (!found_ext && !diskStructure->omit_trailing_period)
15956163fc9cSnatano 			*newname++ = '.';
15966163fc9cSnatano 		/* Add version */
1597d95291fdStedu 		snprintf(newname, newnamelen - (newname - orignewname), ";%i", 1);
15986163fc9cSnatano 	}
15996163fc9cSnatano 	return namelen + extlen + found_ext;
16006163fc9cSnatano }
16016163fc9cSnatano 
16026163fc9cSnatano /*
16036163fc9cSnatano  * Convert a file name to ISO compliant file name
16046163fc9cSnatano  * @param char * oldname The original filename
16056163fc9cSnatano  * @param char ** newname The new file name, in the appropriate character
16066163fc9cSnatano  *                        set and of appropriate length
16076163fc9cSnatano  * @param int 1 if file, 0 if directory
16086163fc9cSnatano  * @returns int The length of the new string
16096163fc9cSnatano  */
16106163fc9cSnatano static int
16116163fc9cSnatano cd9660_convert_filename(iso9660_disk *diskStructure, const char *oldname,
1612d95291fdStedu     char *newname, size_t newnamelen, int is_file)
16136163fc9cSnatano {
16146163fc9cSnatano 	if (diskStructure->isoLevel == 1)
16154095a2e0Stedu 		return cd9660_level1_convert_filename(diskStructure,
16164095a2e0Stedu 		    oldname, newname, newnamelen, is_file);
16176163fc9cSnatano 	else if (diskStructure->isoLevel == 2)
16184095a2e0Stedu 		return cd9660_level2_convert_filename(diskStructure,
16194095a2e0Stedu 		    oldname, newname, newnamelen, is_file);
16204095a2e0Stedu 	abort();
16216163fc9cSnatano }
16226163fc9cSnatano 
16236163fc9cSnatano int
16246163fc9cSnatano cd9660_compute_record_size(iso9660_disk *diskStructure, cd9660node *node)
16256163fc9cSnatano {
16266163fc9cSnatano 	int size = node->isoDirRecord->length[0];
16276163fc9cSnatano 
16286163fc9cSnatano 	if (diskStructure->rock_ridge_enabled)
16296163fc9cSnatano 		size += node->susp_entry_size;
16306163fc9cSnatano 	size += node->su_tail_size;
16316163fc9cSnatano 	size += size & 1; /* Ensure length of record is even. */
16326163fc9cSnatano 	assert(size <= 254);
16336163fc9cSnatano 	return size;
16346163fc9cSnatano }
16356163fc9cSnatano 
16366163fc9cSnatano static void
16376163fc9cSnatano cd9660_populate_dot_records(iso9660_disk *diskStructure, cd9660node *node)
16386163fc9cSnatano {
16396163fc9cSnatano 	node->dot_record->fileDataSector = node->fileDataSector;
16406163fc9cSnatano 	memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34);
16416163fc9cSnatano 	node->dot_record->isoDirRecord->name_len[0] = 1;
16426163fc9cSnatano 	node->dot_record->isoDirRecord->name[0] = 0;
16436163fc9cSnatano 	node->dot_record->isoDirRecord->name[1] = 0;
16446163fc9cSnatano 	node->dot_record->isoDirRecord->length[0] = 34;
16456163fc9cSnatano 	node->dot_record->fileRecordSize =
16466163fc9cSnatano 	    cd9660_compute_record_size(diskStructure, node->dot_record);
16476163fc9cSnatano 
16486163fc9cSnatano 	if (node == diskStructure->rootNode) {
16496163fc9cSnatano 		node->dot_dot_record->fileDataSector = node->fileDataSector;
16506163fc9cSnatano 		memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord,
16516163fc9cSnatano 		    34);
16526163fc9cSnatano 	} else {
16536163fc9cSnatano 		node->dot_dot_record->fileDataSector =
16546163fc9cSnatano 		    node->parent->fileDataSector;
16556163fc9cSnatano 		memcpy(node->dot_dot_record->isoDirRecord,
16566163fc9cSnatano 		    node->parent->isoDirRecord,34);
16576163fc9cSnatano 	}
16586163fc9cSnatano 	node->dot_dot_record->isoDirRecord->name_len[0] = 1;
16596163fc9cSnatano 	node->dot_dot_record->isoDirRecord->name[0] = 1;
16606163fc9cSnatano 	node->dot_dot_record->isoDirRecord->name[1] = 0;
16616163fc9cSnatano 	node->dot_dot_record->isoDirRecord->length[0] = 34;
16626163fc9cSnatano 	node->dot_dot_record->fileRecordSize =
16636163fc9cSnatano 	    cd9660_compute_record_size(diskStructure, node->dot_dot_record);
16646163fc9cSnatano }
16656163fc9cSnatano 
16666163fc9cSnatano /*
16676163fc9cSnatano  * @param struct cd9660node *node The node
16686163fc9cSnatano  * @param int The offset (in bytes) - SHOULD align to the beginning of a sector
16696163fc9cSnatano  * @returns int The total size of files and directory entries (should be
16706163fc9cSnatano  *              a multiple of sector size)
16716163fc9cSnatano */
16726163fc9cSnatano static int64_t
16736163fc9cSnatano cd9660_compute_offsets(iso9660_disk *diskStructure, cd9660node *node,
16746163fc9cSnatano     int64_t startOffset)
16756163fc9cSnatano {
16766163fc9cSnatano 	/*
16776163fc9cSnatano 	 * This function needs to compute the size of directory records and
16786163fc9cSnatano 	 * runs, file lengths, and set the appropriate variables both in
16796163fc9cSnatano 	 * cd9660node and isoDirEntry
16806163fc9cSnatano 	 */
16816163fc9cSnatano 	int64_t used_bytes = 0;
16826163fc9cSnatano 	int64_t current_sector_usage = 0;
16836163fc9cSnatano 	cd9660node *child;
16846163fc9cSnatano 	fsinode *inode;
16856163fc9cSnatano 	int64_t r;
16866163fc9cSnatano 
16876163fc9cSnatano 	assert(node != NULL);
16886163fc9cSnatano 
16896163fc9cSnatano 
16906163fc9cSnatano 	/*
16916163fc9cSnatano 	 * NOTE : There needs to be some special case detection for
16926163fc9cSnatano 	 * the "real root" node, since for it, node->node is undefined
16936163fc9cSnatano 	 */
16946163fc9cSnatano 
16956163fc9cSnatano 	node->fileDataSector = -1;
16966163fc9cSnatano 
16976163fc9cSnatano 	if (node->type & CD9660_TYPE_DIR) {
16986163fc9cSnatano 		node->fileRecordSize = cd9660_compute_record_size(
16996163fc9cSnatano 		    diskStructure, node);
17006163fc9cSnatano 		/*Set what sector this directory starts in*/
17016163fc9cSnatano 		node->fileDataSector =
17026163fc9cSnatano 		    CD9660_BLOCKS(diskStructure->sectorSize,startOffset);
17036163fc9cSnatano 
17046163fc9cSnatano 		cd9660_bothendian_dword(node->fileDataSector,
17056163fc9cSnatano 		    node->isoDirRecord->extent);
17066163fc9cSnatano 
17076163fc9cSnatano 		/*
17086163fc9cSnatano 		 * First loop over children, need to know the size of
17096163fc9cSnatano 		 * their directory records
17106163fc9cSnatano 		 */
17116163fc9cSnatano 		node->fileSectorsUsed = 1;
17126163fc9cSnatano 		TAILQ_FOREACH(child, &node->cn_children, cn_next_child) {
17136163fc9cSnatano 			node->fileDataLength +=
17146163fc9cSnatano 			    cd9660_compute_record_size(diskStructure, child);
17156163fc9cSnatano 			if ((cd9660_compute_record_size(diskStructure, child) +
17166163fc9cSnatano 			    current_sector_usage) >=
17176163fc9cSnatano 			    diskStructure->sectorSize) {
17186163fc9cSnatano 				current_sector_usage = 0;
17196163fc9cSnatano 				node->fileSectorsUsed++;
17206163fc9cSnatano 			}
17216163fc9cSnatano 
17226163fc9cSnatano 			current_sector_usage +=
17236163fc9cSnatano 			    cd9660_compute_record_size(diskStructure, child);
17246163fc9cSnatano 		}
17256163fc9cSnatano 
17266163fc9cSnatano 		cd9660_bothendian_dword(node->fileSectorsUsed *
17276163fc9cSnatano 			diskStructure->sectorSize,node->isoDirRecord->size);
17286163fc9cSnatano 
17296163fc9cSnatano 		/*
17306163fc9cSnatano 		 * This should point to the sector after the directory
17316163fc9cSnatano 		 * record (or, the first byte in that sector)
17326163fc9cSnatano 		 */
17336163fc9cSnatano 		used_bytes += node->fileSectorsUsed * diskStructure->sectorSize;
17346163fc9cSnatano 
17356163fc9cSnatano 		for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
17366163fc9cSnatano 		     child != NULL; child = TAILQ_NEXT(child, cn_next_child)) {
17376163fc9cSnatano 			/* Directories need recursive call */
17386163fc9cSnatano 			if (S_ISDIR(child->node->type)) {
17396163fc9cSnatano 				r = cd9660_compute_offsets(diskStructure, child,
17406163fc9cSnatano 				    used_bytes + startOffset);
17416163fc9cSnatano 
17426163fc9cSnatano 				if (r != -1)
17436163fc9cSnatano 					used_bytes += r;
17446163fc9cSnatano 				else
17456163fc9cSnatano 					return -1;
17466163fc9cSnatano 			}
17476163fc9cSnatano 		}
17486163fc9cSnatano 
17496163fc9cSnatano 		/* Explicitly set the . and .. records */
17506163fc9cSnatano 		cd9660_populate_dot_records(diskStructure, node);
17516163fc9cSnatano 
17526163fc9cSnatano 		/* Finally, do another iteration to write the file data*/
17536163fc9cSnatano 		for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
17546163fc9cSnatano 		     child != NULL;
17556163fc9cSnatano 		     child = TAILQ_NEXT(child, cn_next_child)) {
17566163fc9cSnatano 			/* Files need extent set */
17576163fc9cSnatano 			if (S_ISDIR(child->node->type))
17586163fc9cSnatano 				continue;
17596163fc9cSnatano 			child->fileRecordSize =
17606163fc9cSnatano 			    cd9660_compute_record_size(diskStructure, child);
17616163fc9cSnatano 
17626163fc9cSnatano 			child->fileSectorsUsed =
17636163fc9cSnatano 			    CD9660_BLOCKS(diskStructure->sectorSize,
17646163fc9cSnatano 				child->fileDataLength);
17656163fc9cSnatano 
17666163fc9cSnatano 			inode = child->node->inode;
17676163fc9cSnatano 			if ((inode->flags & FI_ALLOCATED) == 0) {
17686163fc9cSnatano 				inode->ino =
17696163fc9cSnatano 				    CD9660_BLOCKS(diskStructure->sectorSize,
17706163fc9cSnatano 				        used_bytes + startOffset);
17716163fc9cSnatano 				inode->flags |= FI_ALLOCATED;
17726163fc9cSnatano 				used_bytes += child->fileSectorsUsed *
17736163fc9cSnatano 				    diskStructure->sectorSize;
17746163fc9cSnatano 			} else {
17756163fc9cSnatano 				INODE_WARNX(("%s: already allocated inode %d "
17766163fc9cSnatano 				      "data sectors at %" PRIu32, __func__,
17776163fc9cSnatano 				      (int)inode->st.st_ino, inode->ino));
17786163fc9cSnatano 			}
17796163fc9cSnatano 			child->fileDataSector = inode->ino;
17806163fc9cSnatano 			cd9660_bothendian_dword(child->fileDataSector,
17816163fc9cSnatano 				child->isoDirRecord->extent);
17826163fc9cSnatano 		}
17836163fc9cSnatano 	}
17846163fc9cSnatano 
17856163fc9cSnatano 	return used_bytes;
17866163fc9cSnatano }
17876163fc9cSnatano 
17886163fc9cSnatano #if 0
17896163fc9cSnatano /* Might get rid of this func */
17906163fc9cSnatano static int
17916163fc9cSnatano cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file)
17926163fc9cSnatano {
17936163fc9cSnatano 	to->node->inode->st.st_dev = 0;
17946163fc9cSnatano 	to->node->inode->st.st_ino = 0;
17956163fc9cSnatano 	to->node->inode->st.st_size = 0;
17966163fc9cSnatano 	to->node->inode->st.st_blksize = from->node->inode->st.st_blksize;
17976163fc9cSnatano 	to->node->inode->st.st_atime = from->node->inode->st.st_atime;
17986163fc9cSnatano 	to->node->inode->st.st_mtime = from->node->inode->st.st_mtime;
17996163fc9cSnatano 	to->node->inode->st.st_ctime = from->node->inode->st.st_ctime;
18006163fc9cSnatano 	to->node->inode->st.st_uid = from->node->inode->st.st_uid;
18016163fc9cSnatano 	to->node->inode->st.st_gid = from->node->inode->st.st_gid;
18026163fc9cSnatano 	to->node->inode->st.st_mode = from->node->inode->st.st_mode;
18036163fc9cSnatano 	/* Clear out type */
18046163fc9cSnatano 	to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT);
18056163fc9cSnatano 	if (file)
18066163fc9cSnatano 		to->node->inode->st.st_mode |= S_IFREG;
18076163fc9cSnatano 	else
18086163fc9cSnatano 		to->node->inode->st.st_mode |= S_IFDIR;
18096163fc9cSnatano 	return 1;
18106163fc9cSnatano }
18116163fc9cSnatano #endif
18126163fc9cSnatano 
18136163fc9cSnatano static cd9660node *
18146163fc9cSnatano cd9660_create_virtual_entry(iso9660_disk *diskStructure, const char *name,
18156163fc9cSnatano     cd9660node *parent, int file, int insert)
18166163fc9cSnatano {
18176163fc9cSnatano 	cd9660node *temp;
18186163fc9cSnatano 	fsnode * tfsnode;
18196163fc9cSnatano 
18206163fc9cSnatano 	assert(parent != NULL);
18216163fc9cSnatano 
18226163fc9cSnatano 	temp = cd9660_allocate_cd9660node();
18236163fc9cSnatano 	if (temp == NULL)
18246163fc9cSnatano 		return NULL;
18256163fc9cSnatano 
18266163fc9cSnatano 	tfsnode = emalloc(sizeof(*tfsnode));
18276163fc9cSnatano 	tfsnode->name = estrdup(name);
18286163fc9cSnatano 	temp->isoDirRecord = emalloc(sizeof(*temp->isoDirRecord));
18296163fc9cSnatano 
18306163fc9cSnatano 	cd9660_convert_filename(diskStructure, tfsnode->name,
1831d95291fdStedu 	    temp->isoDirRecord->name, sizeof temp->isoDirRecord->name, file);
18326163fc9cSnatano 
18336163fc9cSnatano 	temp->node = tfsnode;
18346163fc9cSnatano 	temp->parent = parent;
18356163fc9cSnatano 
18366163fc9cSnatano 	if (insert) {
18376163fc9cSnatano 		if (temp->parent != NULL) {
18386163fc9cSnatano 			temp->level = temp->parent->level + 1;
18396163fc9cSnatano 			if (!TAILQ_EMPTY(&temp->parent->cn_children))
18406163fc9cSnatano 				cd9660_sorted_child_insert(temp->parent, temp);
18416163fc9cSnatano 			else
18426163fc9cSnatano 				TAILQ_INSERT_HEAD(&temp->parent->cn_children,
18436163fc9cSnatano 				    temp, cn_next_child);
18446163fc9cSnatano 		}
18456163fc9cSnatano 	}
18466163fc9cSnatano 
18476163fc9cSnatano 	if (parent->node != NULL) {
18486163fc9cSnatano 		tfsnode->type = parent->node->type;
18496163fc9cSnatano 	}
18506163fc9cSnatano 
18516163fc9cSnatano 	/* Clear out file type bits */
18526163fc9cSnatano 	tfsnode->type &= ~(S_IFMT);
18536163fc9cSnatano 	if (file)
18546163fc9cSnatano 		tfsnode->type |= S_IFREG;
18556163fc9cSnatano 	else
18566163fc9cSnatano 		tfsnode->type |= S_IFDIR;
18576163fc9cSnatano 
18586163fc9cSnatano 	/* Indicate that there is no spec entry (inode) */
18596163fc9cSnatano 	tfsnode->flags &= ~(FSNODE_F_HASSPEC);
18606163fc9cSnatano #if 0
18616163fc9cSnatano 	cd9660_copy_stat_info(parent, temp, file);
18626163fc9cSnatano #endif
18636163fc9cSnatano 	return temp;
18646163fc9cSnatano }
18656163fc9cSnatano 
18666163fc9cSnatano static cd9660node *
18676163fc9cSnatano cd9660_create_file(iso9660_disk *diskStructure, const char *name,
18686163fc9cSnatano     cd9660node *parent, cd9660node *me)
18696163fc9cSnatano {
18706163fc9cSnatano 	cd9660node *temp;
18716163fc9cSnatano 
18726163fc9cSnatano 	temp = cd9660_create_virtual_entry(diskStructure, name, parent, 1, 1);
18736163fc9cSnatano 	if (temp == NULL)
18746163fc9cSnatano 		return NULL;
18756163fc9cSnatano 
18766163fc9cSnatano 	temp->fileDataLength = 0;
18776163fc9cSnatano 
18786163fc9cSnatano 	temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL;
18796163fc9cSnatano 
18806163fc9cSnatano 	temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
18816163fc9cSnatano 	*temp->node->inode = *me->node->inode;
18826163fc9cSnatano 
18836163fc9cSnatano 	if (cd9660_translate_node_common(diskStructure, temp) == 0)
18846163fc9cSnatano 		return NULL;
18856163fc9cSnatano 	return temp;
18866163fc9cSnatano }
18876163fc9cSnatano 
18886163fc9cSnatano /*
18896163fc9cSnatano  * Create a new directory which does not exist on disk
18906163fc9cSnatano  * @param const char * name The name to assign to the directory
18916163fc9cSnatano  * @param const char * parent Pointer to the parent directory
18926163fc9cSnatano  * @returns cd9660node * Pointer to the new directory
18936163fc9cSnatano  */
18946163fc9cSnatano static cd9660node *
18956163fc9cSnatano cd9660_create_directory(iso9660_disk *diskStructure, const char *name,
18966163fc9cSnatano     cd9660node *parent, cd9660node *me)
18976163fc9cSnatano {
18986163fc9cSnatano 	cd9660node *temp;
18996163fc9cSnatano 
19006163fc9cSnatano 	temp = cd9660_create_virtual_entry(diskStructure, name, parent, 0, 1);
19016163fc9cSnatano 	if (temp == NULL)
19026163fc9cSnatano 		return NULL;
19036163fc9cSnatano 	temp->node->type |= S_IFDIR;
19046163fc9cSnatano 
19056163fc9cSnatano 	temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL;
19066163fc9cSnatano 
19076163fc9cSnatano 	temp->node->inode = ecalloc(1, sizeof(*temp->node->inode));
19086163fc9cSnatano 	*temp->node->inode = *me->node->inode;
19096163fc9cSnatano 
19106163fc9cSnatano 	if (cd9660_translate_node_common(diskStructure, temp) == 0)
19116163fc9cSnatano 		return NULL;
19126163fc9cSnatano 	return temp;
19136163fc9cSnatano }
19146163fc9cSnatano 
19156163fc9cSnatano static cd9660node *
19166163fc9cSnatano cd9660_create_special_directory(iso9660_disk *diskStructure, u_char type,
19176163fc9cSnatano     cd9660node *parent)
19186163fc9cSnatano {
19196163fc9cSnatano 	cd9660node *temp, *first;
19206163fc9cSnatano 	char na[2];
19216163fc9cSnatano 
19226163fc9cSnatano 	assert(parent != NULL);
19236163fc9cSnatano 
19246163fc9cSnatano 	if (type == CD9660_TYPE_DOT)
19256163fc9cSnatano 		na[0] = 0;
19266163fc9cSnatano 	else if (type == CD9660_TYPE_DOTDOT)
19276163fc9cSnatano 		na[0] = 1;
19286163fc9cSnatano 	else
19296163fc9cSnatano 		return 0;
19306163fc9cSnatano 
19316163fc9cSnatano 	na[1] = 0;
19326163fc9cSnatano 	if ((temp = cd9660_create_virtual_entry(diskStructure, na, parent,
19336163fc9cSnatano 	    0, 0)) == NULL)
19346163fc9cSnatano 		return NULL;
19356163fc9cSnatano 
19366163fc9cSnatano 	temp->parent = parent;
19376163fc9cSnatano 	temp->type = type;
19386163fc9cSnatano 	temp->isoDirRecord->length[0] = 34;
19396163fc9cSnatano 	/* Dot record is always first */
19406163fc9cSnatano 	if (type == CD9660_TYPE_DOT) {
19416163fc9cSnatano 		parent->dot_record = temp;
19426163fc9cSnatano 		TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child);
19436163fc9cSnatano 	/* DotDot should be second */
19446163fc9cSnatano 	} else if (type == CD9660_TYPE_DOTDOT) {
19456163fc9cSnatano 		parent->dot_dot_record = temp;
19466163fc9cSnatano 		/*
19476163fc9cSnatano                  * If the first child is the dot record, insert
19486163fc9cSnatano                  * this second.  Otherwise, insert it at the head.
19496163fc9cSnatano 		 */
19506163fc9cSnatano 		if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL ||
19516163fc9cSnatano 		    (first->type & CD9660_TYPE_DOT) == 0) {
19526163fc9cSnatano 			TAILQ_INSERT_HEAD(&parent->cn_children, temp,
19536163fc9cSnatano 			    cn_next_child);
19546163fc9cSnatano 		} else {
19556163fc9cSnatano 			TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,
19566163fc9cSnatano 			    cn_next_child);
19576163fc9cSnatano 		}
19586163fc9cSnatano 	}
19596163fc9cSnatano 
19606163fc9cSnatano 	return temp;
19616163fc9cSnatano }
19626163fc9cSnatano 
19636163fc9cSnatano static int
19646163fc9cSnatano cd9660_add_generic_bootimage(iso9660_disk *diskStructure, const char *bootimage)
19656163fc9cSnatano {
19666163fc9cSnatano 	struct stat stbuf;
19676163fc9cSnatano 
19686163fc9cSnatano 	assert(bootimage != NULL);
19696163fc9cSnatano 
19706163fc9cSnatano 	if (*bootimage == '\0') {
19716163fc9cSnatano 		warnx("Error: Boot image must be a filename");
19726163fc9cSnatano 		return 0;
19736163fc9cSnatano 	}
19746163fc9cSnatano 
19756163fc9cSnatano 	diskStructure->generic_bootimage = estrdup(bootimage);
19766163fc9cSnatano 
1977c8f48d9bSyasuoka 	if (unveil(diskStructure->generic_bootimage, "r") == -1)
1978bc5a8259Sbeck 		err(1, "unveil %s", diskStructure->generic_bootimage);
19796163fc9cSnatano 	/* Get information about the file */
19806163fc9cSnatano 	if (lstat(diskStructure->generic_bootimage, &stbuf) == -1)
1981944eabd5Snatano 		err(1, "%s: lstat(\"%s\")", __func__,
19826163fc9cSnatano 		    diskStructure->generic_bootimage);
19836163fc9cSnatano 
19846163fc9cSnatano 	if (stbuf.st_size > 32768) {
19856163fc9cSnatano 		warnx("Error: Boot image must be no greater than 32768 bytes");
19866163fc9cSnatano 		return 0;
19876163fc9cSnatano 	}
19886163fc9cSnatano 
19896163fc9cSnatano 	diskStructure->has_generic_bootimage = 1;
19906163fc9cSnatano 	return 1;
19916163fc9cSnatano }
1992