summaryrefslogtreecommitdiffstats
path: root/usr.sbin/makefs
diff options
context:
space:
mode:
authorcognet <cognet@FreeBSD.org>2010-11-07 16:05:04 +0000
committercognet <cognet@FreeBSD.org>2010-11-07 16:05:04 +0000
commit69d9f8b92c590010252135df10fc18177928b63d (patch)
tree60af890ef59672ab4e08377f2819cf9ec9d4e9e3 /usr.sbin/makefs
parent11d20f608be0ff59e94af8a9e55fd84794ac1882 (diff)
downloadFreeBSD-src-69d9f8b92c590010252135df10fc18177928b63d.zip
FreeBSD-src-69d9f8b92c590010252135df10fc18177928b63d.tar.gz
Sync with the latest version from NetBSD. It notably addds ISO9660 support.
Submitted by: bapt
Diffstat (limited to 'usr.sbin/makefs')
-rw-r--r--usr.sbin/makefs/Makefile19
-rw-r--r--usr.sbin/makefs/cd9660.c2154
-rw-r--r--usr.sbin/makefs/cd9660.h364
-rw-r--r--usr.sbin/makefs/cd9660/Makefile.inc9
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_archimedes.c126
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_archimedes.h50
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_conversion.c202
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_debug.c488
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_eltorito.c539
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_eltorito.h164
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_strings.c120
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_write.c518
-rw-r--r--usr.sbin/makefs/cd9660/iso9660_rrip.c836
-rw-r--r--usr.sbin/makefs/cd9660/iso9660_rrip.h290
-rw-r--r--usr.sbin/makefs/compat/Makefile.inc8
-rw-r--r--usr.sbin/makefs/ffs.c236
-rw-r--r--usr.sbin/makefs/ffs.h66
-rw-r--r--usr.sbin/makefs/ffs/Makefile.inc9
-rw-r--r--usr.sbin/makefs/ffs/buf.c6
-rw-r--r--usr.sbin/makefs/ffs/ffs_alloc.c27
-rw-r--r--usr.sbin/makefs/ffs/mkfs.c32
-rw-r--r--usr.sbin/makefs/makefs.8278
-rw-r--r--usr.sbin/makefs/makefs.c36
-rw-r--r--usr.sbin/makefs/makefs.h79
-rw-r--r--usr.sbin/makefs/walk.c237
25 files changed, 6510 insertions, 383 deletions
diff --git a/usr.sbin/makefs/Makefile b/usr.sbin/makefs/Makefile
index 0356029..37eeb38 100644
--- a/usr.sbin/makefs/Makefile
+++ b/usr.sbin/makefs/Makefile
@@ -1,22 +1,23 @@
# $FreeBSD$
PROG= makefs
+
+CFLAGS+=-I${.CURDIR}
+
+SRCS= cd9660.c ffs.c \
+ getid.c \
+ makefs.c \
+ walk.c
MAN= makefs.8
WARNS?= 2
-CFLAGS+=-I${.CURDIR}
-SRCS= ffs.c getid.c makefs.c walk.c
+.include "${.CURDIR}/cd9660/Makefile.inc"
+.include "${.CURDIR}/ffs/Makefile.inc"
+.include "${.CURDIR}/compat/Makefile.inc"
-.PATH: ${.CURDIR}/ffs
-CFLAGS+=-I${.CURDIR}/ffs
CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1
CFLAGS+=-DHAVE_STRUCT_STAT_ST_GEN=1
-SRCS+= buf.c ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c mkfs.c ufs_bmap.c
-
-.PATH: ${.CURDIR}/compat
-CFLAGS+=-I${.CURDIR}/compat
-SRCS+= pwcache.c strsuftoll.c
.PATH: ${.CURDIR}/../mtree
CFLAGS+=-I${.CURDIR}/../mtree
diff --git a/usr.sbin/makefs/cd9660.c b/usr.sbin/makefs/cd9660.c
new file mode 100644
index 0000000..bed764f
--- /dev/null
+++ b/usr.sbin/makefs/cd9660.c
@@ -0,0 +1,2154 @@
+/* $NetBSD: cd9660.c,v 1.27 2010/10/27 18:51:34 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Luke Mewburn for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <string.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "cd9660/iso9660_rrip.h"
+#include "cd9660/cd9660_archimedes.h"
+
+/*
+ * Global variables
+ */
+iso9660_disk diskStructure;
+
+static void cd9660_finalize_PVD(void);
+static cd9660node *cd9660_allocate_cd9660node(void);
+static void cd9660_set_defaults(void);
+static int cd9660_arguments_set_string(const char *, const char *, int,
+ char, char *);
+static void cd9660_populate_iso_dir_record(
+ struct _iso_directory_record_cd9660 *, u_char, u_char, u_char,
+ const char *);
+static void cd9660_setup_root_node(void);
+static int cd9660_setup_volume_descriptors(void);
+#if 0
+static int cd9660_fill_extended_attribute_record(cd9660node *);
+#endif
+static void cd9660_sort_nodes(cd9660node *);
+static int cd9960_translate_node_common(cd9660node *);
+static int cd9660_translate_node(fsnode *, cd9660node *);
+static int cd9660_compare_filename(const char *, const char *);
+static void cd9660_sorted_child_insert(cd9660node *, cd9660node *);
+static int cd9660_handle_collisions(cd9660node *, int);
+static cd9660node *cd9660_rename_filename(cd9660node *, int, int);
+static void cd9660_copy_filenames(cd9660node *);
+static void cd9660_sorting_nodes(cd9660node *);
+static int cd9660_count_collisions(cd9660node *);
+static cd9660node *cd9660_rrip_move_directory(cd9660node *);
+static int cd9660_add_dot_records(cd9660node *);
+
+static void cd9660_convert_structure(fsnode *, cd9660node *, int,
+ int *, int *);
+static void cd9660_free_structure(cd9660node *);
+static int cd9660_generate_path_table(void);
+static int cd9660_level1_convert_filename(const char *, char *, int);
+static int cd9660_level2_convert_filename(const char *, char *, int);
+#if 0
+static int cd9660_joliet_convert_filename(const char *, char *, int);
+#endif
+static int cd9660_convert_filename(const char *, char *, int);
+static void cd9660_populate_dot_records(cd9660node *);
+static int64_t cd9660_compute_offsets(cd9660node *, int64_t);
+#if 0
+static int cd9660_copy_stat_info(cd9660node *, cd9660node *, int);
+#endif
+static cd9660node *cd9660_create_virtual_entry(const char *, cd9660node *, int,
+ int);
+static cd9660node *cd9660_create_file(const char *, cd9660node *, cd9660node *);
+static cd9660node *cd9660_create_directory(const char *, cd9660node *,
+ cd9660node *);
+static cd9660node *cd9660_create_special_directory(u_char, cd9660node *);
+
+
+/*
+ * Allocate and initalize a cd9660node
+ * @returns struct cd9660node * Pointer to new node, or NULL on error
+ */
+static cd9660node *
+cd9660_allocate_cd9660node(void)
+{
+ cd9660node *temp;
+
+ if ((temp = calloc(1, sizeof(cd9660node))) == NULL)
+ err(EXIT_FAILURE, "%s: calloc", __func__);
+ TAILQ_INIT(&temp->cn_children);
+ temp->parent = temp->dot_record = temp->dot_dot_record = NULL;
+ temp->ptnext = temp->ptprev = temp->ptlast = NULL;
+ temp->node = NULL;
+ temp->isoDirRecord = NULL;
+ temp->isoExtAttributes = NULL;
+ temp->rr_real_parent = temp->rr_relocated = NULL;
+ temp->su_tail_data = NULL;
+ return temp;
+}
+
+int cd9660_defaults_set = 0;
+
+/**
+* Set default values for cd9660 extension to makefs
+*/
+static void
+cd9660_set_defaults(void)
+{
+ /*Fix the sector size for now, though the spec allows for other sizes*/
+ diskStructure.sectorSize = 2048;
+
+ /* Set up defaults in our own structure */
+ diskStructure.verbose_level = 0;
+ diskStructure.keep_bad_images = 0;
+ diskStructure.follow_sym_links = 0;
+ diskStructure.isoLevel = 2;
+
+ diskStructure.rock_ridge_enabled = 0;
+ diskStructure.rock_ridge_renamed_dir_name = 0;
+ diskStructure.rock_ridge_move_count = 0;
+ diskStructure.rr_moved_dir = 0;
+
+ diskStructure.archimedes_enabled = 0;
+
+ diskStructure.include_padding_areas = 1;
+
+ /* Spec breaking functionality */
+ diskStructure.allow_deep_trees =
+ diskStructure.allow_start_dot =
+ diskStructure.allow_max_name =
+ diskStructure.allow_illegal_chars =
+ diskStructure.allow_lowercase =
+ diskStructure.allow_multidot =
+ diskStructure.omit_trailing_period = 0;
+
+ /* Make sure the PVD is clear */
+ memset(&diskStructure.primaryDescriptor, 0, 2048);
+
+ memset(diskStructure.primaryDescriptor.volume_set_id, 0x20,32);
+ memset(diskStructure.primaryDescriptor.publisher_id, 0x20,128);
+ memset(diskStructure.primaryDescriptor.preparer_id, 0x20,128);
+ memset(diskStructure.primaryDescriptor.application_id, 0x20,128);
+ memset(diskStructure.primaryDescriptor.copyright_file_id, 0x20,128);
+ memset(diskStructure.primaryDescriptor.abstract_file_id, 0x20,128);
+ memset(diskStructure.primaryDescriptor.bibliographic_file_id, 0x20,128);
+
+ strcpy(diskStructure.primaryDescriptor.system_id,"NetBSD");
+
+ cd9660_defaults_set = 1;
+
+ /* Boot support: Initially disabled */
+ diskStructure.has_generic_bootimage = 0;
+ diskStructure.generic_bootimage = NULL;
+
+ diskStructure.boot_image_directory = 0;
+ /*memset(diskStructure.boot_descriptor, 0, 2048);*/
+
+ diskStructure.is_bootable = 0;
+ TAILQ_INIT(&diskStructure.boot_images);
+ LIST_INIT(&diskStructure.boot_entries);
+}
+
+void
+cd9660_prep_opts(fsinfo_t *fsopts __unused)
+{
+ cd9660_set_defaults();
+}
+
+void
+cd9660_cleanup_opts(fsinfo_t *fsopts __unused)
+{
+
+}
+
+static int
+cd9660_arguments_set_string(const char *val, const char *fieldtitle, int length,
+ char testmode, char * dest)
+{
+ int len, test;
+
+ if (val == NULL)
+ warnx("error: The %s requires a string argument", fieldtitle);
+ else if ((len = strlen(val)) <= length) {
+ if (testmode == 'd')
+ test = cd9660_valid_d_chars(val);
+ else
+ test = cd9660_valid_a_chars(val);
+ if (test) {
+ memcpy(dest, val, len);
+ if (test == 2)
+ cd9660_uppercase_characters(dest, len);
+ return 1;
+ } else
+ warnx("error: The %s must be composed of "
+ "%c-characters", fieldtitle, testmode);
+ } else
+ warnx("error: The %s must be at most 32 characters long",
+ fieldtitle);
+ return 0;
+}
+
+/*
+ * Command-line parsing function
+ */
+
+int
+cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
+{
+ char *var, *val;
+ int rv;
+ /* Set up allowed options - integer options ONLY */
+ option_t cd9660_options[] = {
+ { "l", &diskStructure.isoLevel, 1, 3, "ISO Level" },
+ { "isolevel", &diskStructure.isoLevel, 1, 3, "ISO Level" },
+ { "verbose", &diskStructure.verbose_level, 0, 2,
+ "Turns on verbose output" },
+ { "v", &diskStructure.verbose_level, 0 , 2,
+ "Turns on verbose output"},
+ { .name = NULL }
+ };
+
+ if (cd9660_defaults_set == 0)
+ cd9660_set_defaults();
+
+ /*
+ * Todo : finish implementing this, and make a function that
+ * parses them
+ */
+ /*
+ string_option_t cd9660_string_options[] = {
+ { "L", "Label", &diskStructure.primaryDescriptor.volume_id, 1, 32, "Disk Label", ISO_STRING_FILTER_DCHARS },
+ { NULL }
+ }
+ */
+
+ assert(option != NULL);
+
+ if (debug & DEBUG_FS_PARSE_OPTS)
+ printf("cd9660_parse_opts: got `%s'\n", option);
+
+ if ((var = strdup(option)) == NULL)
+ err(1, "allocating memory for copy of option string");
+ rv = 1;
+
+ val = strchr(var, '=');
+ if (val != NULL)
+ *val++ = '\0';
+
+ /* First handle options with no parameters */
+ if (strcmp(var, "h") == 0) {
+ diskStructure.displayHelp = 1;
+ rv = 1;
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "S", "follow-symlinks")) {
+ /* this is not handled yet */
+ diskStructure.follow_sym_links = 1;
+ rv = 1;
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "L", "label")) {
+ rv = cd9660_arguments_set_string(val, "Disk Label", 32, 'd',
+ diskStructure.primaryDescriptor.volume_id);
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "applicationid")) {
+ rv = cd9660_arguments_set_string(val, "Application Identifier", 128, 'a',
+ diskStructure.primaryDescriptor.application_id);
+ } else if(CD9660_IS_COMMAND_ARG_DUAL(var, "P", "publisher")) {
+ rv = cd9660_arguments_set_string(val, "Publisher Identifier",
+ 128, 'a', diskStructure.primaryDescriptor.publisher_id);
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "p", "preparer")) {
+ rv = cd9660_arguments_set_string(val, "Preparer Identifier",
+ 128, 'a', diskStructure.primaryDescriptor.preparer_id);
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "V", "volumeid")) {
+ rv = cd9660_arguments_set_string(val, "Volume Set Identifier",
+ 128, 'a', diskStructure.primaryDescriptor.volume_set_id);
+ /* Boot options */
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "B", "bootimage")) {
+ if (val == NULL)
+ warnx("error: The Boot Image parameter requires a valid boot information string");
+ else
+ rv = cd9660_add_boot_disk(val);
+ } else if (CD9660_IS_COMMAND_ARG(var, "bootimagedir")) {
+ /*
+ * XXXfvdl this is unused.
+ */
+ if (val == NULL)
+ errx(1, "error: The Boot Image Directory parameter"
+ " requires a directory name\n");
+ else {
+ if ((diskStructure.boot_image_directory =
+ malloc(strlen(val) + 1)) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_parse_opts");
+ exit(1);
+ }
+
+ /* BIG TODO: Add the max length function here */
+ cd9660_arguments_set_string(val, "Boot Image Directory",
+ 12 , 'd', diskStructure.boot_image_directory);
+ }
+ } else if (CD9660_IS_COMMAND_ARG_DUAL(var, "G", "generic-bootimage")) {
+ if (val == NULL)
+ warnx("error: The Boot Image parameter requires a valid boot information string");
+ else
+ rv = cd9660_add_generic_bootimage(val);
+ } else if (CD9660_IS_COMMAND_ARG(var, "no-trailing-padding"))
+ diskStructure.include_padding_areas = 0;
+ /* RRIP */
+ else if (CD9660_IS_COMMAND_ARG_DUAL(var, "R", "rockridge"))
+ diskStructure.rock_ridge_enabled = 1;
+ else if (CD9660_IS_COMMAND_ARG_DUAL(var, "A", "archimedes"))
+ diskStructure.archimedes_enabled = 1;
+ else if (CD9660_IS_COMMAND_ARG_DUAL(var, "K", "keep-bad-images"))
+ diskStructure.keep_bad_images = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "allow-deep-trees"))
+ diskStructure.allow_deep_trees = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "allow-max-name"))
+ diskStructure.allow_max_name = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "allow-illegal-chars"))
+ diskStructure.allow_illegal_chars = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "allow-lowercase"))
+ diskStructure.allow_lowercase = 1;
+ else if (CD9660_IS_COMMAND_ARG(var,"allow-multidot"))
+ diskStructure.allow_multidot = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "omit-trailing-period"))
+ diskStructure.omit_trailing_period = 1;
+ else if (CD9660_IS_COMMAND_ARG(var, "no-emul-boot") ||
+ CD9660_IS_COMMAND_ARG(var, "no-boot") ||
+ CD9660_IS_COMMAND_ARG(var, "hard-disk-boot")) {
+ cd9660_eltorito_add_boot_option(var, 0);
+
+ /* End of flag variables */
+ } else if (CD9660_IS_COMMAND_ARG(var, "boot-load-segment")) {
+ if (val == NULL) {
+ warnx("Option `%s' doesn't contain a value", var);
+ rv = 0;
+ } else {
+ cd9660_eltorito_add_boot_option(var, val);
+ }
+ } else {
+ if (val == NULL) {
+ warnx("Option `%s' doesn't contain a value", var);
+ rv = 0;
+ } else
+ rv = set_option(cd9660_options, var, val);
+ }
+
+ if (var)
+ free(var);
+ return (rv);
+}
+
+/*
+ * Main function for cd9660_makefs
+ * Builds the ISO image file
+ * @param const char *image The image filename to create
+ * @param const char *dir The directory that is being read
+ * @param struct fsnode *root The root node of the filesystem tree
+ * @param struct fsinfo_t *fsopts Any options
+ */
+void
+cd9660_makefs(const char *image, const char *dir, fsnode *root,
+ fsinfo_t *fsopts)
+{
+ int64_t startoffset;
+ int numDirectories;
+ uint64_t pathTableSectors;
+ int64_t firstAvailableSector;
+ int64_t totalSpace;
+ int error;
+ cd9660node *real_root;
+
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: ISO level is %i\n",
+ diskStructure.isoLevel);
+ if (diskStructure.isoLevel < 2 &&
+ diskStructure.allow_multidot)
+ errx(1, "allow-multidot requires iso level of 2\n");
+
+ assert(image != NULL);
+ assert(dir != NULL);
+ assert(root != NULL);
+
+ if (diskStructure.displayHelp) {
+ /*
+ * Display help here - probably want to put it in
+ * a separate function
+ */
+ return;
+ }
+
+ diskStructure.rootFilesystemPath = dir;
+
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: image %s directory %s root %p\n",
+ image, dir, root);
+
+ /* Set up some constants. Later, these will be defined with options */
+
+ /* Counter needed for path tables */
+ numDirectories = 0;
+
+ /* Convert tree to our own format */
+ /* Actually, we now need to add the REAL root node, at level 0 */
+
+ real_root = cd9660_allocate_cd9660node();
+ if ((real_root->isoDirRecord =
+ malloc( sizeof(iso_directory_record_cd9660) )) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_makefs");
+ exit(1);
+ }
+
+ /* Leave filename blank for root */
+ memset(real_root->isoDirRecord->name, 0,
+ ISO_FILENAME_MAXLENGTH_WITH_PADDING);
+
+ real_root->level = 0;
+ diskStructure.rootNode = real_root;
+ real_root->type = CD9660_TYPE_DIR;
+ error = 0;
+ real_root->node = root;
+ cd9660_convert_structure(root, real_root, 1, &numDirectories, &error);
+
+ if (TAILQ_EMPTY(&real_root->cn_children)) {
+ errx(1, "cd9660_makefs: converted directory is empty. "
+ "Tree conversion failed\n");
+ } else if (error != 0) {
+ errx(1, "cd9660_makefs: tree conversion failed\n");
+ } else {
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: tree converted\n");
+ }
+
+ /* Add the dot and dot dot records */
+ cd9660_add_dot_records(real_root);
+
+ cd9660_setup_root_node();
+
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: done converting tree\n");
+
+ /* non-SUSP extensions */
+ if (diskStructure.archimedes_enabled)
+ archimedes_convert_tree(diskStructure.rootNode);
+
+ /* Rock ridge / SUSP init pass */
+ if (diskStructure.rock_ridge_enabled) {
+ cd9660_susp_initialize(diskStructure.rootNode,
+ diskStructure.rootNode, NULL);
+ }
+
+ /* Build path table structure */
+ diskStructure.pathTableLength = cd9660_generate_path_table();
+
+ pathTableSectors = CD9660_BLOCKS(diskStructure.sectorSize,
+ diskStructure.pathTableLength);
+
+ firstAvailableSector = cd9660_setup_volume_descriptors();
+ if (diskStructure.is_bootable) {
+ firstAvailableSector = cd9660_setup_boot(firstAvailableSector);
+ if (firstAvailableSector < 0)
+ errx(1, "setup_boot failed");
+ }
+ /* LE first, then BE */
+ diskStructure.primaryLittleEndianTableSector = firstAvailableSector;
+ diskStructure.primaryBigEndianTableSector =
+ diskStructure.primaryLittleEndianTableSector + pathTableSectors;
+
+ /* Set the secondary ones to -1, not going to use them for now */
+ diskStructure.secondaryBigEndianTableSector = -1;
+ diskStructure.secondaryLittleEndianTableSector = -1;
+
+ diskStructure.dataFirstSector =
+ diskStructure.primaryBigEndianTableSector + pathTableSectors;
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: Path table conversion complete. "
+ "Each table is %i bytes, or %" PRIu64 " sectors.\n",
+ diskStructure.pathTableLength, pathTableSectors);
+
+ startoffset = diskStructure.sectorSize*diskStructure.dataFirstSector;
+
+ totalSpace = cd9660_compute_offsets(real_root, startoffset);
+
+ diskStructure.totalSectors = diskStructure.dataFirstSector +
+ CD9660_BLOCKS(diskStructure.sectorSize, totalSpace);
+
+ /* Disabled until pass 1 is done */
+ if (diskStructure.rock_ridge_enabled) {
+ diskStructure.susp_continuation_area_start_sector =
+ diskStructure.totalSectors;
+ diskStructure.totalSectors +=
+ CD9660_BLOCKS(diskStructure.sectorSize,
+ diskStructure.susp_continuation_area_size);
+ cd9660_susp_finalize(diskStructure.rootNode);
+ }
+
+
+ cd9660_finalize_PVD();
+
+ /* Add padding sectors, just for testing purposes right now */
+ /* diskStructure.totalSectors+=150; */
+
+ /* Debugging output */
+ if (diskStructure.verbose_level > 0) {
+ printf("cd9660_makefs: Sectors 0-15 reserved\n");
+ printf("cd9660_makefs: Primary path tables starts in sector %"
+ PRId64 "\n", diskStructure.primaryLittleEndianTableSector);
+ printf("cd9660_makefs: File data starts in sector %"
+ PRId64 "\n", diskStructure.dataFirstSector);
+ printf("cd9660_makefs: Total sectors: %"
+ PRId64 "\n", diskStructure.totalSectors);
+ }
+
+ /*
+ * Add padding sectors at the end
+ * TODO: Clean this up and separate padding
+ */
+ if (diskStructure.include_padding_areas)
+ diskStructure.totalSectors += 150;
+
+ cd9660_write_image(image);
+
+ if (diskStructure.verbose_level > 1) {
+ debug_print_volume_descriptor_information();
+ debug_print_tree(real_root,0);
+ debug_print_path_tree(real_root);
+ }
+
+ /* Clean up data structures */
+ cd9660_free_structure(real_root);
+
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_makefs: done\n");
+}
+
+/* Generic function pointer - implement later */
+typedef int (*cd9660node_func)(cd9660node *);
+
+static void
+cd9660_finalize_PVD(void)
+{
+ time_t tim;
+ unsigned char *temp;
+
+ /* Copy the root directory record */
+ temp = (unsigned char *) &diskStructure.primaryDescriptor;
+
+ /* root should be a fixed size of 34 bytes since it has no name */
+ memcpy(diskStructure.primaryDescriptor.root_directory_record,
+ diskStructure.rootNode->dot_record->isoDirRecord, 34);
+
+ /* In RRIP, this might be longer than 34 */
+ diskStructure.primaryDescriptor.root_directory_record[0] = 34;
+
+ /* Set up all the important numbers in the PVD */
+ cd9660_bothendian_dword(diskStructure.totalSectors,
+ (unsigned char *)diskStructure.primaryDescriptor.volume_space_size);
+ cd9660_bothendian_word(1,
+ (unsigned char *)diskStructure.primaryDescriptor.volume_set_size);
+ cd9660_bothendian_word(1,
+ (unsigned char *)
+ diskStructure.primaryDescriptor.volume_sequence_number);
+ cd9660_bothendian_word(diskStructure.sectorSize,
+ (unsigned char *)
+ diskStructure.primaryDescriptor.logical_block_size);
+ cd9660_bothendian_dword(diskStructure.pathTableLength,
+ (unsigned char *)diskStructure.primaryDescriptor.path_table_size);
+
+ cd9660_731(diskStructure.primaryLittleEndianTableSector,
+ (u_char *)diskStructure.primaryDescriptor.type_l_path_table);
+ cd9660_732(diskStructure.primaryBigEndianTableSector,
+ (u_char *)diskStructure.primaryDescriptor.type_m_path_table);
+
+ diskStructure.primaryDescriptor.file_structure_version[0] = 1;
+
+ /* Pad all strings with spaces instead of nulls */
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.volume_id, 32);
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.system_id, 32);
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.volume_set_id,
+ 128);
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.publisher_id,
+ 128);
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.preparer_id,
+ 128);
+ cd9660_pad_string_spaces(diskStructure.primaryDescriptor.application_id,
+ 128);
+ cd9660_pad_string_spaces(
+ diskStructure.primaryDescriptor.copyright_file_id, 128);
+ cd9660_pad_string_spaces(
+ diskStructure.primaryDescriptor.abstract_file_id, 128);
+ cd9660_pad_string_spaces(
+ diskStructure.primaryDescriptor.bibliographic_file_id, 128);
+
+ /* Setup dates */
+ time(&tim);
+ cd9660_time_8426(
+ (unsigned char *)diskStructure.primaryDescriptor.creation_date,
+ tim);
+ cd9660_time_8426(
+ (unsigned char *)diskStructure.primaryDescriptor.modification_date,
+ tim);
+
+ /*
+ cd9660_set_date(diskStructure.primaryDescriptor.expiration_date, now);
+ */
+
+ memset(diskStructure.primaryDescriptor.expiration_date, '0' ,17);
+ cd9660_time_8426(
+ (unsigned char *)diskStructure.primaryDescriptor.effective_date,
+ tim);
+}
+
+static void
+cd9660_populate_iso_dir_record(struct _iso_directory_record_cd9660 *record,
+ u_char ext_attr_length, u_char flags,
+ u_char name_len, const char * name)
+{
+ record->ext_attr_length[0] = ext_attr_length;
+ record->flags[0] = ISO_FLAG_CLEAR | flags;
+ record->file_unit_size[0] = 0;
+ record->interleave[0] = 0;
+ cd9660_bothendian_word(1, record->volume_sequence_number);
+ record->name_len[0] = name_len;
+ memset(record->name, '\0', sizeof (record->name));
+ memcpy(record->name, name, name_len);
+ record->length[0] = 33 + name_len;
+
+ /* Todo : better rounding */
+ record->length[0] += (record->length[0] & 1) ? 1 : 0;
+}
+
+static void
+cd9660_setup_root_node(void)
+{
+ cd9660_populate_iso_dir_record(diskStructure.rootNode->isoDirRecord,
+ 0, ISO_FLAG_DIRECTORY, 1, "\0");
+
+}
+
+/*********** SUPPORT FUNCTIONS ***********/
+static int
+cd9660_setup_volume_descriptors(void)
+{
+ /* Boot volume descriptor should come second */
+ int sector = 16;
+ /* For now, a fixed 2 : PVD and terminator */
+ volume_descriptor *temp, *t;
+
+ /* Set up the PVD */
+ if ((temp = malloc(sizeof(volume_descriptor))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_setup_volume_descriptors");
+ exit(1);
+ }
+
+ temp->volumeDescriptorData =
+ (unsigned char *)&diskStructure.primaryDescriptor;
+ temp->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_PVD;
+ temp->volumeDescriptorData[6] = 1;
+ temp->sector = sector;
+ memcpy(temp->volumeDescriptorData + 1,
+ ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+ diskStructure.firstVolumeDescriptor = temp;
+
+ sector++;
+ /* Set up boot support if enabled. BVD must reside in sector 17 */
+ if (diskStructure.is_bootable) {
+ if ((t = malloc(sizeof(volume_descriptor))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR(
+ "cd9660_setup_volume_descriptors");
+ exit(1);
+ }
+ if ((t->volumeDescriptorData = malloc(2048)) == NULL) {
+ CD9660_MEM_ALLOC_ERROR(
+ "cd9660_setup_volume_descriptors");
+ exit(1);
+ }
+ temp->next = t;
+ temp = t;
+ memset(t->volumeDescriptorData, 0, 2048);
+ t->sector = 17;
+ if (diskStructure.verbose_level > 0)
+ printf("Setting up boot volume descriptor\n");
+ cd9660_setup_boot_volume_descriptor(t);
+ sector++;
+ }
+
+ /* Set up the terminator */
+ if ((t = malloc(sizeof(volume_descriptor))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_setup_volume_descriptors");
+ exit(1);
+ }
+ if ((t->volumeDescriptorData = malloc(2048)) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_setup_volume_descriptors");
+ exit(1);
+ }
+
+ temp->next = t;
+ memset(t->volumeDescriptorData, 0, 2048);
+ t->volumeDescriptorData[0] = ISO_VOLUME_DESCRIPTOR_TERMINATOR;
+ t->next = 0;
+ t->volumeDescriptorData[6] = 1;
+ t->sector = sector;
+ memcpy(t->volumeDescriptorData + 1,
+ ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+
+ sector++;
+ return sector;
+}
+
+#if 0
+/*
+ * Populate EAR at some point. Not required, but is used by NetBSD's
+ * cd9660 support
+ */
+static int
+cd9660_fill_extended_attribute_record(cd9660node *node)
+{
+ if ((node->isoExtAttributes =
+ malloc(sizeof(struct iso_extended_attributes))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_fill_extended_attribute_record");
+ exit(1);
+ };
+
+ return 1;
+}
+#endif
+
+static int
+cd9960_translate_node_common(cd9660node *newnode)
+{
+ time_t tim;
+ int test;
+ u_char flag;
+ char temp[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
+
+ /* Now populate the isoDirRecord structure */
+ memset(temp, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
+
+ test = cd9660_convert_filename(newnode->node->name,
+ temp, !(S_ISDIR(newnode->node->type)));
+
+ flag = ISO_FLAG_CLEAR;
+ if (S_ISDIR(newnode->node->type))
+ flag |= ISO_FLAG_DIRECTORY;
+
+ cd9660_populate_iso_dir_record(newnode->isoDirRecord, 0,
+ flag, strlen(temp), temp);
+
+ /* Set the various dates */
+
+ /* If we want to use the current date and time */
+ time(&tim);
+
+ cd9660_time_915(newnode->isoDirRecord->date, tim);
+
+ cd9660_bothendian_dword(newnode->fileDataLength,
+ newnode->isoDirRecord->size);
+ /* If the file is a link, we want to set the size to 0 */
+ if (S_ISLNK(newnode->node->type))
+ newnode->fileDataLength = 0;
+
+ return 1;
+}
+
+/*
+ * Translate fsnode to cd9960node
+ * Translate filenames and other metadata, including dates, sizes,
+ * permissions, etc
+ * @param struct fsnode * The node generated by makefs
+ * @param struct cd9660node * The intermediate node to be written to
+ * @returns int 0 on failure, 1 on success
+ */
+static int
+cd9660_translate_node(fsnode *node, cd9660node *newnode)
+{
+ if (node == NULL) {
+ if (diskStructure.verbose_level > 0)
+ printf("cd9660_translate_node: NULL node passed, "
+ "returning\n");
+ return 0;
+ }
+ if ((newnode->isoDirRecord =
+ malloc(sizeof(iso_directory_record_cd9660))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_translate_node");
+ return 0;
+ }
+
+ /* Set the node pointer */
+ newnode->node = node;
+
+ /* Set the size */
+ if (!(S_ISDIR(node->type)))
+ newnode->fileDataLength = node->inode->st.st_size;
+
+ if (cd9960_translate_node_common(newnode) == 0)
+ return 0;
+
+ /* Finally, overwrite some of the values that are set by default */
+ cd9660_time_915(newnode->isoDirRecord->date, node->inode->st.st_mtime);
+
+ return 1;
+}
+
+/*
+ * Compares two ISO filenames
+ * @param const char * The first file name
+ * @param const char * The second file name
+ * @returns : -1 if first is less than second, 0 if they are the same, 1 if
+ * the second is greater than the first
+ */
+static int
+cd9660_compare_filename(const char *first, const char *second)
+{
+ /*
+ * This can be made more optimal once it has been tested
+ * (the extra character, for example, is for testing)
+ */
+
+ int p1 = 0;
+ int p2 = 0;
+ char c1, c2;
+ /* First, on the filename */
+
+ while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1
+ && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION-1) {
+ c1 = first[p1];
+ c2 = second[p2];
+ if (c1 == '.' && c2 =='.')
+ break;
+ else if (c1 == '.') {
+ p2++;
+ c1 = ' ';
+ } else if (c2 == '.') {
+ p1++;
+ c2 = ' ';
+ } else {
+ p1++;
+ p2++;
+ }
+
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2) {
+ return 1;
+ }
+ }
+
+ if (first[p1] == '.' && second[p2] == '.') {
+ p1++;
+ p2++;
+ while (p1 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1
+ && p2 < ISO_FILENAME_MAXLENGTH_BEFORE_VERSION - 1) {
+ c1 = first[p1];
+ c2 = second[p2];
+ if (c1 == ';' && c2 == ';')
+ break;
+ else if (c1 == ';') {
+ p2++;
+ c1 = ' ';
+ } else if (c2 == ';') {
+ p1++;
+ c2 = ' ';
+ } else {
+ p1++;
+ p2++;
+ }
+
+ if (c1 < c2)
+ return -1;
+ else if (c1 > c2)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Insert a node into list with ISO sorting rules
+ * @param cd9660node * The head node of the list
+ * @param cd9660node * The node to be inserted
+ */
+static void
+cd9660_sorted_child_insert(cd9660node *parent, cd9660node *cn_new)
+{
+ int compare;
+ cd9660node *cn;
+ struct cd9660_children_head *head = &parent->cn_children;
+
+ /* TODO: Optimize? */
+ cn_new->parent = parent;
+
+ /*
+ * first will either be 0, the . or the ..
+ * if . or .., this means no other entry may be written before first
+ * if 0, the new node may be inserted at the head
+ */
+
+ TAILQ_FOREACH(cn, head, cn_next_child) {
+ /*
+ * Dont insert a node twice -
+ * that would cause an infinite loop
+ */
+ if (cn_new == cn)
+ return;
+
+ compare = cd9660_compare_filename(cn_new->isoDirRecord->name,
+ cn->isoDirRecord->name);
+
+ if (compare == 0)
+ compare = cd9660_compare_filename(cn_new->node->name,
+ cn->node->name);
+
+ if (compare < 0)
+ break;
+ }
+ if (cn == NULL)
+ TAILQ_INSERT_TAIL(head, cn_new, cn_next_child);
+ else
+ TAILQ_INSERT_BEFORE(cn, cn_new, cn_next_child);
+}
+
+/*
+ * Called After cd9660_sorted_child_insert
+ * handles file collisions by suffixing each filname with ~n
+ * where n represents the files respective place in the ordering
+ */
+static int
+cd9660_handle_collisions(cd9660node *colliding, int past)
+{
+ cd9660node *iter, *next, *prev;
+ int skip;
+ int delete_chars = 0;
+ int temp_past = past;
+ int temp_skip;
+ int flag = 0;
+ cd9660node *end_of_range;
+
+ for (iter = TAILQ_FIRST(&colliding->cn_children);
+ iter != NULL && (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;) {
+ if (strcmp(iter->isoDirRecord->name,
+ next->isoDirRecord->name) != 0) {
+ iter = TAILQ_NEXT(iter, cn_next_child);
+ continue;
+ }
+ flag = 1;
+ temp_skip = skip = cd9660_count_collisions(iter);
+ end_of_range = iter;
+ while (temp_skip > 0) {
+ temp_skip--;
+ end_of_range = TAILQ_NEXT(end_of_range, cn_next_child);
+ }
+ temp_past = past;
+ while (temp_past > 0) {
+ if ((next = TAILQ_NEXT(end_of_range, cn_next_child)) != NULL)
+ end_of_range = next;
+ else if ((prev = TAILQ_PREV(iter, cd9660_children_head, cn_next_child)) != NULL)
+ iter = prev;
+ else
+ delete_chars++;
+ temp_past--;
+ }
+ skip += past;
+ iter = cd9660_rename_filename(iter, skip, delete_chars);
+ }
+ return flag;
+}
+
+
+static cd9660node *
+cd9660_rename_filename(cd9660node *iter, int num, int delete_chars)
+{
+ int i = 0;
+ int numbts, dot, semi, digit, digits, temp, powers, multiplier, count;
+ char *naming;
+ int maxlength;
+ char *tmp;
+
+ if (diskStructure.verbose_level > 0)
+ printf("Rename_filename called\n");
+
+ /* TODO : A LOT of chanes regarding 8.3 filenames */
+ if (diskStructure.isoLevel == 1)
+ maxlength = 8;
+ else if (diskStructure.isoLevel == 2)
+ maxlength = 31;
+ else
+ maxlength = ISO_FILENAME_MAXLENGTH_BEFORE_VERSION;
+
+ tmp = malloc(ISO_FILENAME_MAXLENGTH_WITH_PADDING);
+
+ while (i < num) {
+ powers = 1;
+ count = 0;
+ digits = 1;
+ multiplier = 1;
+ while (((int)(i / powers) ) >= 10) {
+ digits++;
+ powers = powers * 10;
+ }
+
+ naming = iter->o_name;
+
+ /*
+ while ((*naming != '.') && (*naming != ';')) {
+ naming++;
+ count++;
+ }
+ */
+
+ dot = -1;
+ semi = -1;
+ while (count < maxlength) {
+ if (*naming == '.')
+ dot = count;
+ else if (*naming == ';') {
+ semi = count;
+ break;
+ }
+ naming++;
+ count++;
+ }
+
+ if ((count + digits) < maxlength)
+ numbts = count;
+ else
+ numbts = maxlength - (digits);
+ numbts -= delete_chars;
+
+ /* 8.3 rules - keep the extension, add before the dot */
+
+ /*
+ * This code makes a bunch of assumptions.
+ * See if you can spot them all :)
+ */
+
+ /*
+ if (diskStructure.isoLevel == 1) {
+ numbts = 8 - digits - delete_chars;
+ if (dot < 0) {
+
+ } else {
+ if (dot < 8) {
+ memmove(&tmp[numbts],&tmp[dot],4);
+ }
+ }
+ }
+ */
+
+ /* (copying just the filename before the '.' */
+ memcpy(tmp, (iter->o_name), numbts);
+
+ /* adding the appropriate number following the name */
+ temp = i;
+ while (digits > 0) {
+ digit = (int)(temp / powers);
+ temp = temp - digit * powers;
+ sprintf(&tmp[numbts] , "%d", digit);
+ digits--;
+ numbts++;
+ powers = powers / 10;
+ }
+
+ while ((*naming != ';') && (numbts < maxlength)) {
+ tmp[numbts] = (*naming);
+ naming++;
+ numbts++;
+ }
+
+ tmp[numbts] = ';';
+ tmp[numbts+1] = '1';
+ tmp[numbts+2] = '\0';
+
+ /*
+ * now tmp has exactly the identifier
+ * we want so we'll copy it back to record
+ */
+ memcpy((iter->isoDirRecord->name), tmp, numbts + 3);
+
+ iter = TAILQ_NEXT(iter, cn_next_child);
+ i++;
+ }
+
+ free(tmp);
+ return iter;
+}
+
+/* Todo: Figure out why these functions are nec. */
+static void
+cd9660_copy_filenames(cd9660node *node)
+{
+ cd9660node *cn;
+
+ if (TAILQ_EMPTY(&node->cn_children))
+ return;
+
+ if (TAILQ_FIRST(&node->cn_children)->isoDirRecord == NULL) {
+ debug_print_tree(diskStructure.rootNode, 0);
+ exit(1);
+ }
+
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
+ cd9660_copy_filenames(cn);
+ memcpy(cn->o_name, cn->isoDirRecord->name,
+ ISO_FILENAME_MAXLENGTH_WITH_PADDING);
+ }
+}
+
+static void
+cd9660_sorting_nodes(cd9660node *node)
+{
+ cd9660node *cn;
+
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
+ cd9660_sorting_nodes(cn);
+ cd9660_sort_nodes(node);
+}
+
+/* XXX Bubble sort. */
+static void
+cd9660_sort_nodes(cd9660node *node)
+{
+ cd9660node *cn, *next;
+
+ do {
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
+ if ((next = TAILQ_NEXT(cn, cn_next_child)) == NULL)
+ return;
+ else if (strcmp(next->isoDirRecord->name,
+ cn->isoDirRecord->name) >= 0)
+ continue;
+ TAILQ_REMOVE(&node->cn_children, next, cn_next_child);
+ TAILQ_INSERT_BEFORE(cn, next, cn_next_child);
+ break;
+ }
+ } while (cn != NULL);
+}
+
+static int
+cd9660_count_collisions(cd9660node *copy)
+{
+ int count = 0;
+ cd9660node *iter, *next;
+
+ for (iter = copy;
+ (next = TAILQ_NEXT(iter, cn_next_child)) != NULL;
+ iter = next) {
+ if (cd9660_compare_filename(iter->isoDirRecord->name,
+ next->isoDirRecord->name) == 0)
+ count++;
+ else
+ return count;
+ }
+#if 0
+ if ((next = TAILQ_NEXT(iter, cn_next_child)) != NULL) {
+ printf("cd9660_recurse_on_collision: count is %i \n", count);
+ compare = cd9660_compare_filename(iter->isoDirRecord->name,
+ next->isoDirRecord->name);
+ if (compare == 0) {
+ count++;
+ return cd9660_recurse_on_collision(next, count);
+ } else
+ return count;
+ }
+#endif
+ return count;
+}
+
+static cd9660node *
+cd9660_rrip_move_directory(cd9660node *dir)
+{
+ char newname[9];
+ cd9660node *tfile;
+
+ /*
+ * This function needs to:
+ * 1) Create an empty virtual file in place of the old directory
+ * 2) Point the virtual file to the new directory
+ * 3) Point the relocated directory to its old parent
+ * 4) Move the directory specified by dir into rr_moved_dir,
+ * and rename it to "diskStructure.rock_ridge_move_count" (as a string)
+ */
+
+ /* First see if the moved directory even exists */
+ if (diskStructure.rr_moved_dir == NULL) {
+ diskStructure.rr_moved_dir =
+ cd9660_create_directory(ISO_RRIP_DEFAULT_MOVE_DIR_NAME,
+ diskStructure.rootNode, dir);
+ if (diskStructure.rr_moved_dir == NULL)
+ return 0;
+ }
+
+ /* Create a file with the same ORIGINAL name */
+ tfile = cd9660_create_file(dir->node->name, dir->parent, dir);
+ if (tfile == NULL)
+ return NULL;
+
+ diskStructure.rock_ridge_move_count++;
+ snprintf(newname, sizeof(newname), "%08i",
+ diskStructure.rock_ridge_move_count);
+
+ /* Point to old parent */
+ dir->rr_real_parent = dir->parent;
+
+ /* Place the placeholder file */
+ if (TAILQ_EMPTY(&dir->rr_real_parent->cn_children)) {
+ TAILQ_INSERT_HEAD(&dir->rr_real_parent->cn_children, tfile,
+ cn_next_child);
+ } else {
+ cd9660_sorted_child_insert(dir->rr_real_parent, tfile);
+ }
+
+ /* Point to new parent */
+ dir->parent = diskStructure.rr_moved_dir;
+
+ /* Point the file to the moved directory */
+ tfile->rr_relocated = dir;
+
+ /* Actually move the directory */
+ cd9660_sorted_child_insert(diskStructure.rr_moved_dir, dir);
+
+ /* TODO: Inherit permissions / ownership (basically the entire inode) */
+
+ /* Set the new name */
+ memset(dir->isoDirRecord->name, 0, ISO_FILENAME_MAXLENGTH_WITH_PADDING);
+ strncpy(dir->isoDirRecord->name, newname, 8);
+
+ return dir;
+}
+
+static int
+cd9660_add_dot_records(cd9660node *root)
+{
+ struct cd9660_children_head *head = &root->cn_children;
+ cd9660node *cn;
+
+ TAILQ_FOREACH(cn, head, cn_next_child) {
+ if ((cn->type & CD9660_TYPE_DIR) == 0)
+ continue;
+ /* Recursion first */
+ cd9660_add_dot_records(cn);
+ }
+ cd9660_create_special_directory(CD9660_TYPE_DOT, root);
+ cd9660_create_special_directory(CD9660_TYPE_DOTDOT, root);
+ return 1;
+}
+
+/*
+ * Convert node to cd9660 structure
+ * This function is designed to be called recursively on the root node of
+ * the filesystem
+ * Lots of recursion going on here, want to make sure it is efficient
+ * @param struct fsnode * The root node to be converted
+ * @param struct cd9660* The parent node (should not be NULL)
+ * @param int Current directory depth
+ * @param int* Running count of the number of directories that are being created
+ */
+static void
+cd9660_convert_structure(fsnode *root, cd9660node *parent_node, int level,
+ int *numDirectories, int *error)
+{
+ fsnode *iterator = root;
+ cd9660node *this_node;
+ int working_level;
+ int add;
+ int flag = 0;
+ int counter = 0;
+
+ /*
+ * Newer, more efficient method, reduces recursion depth
+ */
+ if (root == NULL) {
+ warnx("%s: root is null\n", __func__);
+ return;
+ }
+
+ /* Test for an empty directory - makefs still gives us the . record */
+ if ((S_ISDIR(root->type)) && (root->name[0] == '.')
+ && (root->name[1] == '\0')) {
+ root = root->next;
+ if (root == NULL)
+ return;
+ }
+ if ((this_node = cd9660_allocate_cd9660node()) == NULL) {
+ CD9660_MEM_ALLOC_ERROR(__func__);
+ }
+
+ /*
+ * To reduce the number of recursive calls, we will iterate over
+ * the next pointers to the right.
+ */
+ while (iterator != NULL) {
+ add = 1;
+ /*
+ * Increment the directory count if this is a directory
+ * Ignore "." entries. We will generate them later
+ */
+ if (!S_ISDIR(iterator->type) ||
+ strcmp(iterator->name, ".") != 0) {
+
+ /* Translate the node, including its filename */
+ this_node->parent = parent_node;
+ cd9660_translate_node(iterator, this_node);
+ this_node->level = level;
+
+ if (S_ISDIR(iterator->type)) {
+ (*numDirectories)++;
+ this_node->type = CD9660_TYPE_DIR;
+ working_level = level + 1;
+
+ /*
+ * If at level 8, directory would be at 8
+ * and have children at 9 which is not
+ * allowed as per ISO spec
+ */
+ if (level == 8) {
+ if ((!diskStructure.allow_deep_trees) &&
+ (!diskStructure.rock_ridge_enabled)) {
+ warnx("error: found entry "
+ "with depth greater "
+ "than 8.");
+ (*error) = 1;
+ return;
+ } else if (diskStructure.
+ rock_ridge_enabled) {
+ working_level = 3;
+ /*
+ * Moved directory is actually
+ * at level 2.
+ */
+ this_node->level =
+ working_level - 1;
+ if (cd9660_rrip_move_directory(
+ this_node) == 0) {
+ warnx("Failure in "
+ "cd9660_rrip_"
+ "move_directory"
+ );
+ (*error) = 1;
+ return;
+ }
+ add = 0;
+ }
+ }
+
+ /* Do the recursive call on the children */
+ if (iterator->child != 0) {
+ cd9660_convert_structure(
+ iterator->child, this_node,
+ working_level,
+ numDirectories, error);
+
+ if ((*error) == 1) {
+ warnx("%s: Error on recursive "
+ "call", __func__);
+ return;
+ }
+ }
+
+ } else {
+ /* Only directories should have children */
+ assert(iterator->child == NULL);
+
+ this_node->type = CD9660_TYPE_FILE;
+ }
+
+ /*
+ * Finally, do a sorted insert
+ */
+ if (add) {
+ cd9660_sorted_child_insert(
+ parent_node, this_node);
+ }
+
+ /*Allocate new temp_node */
+ if (iterator->next != 0) {
+ this_node = cd9660_allocate_cd9660node();
+ if (this_node == NULL)
+ CD9660_MEM_ALLOC_ERROR(__func__);
+ }
+ }
+ iterator = iterator->next;
+ }
+
+ /* cd9660_handle_collisions(first_node); */
+
+ /* TODO: need cleanup */
+ cd9660_copy_filenames(parent_node);
+
+ do {
+ flag = cd9660_handle_collisions(parent_node, counter);
+ counter++;
+ cd9660_sorting_nodes(parent_node);
+ } while ((flag == 1) && (counter < 100));
+}
+
+/*
+ * Clean up the cd9660node tree
+ * This is designed to be called recursively on the root node
+ * @param struct cd9660node *root The node to free
+ * @returns void
+ */
+static void
+cd9660_free_structure(cd9660node *root)
+{
+ cd9660node *cn;
+
+ while ((cn = TAILQ_FIRST(&root->cn_children)) != NULL) {
+ TAILQ_REMOVE(&root->cn_children, cn, cn_next_child);
+ cd9660_free_structure(cn);
+ }
+ free(root);
+}
+
+/*
+ * Be a little more memory conservative:
+ * instead of having the TAILQ_ENTRY as part of the cd9660node,
+ * just create a temporary structure
+ */
+struct ptq_entry
+{
+ TAILQ_ENTRY(ptq_entry) ptq;
+ cd9660node *node;
+} *n;
+
+#define PTQUEUE_NEW(n,s,r,t){\
+ n = malloc(sizeof(struct s)); \
+ if (n == NULL) \
+ return r; \
+ n->node = t;\
+}
+
+/*
+ * Generate the path tables
+ * The specific implementation of this function is left as an exercise to the
+ * programmer. It could be done recursively. Make sure you read how the path
+ * table has to be laid out, it has levels.
+ * @param struct iso9660_disk *disk The disk image
+ * @returns int The number of built path tables (between 1 and 4), 0 on failure
+ */
+static int
+cd9660_generate_path_table(void)
+{
+ cd9660node *cn, *dirNode = diskStructure.rootNode;
+ cd9660node *last = dirNode;
+ int pathTableSize = 0; /* computed as we go */
+ int counter = 1; /* root gets a count of 0 */
+ int parentRecNum = 0; /* root's parent is '0' */
+
+ TAILQ_HEAD(cd9660_pt_head, ptq_entry) pt_head;
+ TAILQ_INIT(&pt_head);
+
+ PTQUEUE_NEW(n, ptq_entry, -1, diskStructure.rootNode);
+
+ /* Push the root node */
+ TAILQ_INSERT_HEAD(&pt_head, n, ptq);
+
+ /* Breadth-first traversal of file structure */
+ while (pt_head.tqh_first != 0) {
+ n = pt_head.tqh_first;
+ dirNode = n->node;
+ TAILQ_REMOVE(&pt_head, pt_head.tqh_first, ptq);
+ free(n);
+
+ /* Update the size */
+ pathTableSize += ISO_PATHTABLE_ENTRY_BASESIZE
+ + dirNode->isoDirRecord->name_len[0]+
+ (dirNode->isoDirRecord->name_len[0] % 2 == 0 ? 0 : 1);
+ /* includes the padding bit */
+
+ dirNode->ptnumber=counter;
+ if (dirNode != last) {
+ last->ptnext = dirNode;
+ dirNode->ptprev = last;
+ }
+ last = dirNode;
+
+ parentRecNum = 1;
+ if (dirNode->parent != 0)
+ parentRecNum = dirNode->parent->ptnumber;
+
+ /* Push children onto queue */
+ TAILQ_FOREACH(cn, &dirNode->cn_children, cn_next_child) {
+ /*
+ * Dont add the DOT and DOTDOT types to the path
+ * table.
+ */
+ if ((cn->type != CD9660_TYPE_DOT)
+ && (cn->type != CD9660_TYPE_DOTDOT)) {
+
+ if (S_ISDIR(cn->node->type)) {
+ PTQUEUE_NEW(n, ptq_entry, -1, cn);
+ TAILQ_INSERT_TAIL(&pt_head, n, ptq);
+ }
+ }
+ }
+ counter++;
+ }
+ return pathTableSize;
+}
+
+void
+cd9660_compute_full_filename(cd9660node *node, char *buf, int level)
+{
+ cd9660node *parent;
+
+ parent = (node->rr_real_parent == NULL ?
+ node->parent : node->rr_real_parent);
+ if (parent != NULL) {
+ cd9660_compute_full_filename(parent, buf, level + 1);
+ strcat(buf, node->node->name);
+ } else {
+ /* We are at the root */
+ strcat(buf, diskStructure.rootFilesystemPath);
+ if (buf[strlen(buf) - 1] == '/')
+ buf[strlen(buf) - 1] = '\0';
+ }
+
+ if (level != 0)
+ strcat(buf, "/");
+}
+
+/* NEW filename conversion method */
+typedef int(*cd9660_filename_conversion_functor)(const char *, char *, int);
+
+
+/*
+ * TODO: These two functions are almost identical.
+ * Some code cleanup is possible here
+ *
+ * XXX bounds checking!
+ */
+static int
+cd9660_level1_convert_filename(const char *oldname, char *newname, int is_file)
+{
+ /*
+ * ISO 9660 : 10.1
+ * File Name shall not contain more than 8 d or d1 characters
+ * File Name Extension shall not contain more than 3 d or d1 characters
+ * Directory Identifier shall not contain more than 8 d or d1 characters
+ */
+ int namelen = 0;
+ int extlen = 0;
+ int found_ext = 0;
+
+ while (*oldname != '\0') {
+ /* Handle period first, as it is special */
+ if (*oldname == '.') {
+ if (found_ext) {
+ *newname++ = '_';
+ extlen ++;
+ }
+ else {
+ *newname++ = '.';
+ found_ext = 1;
+ }
+ } else {
+ /* cut RISC OS file type off ISO name */
+ if (diskStructure.archimedes_enabled &&
+ *oldname == ',' && strlen(oldname) == 4)
+ break;
+ /* Enforce 12.3 / 8 */
+ if (((namelen == 8) && !found_ext) ||
+ (found_ext && extlen == 3)) {
+ break;
+ }
+
+ if (islower((unsigned char)*oldname))
+ *newname++ = toupper((unsigned char)*oldname);
+ else if (isupper((unsigned char)*oldname)
+ || isdigit((unsigned char)*oldname))
+ *newname++ = *oldname;
+ else
+ *newname++ = '_';
+
+ if (found_ext)
+ extlen++;
+ else
+ namelen++;
+ }
+ oldname ++;
+ }
+ if (is_file) {
+ if (!found_ext && !diskStructure.omit_trailing_period)
+ *newname++ = '.';
+ /* Add version */
+ sprintf(newname, ";%i", 1);
+ }
+ return namelen + extlen + found_ext;
+}
+
+/* XXX bounds checking! */
+static int
+cd9660_level2_convert_filename(const char *oldname, char *newname, int is_file)
+{
+ /*
+ * ISO 9660 : 7.5.1
+ * File name : 0+ d or d1 characters
+ * separator 1 (.)
+ * File name extension : 0+ d or d1 characters
+ * separator 2 (;)
+ * File version number (5 characters, 1-32767)
+ * 1 <= Sum of File name and File name extension <= 30
+ */
+ int namelen = 0;
+ int extlen = 0;
+ int found_ext = 0;
+
+ while (*oldname != '\0') {
+ /* Handle period first, as it is special */
+ if (*oldname == '.') {
+ if (found_ext) {
+ if (diskStructure.allow_multidot) {
+ *newname++ = '.';
+ } else {
+ *newname++ = '_';
+ }
+ extlen ++;
+ }
+ else {
+ *newname++ = '.';
+ found_ext = 1;
+ }
+ } else {
+ /* cut RISC OS file type off ISO name */
+ if (diskStructure.archimedes_enabled &&
+ *oldname == ',' && strlen(oldname) == 4)
+ break;
+ if ((namelen + extlen) == 30)
+ break;
+
+ if (islower((unsigned char)*oldname))
+ *newname++ = toupper((unsigned char)*oldname);
+ else if (isupper((unsigned char)*oldname) ||
+ isdigit((unsigned char)*oldname))
+ *newname++ = *oldname;
+ else if (diskStructure.allow_multidot &&
+ *oldname == '.') {
+ *newname++ = '.';
+ } else {
+ *newname++ = '_';
+ }
+
+ if (found_ext)
+ extlen++;
+ else
+ namelen++;
+ }
+ oldname ++;
+ }
+ if (is_file) {
+ if (!found_ext && !diskStructure.omit_trailing_period)
+ *newname++ = '.';
+ /* Add version */
+ sprintf(newname, ";%i", 1);
+ }
+ return namelen + extlen + found_ext;
+}
+
+#if 0
+static int
+cd9660_joliet_convert_filename(const char *oldname, char *newname, int is_file)
+{
+ /* TODO: implement later, move to cd9660_joliet.c ?? */
+}
+#endif
+
+
+/*
+ * Convert a file name to ISO compliant file name
+ * @param char * oldname The original filename
+ * @param char ** newname The new file name, in the appropriate character
+ * set and of appropriate length
+ * @param int 1 if file, 0 if directory
+ * @returns int The length of the new string
+ */
+static int
+cd9660_convert_filename(const char *oldname, char *newname, int is_file)
+{
+ /* NEW */
+ cd9660_filename_conversion_functor conversion_function = 0;
+ if (diskStructure.isoLevel == 1)
+ conversion_function = &cd9660_level1_convert_filename;
+ else if (diskStructure.isoLevel == 2)
+ conversion_function = &cd9660_level2_convert_filename;
+ return (*conversion_function)(oldname, newname, is_file);
+}
+
+int
+cd9660_compute_record_size(cd9660node *node)
+{
+ int size = node->isoDirRecord->length[0];
+
+ if (diskStructure.rock_ridge_enabled)
+ size += node->susp_entry_size;
+ size += node->su_tail_size;
+ size += size & 1; /* Ensure length of record is even. */
+ assert(size <= 254);
+ return size;
+}
+
+static void
+cd9660_populate_dot_records(cd9660node *node)
+{
+ node->dot_record->fileDataSector = node->fileDataSector;
+ memcpy(node->dot_record->isoDirRecord,node->isoDirRecord, 34);
+ node->dot_record->isoDirRecord->name_len[0] = 1;
+ node->dot_record->isoDirRecord->name[0] = 0;
+ node->dot_record->isoDirRecord->name[1] = 0;
+ node->dot_record->isoDirRecord->length[0] = 34;
+ node->dot_record->fileRecordSize =
+ cd9660_compute_record_size(node->dot_record);
+
+ if (node == diskStructure.rootNode) {
+ node->dot_dot_record->fileDataSector = node->fileDataSector;
+ memcpy(node->dot_dot_record->isoDirRecord,node->isoDirRecord,
+ 34);
+ } else {
+ node->dot_dot_record->fileDataSector =
+ node->parent->fileDataSector;
+ memcpy(node->dot_dot_record->isoDirRecord,
+ node->parent->isoDirRecord,34);
+ }
+ node->dot_dot_record->isoDirRecord->name_len[0] = 1;
+ node->dot_dot_record->isoDirRecord->name[0] = 1;
+ node->dot_dot_record->isoDirRecord->name[1] = 0;
+ node->dot_dot_record->isoDirRecord->length[0] = 34;
+ node->dot_dot_record->fileRecordSize =
+ cd9660_compute_record_size(node->dot_dot_record);
+}
+
+/*
+ * @param struct cd9660node *node The node
+ * @param int The offset (in bytes) - SHOULD align to the beginning of a sector
+ * @returns int The total size of files and directory entries (should be
+ * a multiple of sector size)
+*/
+static int64_t
+cd9660_compute_offsets(cd9660node *node, int64_t startOffset)
+{
+ /*
+ * This function needs to compute the size of directory records and
+ * runs, file lengths, and set the appropriate variables both in
+ * cd9660node and isoDirEntry
+ */
+ int64_t used_bytes = 0;
+ int64_t current_sector_usage = 0;
+ cd9660node *child;
+ fsinode *inode;
+ int64_t r;
+
+ assert(node != NULL);
+
+
+ /*
+ * NOTE : There needs to be some special case detection for
+ * the "real root" node, since for it, node->node is undefined
+ */
+
+ node->fileDataSector = -1;
+
+ if (node->type & CD9660_TYPE_DIR) {
+ node->fileRecordSize = cd9660_compute_record_size(node);
+ /*Set what sector this directory starts in*/
+ node->fileDataSector =
+ CD9660_BLOCKS(diskStructure.sectorSize,startOffset);
+
+ cd9660_bothendian_dword(node->fileDataSector,
+ node->isoDirRecord->extent);
+
+ /*
+ * First loop over children, need to know the size of
+ * their directory records
+ */
+ node->fileSectorsUsed = 1;
+ TAILQ_FOREACH(child, &node->cn_children, cn_next_child) {
+ node->fileDataLength +=
+ cd9660_compute_record_size(child);
+ if ((cd9660_compute_record_size(child) +
+ current_sector_usage) >=
+ diskStructure.sectorSize) {
+ current_sector_usage = 0;
+ node->fileSectorsUsed++;
+ }
+
+ current_sector_usage +=
+ cd9660_compute_record_size(child);
+ }
+
+ cd9660_bothendian_dword(node->fileSectorsUsed *
+ diskStructure.sectorSize,node->isoDirRecord->size);
+
+ /*
+ * This should point to the sector after the directory
+ * record (or, the first byte in that sector)
+ */
+ used_bytes += node->fileSectorsUsed * diskStructure.sectorSize;
+
+ for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
+ child != NULL; child = TAILQ_NEXT(child, cn_next_child)) {
+ /* Directories need recursive call */
+ if (S_ISDIR(child->node->type)) {
+ r = cd9660_compute_offsets(child,
+ used_bytes + startOffset);
+
+ if (r != -1)
+ used_bytes += r;
+ else
+ return -1;
+ }
+ }
+
+ /* Explicitly set the . and .. records */
+ cd9660_populate_dot_records(node);
+
+ /* Finally, do another iteration to write the file data*/
+ for (child = TAILQ_NEXT(node->dot_dot_record, cn_next_child);
+ child != NULL;
+ child = TAILQ_NEXT(child, cn_next_child)) {
+ /* Files need extent set */
+ if (S_ISDIR(child->node->type))
+ continue;
+ child->fileRecordSize =
+ cd9660_compute_record_size(child);
+
+ child->fileSectorsUsed =
+ CD9660_BLOCKS(diskStructure.sectorSize,
+ child->fileDataLength);
+
+ inode = child->node->inode;
+ if ((inode->flags & FI_ALLOCATED) == 0) {
+ inode->ino =
+ CD9660_BLOCKS(diskStructure.sectorSize,
+ used_bytes + startOffset);
+ inode->flags |= FI_ALLOCATED;
+ used_bytes += child->fileSectorsUsed *
+ diskStructure.sectorSize;
+ } else {
+ INODE_WARNX(("%s: already allocated inode %d "
+ "data sectors at %" PRIu32, __func__,
+ (int)inode->st.st_ino, inode->ino));
+ }
+ child->fileDataSector = inode->ino;
+ cd9660_bothendian_dword(child->fileDataSector,
+ child->isoDirRecord->extent);
+ }
+ }
+
+ return used_bytes;
+}
+
+#if 0
+/* Might get rid of this func */
+static int
+cd9660_copy_stat_info(cd9660node *from, cd9660node *to, int file)
+{
+ to->node->inode->st.st_dev = 0;
+ to->node->inode->st.st_ino = 0;
+ to->node->inode->st.st_size = 0;
+ to->node->inode->st.st_blksize = from->node->inode->st.st_blksize;
+ to->node->inode->st.st_atime = from->node->inode->st.st_atime;
+ to->node->inode->st.st_mtime = from->node->inode->st.st_mtime;
+ to->node->inode->st.st_ctime = from->node->inode->st.st_ctime;
+ to->node->inode->st.st_uid = from->node->inode->st.st_uid;
+ to->node->inode->st.st_gid = from->node->inode->st.st_gid;
+ to->node->inode->st.st_mode = from->node->inode->st.st_mode;
+ /* Clear out type */
+ to->node->inode->st.st_mode = to->node->inode->st.st_mode & ~(S_IFMT);
+ if (file)
+ to->node->inode->st.st_mode |= S_IFREG;
+ else
+ to->node->inode->st.st_mode |= S_IFDIR;
+ return 1;
+}
+#endif
+
+static cd9660node *
+cd9660_create_virtual_entry(const char *name, cd9660node *parent, int file,
+ int insert)
+{
+ cd9660node *temp;
+ fsnode * tfsnode;
+
+ assert(parent != NULL);
+
+ temp = cd9660_allocate_cd9660node();
+ if (temp == NULL)
+ return NULL;
+
+ if ((tfsnode = malloc(sizeof(fsnode))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry");
+ return NULL;
+ }
+
+ /* Assume for now name is a valid length */
+ if ((tfsnode->name = malloc(strlen(name) + 1)) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry");
+ return NULL;
+ }
+
+ if ((temp->isoDirRecord =
+ malloc(sizeof(iso_directory_record_cd9660))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660_create_virtual_entry");
+ return NULL;
+ }
+
+ strcpy(tfsnode->name, name);
+
+ cd9660_convert_filename(tfsnode->name, temp->isoDirRecord->name, file);
+
+ temp->node = tfsnode;
+ temp->parent = parent;
+
+ if (insert) {
+ if (temp->parent != NULL) {
+ temp->level = temp->parent->level + 1;
+ if (!TAILQ_EMPTY(&temp->parent->cn_children))
+ cd9660_sorted_child_insert(temp->parent, temp);
+ else
+ TAILQ_INSERT_HEAD(&temp->parent->cn_children,
+ temp, cn_next_child);
+ }
+ }
+
+ if (parent->node != NULL) {
+ tfsnode->type = parent->node->type;
+ }
+
+ /* Clear out file type bits */
+ tfsnode->type &= ~(S_IFMT);
+ if (file)
+ tfsnode->type |= S_IFREG;
+ else
+ tfsnode->type |= S_IFDIR;
+
+ /* Indicate that there is no spec entry (inode) */
+ tfsnode->flags &= ~(FSNODE_F_HASSPEC);
+#if 0
+ cd9660_copy_stat_info(parent, temp, file);
+#endif
+ return temp;
+}
+
+static cd9660node *
+cd9660_create_file(const char * name, cd9660node *parent, cd9660node *me)
+{
+ cd9660node *temp;
+
+ temp = cd9660_create_virtual_entry(name,parent,1,1);
+ if (temp == NULL)
+ return NULL;
+
+ temp->fileDataLength = 0;
+
+ temp->type = CD9660_TYPE_FILE | CD9660_TYPE_VIRTUAL;
+
+ if ((temp->node->inode = calloc(1, sizeof(fsinode))) == NULL)
+ return NULL;
+ *temp->node->inode = *me->node->inode;
+
+ if (cd9960_translate_node_common(temp) == 0)
+ return NULL;
+ return temp;
+}
+
+/*
+ * Create a new directory which does not exist on disk
+ * @param const char * name The name to assign to the directory
+ * @param const char * parent Pointer to the parent directory
+ * @returns cd9660node * Pointer to the new directory
+ */
+static cd9660node *
+cd9660_create_directory(const char *name, cd9660node *parent, cd9660node *me)
+{
+ cd9660node *temp;
+
+ temp = cd9660_create_virtual_entry(name,parent,0,1);
+ if (temp == NULL)
+ return NULL;
+ temp->node->type |= S_IFDIR;
+
+ temp->type = CD9660_TYPE_DIR | CD9660_TYPE_VIRTUAL;
+
+ if ((temp->node->inode = calloc(1, sizeof(fsinode))) == NULL)
+ return NULL;
+ *temp->node->inode = *me->node->inode;
+
+ if (cd9960_translate_node_common(temp) == 0)
+ return NULL;
+ return temp;
+}
+
+static cd9660node *
+cd9660_create_special_directory(u_char type, cd9660node *parent)
+{
+ cd9660node *temp, *first;
+ char na[2];
+
+ assert(parent != NULL);
+
+ if (type == CD9660_TYPE_DOT)
+ na[0] = 0;
+ else if (type == CD9660_TYPE_DOTDOT)
+ na[0] = 1;
+ else
+ return 0;
+
+ na[1] = 0;
+ if ((temp = cd9660_create_virtual_entry(na, parent, 0, 0)) == NULL)
+ return NULL;
+
+ temp->parent = parent;
+ temp->type = type;
+ temp->isoDirRecord->length[0] = 34;
+ /* Dot record is always first */
+ if (type == CD9660_TYPE_DOT) {
+ parent->dot_record = temp;
+ TAILQ_INSERT_HEAD(&parent->cn_children, temp, cn_next_child);
+ /* DotDot should be second */
+ } else if (type == CD9660_TYPE_DOTDOT) {
+ parent->dot_dot_record = temp;
+ /*
+ * If the first child is the dot record, insert
+ * this second. Otherwise, insert it at the head.
+ */
+ if ((first = TAILQ_FIRST(&parent->cn_children)) == NULL ||
+ (first->type & CD9660_TYPE_DOT) == 0) {
+ TAILQ_INSERT_HEAD(&parent->cn_children, temp,
+ cn_next_child);
+ } else {
+ TAILQ_INSERT_AFTER(&parent->cn_children, first, temp,
+ cn_next_child);
+ }
+ }
+
+ return temp;
+}
+
+int
+cd9660_add_generic_bootimage(const char *bootimage)
+{
+ struct stat stbuf;
+
+ assert(bootimage != NULL);
+
+ if (*bootimage == '\0') {
+ warnx("Error: Boot image must be a filename");
+ return 0;
+ }
+
+ if ((diskStructure.generic_bootimage = strdup(bootimage)) == NULL) {
+ warn("%s: strdup", __func__);
+ return 0;
+ }
+
+ /* Get information about the file */
+ if (lstat(diskStructure.generic_bootimage, &stbuf) == -1)
+ err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
+ diskStructure.generic_bootimage);
+
+ if (stbuf.st_size > 32768) {
+ warnx("Error: Boot image must be no greater than 32768 bytes");
+ return 0;
+ }
+
+ if (diskStructure.verbose_level > 0) {
+ printf("Generic boot image image has size %lld\n",
+ (long long)stbuf.st_size);
+ }
+
+ diskStructure.has_generic_bootimage = 1;
+
+ return 1;
+}
diff --git a/usr.sbin/makefs/cd9660.h b/usr.sbin/makefs/cd9660.h
new file mode 100644
index 0000000..16c0d64
--- /dev/null
+++ b/usr.sbin/makefs/cd9660.h
@@ -0,0 +1,364 @@
+/* $NetBSD: cd9660.h,v 1.15 2010/10/27 18:51:34 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MAKEFS_CD9660_H
+#define _MAKEFS_CD9660_H
+
+#include <inttypes.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+
+#include "makefs.h"
+#include "iso.h"
+#include "iso_rrip.h"
+#include "cd9660/cd9660_eltorito.h"
+
+#ifdef DEBUG
+#define INODE_WARNX(__x) warnx __x
+#else /* DEBUG */
+#define INODE_WARNX(__x)
+#endif /* DEBUG */
+
+#define CD9660MAXPATH 4096
+
+#define ISO_STRING_FILTER_NONE = 0x00
+#define ISO_STRING_FILTER_DCHARS = 0x01
+#define ISO_STRING_FILTER_ACHARS = 0x02
+
+/*
+Extended preferences type, in the spirit of what makefs gives us (only ints)
+*/
+typedef struct {
+ const char *shortName; /* Short option */
+ const char *name; /* option name */
+ char *value; /* where to stuff the value */
+ int minLength; /* minimum for value */
+ int maxLength; /* maximum for value */
+ const char *desc; /* option description */
+ int filterFlags;
+} string_option_t;
+
+/******** STRUCTURES **********/
+
+/*Defaults*/
+#define ISO_DEFAULT_VOLUMEID "MAKEFS_CD9660_IMAGE"
+#define ISO_DEFAULT_APPID "MAKEFS"
+#define ISO_DEFAULT_PUBLISHER "MAKEFS"
+#define ISO_DEFAULT_PREPARER "MAKEFS"
+
+#define ISO_VOLUME_DESCRIPTOR_STANDARD_ID "CD001"
+#define ISO_VOLUME_DESCRIPTOR_BOOT 0
+#define ISO_VOLUME_DESCRIPTOR_PVD 1
+#define ISO_VOLUME_DESCRIPTOR_TERMINATOR 255
+
+/*30 for name and extension, as well as version number and padding bit*/
+#define ISO_FILENAME_MAXLENGTH_BEFORE_VERSION 30
+#define ISO_FILENAME_MAXLENGTH 36
+#define ISO_FILENAME_MAXLENGTH_WITH_PADDING 37
+
+#define ISO_FLAG_CLEAR 0x00
+#define ISO_FLAG_HIDDEN 0x01
+#define ISO_FLAG_DIRECTORY 0x02
+#define ISO_FLAG_ASSOCIATED 0x04
+#define ISO_FLAG_PERMISSIONS 0x08
+#define ISO_FLAG_RESERVED5 0x10
+#define ISO_FLAG_RESERVED6 0x20
+#define ISO_FLAG_FINAL_RECORD 0x40
+
+#define ISO_PATHTABLE_ENTRY_BASESIZE 8
+
+#define ISO_RRIP_DEFAULT_MOVE_DIR_NAME "RR_MOVED"
+#define RRIP_DEFAULT_MOVE_DIR_NAME ".rr_moved"
+
+#define CD9660_BLOCKS(__sector_size, __bytes) \
+ howmany((__bytes), (__sector_size))
+
+#define CD9660_MEM_ALLOC_ERROR(_F) \
+ err(EXIT_FAILURE, "%s, %s l. %d", _F, __FILE__, __LINE__)
+
+#define CD9660_IS_COMMAND_ARG_DUAL(var,short,long)\
+ (strcmp((var),(short)) == 0) || (strcmp((var),(long))==0)
+
+#define CD9660_IS_COMMAND_ARG(var,arg)\
+ (strcmp((var),(arg)) == 0)
+
+#define CD9660_TYPE_FILE 0x01
+#define CD9660_TYPE_DIR 0x02
+#define CD9660_TYPE_DOT 0x04
+#define CD9660_TYPE_DOTDOT 0x08
+#define CD9660_TYPE_VIRTUAL 0x80
+
+#define CD9660_INODE_HASH_SIZE 1024
+#define CD9660_SECTOR_SIZE 2048
+
+#define CD9660_END_PADDING 150
+
+/* Slight modification of the ISO structure in iso.h */
+typedef struct _iso_directory_record_cd9660 {
+ u_char length [ISODCL (1, 1)]; /* 711 */
+ u_char ext_attr_length [ISODCL (2, 2)]; /* 711 */
+ u_char extent [ISODCL (3, 10)]; /* 733 */
+ u_char size [ISODCL (11, 18)]; /* 733 */
+ u_char date [ISODCL (19, 25)]; /* 7 by 711 */
+ u_char flags [ISODCL (26, 26)];
+ u_char file_unit_size [ISODCL (27, 27)]; /* 711 */
+ u_char interleave [ISODCL (28, 28)]; /* 711 */
+ u_char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
+ u_char name_len [ISODCL (33, 33)]; /* 711 */
+ char name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
+} iso_directory_record_cd9660;
+
+/* TODO: Lots of optimization of this structure */
+typedef struct _cd9660node {
+ u_char type;/* Used internally */
+ /* Tree structure */
+ struct _cd9660node *parent; /* parent (NULL if root) */
+ TAILQ_HEAD(cd9660_children_head, _cd9660node) cn_children;
+ TAILQ_ENTRY(_cd9660node) cn_next_child;
+
+ struct _cd9660node *dot_record; /* For directories, used mainly in RRIP */
+ struct _cd9660node *dot_dot_record;
+
+ fsnode *node; /* pointer to fsnode */
+ struct _iso_directory_record_cd9660 *isoDirRecord;
+ struct iso_extended_attributes *isoExtAttributes;
+
+ /***** SIZE CALCULATION *****/
+ /*already stored in isoDirRecord, but this is an int version, and will be
+ copied to isoDirRecord on writing*/
+ uint32_t fileDataSector;
+
+ /*
+ * same thing, though some notes:
+ * If a file, this is the file size
+ * If a directory, this is the size of all its children's
+ * directory records
+ * plus necessary padding
+ */
+ int64_t fileDataLength;
+
+ int64_t fileSectorsUsed;
+ int fileRecordSize;/*copy of a variable, int for quicker calculations*/
+
+ /* Old name, used for renaming - needs to be optimized but low priority */
+ char o_name [ISO_FILENAME_MAXLENGTH_WITH_PADDING];
+
+ /***** SPACE RESERVED FOR EXTENSIONS *****/
+ /* For memory efficiency's sake - we should move this to a separate struct
+ and point to null if not needed */
+ /* For Rock Ridge */
+ struct _cd9660node *rr_real_parent, *rr_relocated;
+
+ int64_t susp_entry_size;
+ int64_t susp_dot_entry_size;
+ int64_t susp_dot_dot_entry_size;
+
+ /* Continuation area stuff */
+ int64_t susp_entry_ce_start;
+ int64_t susp_dot_ce_start;
+ int64_t susp_dot_dot_ce_start;
+
+ int64_t susp_entry_ce_length;
+ int64_t susp_dot_ce_length;
+ int64_t susp_dot_dot_ce_length;
+
+ /* Data to put at the end of the System Use field */
+ int64_t su_tail_size;
+ char *su_tail_data;
+
+ /*** PATH TABLE STUFF ***/
+ int level; /*depth*/
+ int ptnumber;
+ struct _cd9660node *ptnext, *ptprev, *ptlast;
+
+ /* SUSP entries */
+ TAILQ_HEAD(susp_linked_list, ISO_SUSP_ATTRIBUTES) head;
+} cd9660node;
+
+typedef struct _path_table_entry
+{
+ u_char length[ISODCL (1, 1)];
+ u_char extended_attribute_length[ISODCL (2, 2)];
+ u_char first_sector[ISODCL (3, 6)];
+ u_char parent_number[ISODCL (7, 8)];
+ u_char name[ISO_FILENAME_MAXLENGTH_WITH_PADDING];
+} path_table_entry;
+
+typedef struct _volume_descriptor
+{
+ u_char *volumeDescriptorData; /*ALWAYS 2048 bytes long*/
+ int64_t sector;
+ struct _volume_descriptor *next;
+} volume_descriptor;
+
+typedef struct _iso9660_disk {
+ int sectorSize;
+ struct iso_primary_descriptor primaryDescriptor;
+ struct iso_supplementary_descriptor supplementaryDescriptor;
+
+ volume_descriptor *firstVolumeDescriptor;
+
+ cd9660node *rootNode;
+
+ const char *rootFilesystemPath;
+
+ /* Important sector numbers here */
+ /* primaryDescriptor.type_l_path_table*/
+ int64_t primaryBigEndianTableSector;
+
+ /* primaryDescriptor.type_m_path_table*/
+ int64_t primaryLittleEndianTableSector;
+
+ /* primaryDescriptor.opt_type_l_path_table*/
+ int64_t secondaryBigEndianTableSector;
+
+ /* primaryDescriptor.opt_type_m_path_table*/
+ int64_t secondaryLittleEndianTableSector;
+
+ /* primaryDescriptor.path_table_size*/
+ int pathTableLength;
+ int64_t dataFirstSector;
+
+ int64_t totalSectors;
+ /* OPTIONS GO HERE */
+ int isoLevel;
+
+ int include_padding_areas;
+
+ int follow_sym_links;
+ int verbose_level;
+ int displayHelp;
+ int keep_bad_images;
+
+ /* SUSP options and variables */
+ int64_t susp_continuation_area_start_sector;
+ int64_t susp_continuation_area_size;
+ int64_t susp_continuation_area_current_free;
+
+ int rock_ridge_enabled;
+ /* Other Rock Ridge Variables */
+ char *rock_ridge_renamed_dir_name;
+ int rock_ridge_move_count;
+ cd9660node *rr_moved_dir;
+
+ int archimedes_enabled;
+
+ /* Spec breaking options */
+ u_char allow_deep_trees;
+ u_char allow_start_dot;
+ u_char allow_max_name; /* Allow 37 char filenames*/
+ u_char allow_illegal_chars; /* ~, !, # */
+ u_char allow_lowercase;
+ u_char allow_multidot;
+ u_char omit_trailing_period;
+
+ /* BOOT INFORMATION HERE */
+ int has_generic_bootimage; /* Default to 0 */
+ char *generic_bootimage;
+
+ int is_bootable;/* Default to 0 */
+ int64_t boot_catalog_sector;
+ boot_volume_descriptor *boot_descriptor;
+ char * boot_image_directory;
+
+ TAILQ_HEAD(boot_image_list,cd9660_boot_image) boot_images;
+ int image_serialno;
+ LIST_HEAD(boot_catalog_entries,boot_catalog_entry) boot_entries;
+
+} iso9660_disk;
+
+/******** GLOBAL VARIABLES ***********/
+extern iso9660_disk diskStructure;
+
+/************ FUNCTIONS **************/
+int cd9660_valid_a_chars(const char *);
+int cd9660_valid_d_chars(const char *);
+void cd9660_uppercase_characters(char *, int);
+
+/* ISO Data Types */
+void cd9660_721(uint16_t, unsigned char *);
+void cd9660_731(uint32_t, unsigned char *);
+void cd9660_722(uint16_t, unsigned char *);
+void cd9660_732(uint32_t, unsigned char *);
+void cd9660_bothendian_dword(uint32_t dw, unsigned char *);
+void cd9660_bothendian_word(uint16_t dw, unsigned char *);
+void cd9660_set_date(char *, time_t);
+void cd9660_time_8426(unsigned char *, time_t);
+void cd9660_time_915(unsigned char *, time_t);
+
+/*** Boot Functions ***/
+int cd9660_write_generic_bootimage(FILE *);
+int cd9660_add_generic_bootimage(const char *);
+int cd9660_write_boot(FILE *);
+int cd9660_add_boot_disk(const char *);
+int cd9660_eltorito_add_boot_option(const char *, const char *);
+int cd9660_setup_boot(int);
+int cd9660_setup_boot_volume_descriptor(volume_descriptor *);
+
+
+/*** Write Functions ***/
+int cd9660_write_image(const char *image);
+int cd9660_copy_file(FILE *, off_t, const char *);
+
+void cd9660_compute_full_filename(cd9660node *, char *, int);
+int cd9660_compute_record_size(cd9660node *);
+
+/* Debugging functions */
+void debug_print_tree(cd9660node *,int);
+void debug_print_path_tree(cd9660node *);
+void debug_print_volume_descriptor_information(void);
+void debug_dump_to_xml_ptentry(path_table_entry *,int, int);
+void debug_dump_to_xml_path_table(FILE *, off_t, int, int);
+void debug_dump_to_xml(FILE *);
+int debug_get_encoded_number(unsigned char *, int);
+void debug_dump_integer(const char *, char *,int);
+void debug_dump_string(const char *,unsigned char *,int);
+void debug_dump_directory_record_9_1(unsigned char *);
+void debug_dump_to_xml_volume_descriptor(unsigned char *,int);
+
+void cd9660_pad_string_spaces(char *, int);
+
+#endif
diff --git a/usr.sbin/makefs/cd9660/Makefile.inc b/usr.sbin/makefs/cd9660/Makefile.inc
new file mode 100644
index 0000000..1455fcd
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/cd9660 ${.CURDIR}/../../sys/fs/cd9660/
+
+CFLAGS+=-I${.CURDIR}/../../sys/fs/cd9660/
+
+SRCS+= cd9660_strings.c cd9660_debug.c cd9660_eltorito.c \
+ cd9660_write.c cd9660_conversion.c iso9660_rrip.c cd9660_archimedes.c
diff --git a/usr.sbin/makefs/cd9660/cd9660_archimedes.c b/usr.sbin/makefs/cd9660/cd9660_archimedes.c
new file mode 100644
index 0000000..d18a0f7
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_archimedes.c
@@ -0,0 +1,126 @@
+/* $NetBSD: cd9660_archimedes.c,v 1.1 2009/01/10 22:06:29 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2009 Ben Harris
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
+ *
+ * RISC OS CDFS looks for a special block at the end of the System Use
+ * Field for each file. If present, this contains the RISC OS load
+ * and exec address (used to hold the file timestamp and type), the
+ * file attributes, and a flag indicating whether the first character
+ * of the filename should be replaced with '!' (since many special
+ * RISC OS filenames do).
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "cd9660_archimedes.h"
+
+/*
+ * Convert a Unix time_t (non-leap seconds since 1970-01-01) to a RISC
+ * OS time (non-leap(?) centiseconds since 1900-01-01(?)).
+ */
+
+static u_int64_t
+riscos_date(time_t unixtime)
+{
+ u_int64_t base;
+
+ base = 31536000ULL * 70 + 86400 * 17;
+ return (((u_int64_t)unixtime) + base)*100;
+}
+
+/*
+ * Add "ARCHIMEDES" metadata to a node if that seems appropriate.
+ *
+ * We touch regular files with names matching /,[0-9a-f]{3}$/ and
+ * directories matching /^!/.
+ */
+static void
+archimedes_convert_node(cd9660node *node)
+{
+ struct ISO_ARCHIMEDES *arc;
+ size_t len;
+ int type = -1;
+ uint64_t stamp;
+
+ if (node->su_tail_data != NULL)
+ /* Something else already has the tail. */
+ return;
+
+ len = strlen(node->node->name);
+ if (len < 1) return;
+
+ if (len >= 4 && node->node->name[len-4] == ',')
+ /* XXX should support ,xxx and ,lxa */
+ type = strtoul(node->node->name + len - 3, NULL, 16);
+ if (type == -1 && node->node->name[0] != '!')
+ return;
+ if (type == -1) type = 0;
+
+ assert(sizeof(struct ISO_ARCHIMEDES) == 32);
+ if ((arc = calloc(1, sizeof(struct ISO_ARCHIMEDES))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("archimedes_convert_node");
+ exit(1);
+ }
+
+ stamp = riscos_date(node->node->inode->st.st_mtime);
+
+ memcpy(arc->magic, "ARCHIMEDES", 10);
+ cd9660_731(0xfff00000 | (type << 8) | (stamp >> 32), arc->loadaddr);
+ cd9660_731(stamp & 0x00ffffffffULL, arc->execaddr);
+ arc->ro_attr = RO_ACCESS_UR | RO_ACCESS_OR;
+ arc->cdfs_attr = node->node->name[0] == '!' ? CDFS_PLING : 0;
+ node->su_tail_data = (void *)arc;
+ node->su_tail_size = sizeof(*arc);
+}
+
+/*
+ * Add "ARCHIMEDES" metadata to an entire tree recursively.
+ */
+void
+archimedes_convert_tree(cd9660node *node)
+{
+ cd9660node *cn;
+
+ assert(node != NULL);
+
+ archimedes_convert_node(node);
+
+ /* Recurse on children. */
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
+ archimedes_convert_tree(cn);
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_archimedes.h b/usr.sbin/makefs/cd9660/cd9660_archimedes.h
new file mode 100644
index 0000000..2717bf4
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_archimedes.h
@@ -0,0 +1,50 @@
+/* $NetBSD: cd9660_archimedes.h,v 1.1 2009/01/10 22:06:29 bjh21 Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2009 Ben Harris
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
+ *
+ * $FreeBSD$
+ */
+
+struct ISO_ARCHIMEDES {
+ char magic[10]; /* "ARCHIMEDES" */
+ unsigned char loadaddr[4]; /* Load address, little-endian */
+ unsigned char execaddr[4]; /* Exec address, little-endian */
+ unsigned char ro_attr; /* RISC OS attributes */
+#define RO_ACCESS_UR 0x01 /* Owner read */
+#define RO_ACCESS_UW 0x02 /* Owner write */
+#define RO_ACCESS_L 0x04 /* Locked */
+#define RO_ACCESS_OR 0x10 /* Public read */
+#define RO_ACCESS_OW 0x20 /* Public write */
+ unsigned char cdfs_attr; /* Extra attributes for CDFS */
+#define CDFS_PLING 0x01 /* Filename begins with '!' */
+ char reserved[12];
+};
+
+extern void archimedes_convert_tree(cd9660node *);
diff --git a/usr.sbin/makefs/cd9660/cd9660_conversion.c b/usr.sbin/makefs/cd9660/cd9660_conversion.c
new file mode 100644
index 0000000..e815028
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_conversion.c
@@ -0,0 +1,202 @@
+/* $NetBSD: cd9660_conversion.c,v 1.4 2007/03/14 14:11:17 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+#include "cd9660.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/endian.h>
+
+static char cd9660_compute_gm_offset(time_t);
+
+#if 0
+static inline int
+cd9660_pad_even(length)
+int length;
+{
+ return length + (length & 0x01);
+}
+#endif
+
+/*
+* These can probably be implemented using a macro
+*/
+
+/* Little endian */
+void
+cd9660_721(uint16_t w, unsigned char *twochar)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ w = bswap16(w);
+#endif
+ memcpy(twochar,&w,2);
+}
+
+void
+cd9660_731(uint32_t w, unsigned char *fourchar)
+{
+#if BYTE_ORDER == BIG_ENDIAN
+ w = bswap32(w);
+#endif
+ memcpy(fourchar,&w,4);
+}
+
+/* Big endian */
+void
+cd9660_722(uint16_t w, unsigned char *twochar)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ w = bswap16(w);
+#endif
+ memcpy(twochar,&w,2);
+}
+
+void
+cd9660_732(uint32_t w, unsigned char *fourchar)
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ w = bswap32(w);
+#endif
+ memcpy(fourchar,&w,4);
+}
+
+/**
+* Convert a dword into a double endian string of eight characters
+* @param int The double word to convert
+* @param char* The string to write the both endian double word to - It is assumed this is allocated and at least
+* eight characters long
+*/
+void
+cd9660_bothendian_dword(uint32_t dw, unsigned char *eightchar)
+{
+ uint32_t le, be;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ le = dw;
+ be = bswap32(dw);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ be = dw;
+ le = bswap32(dw);
+#endif
+ memcpy(eightchar, &le, 4);
+ memcpy((eightchar+4), &be, 4);
+}
+
+/**
+* Convert a word into a double endian string of four characters
+* @param int The word to convert
+* @param char* The string to write the both endian word to - It is assumed this is allocated and at least
+* four characters long
+*/
+void
+cd9660_bothendian_word(uint16_t dw, unsigned char *fourchar)
+{
+ uint16_t le, be;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ le = dw;
+ be = bswap16(dw);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ be = dw;
+ le = bswap16(dw);
+#endif
+ memcpy(fourchar, &le, 2);
+ memcpy((fourchar+2), &be, 2);
+}
+
+void
+cd9660_pad_string_spaces(char *str, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i ++) {
+ if (str[i] == '\0')
+ str[i] = 0x20;
+ }
+}
+
+static char
+cd9660_compute_gm_offset(time_t tim)
+{
+ struct tm t, gm;
+
+ (void)localtime_r(&tim, &t);
+ (void)gmtime_r(&tim, &gm);
+ gm.tm_year -= t.tm_year;
+ gm.tm_yday -= t.tm_yday;
+ gm.tm_hour -= t.tm_hour;
+ gm.tm_min -= t.tm_min;
+ if (gm.tm_year < 0)
+ gm.tm_yday = -1;
+ else if (gm.tm_year > 0)
+ gm.tm_yday = 1;
+
+ return (char)(-(gm.tm_min + 60* (24 * gm.tm_yday + gm.tm_hour)) / 15);
+}
+
+/* Long dates: 17 characters */
+void
+cd9660_time_8426(unsigned char *buf, time_t tim)
+{
+ struct tm t;
+ char temp[18];
+
+ (void)localtime_r(&tim, &t);
+ (void)snprintf(temp, sizeof(temp), "%04i%02i%02i%02i%02i%02i%02i",
+ 1900+(int)t.tm_year,
+ (int)t.tm_mon+1,
+ (int)t.tm_mday,
+ (int)t.tm_hour,
+ (int)t.tm_min,
+ (int)t.tm_sec,
+ 0);
+ (void)memcpy(buf, temp, 16);
+ buf[16] = cd9660_compute_gm_offset(tim);
+}
+
+/* Short dates: 7 characters */
+void
+cd9660_time_915(unsigned char *buf, time_t tim)
+{
+ struct tm t;
+
+ (void)localtime_r(&tim, &t);
+ buf[0] = t.tm_year;
+ buf[1] = t.tm_mon+1;
+ buf[2] = t.tm_mday;
+ buf[3] = t.tm_hour;
+ buf[4] = t.tm_min;
+ buf[5] = t.tm_sec;
+ buf[6] = cd9660_compute_gm_offset(tim);
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_debug.c b/usr.sbin/makefs/cd9660/cd9660_debug.c
new file mode 100644
index 0000000..d94ccbe
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_debug.c
@@ -0,0 +1,488 @@
+/* $NetBSD: cd9660_debug.c,v 1.11 2010/10/27 18:51:35 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+
+#include <sys/mount.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+
+static void debug_print_susp_attrs(cd9660node *, int);
+static void debug_dump_to_xml_padded_hex_output(const char *, unsigned char *,
+ int);
+
+static inline void
+print_n_tabs(int n)
+{
+ int i;
+
+ for (i = 1; i <= n; i ++)
+ printf("\t");
+}
+
+#if 0
+void
+debug_print_rrip_info(n)
+cd9660node *n;
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+
+ }
+}
+#endif
+
+static void
+debug_print_susp_attrs(cd9660node *n, int indent)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ TAILQ_FOREACH(t, &n->head, rr_ll) {
+ print_n_tabs(indent);
+ printf("-");
+ printf("%c%c: L:%i",t->attr.su_entry.SP.h.type[0],
+ t->attr.su_entry.SP.h.type[1],
+ (int)t->attr.su_entry.SP.h.length[0]);
+ printf("\n");
+ }
+}
+
+void
+debug_print_tree(cd9660node *node, int level)
+{
+#if !HAVE_NBTOOL_CONFIG_H
+ cd9660node *cn;
+
+ print_n_tabs(level);
+ if (node->type & CD9660_TYPE_DOT) {
+ printf(". (%i)\n",
+ isonum_733(node->isoDirRecord->extent));
+ } else if (node->type & CD9660_TYPE_DOTDOT) {
+ printf("..(%i)\n",
+ isonum_733(node->isoDirRecord->extent));
+ } else if (node->isoDirRecord->name[0]=='\0') {
+ printf("(ROOT) (%" PRIu32 " to %" PRId64 ")\n",
+ node->fileDataSector,
+ node->fileDataSector +
+ node->fileSectorsUsed - 1);
+ } else {
+ printf("%s (%s) (%" PRIu32 " to %" PRId64 ")\n",
+ node->isoDirRecord->name,
+ (node->isoDirRecord->flags[0]
+ & ISO_FLAG_DIRECTORY) ? "DIR" : "FILE",
+ node->fileDataSector,
+ (node->fileSectorsUsed == 0) ?
+ node->fileDataSector :
+ node->fileDataSector
+ + node->fileSectorsUsed - 1);
+ }
+ if (diskStructure.rock_ridge_enabled)
+ debug_print_susp_attrs(node, level + 1);
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
+ debug_print_tree(cn, level + 1);
+#else
+ printf("Sorry, debugging is not supported in host-tools mode.\n");
+#endif
+}
+
+void
+debug_print_path_tree(cd9660node *n)
+{
+ cd9660node *iterator = n;
+
+ /* Only display this message when called with the root node */
+ if (n->parent == NULL)
+ printf("debug_print_path_table: Dumping path table contents\n");
+
+ while (iterator != NULL) {
+ if (iterator->isoDirRecord->name[0] == '\0')
+ printf("0) (ROOT)\n");
+ else
+ printf("%i) %s\n", iterator->level,
+ iterator->isoDirRecord->name);
+
+ iterator = iterator->ptnext;
+ }
+}
+
+void
+debug_print_volume_descriptor_information(void)
+{
+ volume_descriptor *tmp = diskStructure.firstVolumeDescriptor;
+ char temp[CD9660_SECTOR_SIZE];
+
+ printf("==Listing Volume Descriptors==\n");
+
+ while (tmp != NULL) {
+ memset(temp, 0, CD9660_SECTOR_SIZE);
+ memcpy(temp, tmp->volumeDescriptorData + 1, 5);
+ printf("Volume descriptor in sector %" PRId64
+ ": type %i, ID %s\n",
+ tmp->sector, tmp->volumeDescriptorData[0], temp);
+ switch(tmp->volumeDescriptorData[0]) {
+ case 0:/*boot record*/
+ break;
+
+ case 1: /* PVD */
+ break;
+
+ case 2: /* SVD */
+ break;
+
+ case 3: /* Volume Partition Descriptor */
+ break;
+
+ case 255: /* terminator */
+ break;
+ }
+ tmp = tmp->next;
+ }
+
+ printf("==Done Listing Volume Descriptors==\n");
+}
+
+void
+debug_dump_to_xml_ptentry(path_table_entry *pttemp, int num, int mode)
+{
+ printf("<ptentry num=\"%i\">\n" ,num);
+ printf("<length>%i</length>\n", pttemp->length[0]);
+ printf("<extended_attribute_length>%i</extended_attribute_length>\n",
+ pttemp->extended_attribute_length[0]);
+ printf("<parent_number>%i</parent_number>\n",
+ debug_get_encoded_number(pttemp->parent_number,mode));
+ debug_dump_to_xml_padded_hex_output("name",
+ pttemp->name, pttemp->length[0]);
+ printf("</ptentry>\n");
+}
+
+void
+debug_dump_to_xml_path_table(FILE *fd, off_t sector, int size, int mode)
+{
+ path_table_entry pttemp;
+ int t = 0;
+ int n = 0;
+
+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ while (t < size) {
+ /* Read fixed data first */
+ fread(&pttemp, 1, 8, fd);
+ t += 8;
+ /* Read variable */
+ fread(((unsigned char*)&pttemp) + 8, 1, pttemp.length[0], fd);
+ t += pttemp.length[0];
+ debug_dump_to_xml_ptentry(&pttemp, n, mode);
+ n++;
+ }
+
+}
+
+/*
+ * XML Debug output functions
+ * Dump hierarchy of CD, as well as volume info, to XML
+ * Can be used later to diff against a standard,
+ * or just provide easy to read detailed debug output
+ */
+void
+debug_dump_to_xml(FILE *fd)
+{
+ unsigned char buf[CD9660_SECTOR_SIZE];
+ off_t sector;
+ int t, t2;
+ struct iso_primary_descriptor primaryVD;
+ struct _boot_volume_descriptor bootVD;
+
+ printf("<cd9660dump>\n");
+
+ /* Display Volume Descriptors */
+ sector = 16;
+ do {
+ if (fseeko(fd, CD9660_SECTOR_SIZE * sector, SEEK_SET) == -1)
+ err(1, "fseeko");
+ fread(buf, 1, CD9660_SECTOR_SIZE, fd);
+ t = (int)((unsigned char)buf[0]);
+ switch (t) {
+ case 0:
+ memcpy(&bootVD, buf, CD9660_SECTOR_SIZE);
+ break;
+ case 1:
+ memcpy(&primaryVD, buf, CD9660_SECTOR_SIZE);
+ break;
+ }
+ debug_dump_to_xml_volume_descriptor(buf, sector);
+ sector++;
+ } while (t != 255);
+
+ t = debug_get_encoded_number((u_char *)primaryVD.type_l_path_table,
+ 731);
+ t2 = debug_get_encoded_number((u_char *)primaryVD.path_table_size, 733);
+ printf("Path table 1 located at sector %i and is %i bytes long\n",
+ t,t2);
+ debug_dump_to_xml_path_table(fd, t, t2, 721);
+
+ t = debug_get_encoded_number((u_char *)primaryVD.type_m_path_table,
+ 731);
+ debug_dump_to_xml_path_table(fd, t, t2, 722);
+
+ printf("</cd9660dump>\n");
+}
+
+static void
+debug_dump_to_xml_padded_hex_output(const char *element, unsigned char *buf,
+ int len)
+{
+ int i;
+ int t;
+
+ printf("<%s>",element);
+ for (i = 0; i < len; i++) {
+ t = (unsigned char)buf[i];
+ if (t >= 32 && t < 127)
+ printf("%c",t);
+ }
+ printf("</%s>\n",element);
+
+ printf("<%s:hex>",element);
+ for (i = 0; i < len; i++) {
+ t = (unsigned char)buf[i];
+ printf(" %x",t);
+ }
+ printf("</%s:hex>\n",element);
+}
+
+int
+debug_get_encoded_number(unsigned char* buf, int mode)
+{
+#if !HAVE_NBTOOL_CONFIG_H
+ switch (mode) {
+ /* 711: Single bite */
+ case 711:
+ return isonum_711(buf);
+
+ /* 712: Single signed byte */
+ case 712:
+ return isonum_712((signed char *)buf);
+
+ /* 721: 16 bit LE */
+ case 721:
+ return isonum_721(buf);
+
+ /* 731: 32 bit LE */
+ case 731:
+ return isonum_731(buf);
+
+ /* 722: 16 bit BE */
+ case 722:
+ return isonum_722(buf);
+
+ /* 732: 32 bit BE */
+ case 732:
+ return isonum_732(buf);
+
+ /* 723: 16 bit bothE */
+ case 723:
+ return isonum_723(buf);
+
+ /* 733: 32 bit bothE */
+ case 733:
+ return isonum_733(buf);
+ }
+#endif
+ return 0;
+}
+
+void
+debug_dump_integer(const char *element, char* buf, int mode)
+{
+ printf("<%s>%i</%s>\n", element,
+ debug_get_encoded_number((unsigned char *)buf, mode), element);
+}
+
+void
+debug_dump_string(const char *element __unused, unsigned char *buf __unused, int len __unused)
+{
+
+}
+
+void
+debug_dump_directory_record_9_1(unsigned char* buf)
+{
+ printf("<directoryrecord>\n");
+ debug_dump_integer("length",
+ ((struct iso_directory_record*) buf)->length, 711);
+ debug_dump_integer("ext_attr_length",
+ ((struct iso_directory_record*) buf)->ext_attr_length,711);
+ debug_dump_integer("extent",
+ (char *)((struct iso_directory_record*) buf)->extent, 733);
+ debug_dump_integer("size",
+ (char *)((struct iso_directory_record*) buf)->size, 733);
+ debug_dump_integer("flags",
+ ((struct iso_directory_record*) buf)->flags, 711);
+ debug_dump_integer("file_unit_size",
+ ((struct iso_directory_record*) buf)->file_unit_size,711);
+ debug_dump_integer("interleave",
+ ((struct iso_directory_record*) buf)->interleave, 711);
+ debug_dump_integer("volume_sequence_number",
+ ((struct iso_directory_record*) buf)->volume_sequence_number,
+ 723);
+ debug_dump_integer("name_len",
+ ((struct iso_directory_record*) buf)->name_len, 711);
+ debug_dump_to_xml_padded_hex_output("name",
+ (u_char *)((struct iso_directory_record*) buf)->name,
+ debug_get_encoded_number((u_char *)
+ ((struct iso_directory_record*) buf)->length, 711));
+ printf("</directoryrecord>\n");
+}
+
+
+void
+debug_dump_to_xml_volume_descriptor(unsigned char* buf, int sector)
+{
+ printf("<volumedescriptor sector=\"%i\">\n", sector);
+ printf("<vdtype>");
+ switch(buf[0]) {
+ case 0:
+ printf("boot");
+ break;
+
+ case 1:
+ printf("primary");
+ break;
+
+ case 2:
+ printf("supplementary");
+ break;
+
+ case 3:
+ printf("volume partition descriptor");
+ break;
+
+ case 255:
+ printf("terminator");
+ break;
+ }
+
+ printf("</vdtype>\n");
+ switch(buf[0]) {
+ case 1:
+ debug_dump_integer("type",
+ ((struct iso_primary_descriptor*)buf)->type, 711);
+ debug_dump_to_xml_padded_hex_output("id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->id,
+ ISODCL ( 2, 6));
+ debug_dump_integer("version",
+ ((struct iso_primary_descriptor*)buf)->version,
+ 711);
+ debug_dump_to_xml_padded_hex_output("system_id",
+ (u_char *)((struct iso_primary_descriptor*)buf)->system_id,
+ ISODCL(9,40));
+ debug_dump_to_xml_padded_hex_output("volume_id",
+ (u_char *)((struct iso_primary_descriptor*)buf)->volume_id,
+ ISODCL(41,72));
+ debug_dump_integer("volume_space_size",
+ ((struct iso_primary_descriptor*)buf)->volume_space_size,
+ 733);
+ debug_dump_integer("volume_set_size",
+ ((struct iso_primary_descriptor*)buf)->volume_set_size,
+ 733);
+ debug_dump_integer("volume_sequence_number",
+ ((struct iso_primary_descriptor*)buf)->volume_sequence_number,
+ 723);
+ debug_dump_integer("logical_block_size",
+ ((struct iso_primary_descriptor*)buf)->logical_block_size,
+ 723);
+ debug_dump_integer("path_table_size",
+ ((struct iso_primary_descriptor*)buf)->path_table_size,
+ 733);
+ debug_dump_integer("type_l_path_table",
+ ((struct iso_primary_descriptor*)buf)->type_l_path_table,
+ 731);
+ debug_dump_integer("opt_type_l_path_table",
+ ((struct iso_primary_descriptor*)buf)->opt_type_l_path_table,
+ 731);
+ debug_dump_integer("type_m_path_table",
+ ((struct iso_primary_descriptor*)buf)->type_m_path_table,
+ 732);
+ debug_dump_integer("opt_type_m_path_table",
+ ((struct iso_primary_descriptor*)buf)->opt_type_m_path_table,732);
+ debug_dump_directory_record_9_1(
+ (u_char *)((struct iso_primary_descriptor*)buf)->root_directory_record);
+ debug_dump_to_xml_padded_hex_output("volume_set_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->volume_set_id,
+ ISODCL (191, 318));
+ debug_dump_to_xml_padded_hex_output("publisher_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->publisher_id,
+ ISODCL (319, 446));
+ debug_dump_to_xml_padded_hex_output("preparer_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->preparer_id,
+ ISODCL (447, 574));
+ debug_dump_to_xml_padded_hex_output("application_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->application_id,
+ ISODCL (575, 702));
+ debug_dump_to_xml_padded_hex_output("copyright_file_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->copyright_file_id,
+ ISODCL (703, 739));
+ debug_dump_to_xml_padded_hex_output("abstract_file_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->abstract_file_id,
+ ISODCL (740, 776));
+ debug_dump_to_xml_padded_hex_output("bibliographic_file_id",
+ (u_char *)((struct iso_primary_descriptor*) buf)->bibliographic_file_id,
+ ISODCL (777, 813));
+
+ debug_dump_to_xml_padded_hex_output("creation_date",
+ (u_char *)((struct iso_primary_descriptor*) buf)->creation_date,
+ ISODCL (814, 830));
+ debug_dump_to_xml_padded_hex_output("modification_date",
+ (u_char *)((struct iso_primary_descriptor*) buf)->modification_date,
+ ISODCL (831, 847));
+ debug_dump_to_xml_padded_hex_output("expiration_date",
+ (u_char *)((struct iso_primary_descriptor*) buf)->expiration_date,
+ ISODCL (848, 864));
+ debug_dump_to_xml_padded_hex_output("effective_date",
+ (u_char *)((struct iso_primary_descriptor*) buf)->effective_date,
+ ISODCL (865, 881));
+
+ debug_dump_to_xml_padded_hex_output("file_structure_version",
+ (u_char *)((struct iso_primary_descriptor*) buf)->file_structure_version,
+ ISODCL(882,882));
+ break;
+ }
+ printf("</volumedescriptor>\n");
+}
+
diff --git a/usr.sbin/makefs/cd9660/cd9660_eltorito.c b/usr.sbin/makefs/cd9660/cd9660_eltorito.c
new file mode 100644
index 0000000..055451d
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_eltorito.c
@@ -0,0 +1,539 @@
+/* $NetBSD: cd9660_eltorito.c,v 1.14 2010/10/27 18:51:35 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+#include "cd9660.h"
+#include "cd9660_eltorito.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifdef DEBUG
+#define ELTORITO_DPRINTF(__x) printf __x
+#else
+#define ELTORITO_DPRINTF(__x)
+#endif
+
+static struct boot_catalog_entry *cd9660_init_boot_catalog_entry(void);
+static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
+static struct boot_catalog_entry *cd9660_boot_setup_default_entry(
+ struct cd9660_boot_image *);
+static struct boot_catalog_entry *cd9660_boot_setup_section_head(char);
+static struct boot_catalog_entry *cd9660_boot_setup_validation_entry(char);
+#if 0
+static u_char cd9660_boot_get_system_type(struct cd9660_boot_image *);
+#endif
+
+int
+cd9660_add_boot_disk(const char *boot_info)
+{
+ struct stat stbuf;
+ const char *mode_msg;
+ char *temp;
+ char *sysname;
+ char *filename;
+ struct cd9660_boot_image *new_image, *tmp_image;
+
+ assert(boot_info != NULL);
+
+ if (*boot_info == '\0') {
+ warnx("Error: Boot disk information must be in the "
+ "format 'system;filename'");
+ return 0;
+ }
+
+ /* First decode the boot information */
+ if ((temp = strdup(boot_info)) == NULL) {
+ warn("%s: strdup", __func__);
+ return 0;
+ }
+
+ sysname = temp;
+ filename = strchr(sysname, ';');
+ if (filename == NULL) {
+ warnx("supply boot disk information in the format "
+ "'system;filename'");
+ free(temp);
+ return 0;
+ }
+
+ *filename++ = '\0';
+
+ if (diskStructure.verbose_level > 0) {
+ printf("Found bootdisk with system %s, and filename %s\n",
+ sysname, filename);
+ }
+ if ((new_image = malloc(sizeof(*new_image))) == NULL) {
+ warn("%s: malloc", __func__);
+ free(temp);
+ return 0;
+ }
+ (void)memset(new_image, 0, sizeof(*new_image));
+ new_image->loadSegment = 0; /* default for now */
+
+ /* Decode System */
+ if (strcmp(sysname, "i386") == 0)
+ new_image->system = ET_SYS_X86;
+ else if (strcmp(sysname, "powerpc") == 0)
+ new_image->system = ET_SYS_PPC;
+ else if (strcmp(sysname, "macppc") == 0 ||
+ strcmp(sysname, "mac68k") == 0)
+ new_image->system = ET_SYS_MAC;
+ else {
+ warnx("boot disk system must be "
+ "i386, powerpc, macppc, or mac68k");
+ free(temp);
+ free(new_image);
+ return 0;
+ }
+
+
+ if ((new_image->filename = strdup(filename)) == NULL) {
+ warn("%s: strdup", __func__);
+ free(temp);
+ free(new_image);
+ return 0;
+ }
+
+ free(temp);
+
+ /* Get information about the file */
+ if (lstat(new_image->filename, &stbuf) == -1)
+ err(EXIT_FAILURE, "%s: lstat(\"%s\")", __func__,
+ new_image->filename);
+
+ switch (stbuf.st_size) {
+ case 1440 * 1024:
+ new_image->targetMode = ET_MEDIA_144FDD;
+ mode_msg = "Assigned boot image to 1.44 emulation mode";
+ break;
+ case 1200 * 1024:
+ new_image->targetMode = ET_MEDIA_12FDD;
+ mode_msg = "Assigned boot image to 1.2 emulation mode";
+ break;
+ case 2880 * 1024:
+ new_image->targetMode = ET_MEDIA_288FDD;
+ mode_msg = "Assigned boot image to 2.88 emulation mode";
+ break;
+ default:
+ new_image->targetMode = ET_MEDIA_NOEM;
+ mode_msg = "Assigned boot image to no emulation mode";
+ break;
+ }
+
+ if (diskStructure.verbose_level > 0)
+ printf("%s\n", mode_msg);
+
+ new_image->size = stbuf.st_size;
+ new_image->num_sectors =
+ howmany(new_image->size, diskStructure.sectorSize) *
+ howmany(diskStructure.sectorSize, 512);
+ if (diskStructure.verbose_level > 0) {
+ printf("New image has size %d, uses %d 512-byte sectors\n",
+ new_image->size, new_image->num_sectors);
+ }
+ new_image->sector = -1;
+ /* Bootable by default */
+ new_image->bootable = ET_BOOTABLE;
+ /* Add boot disk */
+
+ /* Group images for the same platform together. */
+ TAILQ_FOREACH(tmp_image, &diskStructure.boot_images, image_list) {
+ if (tmp_image->system != new_image->system)
+ break;
+ }
+
+ if (tmp_image == NULL) {
+ TAILQ_INSERT_HEAD(&diskStructure.boot_images, new_image,
+ image_list);
+ } else
+ TAILQ_INSERT_BEFORE(tmp_image, new_image, image_list);
+
+ new_image->serialno = diskStructure.image_serialno++;
+
+ /* TODO : Need to do anything about the boot image in the tree? */
+ diskStructure.is_bootable = 1;
+
+ return 1;
+}
+
+int
+cd9660_eltorito_add_boot_option(const char *option_string, const char *value)
+{
+ char *eptr;
+ struct cd9660_boot_image *image;
+
+ assert(option_string != NULL);
+
+ /* Find the last image added */
+ TAILQ_FOREACH(image, &diskStructure.boot_images, image_list) {
+ if (image->serialno + 1 == diskStructure.image_serialno)
+ break;
+ }
+ if (image == NULL)
+ errx(EXIT_FAILURE, "Attempted to add boot option, "
+ "but no boot images have been specified");
+
+ if (strcmp(option_string, "no-emul-boot") == 0) {
+ image->targetMode = ET_MEDIA_NOEM;
+ } else if (strcmp(option_string, "no-boot") == 0) {
+ image->bootable = ET_NOT_BOOTABLE;
+ } else if (strcmp(option_string, "hard-disk-boot") == 0) {
+ image->targetMode = ET_MEDIA_HDD;
+ } else if (strcmp(option_string, "boot-load-segment") == 0) {
+ image->loadSegment = strtoul(value, &eptr, 16);
+ if (eptr == value || *eptr != '\0' || errno != ERANGE) {
+ warn("%s: strtoul", __func__);
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+static struct boot_catalog_entry *
+cd9660_init_boot_catalog_entry(void)
+{
+ struct boot_catalog_entry *temp;
+
+ if ((temp = malloc(sizeof(*temp))) == NULL)
+ return NULL;
+
+ return memset(temp, 0, sizeof(*temp));
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_validation_entry(char sys)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_validation_entry *ve;
+ int16_t checksum;
+ unsigned char *csptr;
+ int i;
+ entry = cd9660_init_boot_catalog_entry();
+
+ if (entry == NULL) {
+ warnx("Error: memory allocation failed in "
+ "cd9660_boot_setup_validation_entry");
+ return 0;
+ }
+ ve = &entry->entry_data.VE;
+
+ ve->header_id[0] = 1;
+ ve->platform_id[0] = sys;
+ ve->key[0] = 0x55;
+ ve->key[1] = 0xAA;
+
+ /* Calculate checksum */
+ checksum = 0;
+ cd9660_721(0, ve->checksum);
+ csptr = (unsigned char*)ve;
+ for (i = 0; i < sizeof(*ve); i += 2) {
+ checksum += (int16_t)csptr[i];
+ checksum += 256 * (int16_t)csptr[i + 1];
+ }
+ checksum = -checksum;
+ cd9660_721(checksum, ve->checksum);
+
+ ELTORITO_DPRINTF(("%s: header_id %d, platform_id %d, key[0] %d, key[1] %d, "
+ "checksum %04x\n", __func__, ve->header_id[0], ve->platform_id[0],
+ ve->key[0], ve->key[1], checksum));
+ return entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_default_entry(struct cd9660_boot_image *disk)
+{
+ struct boot_catalog_entry *default_entry;
+ boot_catalog_initial_entry *ie;
+
+ default_entry = cd9660_init_boot_catalog_entry();
+ if (default_entry == NULL)
+ return NULL;
+
+ ie = &default_entry->entry_data.IE;
+
+ ie->boot_indicator[0] = disk->bootable;
+ ie->media_type[0] = disk->targetMode;
+ cd9660_721(disk->loadSegment, ie->load_segment);
+ ie->system_type[0] = disk->system;
+ cd9660_721(disk->num_sectors, ie->sector_count);
+ cd9660_731(disk->sector, ie->load_rba);
+
+ ELTORITO_DPRINTF(("%s: boot indicator %d, media type %d, "
+ "load segment %04x, system type %d, sector count %d, "
+ "load rba %d\n", __func__, ie->boot_indicator[0],
+ ie->media_type[0], disk->loadSegment, ie->system_type[0],
+ disk->num_sectors, disk->sector));
+ return default_entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_section_head(char platform)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_section_header *sh;
+
+ entry = cd9660_init_boot_catalog_entry();
+ if (entry == NULL)
+ return NULL;
+
+ sh = &entry->entry_data.SH;
+ /* More by default. The last one will manually be set to 0x91 */
+ sh->header_indicator[0] = ET_SECTION_HEADER_MORE;
+ sh->platform_id[0] = platform;
+ sh->num_section_entries[0] = 0;
+ return entry;
+}
+
+static struct boot_catalog_entry *
+cd9660_boot_setup_section_entry(struct cd9660_boot_image *disk)
+{
+ struct boot_catalog_entry *entry;
+ boot_catalog_section_entry *se;
+ if ((entry = cd9660_init_boot_catalog_entry()) == NULL)
+ return NULL;
+
+ se = &entry->entry_data.SE;
+
+ se->boot_indicator[0] = ET_BOOTABLE;
+ se->media_type[0] = disk->targetMode;
+ cd9660_721(disk->loadSegment, se->load_segment);
+ cd9660_721(disk->num_sectors, se->sector_count);
+ cd9660_731(disk->sector, se->load_rba);
+ return entry;
+}
+
+#if 0
+static u_char
+cd9660_boot_get_system_type(struct cd9660_boot_image *disk)
+{
+ /*
+ For hard drive booting, we need to examine the MBR to figure
+ out what the partition type is
+ */
+ return 0;
+}
+#endif
+
+/*
+ * Set up the BVD, Boot catalog, and the boot entries, but do no writing
+ */
+int
+cd9660_setup_boot(int first_sector)
+{
+ int sector;
+ int used_sectors;
+ int num_entries = 0;
+ int catalog_sectors;
+ struct boot_catalog_entry *x86_head, *mac_head, *ppc_head,
+ *valid_entry, *default_entry, *temp, *head, **headp, *next;
+ struct cd9660_boot_image *tmp_disk;
+
+ headp = NULL;
+ x86_head = mac_head = ppc_head = NULL;
+
+ /* If there are no boot disks, don't bother building boot information */
+ if (TAILQ_EMPTY(&diskStructure.boot_images))
+ return 0;
+
+ /* Point to catalog: For now assume it consumes one sector */
+ ELTORITO_DPRINTF(("Boot catalog will go in sector %d\n", first_sector));
+ diskStructure.boot_catalog_sector = first_sector;
+ cd9660_bothendian_dword(first_sector,
+ diskStructure.boot_descriptor->boot_catalog_pointer);
+
+ /* Step 1: Generate boot catalog */
+ /* Step 1a: Validation entry */
+ valid_entry = cd9660_boot_setup_validation_entry(ET_SYS_X86);
+ if (valid_entry == NULL)
+ return -1;
+
+ /*
+ * Count how many boot images there are,
+ * and how many sectors they consume.
+ */
+ num_entries = 1;
+ used_sectors = 0;
+
+ TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) {
+ used_sectors += tmp_disk->num_sectors;
+
+ /* One default entry per image */
+ num_entries++;
+ }
+ catalog_sectors = howmany(num_entries * 0x20, diskStructure.sectorSize);
+ used_sectors += catalog_sectors;
+
+ if (diskStructure.verbose_level > 0) {
+ printf("%s: there will be %i entries consuming %i sectors. "
+ "Catalog is %i sectors\n", __func__, num_entries,
+ used_sectors, catalog_sectors);
+ }
+
+ /* Populate sector numbers */
+ sector = first_sector + catalog_sectors;
+ TAILQ_FOREACH(tmp_disk, &diskStructure.boot_images, image_list) {
+ tmp_disk->sector = sector;
+ sector += tmp_disk->num_sectors;
+ }
+
+ LIST_INSERT_HEAD(&diskStructure.boot_entries, valid_entry, ll_struct);
+
+ /* Step 1b: Initial/default entry */
+ /* TODO : PARAM */
+ tmp_disk = TAILQ_FIRST(&diskStructure.boot_images);
+ default_entry = cd9660_boot_setup_default_entry(tmp_disk);
+ if (default_entry == NULL) {
+ warnx("Error: memory allocation failed in cd9660_setup_boot");
+ return -1;
+ }
+
+ LIST_INSERT_AFTER(valid_entry, default_entry, ll_struct);
+
+ /* Todo: multiple default entries? */
+
+ tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
+
+ temp = default_entry;
+
+ /* If multiple boot images are given : */
+ while (tmp_disk != NULL) {
+ /* Step 2: Section header */
+ switch (tmp_disk->system) {
+ case ET_SYS_X86:
+ headp = &x86_head;
+ break;
+ case ET_SYS_PPC:
+ headp = &ppc_head;
+ break;
+ case ET_SYS_MAC:
+ headp = &mac_head;
+ break;
+ default:
+ warnx("%s: internal error: unknown system type",
+ __func__);
+ return -1;
+ }
+
+ if (*headp == NULL) {
+ head =
+ cd9660_boot_setup_section_head(tmp_disk->system);
+ if (head == NULL) {
+ warnx("Error: memory allocation failed in "
+ "cd9660_setup_boot");
+ return -1;
+ }
+ LIST_INSERT_AFTER(default_entry, head, ll_struct);
+ *headp = head;
+ } else
+ head = *headp;
+
+ head->entry_data.SH.num_section_entries[0]++;
+
+ /* Step 2a: Section entry and extensions */
+ temp = cd9660_boot_setup_section_entry(tmp_disk);
+ if (temp == NULL) {
+ warn("%s: cd9660_boot_setup_section_entry", __func__);
+ return -1;
+ }
+
+ while ((next = LIST_NEXT(head, ll_struct)) != NULL &&
+ next->entry_type == ET_ENTRY_SE)
+ head = next;
+
+ LIST_INSERT_AFTER(head, temp, ll_struct);
+ tmp_disk = TAILQ_NEXT(tmp_disk, image_list);
+ }
+
+ /* TODO: Remaining boot disks when implemented */
+
+ return first_sector + used_sectors;
+}
+
+int
+cd9660_setup_boot_volume_descriptor(volume_descriptor *bvd)
+{
+ boot_volume_descriptor *bvdData =
+ (boot_volume_descriptor*)bvd->volumeDescriptorData;
+
+ bvdData->boot_record_indicator[0] = ISO_VOLUME_DESCRIPTOR_BOOT;
+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+ bvdData->version[0] = 1;
+ memcpy(bvdData->boot_system_identifier, ET_ID, 23);
+ memcpy(bvdData->identifier, ISO_VOLUME_DESCRIPTOR_STANDARD_ID, 5);
+ diskStructure.boot_descriptor =
+ (boot_volume_descriptor*) bvd->volumeDescriptorData;
+ return 1;
+}
+
+int
+cd9660_write_boot(FILE *fd)
+{
+ struct boot_catalog_entry *e;
+ struct cd9660_boot_image *t;
+
+ /* write boot catalog */
+ if (fseeko(fd, (off_t)diskStructure.boot_catalog_sector *
+ diskStructure.sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ if (diskStructure.verbose_level > 0) {
+ printf("Writing boot catalog to sector %" PRId64 "\n",
+ diskStructure.boot_catalog_sector);
+ }
+ LIST_FOREACH(e, &diskStructure.boot_entries, ll_struct) {
+ if (diskStructure.verbose_level > 0) {
+ printf("Writing catalog entry of type %d\n",
+ e->entry_type);
+ }
+ /*
+ * It doesnt matter which one gets written
+ * since they are the same size
+ */
+ fwrite(&(e->entry_data.VE), 1, 32, fd);
+ }
+ if (diskStructure.verbose_level > 0)
+ printf("Finished writing boot catalog\n");
+
+ /* copy boot images */
+ TAILQ_FOREACH(t, &diskStructure.boot_images, image_list) {
+ if (diskStructure.verbose_level > 0) {
+ printf("Writing boot image from %s to sectors %d\n",
+ t->filename, t->sector);
+ }
+ cd9660_copy_file(fd, t->sector, t->filename);
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_eltorito.h b/usr.sbin/makefs/cd9660/cd9660_eltorito.h
new file mode 100644
index 0000000..02f153d
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_eltorito.h
@@ -0,0 +1,164 @@
+/* $NetBSD: cd9660_eltorito.h,v 1.5 2009/07/04 14:31:38 ahoka Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _CD9660_ELTORITO_H_
+#define _CD9660_ELTORITO_H_
+
+/* Boot defines */
+#define ET_ID "EL TORITO SPECIFICATION"
+#define ET_SYS_X86 0
+#define ET_SYS_PPC 1
+#define ET_SYS_MAC 2
+
+#define ET_BOOT_ENTRY_SIZE 0x20
+
+#define ET_BOOTABLE 0x88
+#define ET_NOT_BOOTABLE 0
+
+#define ET_MEDIA_NOEM 0
+#define ET_MEDIA_12FDD 1
+#define ET_MEDIA_144FDD 2
+#define ET_MEDIA_288FDD 3
+#define ET_MEDIA_HDD 4
+
+#define ET_INDICATOR_HEADERMORE 0x90
+#define ET_INDICATOR_HEADERLAST 0x91
+#define ET_INDICATOR_EXTENSION 0x44
+
+/*** Boot Structures ***/
+
+typedef struct _boot_volume_descriptor {
+ u_char boot_record_indicator [ISODCL(0x00,0x00)];
+ u_char identifier [ISODCL(0x01,0x05)];
+ u_char version [ISODCL(0x06,0x06)];
+ u_char boot_system_identifier [ISODCL(0x07,0x26)];
+ u_char unused1 [ISODCL(0x27,0x46)];
+ u_char boot_catalog_pointer [ISODCL(0x47,0x4A)];
+ u_char unused2 [ISODCL(0x4B,0x7FF)];
+} boot_volume_descriptor;
+
+typedef struct _boot_catalog_validation_entry {
+ u_char header_id [ISODCL(0x00,0x00)];
+ u_char platform_id [ISODCL(0x01,0x01)];
+ u_char reserved1 [ISODCL(0x02,0x03)];
+ u_char manufacturer [ISODCL(0x04,0x1B)];
+ u_char checksum [ISODCL(0x1C,0x1D)];
+ u_char key [ISODCL(0x1E,0x1F)];
+} boot_catalog_validation_entry;
+
+typedef struct _boot_catalog_initial_entry {
+ u_char boot_indicator [ISODCL(0x00,0x00)];
+ u_char media_type [ISODCL(0x01,0x01)];
+ u_char load_segment [ISODCL(0x02,0x03)];
+ u_char system_type [ISODCL(0x04,0x04)];
+ u_char unused_1 [ISODCL(0x05,0x05)];
+ u_char sector_count [ISODCL(0x06,0x07)];
+ u_char load_rba [ISODCL(0x08,0x0B)];
+ u_char unused_2 [ISODCL(0x0C,0x1F)];
+} boot_catalog_initial_entry;
+
+#define ET_SECTION_HEADER_MORE 0x90
+#define ET_SECTION_HEADER_LAST 0x91
+
+typedef struct _boot_catalog_section_header {
+ u_char header_indicator [ISODCL(0x00,0x00)];
+ u_char platform_id [ISODCL(0x01,0x01)];
+ u_char num_section_entries [ISODCL(0x02,0x03)];
+ u_char id_string [ISODCL(0x04,0x1F)];
+} boot_catalog_section_header;
+
+typedef struct _boot_catalog_section_entry {
+ u_char boot_indicator [ISODCL(0x00,0x00)];
+ u_char media_type [ISODCL(0x01,0x01)];
+ u_char load_segment [ISODCL(0x02,0x03)];
+ u_char system_type [ISODCL(0x04,0x04)];
+ u_char unused_1 [ISODCL(0x05,0x05)];
+ u_char sector_count [ISODCL(0x06,0x07)];
+ u_char load_rba [ISODCL(0x08,0x0B)];
+ u_char selection_criteria [ISODCL(0x0C,0x0C)];
+ u_char vendor_criteria [ISODCL(0x0D,0x1F)];
+} boot_catalog_section_entry;
+
+typedef struct _boot_catalog_section_entry_extension {
+ u_char extension_indicator [ISODCL(0x00,0x00)];
+ u_char flags [ISODCL(0x01,0x01)];
+ u_char vendor_criteria [ISODCL(0x02,0x1F)];
+} boot_catalog_section_entry_extension;
+
+#define ET_ENTRY_VE 1
+#define ET_ENTRY_IE 2
+#define ET_ENTRY_SH 3
+#define ET_ENTRY_SE 4
+#define ET_ENTRY_EX 5
+
+struct boot_catalog_entry {
+ char entry_type;
+ union {
+ boot_catalog_validation_entry VE;
+ boot_catalog_initial_entry IE;
+ boot_catalog_section_header SH;
+ boot_catalog_section_entry SE;
+ boot_catalog_section_entry_extension EX;
+ } entry_data;
+
+ LIST_ENTRY(boot_catalog_entry) ll_struct;
+};
+
+/* Temporary structure */
+struct cd9660_boot_image {
+ char *filename;
+ int size;
+ int sector; /* copied to LoadRBA */
+ int num_sectors;
+ unsigned int loadSegment;
+ u_char targetMode;
+ u_char system;
+ u_char bootable;
+ /*
+ * If the boot image exists in the filesystem
+ * already, this is a pointer to that node. For the sake
+ * of simplicity in future versions, this pointer is only
+ * to the node in the primary volume. This SHOULD be done
+ * via a hashtable lookup.
+ */
+ struct _cd9660node *boot_image_node;
+ TAILQ_ENTRY(cd9660_boot_image) image_list;
+ int serialno;
+};
+
+
+#endif /* _CD9660_ELTORITO_H_ */
+
diff --git a/usr.sbin/makefs/cd9660/cd9660_strings.c b/usr.sbin/makefs/cd9660/cd9660_strings.c
new file mode 100644
index 0000000..7789c8e
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_strings.c
@@ -0,0 +1,120 @@
+/* $NetBSD: cd9660_strings.c,v 1.4 2007/01/16 17:32:05 hubertf Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include <sys/mount.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+#include <ctype.h>
+
+#include "makefs.h"
+#include "cd9660.h"
+
+
+void
+cd9660_uppercase_characters(char *str, int len)
+{
+ int p;
+
+ for (p = 0; p < len; p++) {
+ if (islower((unsigned char)str[p]) )
+ str[p] -= 32;
+ }
+}
+
+static inline int
+cd9660_is_a_char(char c)
+{
+ return (isupper((unsigned char)c)
+ || c == '_'
+ || (c >= '0' && c <= '?'));
+}
+
+static inline int
+cd9660_is_d_char(char c)
+{
+ return (isupper((unsigned char)c)
+ || c == '_'
+ || (c >= '%' && c <= '9')
+ || (c >= ' ' && c <= '\"'));
+}
+
+/*
+ * Test a string to see if it is composed of valid a characters
+ * @param const char* The string to test
+ * @returns int 1 if valid, 2 if valid if characters are converted to
+ * upper case, 0 otherwise
+ */
+int
+cd9660_valid_a_chars(const char *str)
+{
+ const char *c = str;
+ int upperFound = 0;
+
+ while ((*c) != '\0') {
+ if (!(cd9660_is_a_char(*c))) {
+ if (islower((unsigned char)*c) )
+ upperFound = 1;
+ else
+ return 0;
+ }
+ c++;
+ }
+ return upperFound + 1;
+}
+
+/*
+ * Test a string to see if it is composed of valid d characters
+ * @param const char* The string to test
+ * @returns int 1 if valid, 2 if valid if characters are converted to
+ * upper case, 0 otherwise
+ */
+int
+cd9660_valid_d_chars(const char *str)
+{
+ const char *c=str;
+ int upperFound = 0;
+
+ while ((*c) != '\0') {
+ if (!(cd9660_is_d_char(*c))) {
+ if (islower((unsigned char)*c) )
+ upperFound = 1;
+ else
+ return 0;
+ }
+ c++;
+ }
+ return upperFound + 1;
+}
diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c
new file mode 100644
index 0000000..46d4a34
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/cd9660_write.c
@@ -0,0 +1,518 @@
+/* $NetBSD: cd9660_write.c,v 1.13 2010/10/22 00:49:15 christos Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+static int cd9660_write_volume_descriptors(FILE *);
+static int cd9660_write_path_table(FILE *, off_t, int);
+static int cd9660_write_path_tables(FILE *);
+static int cd9660_write_file(FILE *, cd9660node *);
+static int cd9660_write_filedata(FILE *, off_t, const unsigned char *, int);
+#if 0
+static int cd9660_write_buffered(FILE *, off_t, int, const unsigned char *);
+#endif
+static void cd9660_write_rr(FILE *, cd9660node *, off_t, off_t);
+
+/*
+ * Write the image
+ * Writes the entire image
+ * @param const char* The filename for the image
+ * @returns int 1 on success, 0 on failure
+ */
+int
+cd9660_write_image(const char* image)
+{
+ FILE *fd;
+ int status;
+ char buf[CD9660_SECTOR_SIZE];
+
+ if ((fd = fopen(image, "w+")) == NULL) {
+ err(EXIT_FAILURE, "%s: Can't open `%s' for writing", __func__,
+ image);
+ }
+
+ if (diskStructure.verbose_level > 0)
+ printf("Writing image\n");
+
+ if (diskStructure.has_generic_bootimage) {
+ status = cd9660_copy_file(fd, 0,
+ diskStructure.generic_bootimage);
+ if (status == 0) {
+ warnx("%s: Error writing generic boot image",
+ __func__);
+ goto cleanup_bad_image;
+ }
+ }
+
+ /* Write the volume descriptors */
+ status = cd9660_write_volume_descriptors(fd);
+ if (status == 0) {
+ warnx("%s: Error writing volume descriptors to image",
+ __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure.verbose_level > 0)
+ printf("Volume descriptors written\n");
+
+ /*
+ * Write the path tables: there are actually four, but right
+ * now we are only concearned with two.
+ */
+ status = cd9660_write_path_tables(fd);
+ if (status == 0) {
+ warnx("%s: Error writing path tables to image", __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure.verbose_level > 0)
+ printf("Path tables written\n");
+
+ /* Write the directories and files */
+ status = cd9660_write_file(fd, diskStructure.rootNode);
+ if (status == 0) {
+ warnx("%s: Error writing files to image", __func__);
+ goto cleanup_bad_image;
+ }
+
+ if (diskStructure.is_bootable) {
+ cd9660_write_boot(fd);
+ }
+
+ /* Write padding bits. This is temporary */
+ memset(buf, 0, CD9660_SECTOR_SIZE);
+ cd9660_write_filedata(fd, diskStructure.totalSectors - 1, buf, 1);
+
+ if (diskStructure.verbose_level > 0)
+ printf("Files written\n");
+ fclose(fd);
+
+ if (diskStructure.verbose_level > 0)
+ printf("Image closed\n");
+ return 1;
+
+cleanup_bad_image:
+ fclose(fd);
+ if (!diskStructure.keep_bad_images)
+ unlink(image);
+ if (diskStructure.verbose_level > 0)
+ printf("Bad image cleaned up\n");
+ return 0;
+}
+
+static int
+cd9660_write_volume_descriptors(FILE *fd)
+{
+ volume_descriptor *vd_temp = diskStructure.firstVolumeDescriptor;
+ int pos;
+
+ while (vd_temp != NULL) {
+ pos = vd_temp->sector * diskStructure.sectorSize;
+ cd9660_write_filedata(fd, vd_temp->sector,
+ vd_temp->volumeDescriptorData, 1);
+ vd_temp = vd_temp->next;
+ }
+ return 1;
+}
+
+/*
+ * Write out an individual path table
+ * Used just to keep redundant code to a minimum
+ * @param FILE *fd Valid file pointer
+ * @param int Sector to start writing path table to
+ * @param int Endian mode : BIG_ENDIAN or LITTLE_ENDIAN
+ * @returns int 1 on success, 0 on failure
+ */
+static int
+cd9660_write_path_table(FILE *fd, off_t sector, int mode)
+{
+ int path_table_sectors = CD9660_BLOCKS(diskStructure.sectorSize,
+ diskStructure.pathTableLength);
+ unsigned char *buffer;
+ unsigned char *buffer_head;
+ int len;
+ path_table_entry temp_entry;
+ cd9660node *ptcur;
+
+ buffer = malloc(diskStructure.sectorSize * path_table_sectors);
+ if (buffer == NULL) {
+ warnx("%s: Memory allocation error allocating buffer",
+ __func__);
+ return 0;
+ }
+ buffer_head = buffer;
+ memset(buffer, 0, diskStructure.sectorSize * path_table_sectors);
+
+ ptcur = diskStructure.rootNode;
+
+ while (ptcur != NULL) {
+ memset(&temp_entry, 0, sizeof(path_table_entry));
+ temp_entry.length[0] = ptcur->isoDirRecord->name_len[0];
+ temp_entry.extended_attribute_length[0] =
+ ptcur->isoDirRecord->ext_attr_length[0];
+ memcpy(temp_entry.name, ptcur->isoDirRecord->name,
+ temp_entry.length[0] + 1);
+
+ /* round up */
+ len = temp_entry.length[0] + 8 + (temp_entry.length[0] & 0x01);
+
+ /* todo: function pointers instead */
+ if (mode == LITTLE_ENDIAN) {
+ cd9660_731(ptcur->fileDataSector,
+ temp_entry.first_sector);
+ cd9660_721((ptcur->parent == NULL ?
+ 1 : ptcur->parent->ptnumber),
+ temp_entry.parent_number);
+ } else {
+ cd9660_732(ptcur->fileDataSector,
+ temp_entry.first_sector);
+ cd9660_722((ptcur->parent == NULL ?
+ 1 : ptcur->parent->ptnumber),
+ temp_entry.parent_number);
+ }
+
+
+ memcpy(buffer, &temp_entry, len);
+ buffer += len;
+
+ ptcur = ptcur->ptnext;
+ }
+
+ return cd9660_write_filedata(fd, sector, buffer_head,
+ path_table_sectors);
+}
+
+
+/*
+ * Write out the path tables to disk
+ * Each file descriptor should be pointed to by the PVD, so we know which
+ * sector to copy them to. One thing to watch out for: the only path tables
+ * stored are in the endian mode that the application is compiled for. So,
+ * the first thing to do is write out that path table, then to write the one
+ * in the other endian mode requires to convert the endianness of each entry
+ * in the table. The best way to do this would be to create a temporary
+ * path_table_entry structure, then for each path table entry, copy it to
+ * the temporary entry, translate, then copy that to disk.
+ *
+ * @param FILE* Valid file descriptor
+ * @returns int 0 on failure, 1 on success
+ */
+static int
+cd9660_write_path_tables(FILE *fd)
+{
+ if (cd9660_write_path_table(fd,
+ diskStructure.primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0)
+ return 0;
+
+ if (cd9660_write_path_table(fd,
+ diskStructure.primaryBigEndianTableSector, BIG_ENDIAN) == 0)
+ return 0;
+
+ /* @TODO: handle remaining two path tables */
+ return 1;
+}
+
+/*
+ * Write a file to disk
+ * Writes a file, its directory record, and its data to disk
+ * This file is designed to be called RECURSIVELY, so initially call it
+ * with the root node. All of the records should store what sector the
+ * file goes in, so no computation should be necessary.
+ *
+ * @param int fd Valid file descriptor
+ * @param struct cd9660node* writenode Pointer to the file to be written
+ * @returns int 0 on failure, 1 on success
+ */
+static int
+cd9660_write_file(FILE *fd, cd9660node *writenode)
+{
+ char *buf;
+ char *temp_file_name;
+ int ret;
+ off_t working_sector;
+ int cur_sector_offset;
+ int written;
+ iso_directory_record_cd9660 temp_record;
+ cd9660node *temp;
+ int rv = 0;
+
+ /* Todo : clean up variables */
+
+ temp_file_name = malloc(CD9660MAXPATH + 1);
+ if (temp_file_name == NULL)
+ err(EXIT_FAILURE, "%s: malloc", __func__);
+
+ memset(temp_file_name, 0, CD9660MAXPATH + 1);
+
+ buf = malloc(diskStructure.sectorSize);
+ if (buf == NULL)
+ err(EXIT_FAILURE, "%s: malloc", __func__);
+
+ if ((writenode->level != 0) &&
+ !(writenode->node->type & S_IFDIR)) {
+ fsinode *inode = writenode->node->inode;
+ /* Only attempt to write unwritten files that have length. */
+ if ((inode->flags & FI_WRITTEN) != 0) {
+ INODE_WARNX(("%s: skipping written inode %d", __func__,
+ (int)inode->st.st_ino));
+ } else if (writenode->fileDataLength > 0) {
+ INODE_WARNX(("%s: writing inode %d blocks at %" PRIu32,
+ __func__, (int)inode->st.st_ino, inode->ino));
+ inode->flags |= FI_WRITTEN;
+ cd9660_compute_full_filename(writenode,
+ temp_file_name, 0);
+ ret = cd9660_copy_file(fd, writenode->fileDataSector,
+ temp_file_name);
+ if (ret == 0)
+ goto out;
+ }
+ } else {
+ /*
+ * Here is a new revelation that ECMA didnt explain
+ * (at least not well).
+ * ALL . and .. records store the name "\0" and "\1"
+ * resepctively. So, for each directory, we have to
+ * make a new node.
+ *
+ * This is where it gets kinda messy, since we have to
+ * be careful of sector boundaries
+ */
+ cur_sector_offset = 0;
+ working_sector = writenode->fileDataSector;
+ if (fseeko(fd, working_sector * diskStructure.sectorSize,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ /*
+ * Now loop over children, writing out their directory
+ * records - beware of sector boundaries
+ */
+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
+ /*
+ * Copy the temporary record and adjust its size
+ * if necessary
+ */
+ memcpy(&temp_record, temp->isoDirRecord,
+ sizeof(iso_directory_record_cd9660));
+
+ temp_record.length[0] =
+ cd9660_compute_record_size(temp);
+
+ if (temp_record.length[0] + cur_sector_offset >=
+ diskStructure.sectorSize) {
+ cur_sector_offset = 0;
+ working_sector++;
+
+ /* Seek to the next sector. */
+ if (fseeko(fd, working_sector *
+ diskStructure.sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+ }
+ /* Write out the basic ISO directory record */
+ written = fwrite(&temp_record, 1,
+ temp->isoDirRecord->length[0], fd);
+ if (diskStructure.rock_ridge_enabled) {
+ cd9660_write_rr(fd, temp,
+ cur_sector_offset, working_sector);
+ }
+ if (fseeko(fd, working_sector *
+ diskStructure.sectorSize + cur_sector_offset +
+ temp_record.length[0] - temp->su_tail_size,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+ if (temp->su_tail_size > 0)
+ fwrite(temp->su_tail_data, 1,
+ temp->su_tail_size, fd);
+ if (ferror(fd)) {
+ warnx("%s: write error", __func__);
+ goto out;
+ }
+ cur_sector_offset += temp_record.length[0];
+
+ }
+
+ /*
+ * Recurse on children.
+ */
+ TAILQ_FOREACH(temp, &writenode->cn_children, cn_next_child) {
+ if ((ret = cd9660_write_file(fd, temp)) == 0)
+ goto out;
+ }
+ }
+ rv = 1;
+out:
+ free(temp_file_name);
+ free(buf);
+ return rv;
+}
+
+/*
+ * Wrapper function to write a buffer (one sector) to disk.
+ * Seeks and writes the buffer.
+ * NOTE: You dont NEED to use this function, but it might make your
+ * life easier if you have to write things that align to a sector
+ * (such as volume descriptors).
+ *
+ * @param int fd Valid file descriptor
+ * @param int sector Sector number to write to
+ * @param const unsigned char* Buffer to write. This should be the
+ * size of a sector, and if only a portion
+ * is written, the rest should be set to 0.
+ */
+static int
+cd9660_write_filedata(FILE *fd, off_t sector, const unsigned char *buf,
+ int numsecs)
+{
+ off_t curpos;
+ size_t success;
+
+ curpos = ftello(fd);
+
+ if (fseeko(fd, sector * diskStructure.sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ success = fwrite(buf, diskStructure.sectorSize * numsecs, 1, fd);
+
+ if (fseeko(fd, curpos, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ if (success == 1)
+ success = diskStructure.sectorSize * numsecs;
+ return success;
+}
+
+#if 0
+static int
+cd9660_write_buffered(FILE *fd, off_t offset, int buff_len,
+ const unsigned char* buffer)
+{
+ static int working_sector = -1;
+ static char buf[CD9660_SECTOR_SIZE];
+
+ return 0;
+}
+#endif
+
+int
+cd9660_copy_file(FILE *fd, off_t start_sector, const char *filename)
+{
+ FILE *rf;
+ int bytes_read;
+ off_t sector = start_sector;
+ int buf_size = diskStructure.sectorSize;
+ char *buf;
+
+ buf = malloc(buf_size);
+ if (buf == NULL)
+ err(EXIT_FAILURE, "%s: malloc", __func__);
+
+ if ((rf = fopen(filename, "rb")) == NULL) {
+ warn("%s: cannot open %s", __func__, filename);
+ free(buf);
+ return 0;
+ }
+
+ if (diskStructure.verbose_level > 1)
+ printf("Writing file: %s\n",filename);
+
+ if (fseeko(fd, start_sector * diskStructure.sectorSize, SEEK_SET) == -1)
+ err(1, "fseeko");
+
+ while (!feof(rf)) {
+ bytes_read = fread(buf,1,buf_size,rf);
+ if (ferror(rf)) {
+ warn("%s: fread", __func__);
+ free(buf);
+ return 0;
+ }
+
+ fwrite(buf,1,bytes_read,fd);
+ if (ferror(fd)) {
+ warn("%s: fwrite", __func__);
+ free(buf);
+ return 0;
+ }
+ sector++;
+ }
+
+ fclose(rf);
+ free(buf);
+ return 1;
+}
+
+static void
+cd9660_write_rr(FILE *fd, cd9660node *writenode, off_t offset, off_t sector)
+{
+ int in_ca = 0;
+ struct ISO_SUSP_ATTRIBUTES *myattr;
+
+ offset += writenode->isoDirRecord->length[0];
+ if (fseeko(fd, sector * diskStructure.sectorSize + offset, SEEK_SET) ==
+ -1)
+ err(1, "fseeko");
+ /* Offset now points at the end of the record */
+ TAILQ_FOREACH(myattr, &writenode->head, rr_ll) {
+ fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd);
+
+ if (!in_ca) {
+ offset += CD9660_SUSP_ENTRY_SIZE(myattr);
+ if (myattr->last_in_suf) {
+ /*
+ * Point the offset to the start of this
+ * record's CE area
+ */
+ if (fseeko(fd, ((off_t)diskStructure.
+ susp_continuation_area_start_sector *
+ diskStructure.sectorSize)
+ + writenode->susp_entry_ce_start,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+ in_ca = 1;
+ }
+ }
+ }
+
+ /*
+ * If we had to go to the continuation area, head back to
+ * where we should be.
+ */
+ if (in_ca)
+ if (fseeko(fd, sector * diskStructure.sectorSize + offset,
+ SEEK_SET) == -1)
+ err(1, "fseeko");
+}
diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.c b/usr.sbin/makefs/cd9660/iso9660_rrip.c
new file mode 100644
index 0000000..71f77aa
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/iso9660_rrip.c
@@ -0,0 +1,836 @@
+/* $NetBSD: iso9660_rrip.c,v 1.8 2009/01/10 22:06:29 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+/* This will hold all the function definitions
+ * defined in iso9660_rrip.h
+ */
+
+#include "makefs.h"
+#include "cd9660.h"
+#include "iso9660_rrip.h"
+#include <sys/queue.h>
+#include <stdio.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+static void cd9660_rrip_initialize_inode(cd9660node *);
+static int cd9660_susp_handle_continuation(cd9660node *);
+static int cd9660_susp_handle_continuation_common(cd9660node *, int);
+
+int
+cd9660_susp_initialize(cd9660node *node, cd9660node *parent,
+ cd9660node *grandparent)
+{
+ cd9660node *cn;
+ int r;
+
+ /* Make sure the node is not NULL. If it is, there are major problems */
+ assert(node != NULL);
+
+ if (!(node->type & CD9660_TYPE_DOT) &&
+ !(node->type & CD9660_TYPE_DOTDOT))
+ TAILQ_INIT(&(node->head));
+ if (node->dot_record != 0)
+ TAILQ_INIT(&(node->dot_record->head));
+ if (node->dot_dot_record != 0)
+ TAILQ_INIT(&(node->dot_dot_record->head));
+
+ /* SUSP specific entries here */
+ if ((r = cd9660_susp_initialize_node(node)) < 0)
+ return r;
+
+ /* currently called cd9660node_rrip_init_links */
+ r = cd9660_rrip_initialize_node(node, parent, grandparent);
+ if (r < 0)
+ return r;
+
+ /*
+ * See if we need a CE record, and set all of the
+ * associated counters.
+ *
+ * This should be called after all extensions. After
+ * this is called, no new records should be added.
+ */
+ if ((r = cd9660_susp_handle_continuation(node)) < 0)
+ return r;
+
+ /* Recurse on children. */
+ TAILQ_FOREACH(cn, &node->cn_children, cn_next_child) {
+ if ((r = cd9660_susp_initialize(cn, node, parent)) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+cd9660_susp_finalize(cd9660node *node)
+{
+ cd9660node *temp;
+ int r;
+
+ assert(node != NULL);
+
+ if (node == diskStructure.rootNode)
+ diskStructure.susp_continuation_area_current_free = 0;
+
+ if ((r = cd9660_susp_finalize_node(node)) < 0)
+ return r;
+ if ((r = cd9660_rrip_finalize_node(node)) < 0)
+ return r;
+
+ TAILQ_FOREACH(temp, &node->cn_children, cn_next_child) {
+ if ((r = cd9660_susp_finalize(temp)) < 0)
+ return r;
+ }
+ return 1;
+}
+
+/*
+ * If we really wanted to speed things up, we could have some sort of
+ * lookup table on the SUSP entry type that calls a functor. Or, we could
+ * combine the functions. These functions are kept separate to allow
+ * easier addition of other extensions.
+
+ * For the sake of simplicity and clarity, we won't be doing that for now.
+ */
+
+/*
+ * SUSP needs to update the following types:
+ * CE (continuation area)
+ */
+int
+cd9660_susp_finalize_node(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ /* Handle CE counters */
+ if (node->susp_entry_ce_length > 0) {
+ node->susp_entry_ce_start =
+ diskStructure.susp_continuation_area_current_free;
+ diskStructure.susp_continuation_area_current_free +=
+ node->susp_entry_ce_length;
+ }
+
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+ if (t->susp_type != SUSP_TYPE_SUSP ||
+ t->entry_type != SUSP_ENTRY_SUSP_CE)
+ continue;
+ cd9660_bothendian_dword(
+ diskStructure.
+ susp_continuation_area_start_sector,
+ t->attr.su_entry.CE.ca_sector);
+
+ cd9660_bothendian_dword(
+ diskStructure.
+ susp_continuation_area_start_sector,
+ t->attr.su_entry.CE.ca_sector);
+ cd9660_bothendian_dword(node->susp_entry_ce_start,
+ t->attr.su_entry.CE.offset);
+ cd9660_bothendian_dword(node->susp_entry_ce_length,
+ t->attr.su_entry.CE.length);
+ }
+ return 0;
+}
+
+int
+cd9660_rrip_finalize_node(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *t;
+
+ TAILQ_FOREACH(t, &node->head, rr_ll) {
+ if (t->susp_type != SUSP_TYPE_RRIP)
+ continue;
+ switch (t->entry_type) {
+ case SUSP_ENTRY_RRIP_CL:
+ /* Look at rr_relocated*/
+ if (node->rr_relocated == NULL)
+ return -1;
+ cd9660_bothendian_dword(
+ node->rr_relocated->fileDataSector,
+ (unsigned char *)
+ t->attr.rr_entry.CL.dir_loc);
+ break;
+ case SUSP_ENTRY_RRIP_PL:
+ /* Look at rr_real_parent */
+ if (node->rr_real_parent == NULL)
+ return -1;
+ cd9660_bothendian_dword(
+ node->rr_real_parent->fileDataSector,
+ (unsigned char *)
+ t->attr.rr_entry.PL.dir_loc);
+ break;
+ }
+ }
+ return 0;
+}
+
+static int
+cd9660_susp_handle_continuation_common(cd9660node *node, int space)
+{
+ int ca_used, susp_used, susp_used_pre_ce, working;
+ struct ISO_SUSP_ATTRIBUTES *temp, *pre_ce, *last, *CE, *ST;
+
+ pre_ce = last = NULL;
+ working = 254 - space;
+ if (node->su_tail_size > 0)
+ /* Allow 4 bytes for "ST" record. */
+ working -= node->su_tail_size + 4;
+ /* printf("There are %i bytes to work with\n",working); */
+
+ susp_used_pre_ce = susp_used = 0;
+ ca_used = 0;
+ TAILQ_FOREACH(temp, &node->head, rr_ll) {
+ if (working < 0)
+ break;
+ /*
+ * printf("SUSP Entry found, length is %i\n",
+ * CD9660_SUSP_ENTRY_SIZE(temp));
+ */
+ working -= CD9660_SUSP_ENTRY_SIZE(temp);
+ if (working >= 0) {
+ last = temp;
+ susp_used += CD9660_SUSP_ENTRY_SIZE(temp);
+ }
+ if (working >= 28) {
+ /*
+ * Remember the last entry after which we
+ * could insert a "CE" entry.
+ */
+ pre_ce = last;
+ susp_used_pre_ce = susp_used;
+ }
+ }
+
+ /* A CE entry is needed */
+ if (working <= 0) {
+ CE = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_CE, "CE", SUSP_LOC_ENTRY);
+ cd9660_susp_ce(CE, node);
+ /* This will automatically insert at the appropriate location */
+ if (pre_ce != NULL)
+ TAILQ_INSERT_AFTER(&node->head, pre_ce, CE, rr_ll);
+ else
+ TAILQ_INSERT_HEAD(&node->head, CE, rr_ll);
+ last = CE;
+ susp_used = susp_used_pre_ce + 28;
+ /* Count how much CA data is necessary */
+ for (temp = TAILQ_NEXT(last, rr_ll); temp != NULL;
+ temp = TAILQ_NEXT(temp, rr_ll)) {
+ ca_used += CD9660_SUSP_ENTRY_SIZE(temp);
+ }
+ }
+
+ /* An ST entry is needed */
+ if (node->su_tail_size > 0) {
+ ST = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_ST, "ST", SUSP_LOC_ENTRY);
+ cd9660_susp_st(ST, node);
+ if (last != NULL)
+ TAILQ_INSERT_AFTER(&node->head, last, ST, rr_ll);
+ else
+ TAILQ_INSERT_HEAD(&node->head, ST, rr_ll);
+ last = ST;
+ susp_used += 4;
+ }
+ if (last != NULL)
+ last->last_in_suf = 1;
+
+ node->susp_entry_size = susp_used;
+ node->susp_entry_ce_length = ca_used;
+
+ diskStructure.susp_continuation_area_size += ca_used;
+ return 1;
+}
+
+/* See if a continuation entry is needed for each of the different types */
+static int
+cd9660_susp_handle_continuation(cd9660node *node)
+{
+ assert (node != NULL);
+
+ /* Entry */
+ if (cd9660_susp_handle_continuation_common(
+ node,(int)(node->isoDirRecord->length[0])) < 0)
+ return 0;
+
+ return 1;
+}
+
+int
+cd9660_susp_initialize_node(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *temp;
+
+ /*
+ * Requirements/notes:
+ * CE: is added for us where needed
+ * ST: not sure if it is even required, but if so, should be
+ * handled by the CE code
+ * PD: isnt needed (though might be added for testing)
+ * SP: is stored ONLY on the . record of the root directory
+ * ES: not sure
+ */
+
+ /* Check for root directory, add SP and ER if needed. */
+ if (node->type & CD9660_TYPE_DOT) {
+ if (node->parent == diskStructure.rootNode) {
+ temp = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_SP, "SP", SUSP_LOC_DOT);
+ cd9660_susp_sp(temp, node);
+
+ /* Should be first entry. */
+ TAILQ_INSERT_HEAD(&node->head, temp, rr_ll);
+ }
+ }
+ return 1;
+}
+
+static void
+cd9660_rrip_initialize_inode(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES *attr;
+
+ /*
+ * Inode dependent values - this may change,
+ * but for now virtual files and directories do
+ * not have an inode structure
+ */
+
+ if ((node->node != NULL) && (node->node->inode != NULL)) {
+ /* PX - POSIX attributes */
+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(attr, node->node);
+
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+
+ /* TF - timestamp */
+ attr = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_TF, "TF", SUSP_LOC_ENTRY);
+ cd9660node_rrip_tf(attr, node->node);
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+
+ /* SL - Symbolic link */
+ /* ?????????? Dan - why is this here? */
+ if (TAILQ_EMPTY(&node->cn_children) &&
+ node->node->inode != NULL &&
+ S_ISLNK(node->node->inode->st.st_mode))
+ cd9660_createSL(node);
+
+ /* PN - device number */
+ if (node->node->inode != NULL &&
+ ((S_ISCHR(node->node->inode->st.st_mode) ||
+ S_ISBLK(node->node->inode->st.st_mode)))) {
+ attr =
+ cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PN, "PN",
+ SUSP_LOC_ENTRY);
+ cd9660node_rrip_pn(attr, node->node);
+ TAILQ_INSERT_TAIL(&node->head, attr, rr_ll);
+ }
+ }
+}
+
+int
+cd9660_rrip_initialize_node(cd9660node *node, cd9660node *parent,
+ cd9660node *grandparent)
+{
+ struct ISO_SUSP_ATTRIBUTES *current = NULL;
+
+ assert(node != NULL);
+
+ if (node->type & CD9660_TYPE_DOT) {
+ /*
+ * Handle ER - should be the only entry to appear on
+ * a "." record
+ */
+ if (node->parent == diskStructure.rootNode) {
+ cd9660_susp_ER(node, 1, SUSP_RRIP_ER_EXT_ID,
+ SUSP_RRIP_ER_EXT_DES, SUSP_RRIP_ER_EXT_SRC);
+ }
+ if (parent != NULL && parent->node != NULL &&
+ parent->node->inode != NULL) {
+ /* PX - POSIX attributes */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(current, parent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ } else if (node->type & CD9660_TYPE_DOTDOT) {
+ if (grandparent != NULL && grandparent->node != NULL &&
+ grandparent->node->inode != NULL) {
+ /* PX - POSIX attributes */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PX, "PX", SUSP_LOC_ENTRY);
+ cd9660node_rrip_px(current, grandparent->node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ } else {
+ cd9660_rrip_initialize_inode(node);
+
+ /*
+ * Not every node needs a NM set - only if the name is
+ * actually different. IE: If a file is TEST -> TEST,
+ * no NM. test -> TEST, need a NM
+ *
+ * The rr_moved_dir needs to be assigned a NM record as well.
+ */
+ if (node == diskStructure.rr_moved_dir) {
+ cd9660_rrip_add_NM(node, RRIP_DEFAULT_MOVE_DIR_NAME);
+ }
+ else if ((node->node != NULL) &&
+ ((strlen(node->node->name) !=
+ (int)node->isoDirRecord->name_len[0]) ||
+ (memcmp(node->node->name,node->isoDirRecord->name,
+ (int) node->isoDirRecord->name_len[0]) != 0))) {
+ cd9660_rrip_NM(node);
+ }
+
+
+
+ /* Rock ridge directory relocation code here. */
+
+ /* First handle the CL for the placeholder file. */
+ if (node->rr_relocated != NULL) {
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_CL, "CL", SUSP_LOC_ENTRY);
+ cd9660_rrip_CL(current, node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+
+ /* Handle RE*/
+ if (node->rr_real_parent != NULL) {
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_RE, "RE", SUSP_LOC_ENTRY);
+ cd9660_rrip_RE(current,node);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+
+ /* Handle PL */
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_PL, "PL", SUSP_LOC_DOTDOT);
+ cd9660_rrip_PL(current,node->dot_dot_record);
+ TAILQ_INSERT_TAIL(&node->dot_dot_record->head, current,
+ rr_ll);
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ }
+ }
+ return 1;
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660node_susp_create_node(int susp_type, int entry_type, const char *type_id,
+ int write_loc)
+{
+ struct ISO_SUSP_ATTRIBUTES* temp;
+
+ if ((temp = malloc(sizeof(struct ISO_SUSP_ATTRIBUTES))) == NULL) {
+ CD9660_MEM_ALLOC_ERROR("cd9660node_susp_create_node");
+ exit(1);
+ }
+
+ temp->susp_type = susp_type;
+ temp->entry_type = entry_type;
+ temp->last_in_suf = 0;
+ /* Phase this out */
+ temp->type_of[0] = type_id[0];
+ temp->type_of[1] = type_id[1];
+ temp->write_location = write_loc;
+
+ /*
+ * Since the first four bytes is common, lets go ahead and
+ * set the type identifier, since we are passing that to this
+ * function anyhow.
+ */
+ temp->attr.su_entry.SP.h.type[0] = type_id[0];
+ temp->attr.su_entry.SP.h.type[1] = type_id[1];
+ return temp;
+}
+
+int
+cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES* p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.PL.h.length[0] = 12;
+ p->attr.rr_entry.PL.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.CL.h.length[0] = 12;
+ p->attr.rr_entry.CL.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *node __unused)
+{
+ p->attr.rr_entry.RE.h.length[0] = 0;
+ p->attr.rr_entry.RE.h.version[0] = 1;
+ return 1;
+}
+
+void
+cd9660_createSL(cd9660node *node)
+{
+ struct ISO_SUSP_ATTRIBUTES* current;
+ int path_count, dir_count, done, i, j, dir_copied;
+ char temp_cr[255];
+ char temp_sl[255]; /* used in copying continuation entry*/
+ char* sl_ptr;
+
+ sl_ptr = node->node->symlink;
+
+ done = 0;
+ path_count = 0;
+ dir_count = 0;
+ dir_copied = 0;
+ current = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
+
+ current->attr.rr_entry.SL.h.version[0] = 1;
+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
+
+ if (*sl_ptr == '/') {
+ temp_cr[0] = SL_FLAGS_ROOT;
+ temp_cr[1] = 0;
+ memcpy(current->attr.rr_entry.SL.component + path_count,
+ temp_cr, 2);
+ path_count += 2;
+ sl_ptr++;
+ }
+
+ for (i = 0; i < (dir_count + 2); i++)
+ temp_cr[i] = '\0';
+
+ while (!done) {
+ while ((*sl_ptr != '/') && (*sl_ptr != '\0')) {
+ dir_copied = 1;
+ if (*sl_ptr == '.') {
+ if ((*(sl_ptr + 1) == '/') || (*(sl_ptr + 1)
+ == '\0')) {
+ temp_cr[0] = SL_FLAGS_CURRENT;
+ sl_ptr++;
+ } else if(*(sl_ptr + 1) == '.') {
+ if ((*(sl_ptr + 2) == '/') ||
+ (*(sl_ptr + 2) == '\0')) {
+ temp_cr[0] = SL_FLAGS_PARENT;
+ sl_ptr += 2;
+ }
+ } else {
+ temp_cr[dir_count+2] = *sl_ptr;
+ sl_ptr++;
+ dir_count++;
+ }
+ } else {
+ temp_cr[dir_count + 2] = *sl_ptr;
+ sl_ptr++;
+ dir_count++;
+ }
+ }
+
+ if ((path_count + dir_count) >= 249) {
+ current->attr.rr_entry.SL.flags[0] |= SL_FLAGS_CONTINUE;
+
+ j = 0;
+
+ if (path_count <= 249) {
+ while(j != (249 - path_count)) {
+ temp_sl[j] = temp_cr[j];
+ j++;
+ }
+ temp_sl[0] = SL_FLAGS_CONTINUE;
+ temp_sl[1] = j - 2;
+ memcpy(
+ current->attr.rr_entry.SL.component +
+ path_count,
+ temp_sl, j);
+ }
+
+ path_count += j;
+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ current= cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_SL, "SL", SUSP_LOC_ENTRY);
+ current->attr.rr_entry.SL.h.version[0] = 1;
+ current->attr.rr_entry.SL.flags[0] = SL_FLAGS_NONE;
+
+ path_count = 0;
+
+ if (dir_count > 2) {
+ while (j != dir_count + 2) {
+ current->attr.rr_entry.SL.component[
+ path_count + 2] = temp_cr[j];
+ j++;
+ path_count++;
+ }
+ current->attr.rr_entry.SL.component[1]
+ = path_count;
+ path_count+= 2;
+ } else {
+ while(j != dir_count) {
+ current->attr.rr_entry.SL.component[
+ path_count+2] = temp_cr[j];
+ j++;
+ path_count++;
+ }
+ }
+ } else {
+ if (dir_copied == 1) {
+ temp_cr[1] = dir_count;
+ memcpy(current->attr.rr_entry.SL.component +
+ path_count,
+ temp_cr, dir_count + 2);
+ path_count += dir_count + 2;
+ }
+ }
+
+ if (*sl_ptr == '\0') {
+ done = 1;
+ current->attr.rr_entry.SL.h.length[0] = path_count + 5;
+ TAILQ_INSERT_TAIL(&node->head, current, rr_ll);
+ } else {
+ sl_ptr++;
+ dir_count = 0;
+ dir_copied = 0;
+ for(i = 0; i < 255; i++) {
+ temp_cr[i] = '\0';
+ }
+ }
+ }
+}
+
+int
+cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *v, fsnode *pxinfo)
+{
+ v->attr.rr_entry.PX.h.length[0] = 36;
+ v->attr.rr_entry.PX.h.version[0] = 1;
+ cd9660_bothendian_dword(pxinfo->inode->st.st_mode,
+ v->attr.rr_entry.PX.mode);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_nlink,
+ v->attr.rr_entry.PX.links);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_uid,
+ v->attr.rr_entry.PX.uid);
+ cd9660_bothendian_dword(pxinfo->inode->st.st_gid,
+ v->attr.rr_entry.PX.gid);
+
+ /* Ignoring the serial number for now */
+ return 1;
+}
+
+int
+cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *pn_field, fsnode *fnode)
+{
+ pn_field->attr.rr_entry.PN.h.length[0] = 20;
+ pn_field->attr.rr_entry.PN.h.version[0] = 1;
+
+ if (sizeof (fnode->inode->st.st_dev) > 32)
+ cd9660_bothendian_dword((uint64_t)fnode->inode->st.st_dev >> 32,
+ pn_field->attr.rr_entry.PN.high);
+ else
+ cd9660_bothendian_dword(0, pn_field->attr.rr_entry.PN.high);
+
+ cd9660_bothendian_dword(fnode->inode->st.st_dev & 0xffffffff,
+ pn_field->attr.rr_entry.PN.low);
+ return 1;
+}
+
+#if 0
+int
+cd9660node_rrip_nm(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *file_node)
+{
+ int nm_length = strlen(file_node->isoDirRecord->name) + 5;
+ p->attr.rr_entry.NM.h.type[0] = 'N';
+ p->attr.rr_entry.NM.h.type[1] = 'M';
+ sprintf(p->attr.rr_entry.NM.altname, "%s", file_node->isoDirRecord->name);
+ p->attr.rr_entry.NM.h.length[0] = (unsigned char)nm_length;
+ p->attr.rr_entry.NM.h.version[0] = (unsigned char)1;
+ p->attr.rr_entry.NM.flags[0] = (unsigned char) NM_PARENT;
+ return 1;
+}
+#endif
+
+int
+cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *p, fsnode *_node)
+{
+ p->attr.rr_entry.TF.flags[0] = TF_MODIFY | TF_ACCESS | TF_ATTRIBUTES;
+ p->attr.rr_entry.TF.h.length[0] = 4;
+ p->attr.rr_entry.TF.h.version[0] = 1;
+
+ /*
+ * Need to add creation time, backup time,
+ * expiration time, and effective time.
+ */
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp,
+ _node->inode->st.st_atime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 7,
+ _node->inode->st.st_mtime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+
+ cd9660_time_915(p->attr.rr_entry.TF.timestamp + 14,
+ _node->inode->st.st_ctime);
+ p->attr.rr_entry.TF.h.length[0] += 7;
+ return 1;
+}
+
+int
+cd9660_susp_sp(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
+{
+ p->attr.su_entry.SP.h.length[0] = 7;
+ p->attr.su_entry.SP.h.version[0] = 1;
+ p->attr.su_entry.SP.check[0] = 0xBE;
+ p->attr.su_entry.SP.check[1] = 0xEF;
+ p->attr.su_entry.SP.len_skp[0] = 0;
+ return 1;
+}
+
+int
+cd9660_susp_st(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *stinfo __unused)
+{
+ p->attr.su_entry.ST.h.type[0] = 'S';
+ p->attr.su_entry.ST.h.type[1] = 'T';
+ p->attr.su_entry.ST.h.length[0] = 4;
+ p->attr.su_entry.ST.h.version[0] = 1;
+ return 1;
+}
+
+int
+cd9660_susp_ce(struct ISO_SUSP_ATTRIBUTES *p, cd9660node *spinfo __unused)
+{
+ p->attr.su_entry.CE.h.length[0] = 28;
+ p->attr.su_entry.CE.h.version[0] = 1;
+ /* Other attributes dont matter right now, will be updated later */
+ return 1;
+}
+
+int
+cd9660_susp_pd(struct ISO_SUSP_ATTRIBUTES *p __unused, int length __unused)
+{
+ return 1;
+}
+
+void
+cd9660_rrip_add_NM(cd9660node *node, const char *name)
+{
+ int working,len;
+ const char *p;
+ struct ISO_SUSP_ATTRIBUTES *r;
+
+ /*
+ * Each NM record has 254 byes to work with. This means that
+ * the name data itself only has 249 bytes to work with. So, a
+ * name with 251 characters would require two nm records.
+ */
+ p = name;
+ working = 1;
+ while (working) {
+ r = cd9660node_susp_create_node(SUSP_TYPE_RRIP,
+ SUSP_ENTRY_RRIP_NM, "NM", SUSP_LOC_ENTRY);
+ r->attr.rr_entry.NM.h.version[0] = 1;
+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_NONE;
+ len = strlen(p);
+
+ if (len > 249) {
+ len = 249;
+ r->attr.rr_entry.NM.flags[0] = RRIP_NM_FLAGS_CONTINUE;
+ } else {
+ working = 0;
+ }
+ memcpy(r->attr.rr_entry.NM.altname, p, len);
+ r->attr.rr_entry.NM.h.length[0] = 5 + len;
+
+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
+
+ p += len;
+ }
+}
+
+void
+cd9660_rrip_NM(cd9660node *node)
+{
+ cd9660_rrip_add_NM(node, node->node->name);
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660_susp_ER(cd9660node *node,
+ u_char ext_version, const char* ext_id, const char* ext_des,
+ const char* ext_src)
+{
+ int l;
+ struct ISO_SUSP_ATTRIBUTES *r;
+
+ r = cd9660node_susp_create_node(SUSP_TYPE_SUSP,
+ SUSP_ENTRY_SUSP_ER, "ER", SUSP_LOC_DOT);
+
+ /* Fixed data is 8 bytes */
+ r->attr.su_entry.ER.h.length[0] = 8;
+ r->attr.su_entry.ER.h.version[0] = 1;
+
+ r->attr.su_entry.ER.len_id[0] = (u_char)strlen(ext_id);
+ r->attr.su_entry.ER.len_des[0] = (u_char)strlen(ext_des);
+ r->attr.su_entry.ER.len_src[0] = (u_char)strlen(ext_src);
+
+ l = r->attr.su_entry.ER.len_id[0] +
+ r->attr.su_entry.ER.len_src[0] +
+ r->attr.su_entry.ER.len_des[0];
+
+ /* Everything must fit. */
+ assert(l + r->attr.su_entry.ER.h.length[0] <= 254);
+
+ r->attr.su_entry.ER.h.length[0] += (u_char)l;
+
+
+ r->attr.su_entry.ER.ext_ver[0] = ext_version;
+ memcpy(r->attr.su_entry.ER.ext_data, ext_id,
+ (int)r->attr.su_entry.ER.len_id[0]);
+ l = (int) r->attr.su_entry.ER.len_id[0];
+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_des,
+ (int)r->attr.su_entry.ER.len_des[0]);
+
+ l += (int)r->attr.su_entry.ER.len_des[0];
+ memcpy(r->attr.su_entry.ER.ext_data + l,ext_src,
+ (int)r->attr.su_entry.ER.len_src[0]);
+
+ TAILQ_INSERT_TAIL(&node->head, r, rr_ll);
+ return r;
+}
+
+struct ISO_SUSP_ATTRIBUTES*
+cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES *last __unused, cd9660node *node __unused)
+{
+ return NULL;
+}
diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.h b/usr.sbin/makefs/cd9660/iso9660_rrip.h
new file mode 100644
index 0000000..3653ac6
--- /dev/null
+++ b/usr.sbin/makefs/cd9660/iso9660_rrip.h
@@ -0,0 +1,290 @@
+/* $NetBSD: iso9660_rrip.h,v 1.5 2009/01/10 22:06:29 bjh21 Exp $ */
+
+/*
+ * Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
+ * Perez-Rathke and Ram Vedam. All rights reserved.
+ *
+ * This code was written by Daniel Watt, Walter Deignan, Ryan Gabrys,
+ * Alan Perez-Rathke and Ram Vedam.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL DANIEL WATT, WALTER DEIGNAN, RYAN
+ * GABRYS, ALAN PEREZ-RATHKE AND RAM VEDAM BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE,DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+#ifndef __ISO9660_RRIP_H__
+#define __ISO9660_RRIP_H__
+
+/*
+ * This will hold all the functions needed to
+ * write an ISO 9660 image with Rock Ridge Extensions
+ */
+
+/* For writing must use ISO_RRIP_EXTREF structure */
+
+#include "makefs.h"
+#include <cd9660_rrip.h>
+#include "cd9660.h"
+#include <sys/queue.h>
+
+#define PX_LENGTH 0x2C
+#define PN_LENGTH 0x14
+#define TF_CREATION 0x00
+#define TF_MODIFY 0x01
+#define TF_ACCESS 0x02
+#define TF_ATTRIBUTES 0x04
+#define TF_BACKUP 0x08
+#define TF_EXPIRATION 0x10
+#define TF_EFFECTIVE 0x20
+#define TF_LONGFORM 0x40
+#define NM_CONTINUE 0x80
+#define NM_CURRENT 0x100
+#define NM_PARENT 0x200
+
+
+#define SUSP_LOC_ENTRY 0x01
+#define SUSP_LOC_DOT 0x02
+#define SUSP_LOC_DOTDOT 0x04
+
+#define SUSP_TYPE_SUSP 1
+#define SUSP_TYPE_RRIP 2
+
+#define SUSP_ENTRY_SUSP_CE 1
+#define SUSP_ENTRY_SUSP_PD 2
+#define SUSP_ENTRY_SUSP_SP 3
+#define SUSP_ENTRY_SUSP_ST 4
+#define SUSP_ENTRY_SUSP_ER 5
+#define SUSP_ENTRY_SUSP_ES 6
+
+#define SUSP_ENTRY_RRIP_PX 1
+#define SUSP_ENTRY_RRIP_PN 2
+#define SUSP_ENTRY_RRIP_SL 3
+#define SUSP_ENTRY_RRIP_NM 4
+#define SUSP_ENTRY_RRIP_CL 5
+#define SUSP_ENTRY_RRIP_PL 6
+#define SUSP_ENTRY_RRIP_RE 7
+#define SUSP_ENTRY_RRIP_TF 8
+#define SUSP_ENTRY_RRIP_SF 9
+
+#define SUSP_RRIP_ER_EXT_ID "IEEE_P1282"
+#define SUSP_RRIP_ER_EXT_DES "THE IEEE P1282 PROTOCOL PROVIDES SUPPORT FOR POSIX FILE SYSTEM SEMANTICS."
+#define SUSP_RRIP_ER_EXT_SRC "PLEASE CONTACT THE IEEE STANDARDS DEPARTMENT, PISCATAWAY, NJ, USA FOR THE P1282 SPECIFICATION."
+
+#define SL_FLAGS_NONE 0
+#define SL_FLAGS_CONTINUE 1
+#define SL_FLAGS_CURRENT 2
+#define SL_FLAGS_PARENT 4
+#define SL_FLAGS_ROOT 8
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char mode [ISODCL(5,12)];
+ u_char links [ISODCL(13,20)];
+ u_char uid [ISODCL(21,28)];
+ u_char gid [ISODCL(29,36)];
+ u_char serial [ISODCL(37,44)];/* Not used */
+} ISO_RRIP_PX;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char high [ISODCL(5,12)];
+ u_char low [ISODCL(13,20)];
+} ISO_RRIP_PN;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char component [ISODCL ( 4, 256)];
+ u_int nBytes;
+} ISO_RRIP_SL;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char timestamp [ISODCL ( 5, 256)];
+} ISO_RRIP_TF;
+
+#define RRIP_NM_FLAGS_NONE 0x00
+#define RRIP_NM_FLAGS_CONTINUE 0x01
+#define RRIP_NM_FLAGS_CURRENT 0x02
+#define RRIP_NM_FLAGS_PARENT 0x04
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char flags [ISODCL ( 4, 4)];
+ u_char altname [ISODCL ( 4, 256)];
+} ISO_RRIP_NM;
+
+/* Note that this is the same structure as cd9660_rrip.h : ISO_RRIP_CONT */
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char ca_sector [ISODCL ( 5, 12)];
+ u_char offset [ISODCL ( 13, 20)];
+ u_char length [ISODCL ( 21, 28)];
+} ISO_SUSP_CE;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char padding_area [ISODCL ( 4, 256)];
+} ISO_SUSP_PD;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char check [ISODCL ( 4, 5)];
+ u_char len_skp [ISODCL ( 6, 6)];
+} ISO_SUSP_SP;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+} ISO_SUSP_ST;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char len_id [ISODCL ( 4, 4)];
+ u_char len_des [ISODCL ( 5, 5)];
+ u_char len_src [ISODCL ( 6, 6)];
+ u_char ext_ver [ISODCL ( 7, 7)];
+ u_char ext_data [ISODCL (8,256)];
+/* u_char ext_id [ISODCL ( 8, 256)];
+ u_char ext_des [ISODCL ( 257, 513)];
+ u_char ext_src [ISODCL ( 514, 770)];*/
+} ISO_SUSP_ER;
+
+typedef struct {
+ ISO_SUSP_HEADER h;
+ u_char ext_seq [ISODCL ( 4, 4)];
+} ISO_SUSP_ES;
+
+typedef union {
+ ISO_RRIP_PX PX;
+ ISO_RRIP_PN PN;
+ ISO_RRIP_SL SL;
+ ISO_RRIP_NM NM;
+ ISO_RRIP_CLINK CL;
+ ISO_RRIP_PLINK PL;
+ ISO_RRIP_RELDIR RE;
+ ISO_RRIP_TF TF;
+} rrip_entry;
+
+typedef union {
+ ISO_SUSP_CE CE;
+ ISO_SUSP_PD PD;
+ ISO_SUSP_SP SP;
+ ISO_SUSP_ST ST;
+ ISO_SUSP_ER ER;
+ ISO_SUSP_ES ES;
+} susp_entry;
+
+typedef union {
+ susp_entry su_entry;
+ rrip_entry rr_entry;
+} SUSP_ENTRIES;
+
+struct ISO_SUSP_ATTRIBUTES {
+ SUSP_ENTRIES attr;
+ int type;
+ char type_of[2];
+ char last_in_suf; /* last entry in the System Use Field? */
+ /* Dan's addons - will merge later. This allows use of a switch */
+ char susp_type; /* SUSP or RRIP */
+ char entry_type; /* Record type */
+ char write_location;
+ TAILQ_ENTRY(ISO_SUSP_ATTRIBUTES) rr_ll;
+};
+
+#define CD9660_SUSP_ENTRY_SIZE(entry)\
+ ((int) ((entry)->attr.su_entry.SP.h.length[0]))
+
+/* Recursive function - move later to func pointer code*/
+int cd9660_susp_finalize(cd9660node *);
+
+/* These two operate on single nodes */
+int cd9660_susp_finalize_node(cd9660node *);
+int cd9660_rrip_finalize_node(cd9660node *);
+
+/* POSIX File attribute */
+int cd9660node_rrip_px(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Device number */
+int cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Symbolic link */
+int cd9660node_rrip_SL(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+/* Alternate Name function */
+void cd9660_rrip_NM(cd9660node *);
+void cd9660_rrip_add_NM(cd9660node *,const char *);
+
+/* Parent and child link function */
+int cd9660_rrip_PL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_rrip_CL(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_rrip_RE(struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+
+int cd9660node_rrip_tf(struct ISO_SUSP_ATTRIBUTES *, fsnode *);
+
+
+
+/*
+ * Relocation directory function. I'm not quite sure what
+ * sort of parameters are needed, but personally I don't think
+ * any parameters are needed except for the memory address where
+ * the information needs to be put in
+ */
+int cd9660node_rrip_re(void *, fsnode *);
+
+/*
+ * Don't know if this function is needed because it apparently is an
+ * optional feature that does not really need to be implemented but I
+ * thought I should add it anyway.
+ */
+int cd9660_susp_ce (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_susp_pd (struct ISO_SUSP_ATTRIBUTES *, int);
+int cd9660_susp_sp (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+int cd9660_susp_st (struct ISO_SUSP_ATTRIBUTES *, cd9660node *);
+
+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ER(cd9660node *, u_char, const char *,
+ const char *, const char *);
+struct ISO_SUSP_ATTRIBUTES *cd9660_susp_ES(struct ISO_SUSP_ATTRIBUTES*,
+ cd9660node *);
+
+
+/* Helper functions */
+
+/* Common SUSP/RRIP functions */
+int cd9660_susp_initialize(cd9660node *, cd9660node *, cd9660node *);
+int cd9660_susp_initialize_node(cd9660node *);
+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_create_node(int, int, const char *,
+ int);
+struct ISO_SUSP_ATTRIBUTES *cd9660node_susp_add_entry(cd9660node *,
+ struct ISO_SUSP_ATTRIBUTES *, struct ISO_SUSP_ATTRIBUTES *, int);
+
+/* RRIP specific functions */
+int cd9660_rrip_initialize_node(cd9660node *, cd9660node *, cd9660node *);
+void cd9660_createSL(cd9660node *);
+
+/* Functions that probably can be removed */
+/* int cd9660node_initialize_node(int, char *); */
+
+
+#endif
diff --git a/usr.sbin/makefs/compat/Makefile.inc b/usr.sbin/makefs/compat/Makefile.inc
new file mode 100644
index 0000000..5fdffa1
--- /dev/null
+++ b/usr.sbin/makefs/compat/Makefile.inc
@@ -0,0 +1,8 @@
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/compat
+
+CFLAGS+= -I${.CURDIR}/compat
+
+SRCS+= pwcache.c strsuftoll.c
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index ece8c65..4f3fded 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ffs.c,v 1.30 2004/06/24 22:30:13 lukem Exp $ */
+/* $NetBSD: ffs.c,v 1.44 2009/04/28 22:49:26 joerg Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -76,17 +76,24 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "makefs.h"
+#include "ffs.h"
+
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
+#include <sys/statvfs.h>
+#endif
#include <ufs/ufs/dinode.h>
#include <ufs/ufs/dir.h>
#include <ufs/ffs/fs.h>
+
#include "ffs/ufs_bswap.h"
#include "ffs/ufs_inode.h"
#include "ffs/newfs_extern.h"
@@ -94,7 +101,7 @@ __FBSDID("$FreeBSD$");
#undef DIP
#define DIP(dp, field) \
- ((fsopts->version == 1) ? \
+ ((ffs_opts->version == 1) ? \
(dp)->ffs1_din.di_##field : (dp)->ffs2_din.di_##field)
/*
@@ -139,39 +146,71 @@ int sectorsize; /* XXX: for buf.c::getblk() */
/* publically visible functions */
+void
+ffs_prep_opts(fsinfo_t *fsopts)
+{
+ ffs_opt_t *ffs_opts;
+
+ if ((ffs_opts = calloc(1, sizeof(ffs_opt_t))) == NULL)
+ err(1, "Allocating memory for ffs_options");
+
+ fsopts->fs_specific = ffs_opts;
+
+ ffs_opts->bsize= -1;
+ ffs_opts->fsize= -1;
+ ffs_opts->cpg= -1;
+ ffs_opts->density= -1;
+ ffs_opts->minfree= -1;
+ ffs_opts->optimization= -1;
+ ffs_opts->maxcontig= -1;
+ ffs_opts->maxbpg= -1;
+ ffs_opts->avgfilesize= -1;
+ ffs_opts->avgfpdir= -1;
+ ffs_opts->version = 1;
+}
+
+void
+ffs_cleanup_opts(fsinfo_t *fsopts)
+{
+ if (fsopts->fs_specific)
+ free(fsopts->fs_specific);
+}
+
int
ffs_parse_opts(const char *option, fsinfo_t *fsopts)
{
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
+
option_t ffs_options[] = {
- { "bsize", &fsopts->bsize, 1, INT_MAX,
+ { "bsize", &ffs_opts->bsize, 1, INT_MAX,
"block size" },
- { "fsize", &fsopts->fsize, 1, INT_MAX,
+ { "fsize", &ffs_opts->fsize, 1, INT_MAX,
"fragment size" },
- { "density", &fsopts->density, 1, INT_MAX,
+ { "density", &ffs_opts->density, 1, INT_MAX,
"bytes per inode" },
- { "minfree", &fsopts->minfree, 0, 99,
+ { "minfree", &ffs_opts->minfree, 0, 99,
"minfree" },
- { "maxbpf", &fsopts->maxbpg, 1, INT_MAX,
+ { "maxbpf", &ffs_opts->maxbpg, 1, INT_MAX,
"max blocks per file in a cg" },
- { "avgfilesize", &fsopts->avgfilesize, 1, INT_MAX,
+ { "avgfilesize", &ffs_opts->avgfilesize,1, INT_MAX,
"expected average file size" },
- { "avgfpdir", &fsopts->avgfpdir, 1, INT_MAX,
+ { "avgfpdir", &ffs_opts->avgfpdir, 1, INT_MAX,
"expected # of files per directory" },
- { "extent", &fsopts->maxbsize, 1, INT_MAX,
+ { "extent", &ffs_opts->maxbsize, 1, INT_MAX,
"maximum # extent size" },
- { "maxbpcg", &fsopts->maxblkspercg, 1, INT_MAX,
+ { "maxbpcg", &ffs_opts->maxblkspercg,1, INT_MAX,
"max # of blocks per group" },
- { "version", &fsopts->version, 1, 2,
+ { "version", &ffs_opts->version, 1, 2,
"UFS version" },
- { NULL }
+ { .name = NULL }
};
char *var, *val;
int rv;
- (void)&ffs_options;
assert(option != NULL);
assert(fsopts != NULL);
+ assert(ffs_opts != NULL);
if (debug & DEBUG_FS_PARSE_OPTS)
printf("ffs_parse_opts: got `%s'\n", option);
@@ -188,9 +227,9 @@ ffs_parse_opts(const char *option, fsinfo_t *fsopts)
if (strcmp(var, "optimization") == 0) {
if (strcmp(val, "time") == 0) {
- fsopts->optimization = FS_OPTTIME;
+ ffs_opts->optimization = FS_OPTTIME;
} else if (strcmp(val, "space") == 0) {
- fsopts->optimization = FS_OPTSPACE;
+ ffs_opts->optimization = FS_OPTSPACE;
} else {
warnx("Invalid optimization `%s'", val);
goto leave_ffs_parse_opts;
@@ -277,11 +316,12 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
#if notyet
int32_t spc, nspf, ncyl, fssize;
#endif
- off_t size;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
+ assert(ffs_opts != NULL);
if (debug & DEBUG_FS_VALIDATE) {
printf("ffs_validate: before defaults set:\n");
@@ -291,31 +331,31 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
/* set FFS defaults */
if (fsopts->sectorsize == -1)
fsopts->sectorsize = DFL_SECSIZE;
- if (fsopts->fsize == -1)
- fsopts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
- if (fsopts->bsize == -1)
- fsopts->bsize = MIN(DFL_BLKSIZE, 8 * fsopts->fsize);
- if (fsopts->cpg == -1)
- fsopts->cpg = DFL_CYLSPERGROUP;
+ if (ffs_opts->fsize == -1)
+ ffs_opts->fsize = MAX(DFL_FRAGSIZE, fsopts->sectorsize);
+ if (ffs_opts->bsize == -1)
+ ffs_opts->bsize = MIN(DFL_BLKSIZE, 8 * ffs_opts->fsize);
+ if (ffs_opts->cpg == -1)
+ ffs_opts->cpg = DFL_CYLSPERGROUP;
else
- fsopts->cpgflg = 1;
+ ffs_opts->cpgflg = 1;
/* fsopts->density is set below */
- if (fsopts->nsectors == -1)
- fsopts->nsectors = DFL_NSECTORS;
- if (fsopts->minfree == -1)
- fsopts->minfree = MINFREE;
- if (fsopts->optimization == -1)
- fsopts->optimization = DEFAULTOPT;
- if (fsopts->maxcontig == -1)
- fsopts->maxcontig =
- MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / fsopts->bsize);
+ if (ffs_opts->nsectors == -1)
+ ffs_opts->nsectors = DFL_NSECTORS;
+ if (ffs_opts->minfree == -1)
+ ffs_opts->minfree = MINFREE;
+ if (ffs_opts->optimization == -1)
+ ffs_opts->optimization = DEFAULTOPT;
+ if (ffs_opts->maxcontig == -1)
+ ffs_opts->maxcontig =
+ MAX(1, MIN(MAXPHYS, FFS_MAXBSIZE) / ffs_opts->bsize);
/* XXX ondisk32 */
- if (fsopts->maxbpg == -1)
- fsopts->maxbpg = fsopts->bsize / sizeof(int32_t);
- if (fsopts->avgfilesize == -1)
- fsopts->avgfilesize = AVFILESIZ;
- if (fsopts->avgfpdir == -1)
- fsopts->avgfpdir = AFPDIR;
+ if (ffs_opts->maxbpg == -1)
+ ffs_opts->maxbpg = ffs_opts->bsize / sizeof(int32_t);
+ if (ffs_opts->avgfilesize == -1)
+ ffs_opts->avgfilesize = AVFILESIZ;
+ if (ffs_opts->avgfpdir == -1)
+ ffs_opts->avgfpdir = AFPDIR;
/* calculate size of tree */
ffs_size_dir(root, fsopts);
@@ -343,17 +383,19 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
*/
fsopts->size += (SBLOCK_UFS1 + SBLOCKSIZE) * ncg;
/* add space needed to store inodes, x3 for blockmaps, etc */
- if (fsopts->version == 1)
+ if (ffs_opts->version == 1)
fsopts->size += ncg * DINODE1_SIZE *
- roundup(fsopts->inodes / ncg, fsopts->bsize / DINODE1_SIZE);
+ roundup(fsopts->inodes / ncg,
+ ffs_opts->bsize / DINODE1_SIZE);
else
fsopts->size += ncg * DINODE2_SIZE *
- roundup(fsopts->inodes / ncg, fsopts->bsize / DINODE2_SIZE);
+ roundup(fsopts->inodes / ncg,
+ ffs_opts->bsize / DINODE2_SIZE);
/* add minfree */
- if (fsopts->minfree > 0)
+ if (ffs_opts->minfree > 0)
fsopts->size =
- fsopts->size * (100 + fsopts->minfree) / 100;
+ fsopts->size * (100 + ffs_opts->minfree) / 100;
/*
* XXX any other fs slop to add, such as csum's, bitmaps, etc ??
*/
@@ -362,24 +404,11 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
fsopts->size = fsopts->minsize;
/* round up to the next block */
- size = roundup(fsopts->size, fsopts->bsize);
-
- /* now check calculated sizes vs requested sizes */
- if (fsopts->maxsize > 0 && size > fsopts->maxsize) {
- if (debug & DEBUG_FS_VALIDATE) {
- printf("%s: `%s' size of %lld is larger than the "
- "maxsize of %lld; rounding down to %lld.",
- __func__, dir, (long long)size,
- (long long)fsopts->maxsize,
- (long long) rounddown(fsopts->size, fsopts->bsize));
- }
- size = rounddown(fsopts->size, fsopts->bsize);
- }
- fsopts->size = size;
+ fsopts->size = roundup(fsopts->size, ffs_opts->bsize);
/* calculate density if necessary */
- if (fsopts->density == -1)
- fsopts->density = fsopts->size / fsopts->inodes + 1;
+ if (ffs_opts->density == -1)
+ ffs_opts->density = fsopts->size / fsopts->inodes + 1;
if (debug & DEBUG_FS_VALIDATE) {
printf("ffs_validate: after defaults set:\n");
@@ -388,6 +417,12 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
dir, (long long)fsopts->size, (long long)fsopts->inodes);
}
sectorsize = fsopts->sectorsize; /* XXX - see earlier */
+
+ /* now check calculated sizes vs requested sizes */
+ if (fsopts->maxsize > 0 && fsopts->size > fsopts->maxsize) {
+ errx(1, "`%s' size of %lld is larger than the maxsize of %lld.",
+ dir, (long long)fsopts->size, (long long)fsopts->maxsize);
+ }
}
@@ -395,6 +430,8 @@ static void
ffs_dump_fsinfo(fsinfo_t *f)
{
+ ffs_opt_t *fs = f->fs_specific;
+
printf("fsopts at %p\n", f);
printf("\tsize %lld, inodes %lld, curinode %u\n",
@@ -409,20 +446,20 @@ ffs_dump_fsinfo(fsinfo_t *f)
printf("\tneedswap %d, sectorsize %d\n", f->needswap, f->sectorsize);
printf("\tbsize %d, fsize %d, cpg %d, density %d\n",
- f->bsize, f->fsize, f->cpg, f->density);
+ fs->bsize, fs->fsize, fs->cpg, fs->density);
printf("\tnsectors %d, rpm %d, minfree %d\n",
- f->nsectors, f->rpm, f->minfree);
+ fs->nsectors, fs->rpm, fs->minfree);
printf("\tmaxcontig %d, maxbpg %d\n",
- f->maxcontig, f->maxbpg);
+ fs->maxcontig, fs->maxbpg);
printf("\toptimization %s\n",
- f->optimization == FS_OPTSPACE ? "space" : "time");
+ fs->optimization == FS_OPTSPACE ? "space" : "time");
}
static int
ffs_create_image(const char *image, fsinfo_t *fsopts)
{
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
struct statvfs sfs;
#endif
struct fs *fs;
@@ -434,18 +471,18 @@ ffs_create_image(const char *image, fsinfo_t *fsopts)
assert (fsopts != NULL);
/* create image */
- if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0777))
+ if ((fsopts->fd = open(image, O_RDWR | O_CREAT | O_TRUNC, 0666))
== -1) {
warn("Can't open `%s' for writing", image);
return (-1);
}
/* zero image */
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
if (fstatvfs(fsopts->fd, &sfs) == -1) {
#endif
bufsize = 8192;
-#if HAVE_STRUCT_STATVFS_F_IOSIZE
+#if HAVE_STRUCT_STATVFS_F_IOSIZE && HAVE_FSTATVFS
warn("can't fstatvfs `%s', using default %d byte chunk",
image, bufsize);
} else
@@ -465,10 +502,12 @@ ffs_create_image(const char *image, fsinfo_t *fsopts)
if (i == -1) {
warn("zeroing image, %lld bytes to go",
(long long)bufrem);
+ free(buf);
return (-1);
}
bufrem -= i;
}
+ free(buf);
/* make the file system */
if (debug & DEBUG_FS_CREATE_IMAGE)
@@ -492,7 +531,7 @@ ffs_create_image(const char *image, fsinfo_t *fsopts)
warnx(
"Image file `%s' has %lld free inodes; %lld are required.",
image,
- (long long)fs->fs_cstotal.cs_nifree + ROOTINO,
+ (long long)(fs->fs_cstotal.cs_nifree + ROOTINO),
(long long)fsopts->inodes);
return (-1);
}
@@ -506,9 +545,11 @@ ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
struct direct tmpdir;
fsnode * node;
int curdirsize, this;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
/* node may be NULL (empty directory) */
assert(fsopts != NULL);
+ assert(ffs_opts != NULL);
if (debug & DEBUG_FS_SIZE_DIR)
printf("ffs_size_dir: entry: bytes %lld inodes %lld\n",
@@ -516,7 +557,7 @@ ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
#define ADDDIRENT(e) do { \
tmpdir.d_namlen = strlen((e)); \
- this = DIRSIZ_SWAP(0, &tmpdir, 0); \
+ this = DIRSIZ_SWAP(0, &tmpdir, 0); \
if (debug & DEBUG_FS_SIZE_DIR_ADD_DIRENT) \
printf("ADDDIRENT: was: %s (%d) this %d cur %d\n", \
e, tmpdir.d_namlen, this, curdirsize); \
@@ -533,14 +574,12 @@ ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
* by indirect blocks, etc.
*/
#define ADDSIZE(x) do { \
- fsopts->size += roundup((x), fsopts->fsize); \
+ fsopts->size += roundup((x), ffs_opts->fsize); \
} while (0);
curdirsize = 0;
for (node = root; node != NULL; node = node->next) {
ADDDIRENT(node->name);
- if (FSNODE_EXCLUDE_P(fsopts, node))
- continue;
if (node == root) { /* we're at "." */
assert(strcmp(node->name, ".") == 0);
ADDDIRENT("..");
@@ -558,7 +597,7 @@ ffs_size_dir(fsnode *root, fsinfo_t *fsopts)
int slen;
slen = strlen(node->symlink) + 1;
- if (slen >= (fsopts->version == 1 ?
+ if (slen >= (ffs_opts->version == 1 ?
MAXSYMLINKLEN_UFS1 :
MAXSYMLINKLEN_UFS2))
ADDSIZE(slen);
@@ -682,10 +721,12 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
union dinode din;
void *membuf;
char path[MAXPATHLEN + 1];
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
assert(dir != NULL);
assert(root != NULL);
assert(fsopts != NULL);
+ assert(ffs_opts != NULL);
(void)memset(&dirbuf, 0, sizeof(dirbuf));
@@ -696,8 +737,6 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
* pass 1: allocate inode numbers, build directory `file'
*/
for (cur = root; cur != NULL; cur = cur->next) {
- if (FSNODE_EXCLUDE_P(fsopts, cur))
- continue;
if ((cur->inode->flags & FI_ALLOCATED) == 0) {
cur->inode->flags |= FI_ALLOCATED;
if (cur == root && cur->parent != NULL)
@@ -732,8 +771,6 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: PASS 2 dir %s\n", dir);
for (cur = root; cur != NULL; cur = cur->next) {
- if (FSNODE_EXCLUDE_P(fsopts, cur))
- continue;
if (cur->inode->flags & FI_WRITTEN)
continue; /* skip hard-linked entries */
cur->inode->flags |= FI_WRITTEN;
@@ -746,7 +783,7 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
continue; /* child creates own inode */
/* build on-disk inode */
- if (fsopts->version == 1)
+ if (ffs_opts->version == 1)
membuf = ffs_build_dinode1(&din.ffs1_din, &dirbuf, cur,
root, fsopts);
else
@@ -777,8 +814,6 @@ ffs_populate_dir(const char *dir, fsnode *root, fsinfo_t *fsopts)
if (debug & DEBUG_FS_POPULATE)
printf("ffs_populate_dir: PASS 3 dir %s\n", dir);
for (cur = root; cur != NULL; cur = cur->next) {
- if (FSNODE_EXCLUDE_P(fsopts, cur))
- continue;
if (cur->child == NULL)
continue;
if (snprintf(path, sizeof(path), "%s/%s", dir, cur->name)
@@ -804,16 +839,20 @@ ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
int isfile, ffd;
char *fbuf, *p;
off_t bufleft, chunk, offset;
+ ssize_t nread;
struct inode in;
struct buf * bp;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
assert (din != NULL);
assert (buf != NULL);
assert (fsopts != NULL);
+ assert (ffs_opts != NULL);
isfile = S_ISREG(DIP(din, mode));
fbuf = NULL;
ffd = -1;
+ p = NULL;
in.i_fs = (struct fs *)fsopts->superblock;
@@ -830,7 +869,7 @@ ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
in.i_number = ino;
in.i_size = DIP(din, size);
- if (fsopts->version == 1)
+ if (ffs_opts->version == 1)
memcpy(&in.i_din.ffs1_din, &din->ffs1_din,
sizeof(in.i_din.ffs1_din));
else
@@ -842,7 +881,7 @@ ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
goto write_inode_and_leave; /* mmm, cheating */
if (isfile) {
- if ((fbuf = malloc(fsopts->bsize)) == NULL)
+ if ((fbuf = malloc(ffs_opts->bsize)) == NULL)
err(1, "Allocating memory for write buffer");
if ((ffd = open((char *)buf, O_RDONLY, 0444)) == -1) {
warn("Can't open `%s' for reading", (char *)buf);
@@ -854,13 +893,20 @@ ffs_write_file(union dinode *din, uint32_t ino, void *buf, fsinfo_t *fsopts)
chunk = 0;
for (bufleft = DIP(din, size); bufleft > 0; bufleft -= chunk) {
- chunk = MIN(bufleft, fsopts->bsize);
- if (isfile) {
- if (read(ffd, fbuf, chunk) != chunk)
- err(1, "Reading `%s', %lld bytes to go",
- (char *)buf, (long long)bufleft);
+ chunk = MIN(bufleft, ffs_opts->bsize);
+ if (!isfile)
+ ;
+ else if ((nread = read(ffd, fbuf, chunk)) == -1)
+ err(EXIT_FAILURE, "Reading `%s', %lld bytes to go",
+ (char *)buf, (long long)bufleft);
+ else if (nread != chunk)
+ errx(EXIT_FAILURE, "Reading `%s', %lld bytes to go, "
+ "read %zd bytes, expected %ju bytes, does "
+ "metalog size= attribute mismatch source size?",
+ (char *)buf, (long long)bufleft, nread,
+ (uintmax_t)chunk);
+ else
p = fbuf;
- }
offset = DIP(din, size) - bufleft;
if (debug & DEBUG_FS_WRITE_FILE_BLOCK)
printf(
@@ -932,7 +978,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
{
struct direct de, *dp;
uint16_t llen, reclen;
- char *newbuf;
+ u_char *newbuf;
assert (dbuf != NULL);
assert (name != NULL);
@@ -969,7 +1015,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
dbuf->size += DIRBLKSIZ;
memset(dbuf->buf + dbuf->size - DIRBLKSIZ, 0, DIRBLKSIZ);
dbuf->cur = dbuf->size - DIRBLKSIZ;
- } else { /* shrink end of previous */
+ } else if (dp) { /* shrink end of previous */
dp->d_reclen = ufs_rw16(llen,needswap);
dbuf->cur += llen;
}
@@ -993,10 +1039,12 @@ ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
daddr_t d;
char sbbuf[FFS_MAXBSIZE];
int32_t initediblk;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
assert (dp != NULL);
assert (ino > 0);
assert (fsopts != NULL);
+ assert (ffs_opts != NULL);
fs = (struct fs *)fsopts->superblock;
cg = ino_to_cg(fs, ino);
@@ -1041,7 +1089,7 @@ ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
* Initialize inode blocks on the fly for UFS2.
*/
initediblk = ufs_rw32(cgp->cg_initediblk, fsopts->needswap);
- if (fsopts->version == 2 && cgino + INOPB(fs) > initediblk &&
+ if (ffs_opts->version == 2 && cgino + INOPB(fs) > initediblk &&
initediblk < ufs_rw32(cgp->cg_niblk, fsopts->needswap)) {
memset(buf, 0, fs->fs_bsize);
dip = (struct ufs2_dinode *)buf;
@@ -1065,14 +1113,14 @@ ffs_write_inode(union dinode *dp, uint32_t ino, const fsinfo_t *fsopts)
d = fsbtodb(fs, ino_to_fsba(fs, ino));
ffs_rdfs(d, fs->fs_bsize, buf, fsopts);
if (fsopts->needswap) {
- if (fsopts->version == 1)
+ if (ffs_opts->version == 1)
ffs_dinode1_swap(&dp->ffs1_din,
&dp1[ino_to_fsbo(fs, ino)]);
else
ffs_dinode2_swap(&dp->ffs2_din,
&dp2[ino_to_fsbo(fs, ino)]);
} else {
- if (fsopts->version == 1)
+ if (ffs_opts->version == 1)
dp1[ino_to_fsbo(fs, ino)] = dp->ffs1_din;
else
dp2[ino_to_fsbo(fs, ino)] = dp->ffs2_din;
diff --git a/usr.sbin/makefs/ffs.h b/usr.sbin/makefs/ffs.h
new file mode 100644
index 0000000..42611a4
--- /dev/null
+++ b/usr.sbin/makefs/ffs.h
@@ -0,0 +1,66 @@
+/* $NetBSD: ffs.h,v 1.1 2004/12/20 20:51:42 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001-2003 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Luke Mewburn for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FFS_H
+#define _FFS_H
+
+typedef struct {
+ int bsize; /* block size */
+ int fsize; /* fragment size */
+ int cpg; /* cylinders per group */
+ int cpgflg; /* cpg was specified by user */
+ int density; /* bytes per inode */
+ int ntracks; /* number of tracks */
+ int nsectors; /* number of sectors */
+ int rpm; /* rpm */
+ int minfree; /* free space threshold */
+ int optimization; /* optimization (space or time) */
+ int maxcontig; /* max contiguous blocks to allocate */
+ int rotdelay; /* rotational delay between blocks */
+ int maxbpg; /* maximum blocks per file in a cyl group */
+ int nrpos; /* # of distinguished rotational positions */
+ int avgfilesize; /* expected average file size */
+ int avgfpdir; /* expected # of files per directory */
+ int version; /* filesystem version (1 = FFS, 2 = UFS2) */
+ int maxbsize; /* maximum extent size */
+ int maxblkspercg; /* max # of blocks per cylinder group */
+ /* XXX: support `old' file systems ? */
+} ffs_opt_t;
+
+#endif /* _FFS_H */
diff --git a/usr.sbin/makefs/ffs/Makefile.inc b/usr.sbin/makefs/ffs/Makefile.inc
new file mode 100644
index 0000000..d681c4e
--- /dev/null
+++ b/usr.sbin/makefs/ffs/Makefile.inc
@@ -0,0 +1,9 @@
+# $FreeBSD$
+#
+
+.PATH: ${.CURDIR}/ffs ${.CURDIR}/../../sys/ufs/ffs
+
+CFLAGS+= -I${.CURDIR}/../../sys/ufs/ffs
+
+SRCS+= ffs_alloc.c ffs_balloc.c ffs_bswap.c ffs_subr.c ufs_bmap.c
+SRCS+= buf.c mkfs.c
diff --git a/usr.sbin/makefs/ffs/buf.c b/usr.sbin/makefs/ffs/buf.c
index 08fb627..06538f5 100644
--- a/usr.sbin/makefs/ffs/buf.c
+++ b/usr.sbin/makefs/ffs/buf.c
@@ -118,7 +118,7 @@ brelse(struct buf *bp)
bp->b_bcount = 0;
return;
}
-
+
TAILQ_REMOVE(&buftail, bp, b_tailq);
free(bp->b_data);
free(bp);
@@ -160,7 +160,7 @@ bcleanup(void)
* know why there's still some buffers lying around that
* aren't brelse()d
*/
-
+
if (TAILQ_EMPTY(&buftail))
return;
@@ -201,7 +201,7 @@ getblk(int fd, struct fs *fs, daddr_t blkno, int size)
if (bp == NULL) {
if ((bp = calloc(1, sizeof(struct buf))) == NULL)
err(1, "getblk: calloc");
-
+
bp->b_bufsize = 0;
bp->b_blkno = bp->b_lblkno = blkno;
bp->b_fd = fd;
diff --git a/usr.sbin/makefs/ffs/ffs_alloc.c b/usr.sbin/makefs/ffs/ffs_alloc.c
index 0fe65e6..f676a39 100644
--- a/usr.sbin/makefs/ffs/ffs_alloc.c
+++ b/usr.sbin/makefs/ffs/ffs_alloc.c
@@ -87,7 +87,7 @@ static int32_t ffs_mapsearch(struct fs *, struct cg *, daddr_t, int);
* available block is located.
*/
int
-ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
+ffs_alloc(struct inode *ip, daddr_t lbn __unused, daddr_t bpref, int size,
daddr_t *bnp)
{
struct fs *fs = ip->i_fs;
@@ -95,7 +95,7 @@ ffs_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
int cg;
*bnp = 0;
- if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) {
+ if (size > fs->fs_bsize || fragoff(fs, size) != 0) {
errx(1, "ffs_alloc: bad size: bsize %d size %d",
fs->fs_bsize, size);
}
@@ -187,11 +187,7 @@ ffs_blkpref_ufs1(struct inode *ip, daddr_t lbn, int indx, int32_t *bap)
}
daddr_t
-ffs_blkpref_ufs2(ip, lbn, indx, bap)
- struct inode *ip;
- daddr_t lbn;
- int indx;
- int64_t *bap;
+ffs_blkpref_ufs2(struct inode *ip, daddr_t lbn, int indx, int64_t *bap)
{
struct fs *fs;
int cg;
@@ -385,11 +381,11 @@ ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
int32_t bno;
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
- u_int8_t *blksfree;
+ u_int8_t *blksfree_swap;
cgp = (struct cg *)bp->b_data;
- blksfree = cg_blksfree_swap(cgp, needswap);
- if (bpref == 0 || dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
+ blksfree_swap = cg_blksfree_swap(cgp, needswap);
+ if (bpref == 0 || (uint32_t)dtog(fs, bpref) != ufs_rw32(cgp->cg_cgx, needswap)) {
bpref = ufs_rw32(cgp->cg_rotor, needswap);
} else {
bpref = blknum(fs, bpref);
@@ -397,7 +393,7 @@ ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
/*
* if the requested block is available, use it
*/
- if (ffs_isblock(fs, blksfree, fragstoblks(fs, bno)))
+ if (ffs_isblock(fs, blksfree_swap, fragstoblks(fs, bno)))
goto gotit;
}
/*
@@ -409,7 +405,7 @@ ffs_alloccgblk(struct inode *ip, struct buf *bp, daddr_t bpref)
cgp->cg_rotor = ufs_rw32(bno, needswap);
gotit:
blkno = fragstoblks(fs, bno);
- ffs_clrblock(fs, blksfree, (long)blkno);
+ ffs_clrblock(fs, blksfree_swap, (long)blkno);
ffs_clusteracct(fs, cgp, blkno, -1);
ufs_add32(cgp->cg_cs.cs_nbfree, -1, needswap);
fs->fs_cstotal.cs_nbfree--;
@@ -436,14 +432,15 @@ ffs_blkfree(struct inode *ip, daddr_t bno, long size)
struct fs *fs = ip->i_fs;
const int needswap = UFS_FSNEEDSWAP(fs);
- if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0 ||
+ if (size > fs->fs_bsize || fragoff(fs, size) != 0 ||
fragnum(fs, bno) + numfrags(fs, size) > fs->fs_frag) {
errx(1, "blkfree: bad size: bno %lld bsize %d size %ld",
(long long)bno, fs->fs_bsize, size);
}
cg = dtog(fs, bno);
if (bno >= fs->fs_size) {
- warnx("bad block %lld, ino %d", (long long)bno, ip->i_number);
+ warnx("bad block %lld, ino %llu", (long long)bno,
+ (unsigned long long)ip->i_number);
return;
}
error = bread(ip->i_fd, ip->i_fs, fsbtodb(fs, cgtod(fs, cg)),
@@ -622,7 +619,7 @@ ffs_clusteracct(struct fs *fs, struct cg *cgp, int32_t blkno, int cnt)
*/
start = blkno + 1;
end = start + fs->fs_contigsumsize;
- if (end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
+ if ((unsigned)end >= ufs_rw32(cgp->cg_nclusterblks, needswap))
end = ufs_rw32(cgp->cg_nclusterblks, needswap);
mapp = &freemapp[start / NBBY];
map = *mapp++;
diff --git a/usr.sbin/makefs/ffs/mkfs.c b/usr.sbin/makefs/ffs/mkfs.c
index ce9ec59..924ab6c 100644
--- a/usr.sbin/makefs/ffs/mkfs.c
+++ b/usr.sbin/makefs/ffs/mkfs.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include "makefs.h"
+#include "ffs.h"
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
@@ -61,6 +62,10 @@ __FBSDID("$FreeBSD$");
#include "ffs/ffs_extern.h"
#include "ffs/newfs_extern.h"
+#ifndef BBSIZE
+#define BBSIZE 8192 /* size of boot area, with label */
+#endif
+
static void initcg(int, time_t, const fsinfo_t *);
static int ilog2(int);
@@ -102,6 +107,7 @@ static int opt; /* optimization preference (space or time) */
static int density; /* number of bytes per inode */
static int maxcontig; /* max contiguous blocks to allocate */
static int maxbpg; /* maximum blocks per file in a cyl group */
+static int bbsize; /* boot block size */
static int sbsize; /* superblock size */
static int avgfilesize; /* expected average file size */
static int avgfpdir; /* expected number of files per directory */
@@ -115,21 +121,23 @@ ffs_mkfs(const char *fsys, const fsinfo_t *fsopts)
void *space;
int size, blks;
int nprintcols, printcolwidth;
+ ffs_opt_t *ffs_opts = fsopts->fs_specific;
- Oflag = fsopts->version;
+ Oflag = ffs_opts->version;
fssize = fsopts->size / fsopts->sectorsize;
sectorsize = fsopts->sectorsize;
- fsize = fsopts->fsize;
- bsize = fsopts->bsize;
- maxbsize = fsopts->maxbsize;
- maxblkspercg = fsopts->maxblkspercg;
- minfree = fsopts->minfree;
- opt = fsopts->optimization;
- density = fsopts->density;
- maxcontig = fsopts->maxcontig;
- maxbpg = fsopts->maxbpg;
- avgfilesize = fsopts->avgfilesize;
- avgfpdir = fsopts->avgfpdir;
+ fsize = ffs_opts->fsize;
+ bsize = ffs_opts->bsize;
+ maxbsize = ffs_opts->maxbsize;
+ maxblkspercg = ffs_opts->maxblkspercg;
+ minfree = ffs_opts->minfree;
+ opt = ffs_opts->optimization;
+ density = ffs_opts->density;
+ maxcontig = ffs_opts->maxcontig;
+ maxbpg = ffs_opts->maxbpg;
+ avgfilesize = ffs_opts->avgfilesize;
+ avgfpdir = ffs_opts->avgfpdir;
+ bbsize = BBSIZE;
sbsize = SBLOCKSIZE;
if (Oflag == 0) {
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index e0924d5..974477c 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -1,4 +1,4 @@
-.\" $NetBSD: makefs.8,v 1.13 2004/02/13 17:56:18 wiz Exp $
+.\" $NetBSD: makefs.8,v 1.32 2009/01/20 20:47:25 bjh21 Exp $
.\"
.\" Copyright (c) 2001-2003 Wasabi Systems, Inc.
.\" All rights reserved.
@@ -35,7 +35,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 30, 2003
+.Dd January 10, 2009
.Dt MAKEFS 8
.Os
.Sh NAME
@@ -43,43 +43,19 @@
.Nd create a file system image from a directory tree
.Sh SYNOPSIS
.Nm
-.Bk -words
-.Op Fl t Ar fs-type
-.Ek
-.Bk -words
-.Op Fl o Ar fs-options
-.Ek
-.Bk -words
-.Op Fl d Ar debug-mask
-.Ek
-.Bk -words
+.Op Fl x
.Op Fl B Ar byte-order
-.Ek
-.Bk -words
-.Op Fl S Ar sector-size
-.Ek
-.Bk -words
-.Op Fl M Ar minimum-size
-.Ek
-.Bk -words
-.Op Fl m Ar maximum-size
-.Ek
-.Bk -words
-.Op Fl s Ar image-size
-.Ek
-.Bk -words
.Op Fl b Ar free-blocks
-.Ek
-.Bk -words
-.Op Fl f Ar free-files
-.Ek
-.Bk -words
+.Op Fl d Ar debug-mask
.Op Fl F Ar specfile
-.Ek
-.Op Fl x
-.Bk -words
+.Op Fl f Ar free-files
+.Op Fl M Ar minimum-size
+.Op Fl m Ar maximum-size
.Op Fl N Ar userdb-dir
-.Ek
+.Op Fl o Ar fs-options
+.Op Fl S Ar sector-size
+.Op Fl s Ar image-size
+.Op Fl t Ar fs-type
.Ar image-file
.Ar directory
.Sh DESCRIPTION
@@ -93,56 +69,22 @@ No special devices or privileges are required to perform this task.
.Pp
The options are as follows:
.Bl -tag -width flag
-.It Fl t Ar fs-type
-Create an
-.Ar fs-type
-file system image.
-The following file system types are supported:
-.Bl -tag -width ffs -offset indent
-.It Sy ffs
-BSD fast file system (default).
-.El
-.It Fl o Ar fs-options
-Set file system specific options.
-.Ar fs-options
-is a comma separated list of options.
-Valid file system specific options are detailed below.
-.It Fl d Ar debug-mask
-Enable various levels of debugging, depending upon which bits are set
-in
-.Ar debug-mask .
-XXX: document these
.It Fl B Ar byte-order
Set the byte order of the image to
.Ar byte-order .
Valid byte orders are
.Ql 4321 ,
-.Ql big
+.Ql big ,
or
.Ql be
for big endian, and
.Ql 1234 ,
-.Ql little
+.Ql little ,
or
.Ql le
for little endian.
Some file systems may have a fixed byte order; in those cases this
argument will be ignored.
-.It Fl S Ar sector-size
-Set the file system sector size to
-.Ar sector-size .
-Defaults to 512.
-.It Fl M Ar minimum-size
-Set the minimum size of the file system image to
-.Ar minimum-size .
-.It Fl m Ar maximum-size
-Set the maximum size of the file system image to
-.Ar maximum-size .
-An error will be raised if the target file system needs to be larger
-than this to accommodate the provided directory tree.
-.It Fl s Ar image-size
-Set the size of the file system image to
-.Ar image-size .
.It Fl b Ar free-blocks
Ensure that a minimum of
.Ar free-blocks
@@ -151,16 +93,12 @@ An optional
.Ql %
suffix may be provided to indicate that
.Ar free-blocks
-indicates a percentage of the calculated image size
-.It Fl f Ar free-files
-Ensure that a minimum of
-.Ar free-files
-free files (inodes) exist in the image.
-An optional
-.Ql %
-suffix may be provided to indicate that
-.Ar free-files
-indicates a percentage of the calculated image size
+indicates a percentage of the calculated image size.
+.It Fl d Ar debug-mask
+Enable various levels of debugging, depending upon which bits are
+set in
+.Ar debug-mask .
+XXX: document these
.It Fl F Ar specfile
Use
.Ar specfile
@@ -169,23 +107,23 @@ as an
.Sq specfile
specification.
.Pp
-If a specfile entry exists in the underlying file system, its permissions and
-modification time will be used unless specifically overridden by the specfile.
-An error will be raised if the type of entry in the specfile conflicts
-with that of an existing entry.
+If a specfile entry exists in the underlying file system, its
+permissions and modification time will be used unless specifically
+overridden by the specfile.
+An error will be raised if the type of entry in the specfile
+conflicts with that of an existing entry.
.Pp
-In the opposite case
-(where a specfile entry does not have an entry in the underlying file system)
-the following occurs:
+In the opposite case (where a specfile entry does not have an entry
+in the underlying file system) the following occurs:
If the specfile entry is marked
.Sy optional ,
the specfile entry is ignored.
-Otherwise, the entry will be created in the image,
-and it is necessary to specify at least the following parameters
-in the specfile:
+Otherwise, the entry will be created in the image, and it is
+necessary to specify at least the following parameters in the
+specfile:
.Sy type ,
.Sy mode ,
-.Sy gname
+.Sy gname ,
or
.Sy gid ,
and
@@ -203,8 +141,23 @@ If
.Sy flags
isn't provided, the current file flags will be used.
Missing regular file entries will be created as zero-length files.
-.It Fl x
-Exclude file system nodes not explicitly listed in the specfile.
+.It Fl f Ar free-files
+Ensure that a minimum of
+.Ar free-files
+free files (inodes) exist in the image.
+An optional
+.Ql %
+suffix may be provided to indicate that
+.Ar free-files
+indicates a percentage of the calculated image size.
+.It Fl M Ar minimum-size
+Set the minimum size of the file system image to
+.Ar minimum-size .
+.It Fl m Ar maximum-size
+Set the maximum size of the file system image to
+.Ar maximum-size .
+An error will be raised if the target file system needs to be larger
+than this to accommodate the provided directory tree.
.It Fl N Ar dbdir
Use the user database text file
.Pa master.passwd
@@ -217,6 +170,32 @@ rather than using the results from the system's
and
.Xr getgrnam 3
(and related) library calls.
+.It Fl o Ar fs-options
+Set file system specific options.
+.Ar fs-options
+is a comma separated list of options.
+Valid file system specific options are detailed below.
+.It Fl S Ar sector-size
+Set the file system sector size to
+.Ar sector-size .
+.\" XXX: next line also true for cd9660?
+Defaults to 512.
+.It Fl s Ar image-size
+Set the size of the file system image to
+.Ar image-size .
+.It Fl t Ar fs-type
+Create an
+.Ar fs-type
+file system image.
+The following file system types are supported:
+.Bl -tag -width cd9660 -offset indent
+.It Sy ffs
+BSD fast file system (default).
+.It Sy cd9660
+ISO 9660 file system.
+.El
+.It Fl x
+Exclude file system nodes not explicitly listed in the specfile.
.El
.Pp
Where sizes are specified, a decimal number of bytes is expected.
@@ -228,13 +207,13 @@ Each number may have one of the following optional suffixes:
.It b
Block; multiply by 512
.It k
-Kilo; multiply by 1024 (1 KB)
+Kibi; multiply by 1024 (1 KiB)
.It m
-Mega; multiply by 1048576 (1 MB)
+Mebi; multiply by 1048576 (1 MiB)
.It g
-Giga; multiply by 1073741824 (1 GB)
+Gibi; multiply by 1073741824 (1 GiB)
.It t
-Tera; multiply by 1099511627776 (1 TB)
+Tebi; multiply by 1099511627776 (1 TiB)
.It w
Word; multiply by the number of bytes in an integer
.El
@@ -243,37 +222,109 @@ Word; multiply by the number of bytes in an integer
.Ss FFS-specific options
.Sy ffs
images have ffs-specific optional parameters that may be provided.
-Each of the options consists of a keyword, an equals sign
+Each of the options consists of a keyword, an equal sign
.Pq Ql = ,
and a value.
The following keywords are supported:
.Pp
.Bl -tag -width optimization -offset indent -compact
.It Sy avgfilesize
-Expected average file size
+Expected average file size.
.It Sy avgfpdir
-Expected number of files per directory
+Expected number of files per directory.
.It Sy bsize
-Block size
+Block size.
.It Sy density
-Bytes per inode
+Bytes per inode.
.It Sy fsize
-Fragment size
+Fragment size.
.It Sy maxbpg
-Maximum blocks per file in a cylinder group
+Maximum blocks per file in a cylinder group.
.It Sy minfree
-Minimum % free
+Minimum % free.
.It Sy optimization
Optimization preference; one of
.Ql space
or
.Ql time .
.It Sy extent
-Maximum extent size
+Maximum extent size.
.It Sy maxbpcg
-Maximum total number of blocks in a cylinder group
+Maximum total number of blocks in a cylinder group.
.It Sy version
-UFS version. 1 for FFS (default), 2 for UFS2
+UFS version.
+1 for FFS (default), 2 for UFS2.
+.El
+.Ss CD9660-specific options
+.Sy cd9660
+images have ISO9660-specific optional parameters that may be
+provided.
+The arguments consist of a keyword and, optionally, an equal sign
+.Pq Ql = ,
+and a value.
+The following keywords are supported:
+.Pp
+.Bl -tag -width omit-trailing-period -offset indent -compact
+.It Sy allow-deep-trees
+Allow the directory structure to exceed the maximum specified in
+the spec.
+.\" .It Sy allow-illegal-chars
+.\" Unknown
+.\" .It Sy allow-lowercase
+.\" Unknown
+.It Sy allow-max-name
+Allow 37 instead of 33 characters for filenames by omitting the
+version id.
+.It Sy allow-multidot
+Allow multiple dots in a filename.
+.It Sy applicationid
+Application ID of the image.
+.It Sy archimedes
+Use the
+.Ql ARCHIMEDES
+extension to encode
+.Tn RISC OS
+metadata.
+.It Sy boot-load-segment
+Set load segment for the boot image.
+.It Sy bootimage
+Filename of a boot image in the format
+.Dq sysid;filename ,
+where
+.Dq sysid
+is one of
+.Ql i386 ,
+.Ql mac68k ,
+.Ql macppc ,
+or
+.Ql powerpc .
+.It Sy generic-bootimage
+Load a generic boot image into the first 32K of the cd9660 image.
+.It Sy hard-disk-boot
+Boot image is a hard disk image.
+.It Sy keep-bad-images
+Don't throw away images whose write was aborted due to an error.
+For debugging purposes.
+.It Sy label
+Label name of the image.
+.It Sy no-boot
+Boot image is not bootable.
+.It Sy no-emul-boot
+Boot image is a
+.Dq no emulation
+ElTorito image.
+.It Sy no-trailing-padding
+Do not pad the image (apparently Linux needs the padding).
+.\" .It Sy omit-trailing-period
+.\" Unknown
+.It Sy preparer
+Preparer ID of the image.
+.It Sy publisher
+Publisher ID of the image.
+.It Sy rockridge
+Use RockRidge extensions (for longer filenames, etc.).
+.It Sy volumeid
+Volume set identifier of the image.
.El
.Sh SEE ALSO
.Xr mtree 8 ,
@@ -285,4 +336,11 @@ utility appeared in
.Nx 1.6 .
.Sh AUTHORS
.An Luke Mewburn
-.Aq lukem@NetBSD.org .
+.Aq lukem@NetBSD.org
+(original program)
+.An Daniel Watt ,
+.An Walter Deignan ,
+.An Ryan Gabrys ,
+.An Alan Perez-Rathke ,
+.An Ram Vedam
+(cd9660 support)
diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c
index c3e4bd2..f2420b6 100644
--- a/usr.sbin/makefs/makefs.c
+++ b/usr.sbin/makefs/makefs.c
@@ -1,4 +1,4 @@
-/* $NetBSD: makefs.c,v 1.20 2004/06/20 22:20:18 jmc Exp $ */
+/* $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $ */
/*
* Copyright (c) 2001-2003 Wasabi Systems, Inc.
@@ -55,14 +55,18 @@ __FBSDID("$FreeBSD$");
*/
typedef struct {
const char *type;
+ void (*prepare_options)(fsinfo_t *);
int (*parse_options)(const char *, fsinfo_t *);
+ void (*cleanup_options)(fsinfo_t *);
void (*make_fs)(const char *, const char *, fsnode *,
fsinfo_t *);
} fstype_t;
static fstype_t fstypes[] = {
- { "ffs", ffs_parse_opts, ffs_makefs },
- { NULL },
+ { "ffs", ffs_prep_opts, ffs_parse_opts, ffs_cleanup_opts, ffs_makefs },
+ { "cd9660", cd9660_prep_opts, cd9660_parse_opts, cd9660_cleanup_opts,
+ cd9660_makefs},
+ { .type = NULL },
};
u_int debug;
@@ -92,17 +96,9 @@ main(int argc, char *argv[])
(void)memset(&fsoptions, 0, sizeof(fsoptions));
fsoptions.fd = -1;
fsoptions.sectorsize = -1;
- fsoptions.bsize= -1;
- fsoptions.fsize= -1;
- fsoptions.cpg= -1;
- fsoptions.density= -1;
- fsoptions.minfree= -1;
- fsoptions.optimization= -1;
- fsoptions.maxcontig= -1;
- fsoptions.maxbpg= -1;
- fsoptions.avgfilesize= -1;
- fsoptions.avgfpdir= -1;
- fsoptions.version = 1;
+
+ if (fstype->prepare_options)
+ fstype->prepare_options(&fsoptions);
specfile = NULL;
if (gettimeofday(&start, NULL) == -1)
@@ -148,8 +144,7 @@ main(int argc, char *argv[])
break;
case 'd':
- debug =
- (int)strsuftoll("debug mask", optarg, 0, UINT_MAX);
+ debug = strtoll(optarg, NULL, 0);
break;
case 'f':
@@ -212,8 +207,13 @@ main(int argc, char *argv[])
break;
case 't':
+ /* Check current one and cleanup if necessary. */
+ if (fstype->cleanup_options)
+ fstype->cleanup_options(&fsoptions);
+ fsoptions.fs_specific = NULL;
if ((fstype = get_fstype(optarg)) == NULL)
errx(1, "Unknown fs type `%s'.", optarg);
+ fstype->prepare_options(&fsoptions);
break;
case 'x':
@@ -250,7 +250,7 @@ main(int argc, char *argv[])
if (specfile) { /* apply a specfile */
TIMER_START(start);
- apply_specfile(specfile, argv[1], root);
+ apply_specfile(specfile, argv[1], root, fsoptions.onlyspec);
TIMER_RESULTS(start, "apply_specfile");
}
@@ -265,6 +265,8 @@ main(int argc, char *argv[])
fstype->make_fs(argv[0], argv[1], root, &fsoptions);
TIMER_RESULTS(start, "make_fs");
+ free_fsnodes(root);
+
exit(0);
/* NOTREACHED */
}
diff --git a/usr.sbin/makefs/makefs.h b/usr.sbin/makefs/makefs.h
index ce18bf8..997c4db 100644
--- a/usr.sbin/makefs/makefs.h
+++ b/usr.sbin/makefs/makefs.h
@@ -1,4 +1,4 @@
-/* $NetBSD: makefs.h,v 1.14 2004/06/20 22:20:18 jmc Exp $ */
+/* $NetBSD: makefs.h,v 1.20 2008/12/28 21:51:46 christos Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -126,27 +126,7 @@ typedef struct {
int needswap; /* non-zero if byte swapping needed */
int sectorsize; /* sector size */
- /* ffs specific options */
- int bsize; /* block size */
- int fsize; /* fragment size */
- int cpg; /* cylinders per group */
- int cpgflg; /* cpg was specified by user */
- int density; /* bytes per inode */
- int ntracks; /* number of tracks */
- int nsectors; /* number of sectors */
- int rpm; /* rpm */
- int minfree; /* free space threshold */
- int optimization; /* optimization (space or time) */
- int maxcontig; /* max contiguous blocks to allocate */
- int rotdelay; /* rotational delay between blocks */
- int maxbpg; /* maximum blocks per file in a cyl group */
- int nrpos; /* # of distinguished rotational positions */
- int avgfilesize; /* expected average file size */
- int avgfpdir; /* expected # of files per directory */
- int version; /* filesystem version (1 = FFS, 2 = UFS2) */
- int maxbsize; /* maximum extent size */
- int maxblkspercg; /* max # of blocks per cylinder group */
- /* XXX: support `old' file systems ? */
+ void *fs_specific; /* File system specific additions. */
} fsinfo_t;
@@ -164,15 +144,22 @@ typedef struct {
} option_t;
-void apply_specfile(const char *, const char *, fsnode *);
+void apply_specfile(const char *, const char *, fsnode *, int);
void dump_fsnodes(const char *, fsnode *);
const char * inode_type(mode_t);
int set_option(option_t *, const char *, const char *);
fsnode * walk_dir(const char *, fsnode *);
+void free_fsnodes(fsnode *);
+void ffs_prep_opts(fsinfo_t *);
int ffs_parse_opts(const char *, fsinfo_t *);
+void ffs_cleanup_opts(fsinfo_t *);
void ffs_makefs(const char *, const char *, fsnode *, fsinfo_t *);
+void cd9660_prep_opts(fsinfo_t *);
+int cd9660_parse_opts(const char *, fsinfo_t *);
+void cd9660_cleanup_opts(fsinfo_t *);
+void cd9660_makefs(const char *, const char *, fsnode *, fsinfo_t *);
extern u_int debug;
@@ -211,6 +198,7 @@ extern struct timespec start_time;
#define DEBUG_BUF_GETBLK 0x02000000
#define DEBUG_APPLY_SPECFILE 0x04000000
#define DEBUG_APPLY_SPECENTRY 0x08000000
+#define DEBUG_APPLY_SPECONLY 0x10000000
#define TIMER_START(x) \
@@ -222,8 +210,9 @@ extern struct timespec start_time;
struct timeval end, td; \
gettimeofday(&end, NULL); \
timersub(&end, &(x), &td); \
- printf("%s took %ld.%06ld seconds\n", \
- (d), (long) td.tv_sec, (long) td.tv_usec); \
+ printf("%s took %lld.%06ld seconds\n", \
+ (d), (long long)td.tv_sec, \
+ (long)td.tv_usec); \
}
@@ -249,56 +238,56 @@ extern struct timespec start_time;
* File system internal flags, also in fs_flags.
* (Pick highest number to avoid conflicts with others)
*/
-#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
-#define FS_INTERNAL 0x80000000 /* mask for internal flags */
+#define FS_SWAPPED 0x80000000 /* file system is endian swapped */
+#define FS_INTERNAL 0x80000000 /* mask for internal flags */
-#define FS_ISCLEAN 1
+#define FS_ISCLEAN 1
-#define DINODE1_SIZE (sizeof(struct ufs1_dinode))
-#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
+#define DINODE1_SIZE (sizeof(struct ufs1_dinode))
+#define DINODE2_SIZE (sizeof(struct ufs2_dinode))
-#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(ufs1_daddr_t))
-#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(ufs2_daddr_t))
+#define MAXSYMLINKLEN_UFS1 ((NDADDR + NIADDR) * sizeof(ufs1_daddr_t))
+#define MAXSYMLINKLEN_UFS2 ((NDADDR + NIADDR) * sizeof(ufs2_daddr_t))
#if (BYTE_ORDER == LITTLE_ENDIAN)
-#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
- (((oldfmt) && !(needswap)) ? \
+#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
+ (((oldfmt) && !(needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#else
-#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
- (((oldfmt) && (needswap)) ? \
+#define DIRSIZ_SWAP(oldfmt, dp, needswap) \
+ (((oldfmt) && (needswap)) ? \
DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen))
#endif
-#define cg_chkmagic_swap(cgp, ns) \
+#define cg_chkmagic_swap(cgp, ns) \
(ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC)
-#define cg_inosused_swap(cgp, ns) \
+#define cg_inosused_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_iusedoff, (ns))))
-#define cg_blksfree_swap(cgp, ns) \
+#define cg_blksfree_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_freeoff, (ns))))
-#define cg_clustersfree_swap(cgp, ns) \
+#define cg_clustersfree_swap(cgp, ns) \
((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_clusteroff, (ns))))
-#define cg_clustersum_swap(cgp, ns) \
+#define cg_clustersum_swap(cgp, ns) \
((int32_t *)((uintptr_t)(cgp) + ufs_rw32((cgp)->cg_clustersumoff, ns)))
struct fs;
-void ffs_fragacct_swap(struct fs *, int, int32_t [], int, int);
+void ffs_fragacct_swap(struct fs *, int, int32_t [], int, int);
/*
* Declarations for compat routines.
*/
long long strsuftoll(const char *, const char *, long long, long long);
long long strsuftollx(const char *, const char *,
- long long, long long, char *, size_t);
+ long long, long long, char *, size_t);
struct passwd;
int uid_from_user(const char *, uid_t *);
int pwcache_userdb(int (*)(int), void (*)(void),
- struct passwd * (*)(const char *), struct passwd * (*)(uid_t));
+ struct passwd * (*)(const char *), struct passwd * (*)(uid_t));
struct group;
int gid_from_group(const char *, gid_t *);
int pwcache_groupdb(int (*)(int), void (*)(void),
- struct group * (*)(const char *), struct group * (*)(gid_t));
+ struct group * (*)(const char *), struct group * (*)(gid_t));
int setup_getid(const char *dir);
diff --git a/usr.sbin/makefs/walk.c b/usr.sbin/makefs/walk.c
index e485787..0d7bd8e 100644
--- a/usr.sbin/makefs/walk.c
+++ b/usr.sbin/makefs/walk.c
@@ -1,4 +1,4 @@
-/* $NetBSD: walk.c,v 1.17 2004/06/20 22:20:18 jmc Exp $ */
+/* $NetBSD: walk.c,v 1.24 2008/12/28 21:51:46 christos Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -35,41 +35,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-/*
- * The function link_check() was inspired from NetBSD's usr.bin/du/du.c,
- * which has the following copyright notice:
- *
- *
- * Copyright (c) 1989, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Newcomb.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -84,13 +49,13 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
#include "makefs.h"
-
#include "mtree.h"
-#include "extern.h" /* NB: mtree */
+#include "extern.h"
-static void apply_specdir(const char *, NODE *, fsnode *);
+static void apply_specdir(const char *, NODE *, fsnode *, int);
static void apply_specentry(const char *, NODE *, fsnode *);
static fsnode *create_fsnode(const char *, struct stat *);
static fsinode *link_check(fsinode *);
@@ -164,6 +129,10 @@ walk_dir(const char *dir, fsnode *parent)
free(cur->inode);
cur->inode = curino;
cur->inode->nlink++;
+ if (debug & DEBUG_WALK_DIR_LINKCHECK)
+ printf("link_check: found [%llu, %llu]\n",
+ (unsigned long long)curino->st.st_dev,
+ (unsigned long long)curino->st.st_ino);
}
}
if (S_ISLNK(cur->type)) {
@@ -201,6 +170,53 @@ create_fsnode(const char *name, struct stat *stbuf)
}
/*
+ * free_fsnodes --
+ * Removes node from tree and frees it and all of
+ * its decendents.
+ */
+void
+free_fsnodes(fsnode *node)
+{
+ fsnode *cur, *next;
+
+ assert(node != NULL);
+
+ /* for ".", start with actual parent node */
+ if (node->first == node) {
+ assert(node->name[0] == '.' && node->name[1] == '\0');
+ if (node->parent) {
+ assert(node->parent->child == node);
+ node = node->parent;
+ }
+ }
+
+ /* Find ourselves in our sibling list and unlink */
+ if (node->first != node) {
+ for (cur = node->first; cur->next; cur = cur->next) {
+ if (cur->next == node) {
+ cur->next = node->next;
+ node->next = NULL;
+ break;
+ }
+ }
+ }
+
+ for (cur = node; cur != NULL; cur = next) {
+ next = cur->next;
+ if (cur->child) {
+ cur->child->parent = NULL;
+ free_fsnodes(cur->child);
+ }
+ if (cur->inode->nlink-- == 1)
+ free(cur->inode);
+ if (cur->symlink)
+ free(cur->symlink);
+ free(cur->name);
+ free(cur);
+ }
+}
+
+/*
* apply_specfile --
* read in the mtree(8) specfile, and apply it to the tree
* at dir,parent. parameters in parent on equivalent types
@@ -208,7 +224,7 @@ create_fsnode(const char *name, struct stat *stbuf)
* entries will be added.
*/
void
-apply_specfile(const char *specfile, const char *dir, fsnode *parent)
+apply_specfile(const char *specfile, const char *dir, fsnode *parent, int speconly)
{
struct timeval start;
FILE *fp;
@@ -236,7 +252,8 @@ apply_specfile(const char *specfile, const char *dir, fsnode *parent)
assert(root->type == F_DIR);
/* merge in the changes */
- apply_specdir(dir, root, parent);
+ apply_specdir(dir, root, parent, speconly);
+
}
static u_int
@@ -265,8 +282,9 @@ nodetoino(u_int type)
/* NOTREACHED */
}
+
static void
-apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
+apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode, int speconly)
{
char path[MAXPATHLEN + 1];
NODE *curnode;
@@ -287,6 +305,30 @@ apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
apply_specentry(dir, specnode, dirnode);
+ /* Remove any filesystem nodes not found in specfile */
+ /* XXX inefficient. This is O^2 in each dir and it would
+ * have been better never to have walked this part of the tree
+ * to begin with
+ */
+ if (speconly) {
+ fsnode *next;
+ assert(dirnode->name[0] == '.' && dirnode->name[1] == '\0');
+ for (curfsnode = dirnode->next; curfsnode != NULL; curfsnode = next) {
+ next = curfsnode->next;
+ for (curnode = specnode->child; curnode != NULL;
+ curnode = curnode->next) {
+ if (strcmp(curnode->name, curfsnode->name) == 0)
+ break;
+ }
+ if (curnode == NULL) {
+ if (debug & DEBUG_APPLY_SPECONLY) {
+ printf("apply_specdir: trimming %s/%s %p\n", dir, curfsnode->name, curfsnode);
+ }
+ free_fsnodes(curfsnode);
+ }
+ }
+ }
+
/* now walk specnode->child matching up with dirnode */
for (curnode = specnode->child; curnode != NULL;
curnode = curnode->next) {
@@ -328,6 +370,9 @@ apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
curnode->flags & F_GNAME, "group");
NODETEST(curnode->flags & F_UID ||
curnode->flags & F_UNAME, "user");
+/* if (curnode->type == F_BLOCK || curnode->type == F_CHAR)
+ NODETEST(curnode->flags & F_DEV,
+ "device number");*/
#undef NODETEST
if (debug & DEBUG_APPLY_SPECFILE)
@@ -367,7 +412,7 @@ apply_specdir(const char *dir, NODE *specnode, fsnode *dirnode)
if (curfsnode->type != S_IFDIR)
errx(1, "`%s' is not a directory", path);
assert (curfsnode->child != NULL);
- apply_specdir(path, curnode, curfsnode->child);
+ apply_specdir(path, curnode, curfsnode->child, speconly);
}
}
}
@@ -444,6 +489,12 @@ apply_specentry(const char *dir, NODE *specnode, fsnode *dirnode)
dirnode->inode->st.st_flags = specnode->st_flags;
}
#endif
+/* if (specnode->flags & F_DEV) {
+ ASEPRINT("rdev", "%#llx",
+ (unsigned long long)dirnode->inode->st.st_rdev,
+ (unsigned long long)specnode->st_rdev);
+ dirnode->inode->st.st_rdev = specnode->st_rdev;
+ }*/
#undef ASEPRINT
dirnode->flags |= FSNODE_F_HASSPEC;
@@ -493,11 +544,11 @@ dump_fsnodes(const char *dir, fsnode *root)
/*
* inode_type --
* for a given inode type `mode', return a descriptive string.
+ * for most cases, uses inotype() from mtree/misc.c
*/
const char *
inode_type(mode_t mode)
{
-
if (S_ISREG(mode))
return ("file");
if (S_ISLNK(mode))
@@ -521,48 +572,78 @@ inode_type(mode_t mode)
/*
* link_check --
- * return pointer to fsnode matching `entry's st_ino & st_dev if it exists,
+ * return pointer to fsinode matching `entry's st_ino & st_dev if it exists,
* otherwise add `entry' to table and return NULL
*/
+/* This was borrowed from du.c and tweaked to keep an fsnode
+ * pointer instead. -- dbj@netbsd.org
+ */
static fsinode *
link_check(fsinode *entry)
{
- static struct dupnode {
- uint32_t dev;
- uint64_t ino;
- fsinode *dup;
- } *dups, *newdups;
- static int ndups, maxdups;
-
- int i;
-
- assert (entry != NULL);
-
- /* XXX; maybe traverse in reverse for speed? */
- for (i = 0; i < ndups; i++) {
- if (dups[i].dev == entry->st.st_dev &&
- dups[i].ino == entry->st.st_ino) {
- if (debug & DEBUG_WALK_DIR_LINKCHECK)
- printf("link_check: found [%d,%d]\n",
- entry->st.st_dev, entry->st.st_ino);
- return (dups[i].dup);
+ static struct entry {
+ fsinode *data;
+ } *htable;
+ static int htshift; /* log(allocated size) */
+ static int htmask; /* allocated size - 1 */
+ static int htused; /* 2*number of insertions */
+ int h, h2;
+ uint64_t tmp;
+ /* this constant is (1<<64)/((1+sqrt(5))/2)
+ * aka (word size)/(golden ratio)
+ */
+ const uint64_t HTCONST = 11400714819323198485ULL;
+ const int HTBITS = 64;
+
+ /* Never store zero in hashtable */
+ assert(entry);
+
+ /* Extend hash table if necessary, keep load under 0.5 */
+ if (htused<<1 >= htmask) {
+ struct entry *ohtable;
+
+ if (!htable)
+ htshift = 10; /* starting hashtable size */
+ else
+ htshift++; /* exponential hashtable growth */
+
+ htmask = (1 << htshift) - 1;
+ htused = 0;
+
+ ohtable = htable;
+ htable = calloc(htmask+1, sizeof(*htable));
+ if (!htable)
+ err(1, "Memory allocation error");
+
+ /* populate newly allocated hashtable */
+ if (ohtable) {
+ int i;
+ for (i = 0; i <= htmask>>1; i++)
+ if (ohtable[i].data)
+ link_check(ohtable[i].data);
+ free(ohtable);
}
}
- if (debug & DEBUG_WALK_DIR_LINKCHECK)
- printf("link_check: no match for [%d, %d]\n",
- entry->st.st_dev, entry->st.st_ino);
- if (ndups == maxdups) {
- if ((newdups = realloc(dups, sizeof(struct dupnode) * (maxdups + 128)))
- == NULL)
- err(1, "Memory allocation error");
- dups = newdups;
- maxdups += 128;
+ /* multiplicative hashing */
+ tmp = entry->st.st_dev;
+ tmp <<= HTBITS>>1;
+ tmp |= entry->st.st_ino;
+ tmp *= HTCONST;
+ h = tmp >> (HTBITS - htshift);
+ h2 = 1 | ( tmp >> (HTBITS - (htshift<<1) - 1)); /* must be odd */
+
+ /* open address hashtable search with double hash probing */
+ while (htable[h].data) {
+ if ((htable[h].data->st.st_ino == entry->st.st_ino) &&
+ (htable[h].data->st.st_dev == entry->st.st_dev)) {
+ return htable[h].data;
+ }
+ h = (h + h2) & htmask;
}
- dups[ndups].dev = entry->st.st_dev;
- dups[ndups].ino = entry->st.st_ino;
- dups[ndups].dup = entry;
- ndups++;
- return (NULL);
+ /* Insert the current entry into hashtable */
+ htable[h].data = entry;
+ htused++;
+ return NULL;
}
OpenPOWER on IntegriCloud