Sync with the latest version from NetBSD. It notably addds ISO9660 support.

Submitted by:	bapt
This commit is contained in:
Olivier Houchard 2010-11-07 16:05:04 +00:00
parent 96a6480a53
commit 01a0f8531a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=214921
25 changed files with 6509 additions and 382 deletions

View File

@ -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

2154
usr.sbin/makefs/cd9660.c Normal file

File diff suppressed because it is too large Load Diff

364
usr.sbin/makefs/cd9660.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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 *);

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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

View File

@ -0,0 +1,8 @@
# $FreeBSD$
#
.PATH: ${.CURDIR}/compat
CFLAGS+= -I${.CURDIR}/compat
SRCS+= pwcache.c strsuftoll.c

View File

@ -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;

66
usr.sbin/makefs/ffs.h Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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;

View File

@ -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++;

View File

@ -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) {

View File

@ -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 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 F Ar specfile
.Ek
.Op Fl x
.Bk -words
.Op Fl B Ar byte-order
.Op Fl b Ar free-blocks
.Op Fl d Ar debug-mask
.Op Fl F Ar specfile
.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)

View File

@ -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 */
}

View File

@ -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);

View File

@ -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)) {
@ -200,6 +169,53 @@ create_fsnode(const char *name, struct stat *stbuf)
return (cur);
}
/*
* 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
@ -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;
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);
int i;
/* Extend hash table if necessary, keep load under 0.5 */
if (htused<<1 >= htmask) {
struct entry *ohtable;
assert (entry != NULL);
if (!htable)
htshift = 10; /* starting hashtable size */
else
htshift++; /* exponential hashtable growth */
/* 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);
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;
}