diff options
author | cognet <cognet@FreeBSD.org> | 2010-11-07 16:05:04 +0000 |
---|---|---|
committer | cognet <cognet@FreeBSD.org> | 2010-11-07 16:05:04 +0000 |
commit | 69d9f8b92c590010252135df10fc18177928b63d (patch) | |
tree | 60af890ef59672ab4e08377f2819cf9ec9d4e9e3 /usr.sbin | |
parent | 11d20f608be0ff59e94af8a9e55fd84794ac1882 (diff) | |
download | FreeBSD-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')
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; } |