diff --git a/usr.bin/mkimg/mkimg.c b/usr.bin/mkimg/mkimg.c index c5a85aa7c33d..d870f3a8f0c3 100644 --- a/usr.bin/mkimg/mkimg.c +++ b/usr.bin/mkimg/mkimg.c @@ -1,734 +1,734 @@ /*- * Copyright (c) 2013,2014 Juniper Networks, Inc. * 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "image.h" #include "format.h" #include "mkimg.h" #include "scheme.h" #define LONGOPT_FORMATS 0x01000001 #define LONGOPT_SCHEMES 0x01000002 #define LONGOPT_VERSION 0x01000003 #define LONGOPT_CAPACITY 0x01000004 static struct option longopts[] = { { "formats", no_argument, NULL, LONGOPT_FORMATS }, { "schemes", no_argument, NULL, LONGOPT_SCHEMES }, { "version", no_argument, NULL, LONGOPT_VERSION }, { "capacity", required_argument, NULL, LONGOPT_CAPACITY }, { NULL, 0, NULL, 0 } }; static uint64_t min_capacity = 0; static uint64_t max_capacity = 0; struct partlisthead partlist = TAILQ_HEAD_INITIALIZER(partlist); u_int nparts = 0; u_int unit_testing; u_int verbose; u_int ncyls = 0; u_int nheads = 1; u_int nsecs = 1; u_int secsz = 512; u_int blksz = 0; uint32_t active_partition = 0; static void print_formats(int usage) { struct mkimg_format *f; const char *sep; if (usage) { fprintf(stderr, " formats:\n"); f = NULL; while ((f = format_iterate(f)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", f->name, f->description); } } else { sep = ""; f = NULL; while ((f = format_iterate(f)) != NULL) { printf("%s%s", sep, f->name); sep = " "; } putchar('\n'); } } static void print_schemes(int usage) { struct mkimg_scheme *s; const char *sep; if (usage) { fprintf(stderr, " schemes:\n"); s = NULL; while ((s = scheme_iterate(s)) != NULL) { fprintf(stderr, "\t%s\t- %s\n", s->name, s->description); } } else { sep = ""; s = NULL; while ((s = scheme_iterate(s)) != NULL) { printf("%s%s", sep, s->name); sep = " "; } putchar('\n'); } } static void print_version(void) { u_int width; #ifdef __LP64__ width = 64; #else width = 32; #endif printf("mkimg %u (%u-bit)\n", MKIMG_VERSION, width); } static void usage(const char *why) { warnx("error: %s", why); fputc('\n', stderr); fprintf(stderr, "usage: %s \n", getprogname()); fprintf(stderr, " options:\n"); fprintf(stderr, "\t--formats\t- list image formats\n"); fprintf(stderr, "\t--schemes\t- list partition schemes\n"); fprintf(stderr, "\t--version\t- show version information\n"); fputc('\n', stderr); fprintf(stderr, "\t-a \t- mark num'th partion as active\n"); fprintf(stderr, "\t-b \t- file containing boot code\n"); fprintf(stderr, "\t-c \t- minimum capacity (in bytes) of the disk\n"); fprintf(stderr, "\t-C \t- maximum capacity (in bytes) of the disk\n"); fprintf(stderr, "\t-f \n"); fprintf(stderr, "\t-o \t- file to write image into\n"); fprintf(stderr, "\t-p \n"); fprintf(stderr, "\t-s \n"); fprintf(stderr, "\t-v\t\t- increase verbosity\n"); fprintf(stderr, "\t-y\t\t- [developers] enable unit test\n"); fprintf(stderr, "\t-H \t- number of heads to simulate\n"); fprintf(stderr, "\t-P \t- physical sector size\n"); fprintf(stderr, "\t-S \t- logical sector size\n"); fprintf(stderr, "\t-T \t- number of tracks to simulate\n"); fputc('\n', stderr); print_formats(1); fputc('\n', stderr); print_schemes(1); fputc('\n', stderr); fprintf(stderr, " partition specification:\n"); fprintf(stderr, "\t[/]::[:[+]]\t- " "empty partition of given size and\n\t\t\t\t\t" " optional relative or absolute offset\n"); fprintf(stderr, "\t[/]:=\t\t- partition content and size " "are\n\t\t\t\t\t determined by the named file\n"); fprintf(stderr, "\t[/]:-\t\t- partition content and size " "are taken\n\t\t\t\t\t from the output of the command to run\n"); fprintf(stderr, "\t-\t\t\t\t- unused partition entry\n"); fprintf(stderr, "\t where:\n"); fprintf(stderr, "\t\t\t- scheme neutral partition type\n"); fprintf(stderr, "\t\t\t- optional scheme-dependent partition " "label\n"); exit(EX_USAGE); } static int parse_uint32(uint32_t *valp, uint32_t min, uint32_t max, const char *arg) { uint64_t val; if (expand_number(arg, &val) == -1) return (errno); if (val > UINT_MAX || val < (uint64_t)min || val > (uint64_t)max) return (EINVAL); *valp = (uint32_t)val; return (0); } static int parse_uint64(uint64_t *valp, uint64_t min, uint64_t max, const char *arg) { uint64_t val; if (expand_number(arg, &val) == -1) return (errno); if (val < min || val > max) return (EINVAL); *valp = val; return (0); } static int pwr_of_two(u_int nr) { return (((nr & (nr - 1)) == 0) ? 1 : 0); } /* * A partition specification has the following format: * ':' * where: * type the partition type alias * kind the interpretation of the contents specification * ':' contents holds the size of an empty partition * '=' contents holds the name of a file to read * '-' contents holds a command to run; the output of * which is the contents of the partition. * contents the specification of a partition's contents * * A specification that is a single dash indicates an unused partition * entry. */ static int parse_part(const char *spec) { struct part *part; char *sep; size_t len; int error; if (strcmp(spec, "-") == 0) { nparts++; return (0); } part = calloc(1, sizeof(struct part)); if (part == NULL) return (ENOMEM); sep = strchr(spec, ':'); if (sep == NULL) { error = EINVAL; goto errout; } len = sep - spec + 1; if (len < 2) { error = EINVAL; goto errout; } part->alias = malloc(len); if (part->alias == NULL) { error = ENOMEM; goto errout; } strlcpy(part->alias, spec, len); spec = sep + 1; switch (*spec) { case ':': part->kind = PART_KIND_SIZE; break; case '=': part->kind = PART_KIND_FILE; break; case '-': part->kind = PART_KIND_PIPE; break; default: error = EINVAL; goto errout; } spec++; part->contents = strdup(spec); if (part->contents == NULL) { error = ENOMEM; goto errout; } spec = part->alias; sep = strchr(spec, '/'); if (sep != NULL) { *sep++ = '\0'; if (strlen(part->alias) == 0 || strlen(sep) == 0) { error = EINVAL; goto errout; } part->label = strdup(sep); if (part->label == NULL) { error = ENOMEM; goto errout; } } part->index = nparts; TAILQ_INSERT_TAIL(&partlist, part, link); nparts++; return (0); errout: if (part->alias != NULL) free(part->alias); free(part); return (error); } #if defined(SPARSE_WRITE) ssize_t sparse_write(int fd, const void *ptr, size_t sz) { const char *buf, *p; off_t ofs; size_t len; ssize_t wr, wrsz; buf = ptr; wrsz = 0; p = memchr(buf, 0, sz); while (sz > 0) { len = (p != NULL) ? (size_t)(p - buf) : sz; if (len > 0) { len = (len + secsz - 1) & ~(secsz - 1); if (len > sz) len = sz; wr = write(fd, buf, len); if (wr < 0) return (-1); } else { while (len < sz && *p++ == '\0') len++; if (len < sz) len &= ~(secsz - 1); if (len == 0) continue; ofs = lseek(fd, len, SEEK_CUR); if (ofs < 0) return (-1); wr = len; } buf += wr; sz -= wr; wrsz += wr; p = memchr(buf, 0, sz); } return (wrsz); } #endif /* SPARSE_WRITE */ void mkimg_chs(lba_t lba, u_int maxcyl, u_int *cylp, u_int *hdp, u_int *secp) { u_int hd, sec; *cylp = *hdp = *secp = ~0U; if (nsecs == 1 || nheads == 1) return; sec = lba % nsecs + 1; lba /= nsecs; hd = lba % nheads; lba /= nheads; if (lba > maxcyl) return; *cylp = lba; *hdp = hd; *secp = sec; } static int capacity_resize(lba_t end) { lba_t min_capsz, max_capsz; min_capsz = (min_capacity + secsz - 1) / secsz; max_capsz = (max_capacity + secsz - 1) / secsz; if (max_capsz != 0 && end > max_capsz) return (ENOSPC); if (end >= min_capsz) return (0); return (image_set_size(min_capsz)); } static void mkimg_validate(void) { struct part *part, *part2; lba_t start, end, start2, end2; int i, j; i = 0; TAILQ_FOREACH(part, &partlist, link) { start = part->block; end = part->block + part->size; j = i + 1; part2 = TAILQ_NEXT(part, link); if (part2 == NULL) break; TAILQ_FOREACH_FROM(part2, &partlist, link) { start2 = part2->block; end2 = part2->block + part2->size; if ((start >= start2 && start < end2) || (end > start2 && end <= end2)) { errx(1, "partition %d overlaps partition %d", i, j); } j++; } i++; } } static void mkimg(void) { FILE *fp; struct part *part; lba_t block, blkoffset; - off_t bytesize, byteoffset; + uint64_t bytesize, byteoffset; char *size, *offset; bool abs_offset; int error, fd; /* First check partition information */ TAILQ_FOREACH(part, &partlist, link) { error = scheme_check_part(part); if (error) errc(EX_DATAERR, error, "partition %d", part->index+1); } block = scheme_metadata(SCHEME_META_IMG_START, 0); abs_offset = false; TAILQ_FOREACH(part, &partlist, link) { byteoffset = blkoffset = 0; abs_offset = false; /* Look for an offset. Set size too if we can. */ switch (part->kind) { case PART_KIND_SIZE: offset = part->contents; size = strsep(&offset, ":"); if (expand_number(size, &bytesize) == -1) error = errno; if (offset != NULL) { if (*offset != '+') abs_offset = true; else offset++; if (expand_number(offset, &byteoffset) == -1) error = errno; } break; } /* Work out exactly where the partition starts. */ blkoffset = (byteoffset + secsz - 1) / secsz; if (abs_offset) { part->block = scheme_metadata(SCHEME_META_PART_ABSOLUTE, blkoffset); } else { block = scheme_metadata(SCHEME_META_PART_BEFORE, block + blkoffset); part->block = block; } if (verbose) fprintf(stderr, "partition %d: starting block %llu " "... ", part->index + 1, (long long)part->block); /* Pull in partition contents, set size if we haven't yet. */ switch (part->kind) { case PART_KIND_FILE: fd = open(part->contents, O_RDONLY, 0); if (fd != -1) { error = image_copyin(block, fd, &bytesize); close(fd); } else error = errno; break; case PART_KIND_PIPE: fp = popen(part->contents, "r"); if (fp != NULL) { fd = fileno(fp); error = image_copyin(block, fd, &bytesize); pclose(fp); } else error = errno; break; } if (error) errc(EX_IOERR, error, "partition %d", part->index + 1); part->size = (bytesize + secsz - 1) / secsz; if (verbose) { bytesize = part->size * secsz; fprintf(stderr, "size %llu bytes (%llu blocks)\n", (long long)bytesize, (long long)part->size); if (abs_offset) { fprintf(stderr, " location %llu bytes (%llu blocks)\n", (long long)byteoffset, (long long)blkoffset); } else if (blkoffset > 0) { fprintf(stderr, " offset %llu bytes (%llu blocks)\n", (long long)byteoffset, (long long)blkoffset); } } if (!abs_offset) { block = scheme_metadata(SCHEME_META_PART_AFTER, part->block + part->size); } } mkimg_validate(); block = scheme_metadata(SCHEME_META_IMG_END, block); error = image_set_size(block); if (!error) { error = capacity_resize(block); block = image_get_size(); } if (!error) { error = format_resize(block); block = image_get_size(); } if (error) errc(EX_IOERR, error, "image sizing"); ncyls = block / (nsecs * nheads); error = scheme_write(block); if (error) errc(EX_IOERR, error, "writing metadata"); } int main(int argc, char *argv[]) { int bcfd, outfd; int c, error; bcfd = -1; outfd = 1; /* Write to stdout by default */ while ((c = getopt_long(argc, argv, "a:b:c:C:f:o:p:s:vyH:P:S:T:", longopts, NULL)) != -1) { switch (c) { case 'a': /* ACTIVE PARTITION, if supported */ error = parse_uint32(&active_partition, 1, 100, optarg); if (error) errc(EX_DATAERR, error, "Partition ordinal"); break; case 'b': /* BOOT CODE */ if (bcfd != -1) usage("multiple bootcode given"); bcfd = open(optarg, O_RDONLY, 0); if (bcfd == -1) err(EX_UNAVAILABLE, "%s", optarg); break; case 'c': /* MINIMUM CAPACITY */ error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg); if (error) errc(EX_DATAERR, error, "minimum capacity in bytes"); break; case 'C': /* MAXIMUM CAPACITY */ error = parse_uint64(&max_capacity, 1, INT64_MAX, optarg); if (error) errc(EX_DATAERR, error, "maximum capacity in bytes"); break; case 'f': /* OUTPUT FORMAT */ if (format_selected() != NULL) usage("multiple formats given"); error = format_select(optarg); if (error) errc(EX_DATAERR, error, "format"); break; case 'o': /* OUTPUT FILE */ if (outfd != 1) usage("multiple output files given"); outfd = open(optarg, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH); if (outfd == -1) err(EX_CANTCREAT, "%s", optarg); break; case 'p': /* PARTITION */ error = parse_part(optarg); if (error) errc(EX_DATAERR, error, "partition"); break; case 's': /* SCHEME */ if (scheme_selected() != NULL) usage("multiple schemes given"); error = scheme_select(optarg); if (error) errc(EX_DATAERR, error, "scheme"); break; case 'y': unit_testing++; break; case 'v': verbose++; break; case 'H': /* GEOMETRY: HEADS */ error = parse_uint32(&nheads, 1, 255, optarg); if (error) errc(EX_DATAERR, error, "number of heads"); break; case 'P': /* GEOMETRY: PHYSICAL SECTOR SIZE */ error = parse_uint32(&blksz, 512, INT_MAX+1U, optarg); if (error == 0 && !pwr_of_two(blksz)) error = EINVAL; if (error) errc(EX_DATAERR, error, "physical sector size"); break; case 'S': /* GEOMETRY: LOGICAL SECTOR SIZE */ error = parse_uint32(&secsz, 512, INT_MAX+1U, optarg); if (error == 0 && !pwr_of_two(secsz)) error = EINVAL; if (error) errc(EX_DATAERR, error, "logical sector size"); break; case 'T': /* GEOMETRY: TRACK SIZE */ error = parse_uint32(&nsecs, 1, 63, optarg); if (error) errc(EX_DATAERR, error, "track size"); break; case LONGOPT_FORMATS: print_formats(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_SCHEMES: print_schemes(0); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_VERSION: print_version(); exit(EX_OK); /*NOTREACHED*/ case LONGOPT_CAPACITY: error = parse_uint64(&min_capacity, 1, INT64_MAX, optarg); if (error) errc(EX_DATAERR, error, "capacity in bytes"); max_capacity = min_capacity; break; default: usage("unknown option"); } } if (argc > optind) usage("trailing arguments"); if (scheme_selected() == NULL && nparts > 0) usage("no scheme"); if (nparts == 0 && min_capacity == 0) usage("no partitions"); if (max_capacity != 0 && min_capacity > max_capacity) usage("minimum capacity cannot be larger than the maximum one"); if (secsz > blksz) { if (blksz != 0) errx(EX_DATAERR, "the physical block size cannot " "be smaller than the sector size"); blksz = secsz; } if (secsz > scheme_max_secsz()) errx(EX_DATAERR, "maximum sector size supported is %u; " "size specified is %u", scheme_max_secsz(), secsz); if (nparts > scheme_max_parts()) errx(EX_DATAERR, "%d partitions supported; %d given", scheme_max_parts(), nparts); if (format_selected() == NULL) format_select("raw"); if (bcfd != -1) { error = scheme_bootcode(bcfd); close(bcfd); if (error) errc(EX_DATAERR, error, "boot code"); } if (verbose) { fprintf(stderr, "Logical sector size: %u\n", secsz); fprintf(stderr, "Physical block size: %u\n", blksz); fprintf(stderr, "Sectors per track: %u\n", nsecs); fprintf(stderr, "Number of heads: %u\n", nheads); fputc('\n', stderr); if (scheme_selected()) fprintf(stderr, "Partitioning scheme: %s\n", scheme_selected()->name); fprintf(stderr, "Output file format: %s\n", format_selected()->name); fputc('\n', stderr); } error = image_init(); if (error) errc(EX_OSERR, error, "cannot initialize"); mkimg(); if (verbose) { fputc('\n', stderr); fprintf(stderr, "Number of cylinders: %u\n", ncyls); } error = format_write(outfd); if (error) errc(EX_IOERR, error, "writing image"); return (0); } diff --git a/usr.sbin/makefs/cd9660.h b/usr.sbin/makefs/cd9660.h index 05f42c97231e..5f6525d3e94f 100644 --- a/usr.sbin/makefs/cd9660.h +++ b/usr.sbin/makefs/cd9660.h @@ -1,358 +1,358 @@ /* $NetBSD: cd9660.h,v 1.17 2011/06/23 02:35:56 enami Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-NetBSD * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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_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]; + 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; /* 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; int chrp_boot; /* 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; /************ 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_write_boot(iso9660_disk *, FILE *); int cd9660_add_boot_disk(iso9660_disk *, const char *); int cd9660_eltorito_add_boot_option(iso9660_disk *, const char *, const char *); int cd9660_setup_boot(iso9660_disk *, int); int cd9660_setup_boot_volume_descriptor(iso9660_disk *, volume_descriptor *); /*** Write Functions ***/ int cd9660_write_image(iso9660_disk *, const char *image); int cd9660_copy_file(iso9660_disk *, FILE *, off_t, const char *); void cd9660_compute_full_filename(cd9660node *, char *); int cd9660_compute_record_size(iso9660_disk *, cd9660node *); /* Debugging functions */ void debug_print_tree(iso9660_disk *, cd9660node *,int); void debug_print_path_tree(cd9660node *); void debug_print_volume_descriptor_information(iso9660_disk *); 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); +int debug_get_encoded_number(const unsigned char *, int); +void debug_dump_integer(const char *, const unsigned char *, int); +void debug_dump_string(const char *, const unsigned char *, int); void debug_dump_directory_record_9_1(unsigned char *); void debug_dump_to_xml_volume_descriptor(unsigned char *,int); void cd9660_pad_string_spaces(char *, int); #endif diff --git a/usr.sbin/makefs/cd9660/cd9660_debug.c b/usr.sbin/makefs/cd9660/cd9660_debug.c index bcf58a35fa37..b1e07fb85f0f 100644 --- a/usr.sbin/makefs/cd9660/cd9660_debug.c +++ b/usr.sbin/makefs/cd9660/cd9660_debug.c @@ -1,489 +1,456 @@ /* $NetBSD: cd9660_debug.c,v 1.11 2010/10/27 18:51:35 christos Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-NetBSD * * 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 __FBSDID("$FreeBSD$"); #include #include #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 *, +static void debug_dump_to_xml_padded_hex_output(const char *, const 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(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(iso9660_disk *diskStructure, 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(diskStructure, 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(iso9660_disk *diskStructure) { 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("\n" ,num); printf("%i\n", pttemp->length[0]); printf("%i\n", pttemp->extended_attribute_length[0]); printf("%i\n", debug_get_encoded_number(pttemp->parent_number,mode)); debug_dump_to_xml_padded_hex_output("name", pttemp->name, pttemp->length[0]); printf("\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("\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("\n"); } static void -debug_dump_to_xml_padded_hex_output(const char *element, unsigned char *buf, - int len) +debug_dump_to_xml_padded_hex_output(const char *element, const 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("\n",element); printf("<%s:hex>",element); for (i = 0; i < len; i++) { t = (unsigned char)buf[i]; printf(" %x",t); } printf("\n",element); } int -debug_get_encoded_number(unsigned char* buf, int mode) +debug_get_encoded_number(const 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); + return isonum_712(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) +debug_dump_integer(const char *element, const unsigned char* buf, int mode) { - printf("<%s>%i\n", element, - debug_get_encoded_number((unsigned char *)buf, mode), element); + printf("<%s>%i\n", element, debug_get_encoded_number(buf, mode), + element); } void -debug_dump_string(const char *element __unused, unsigned char *buf __unused, int len __unused) +debug_dump_string(const char *element __unused, const unsigned char *buf __unused, int len __unused) { } void debug_dump_directory_record_9_1(unsigned char* buf) { + struct iso_directory_record *rec = (struct iso_directory_record *)buf; printf("\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("length", rec->length, 711); + debug_dump_integer("ext_attr_length", rec->ext_attr_length, 711); + debug_dump_integer("extent", rec->extent, 733); + debug_dump_integer("size", rec->size, 733); + debug_dump_integer("flags", rec->flags, 711); + debug_dump_integer("file_unit_size", rec->file_unit_size, 711); + debug_dump_integer("interleave", rec->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)); + rec->volume_sequence_number, 723); + debug_dump_integer("name_len", rec->name_len, 711); + debug_dump_to_xml_padded_hex_output("name", rec->name, + debug_get_encoded_number(rec->length, 711)); printf("\n"); } void debug_dump_to_xml_volume_descriptor(unsigned char* buf, int sector) { + struct iso_primary_descriptor *desc = + (struct iso_primary_descriptor *)buf; + printf("\n", sector); printf(""); 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("\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_integer("type", desc->type, 711); + debug_dump_to_xml_padded_hex_output("id", desc->id, + ISODCL(2, 6)); + debug_dump_integer("version", (u_char *)desc->version, 711); debug_dump_to_xml_padded_hex_output("system_id", - (u_char *)((struct iso_primary_descriptor*)buf)->system_id, - ISODCL(9,40)); + desc->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)); + desc->volume_id, ISODCL(41, 72)); debug_dump_integer("volume_space_size", - ((struct iso_primary_descriptor*)buf)->volume_space_size, - 733); + (u_char *)desc->volume_space_size, 733); debug_dump_integer("volume_set_size", - ((struct iso_primary_descriptor*)buf)->volume_set_size, - 733); + (u_char *)desc->volume_set_size, 733); debug_dump_integer("volume_sequence_number", - ((struct iso_primary_descriptor*)buf)->volume_sequence_number, - 723); + (u_char *)desc->volume_sequence_number, 723); debug_dump_integer("logical_block_size", - ((struct iso_primary_descriptor*)buf)->logical_block_size, - 723); + (u_char *)desc->logical_block_size, 723); debug_dump_integer("path_table_size", - ((struct iso_primary_descriptor*)buf)->path_table_size, - 733); + (u_char *)desc->path_table_size, 733); debug_dump_integer("type_l_path_table", - ((struct iso_primary_descriptor*)buf)->type_l_path_table, - 731); + (u_char *)desc->type_l_path_table, 731); debug_dump_integer("opt_type_l_path_table", - ((struct iso_primary_descriptor*)buf)->opt_type_l_path_table, - 731); + (u_char *)desc->opt_type_l_path_table, 731); debug_dump_integer("type_m_path_table", - ((struct iso_primary_descriptor*)buf)->type_m_path_table, - 732); + (u_char *)desc->type_m_path_table, 732); debug_dump_integer("opt_type_m_path_table", - ((struct iso_primary_descriptor*)buf)->opt_type_m_path_table,732); + (u_char *)desc->opt_type_m_path_table, 732); debug_dump_directory_record_9_1( - (u_char *)((struct iso_primary_descriptor*)buf)->root_directory_record); + (u_char *)desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->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)); + desc->file_structure_version, ISODCL(882, 882)); break; } printf("\n"); } diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c index 8d4df08275db..3d50fcd6b232 100644 --- a/usr.sbin/makefs/cd9660/cd9660_write.c +++ b/usr.sbin/makefs/cd9660/cd9660_write.c @@ -1,514 +1,514 @@ /* $NetBSD: cd9660_write.c,v 1.14 2011/01/04 09:48:21 wiz Exp $ */ /*- * SPDX-License-Identifier: BSD-2-Clause-NetBSD * * 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 __FBSDID("$FreeBSD$"); #include static int cd9660_write_volume_descriptors(iso9660_disk *, FILE *); static int cd9660_write_path_table(iso9660_disk *, FILE *, off_t, int); static int cd9660_write_path_tables(iso9660_disk *, FILE *); static int cd9660_write_file(iso9660_disk *, FILE *, cd9660node *); static int cd9660_write_filedata(iso9660_disk *, 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(iso9660_disk *, 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(iso9660_disk *diskStructure, const char* image) { FILE *fd; int status; - char buf[CD9660_SECTOR_SIZE]; + unsigned 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(diskStructure, 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(diskStructure, 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(diskStructure, 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(diskStructure, 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(diskStructure, fd); } /* Write padding bits. This is temporary */ memset(buf, 0, CD9660_SECTOR_SIZE); cd9660_write_filedata(diskStructure, 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(iso9660_disk *diskStructure, FILE *fd) { volume_descriptor *vd_temp = diskStructure->firstVolumeDescriptor; while (vd_temp != NULL) { cd9660_write_filedata(diskStructure, 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(iso9660_disk *diskStructure, 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, ret; path_table_entry temp_entry; cd9660node *ptcur; buffer = ecalloc(path_table_sectors, diskStructure->sectorSize); buffer_head = buffer; 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; } ret = cd9660_write_filedata(diskStructure, fd, sector, buffer_head, path_table_sectors); free(buffer_head); return ret; } /* * 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(iso9660_disk *diskStructure, FILE *fd) { if (cd9660_write_path_table(diskStructure, fd, diskStructure->primaryLittleEndianTableSector, LITTLE_ENDIAN) == 0) return 0; if (cd9660_write_path_table(diskStructure, 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(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode) { char *buf; char *temp_file_name; int ret; off_t working_sector; int cur_sector_offset; iso_directory_record_cd9660 temp_record; cd9660node *temp; int rv = 0; /* Todo : clean up variables */ temp_file_name = ecalloc(CD9660MAXPATH + 1, 1); buf = emalloc(diskStructure->sectorSize); 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; if (writenode->node->contents == NULL) cd9660_compute_full_filename(writenode, temp_file_name); ret = cd9660_copy_file(diskStructure, fd, writenode->fileDataSector, (writenode->node->contents != NULL) ? writenode->node->contents : temp_file_name); if (ret == 0) goto out; } } else { /* * Here is a new revelation that ECMA didn't explain * (at least not well). * ALL . and .. records store the name "\0" and "\1" * respectively. 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(diskStructure, 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 */ (void)fwrite(&temp_record, 1, temp->isoDirRecord->length[0], fd); if (diskStructure->rock_ridge_enabled) { cd9660_write_rr(diskStructure, 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(diskStructure, 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(iso9660_disk *diskStructure, 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(iso9660_disk *diskStructure, 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 = emalloc(buf_size); 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); (void)fclose(rf); return 0; } fwrite(buf,1,bytes_read,fd); if (ferror(fd)) { warn("%s: fwrite", __func__); free(buf); (void)fclose(rf); return 0; } sector++; } fclose(rf); free(buf); return 1; } static void cd9660_write_rr(iso9660_disk *diskStructure, FILE *fd, cd9660node *writenode, off_t offset, off_t sector) { int in_ca = 0; struct ISO_SUSP_ATTRIBUTES *myattr; offset += writenode->isoDirRecord->length[0]; if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) == -1) err(1, "fseeko"); /* Offset now points at the end of the record */ TAILQ_FOREACH(myattr, &writenode->head, rr_ll) { fwrite(&(myattr->attr), CD9660_SUSP_ENTRY_SIZE(myattr), 1, fd); if (!in_ca) { offset += CD9660_SUSP_ENTRY_SIZE(myattr); if (myattr->last_in_suf) { /* * Point the offset to the start of this * record's CE area */ if (fseeko(fd, ((off_t)diskStructure-> susp_continuation_area_start_sector * diskStructure->sectorSize) + writenode->susp_entry_ce_start, SEEK_SET) == -1) err(1, "fseeko"); in_ca = 1; } } } /* * If we had to go to the continuation area, head back to * where we should be. */ if (in_ca) if (fseeko(fd, sector * diskStructure->sectorSize + offset, SEEK_SET) == -1) err(1, "fseeko"); } diff --git a/usr.sbin/makefs/ffs/ffs_subr.c b/usr.sbin/makefs/ffs/ffs_subr.c index 97b4dcb05dc1..53e5b97ada48 100644 --- a/usr.sbin/makefs/ffs/ffs_subr.c +++ b/usr.sbin/makefs/ffs/ffs_subr.c @@ -1,184 +1,184 @@ /* $NetBSD: ffs_subr.c,v 1.32 2003/12/30 12:33:24 pk Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ffs_subr.c 8.5 (Berkeley) 3/21/95 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include "ffs/ffs_extern.h" #include "ffs/ufs_bswap.h" /* * Update the frsum fields to reflect addition or deletion * of some frags. */ void -ffs_fragacct_swap(struct fs *fs, int fragmap, int32_t fraglist[], int cnt, int needswap) +ffs_fragacct_swap(struct fs *fs, int fragmap, uint32_t fraglist[], int cnt, int needswap) { int inblk; int field, subfield; int siz, pos; inblk = (int)(fragtbl[fs->fs_frag][fragmap]) << 1; fragmap <<= 1; for (siz = 1; siz < fs->fs_frag; siz++) { if ((inblk & (1 << (siz + (fs->fs_frag & (NBBY - 1))))) == 0) continue; field = around[siz]; subfield = inside[siz]; for (pos = siz; pos <= fs->fs_frag; pos++) { if ((fragmap & field) == subfield) { fraglist[siz] = ufs_rw32( ufs_rw32(fraglist[siz], needswap) + cnt, needswap); pos += siz; field <<= siz; subfield <<= siz; } field <<= 1; subfield <<= 1; } } } /* * block operations * * check if a block is available * returns true if all the corresponding bits in the free map are 1 * returns false if any corresponding bit in the free map is 0 */ int ffs_isblock(struct fs *fs, u_char *cp, int32_t h) { u_char mask; switch ((int)fs->fs_fragshift) { case 3: return (cp[h] == 0xff); case 2: mask = 0x0f << ((h & 0x1) << 2); return ((cp[h >> 1] & mask) == mask); case 1: mask = 0x03 << ((h & 0x3) << 1); return ((cp[h >> 2] & mask) == mask); case 0: mask = 0x01 << (h & 0x7); return ((cp[h >> 3] & mask) == mask); default: panic("ffs_isblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * check if a block is completely allocated * returns true if all the corresponding bits in the free map are 0 * returns false if any corresponding bit in the free map is 1 */ int ffs_isfreeblock(struct fs *fs, u_char *cp, int32_t h) { switch ((int)fs->fs_fragshift) { case 3: return (cp[h] == 0); case 2: return ((cp[h >> 1] & (0x0f << ((h & 0x1) << 2))) == 0); case 1: return ((cp[h >> 2] & (0x03 << ((h & 0x3) << 1))) == 0); case 0: return ((cp[h >> 3] & (0x01 << (h & 0x7))) == 0); default: panic("ffs_isfreeblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * take a block out of the map */ void ffs_clrblock(struct fs *fs, u_char *cp, int32_t h) { switch ((int)fs->fs_fragshift) { case 3: cp[h] = 0; return; case 2: cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); return; case 1: cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); return; case 0: cp[h >> 3] &= ~(0x01 << (h & 0x7)); return; default: panic("ffs_clrblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } /* * put a block into the map */ void ffs_setblock(struct fs *fs, u_char *cp, int32_t h) { switch ((int)fs->fs_fragshift) { case 3: cp[h] = 0xff; return; case 2: cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); return; case 1: cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); return; case 0: cp[h >> 3] |= (0x01 << (h & 0x7)); return; default: panic("ffs_setblock: unknown fs_fragshift %d", (int)fs->fs_fragshift); } } diff --git a/usr.sbin/makefs/ffs/mkfs.c b/usr.sbin/makefs/ffs/mkfs.c index e885d23613bb..ff3c1d594b4e 100644 --- a/usr.sbin/makefs/ffs/mkfs.c +++ b/usr.sbin/makefs/ffs/mkfs.c @@ -1,838 +1,839 @@ /* $NetBSD: mkfs.c,v 1.22 2011/10/09 22:30:13 christos Exp $ */ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2002 Networks Associates Technology, Inc. * All rights reserved. * * This software was developed for the FreeBSD Project by Marshall * Kirk McKusick and Network Associates Laboratories, the Security * Research Division of Network Associates, Inc. under DARPA/SPAWAR * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS * research program * * Copyright (c) 1980, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "makefs.h" #include "ffs.h" #include #include #include "ffs/ufs_bswap.h" #include "ffs/ufs_inode.h" #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(uint32_t, time_t, const fsinfo_t *); static int ilog2(int); static int count_digits(int); /* * make file system for cylinder-group style file systems */ #define UMASK 0755 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) static union { struct fs fs; char pad[SBLOCKSIZE]; } fsun; #define sblock fsun.fs static union { struct cg cg; char pad[FFS_MAXBSIZE]; } cgun; #define acg cgun.cg static char *iobuf; static int iobufsize; static char writebuf[FFS_MAXBSIZE]; static int Oflag; /* format as an 4.3BSD file system */ static int64_t fssize; /* file system size */ static int sectorsize; /* bytes/sector */ static int fsize; /* fragment size */ static int bsize; /* block size */ static int maxbsize; /* maximum clustering */ static int maxblkspercg; static int minfree; /* free space threshold */ 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 */ struct fs * ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; int32_t csfrags; uint32_t i, cylno; long long sizepb; void *space; int size; int nprintcols, printcolwidth; ffs_opt_t *ffs_opts = fsopts->fs_specific; Oflag = ffs_opts->version; fssize = fsopts->size / fsopts->sectorsize; sectorsize = fsopts->sectorsize; 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; - strlcpy(sblock.fs_volname, ffs_opts->label, sizeof(sblock.fs_volname)); + strlcpy((char *)sblock.fs_volname, ffs_opts->label, + sizeof(sblock.fs_volname)); if (Oflag == 0) { sblock.fs_old_inodefmt = FS_42INODEFMT; sblock.fs_maxsymlinklen = 0; sblock.fs_old_flags = 0; } else { sblock.fs_old_inodefmt = FS_44INODEFMT; sblock.fs_maxsymlinklen = (Oflag == 1 ? UFS1_MAXSYMLINKLEN : UFS2_MAXSYMLINKLEN); sblock.fs_old_flags = FS_FLAGS_UPDATED; sblock.fs_flags = 0; } /* * Validate the given file system size. * Verify that its last block can actually be accessed. * Convert to file system fragment sized units. */ if (fssize <= 0) { printf("preposterous size %lld\n", (long long)fssize); exit(13); } ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts); /* * collect and verify the filesystem density info */ sblock.fs_avgfilesize = avgfilesize; sblock.fs_avgfpdir = avgfpdir; if (sblock.fs_avgfilesize <= 0) printf("illegal expected average file size %d\n", sblock.fs_avgfilesize), exit(14); if (sblock.fs_avgfpdir <= 0) printf("illegal expected number of files per directory %d\n", sblock.fs_avgfpdir), exit(15); /* * collect and verify the block and fragment sizes */ sblock.fs_bsize = bsize; sblock.fs_fsize = fsize; if (!POWEROF2(sblock.fs_bsize)) { printf("block size must be a power of 2, not %d\n", sblock.fs_bsize); exit(16); } if (!POWEROF2(sblock.fs_fsize)) { printf("fragment size must be a power of 2, not %d\n", sblock.fs_fsize); exit(17); } if (sblock.fs_fsize < sectorsize) { printf("fragment size %d is too small, minimum is %d\n", sblock.fs_fsize, sectorsize); exit(18); } if (sblock.fs_bsize < MINBSIZE) { printf("block size %d is too small, minimum is %d\n", sblock.fs_bsize, MINBSIZE); exit(19); } if (sblock.fs_bsize > FFS_MAXBSIZE) { printf("block size %d is too large, maximum is %d\n", sblock.fs_bsize, FFS_MAXBSIZE); exit(19); } if (sblock.fs_bsize < sblock.fs_fsize) { printf("block size (%d) cannot be smaller than fragment size (%d)\n", sblock.fs_bsize, sblock.fs_fsize); exit(20); } if (maxbsize < bsize || !POWEROF2(maxbsize)) { sblock.fs_maxbsize = sblock.fs_bsize; printf("Extent size set to %d\n", sblock.fs_maxbsize); } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; printf("Extent size reduced to %d\n", sblock.fs_maxbsize); } else { sblock.fs_maxbsize = maxbsize; } sblock.fs_maxcontig = maxcontig; if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); } if (sblock.fs_maxcontig > 1) sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); sblock.fs_bmask = ~(sblock.fs_bsize - 1); sblock.fs_fmask = ~(sblock.fs_fsize - 1); sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) sblock.fs_bshift++; for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) sblock.fs_fshift++; sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) sblock.fs_fragshift++; if (sblock.fs_frag > MAXFRAG) { printf("fragment size %d is too small, " "minimum with block size %d is %d\n", sblock.fs_fsize, sblock.fs_bsize, sblock.fs_bsize / MAXFRAG); exit(21); } sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); sblock.fs_size = sblock.fs_providersize = fssize = dbtofsb(&sblock, fssize); if (Oflag <= 1) { sblock.fs_magic = FS_UFS1_MAGIC; sblock.fs_sblockloc = SBLOCK_UFS1; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) * sizeof (ufs1_daddr_t)); sblock.fs_old_inodefmt = FS_44INODEFMT; sblock.fs_old_cgoffset = 0; sblock.fs_old_cgmask = 0xffffffff; sblock.fs_old_size = sblock.fs_size; sblock.fs_old_rotdelay = 0; sblock.fs_old_rps = 60; sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; sblock.fs_old_cpg = 1; sblock.fs_old_interleave = 1; sblock.fs_old_trackskew = 0; sblock.fs_old_cpc = 0; sblock.fs_old_postblformat = 1; sblock.fs_old_nrpos = 1; } else { sblock.fs_magic = FS_UFS2_MAGIC; sblock.fs_sblockloc = SBLOCK_UFS2; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); sblock.fs_maxsymlinklen = ((UFS_NDADDR + UFS_NIADDR) * sizeof (ufs2_daddr_t)); if (ffs_opts->softupdates == 1) sblock.fs_flags |= FS_DOSOFTDEP; } sblock.fs_sblkno = roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag); sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; sblock.fs_maxfilesize = sblock.fs_bsize * UFS_NDADDR - 1; for (sizepb = sblock.fs_bsize, i = 0; i < UFS_NIADDR; i++) { sizepb *= NINDIR(&sblock); sblock.fs_maxfilesize += sizepb; } /* * Calculate the number of blocks to put into each cylinder group. * * This algorithm selects the number of blocks per cylinder * group. The first goal is to have at least enough data blocks * in each cylinder group to meet the density requirement. Once * this goal is achieved we try to expand to have at least * 1 cylinder group. Once this goal is achieved, we pack as * many blocks into each cylinder group map as will fit. * * We start by calculating the smallest number of blocks that we * can put into each cylinder group. If this is too big, we reduce * the density until it fits. */ origdensity = density; for (;;) { fragsperinode = MAX(numfrags(&sblock, density), 1); minfpg = fragsperinode * INOPB(&sblock); if (minfpg > sblock.fs_size) minfpg = sblock.fs_size; sblock.fs_ipg = INOPB(&sblock); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) break; density -= sblock.fs_fsize; } if (density != origdensity) printf("density reduced from %d to %d\n", origdensity, density); if (maxblkspercg <= 0 || maxblkspercg >= fssize) maxblkspercg = fssize - 1; /* * Start packing more blocks into the cylinder group until * it cannot grow any larger, the number of cylinder groups * drops below 1, or we reach the size requested. */ for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (sblock.fs_size / sblock.fs_fpg < 1) break; if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) continue; if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); break; } /* * Check to be sure that the last cylinder group has enough blocks * to be viable. If it is too small, reduce the number of blocks * per cylinder group which will have the effect of moving more * blocks into the last cylinder group. */ optimalfpg = sblock.fs_fpg; for (;;) { sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); lastminfpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_size < lastminfpg) { printf("Filesystem size %lld < minimum size of %d\n", (long long)sblock.fs_size, lastminfpg); exit(28); } if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || sblock.fs_size % sblock.fs_fpg == 0) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); } if (optimalfpg != sblock.fs_fpg) printf("Reduced frags per cylinder group from %d to %d %s\n", optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); if (Oflag <= 1) { sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; sblock.fs_old_nsect = sblock.fs_old_spc; sblock.fs_old_npsect = sblock.fs_old_spc; sblock.fs_old_ncyl = sblock.fs_ncg; } /* * fill in remaining fields of the super block */ sblock.fs_csaddr = cgdmin(&sblock, 0); sblock.fs_cssize = fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); /* * Setup memory for temporary in-core cylgroup summaries. * Cribbed from ffs_mountfs(). */ size = sblock.fs_cssize; if (sblock.fs_contigsumsize > 0) size += sblock.fs_ncg * sizeof(int32_t); space = ecalloc(1, size); sblock.fs_si = ecalloc(1, sizeof(struct fs_summary_info)); sblock.fs_csp = space; space = (char *)space + sblock.fs_cssize; if (sblock.fs_contigsumsize > 0) { int32_t *lp; sblock.fs_maxcluster = lp = space; for (i = 0; i < sblock.fs_ncg; i++) *lp++ = sblock.fs_contigsumsize; } sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); if (sblock.fs_sbsize > SBLOCKSIZE) sblock.fs_sbsize = SBLOCKSIZE; sblock.fs_minfree = minfree; sblock.fs_maxcontig = maxcontig; sblock.fs_maxbpg = maxbpg; sblock.fs_optim = opt; sblock.fs_cgrotor = 0; sblock.fs_pendingblocks = 0; sblock.fs_pendinginodes = 0; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_cstotal.cs_nbfree = 0; sblock.fs_cstotal.cs_nifree = 0; sblock.fs_cstotal.cs_nffree = 0; sblock.fs_fmod = 0; sblock.fs_ronly = 0; sblock.fs_state = 0; sblock.fs_clean = FS_ISCLEAN; sblock.fs_ronly = 0; sblock.fs_id[0] = tstamp; sblock.fs_id[1] = random(); sblock.fs_fsmnt[0] = '\0'; csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); sblock.fs_cstotal.cs_nbfree = fragstoblks(&sblock, sblock.fs_dsize) - howmany(csfrags, sblock.fs_frag); sblock.fs_cstotal.cs_nffree = fragnum(&sblock, sblock.fs_size) + (fragnum(&sblock, csfrags) > 0 ? sblock.fs_frag - fragnum(&sblock, csfrags) : 0); sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - UFS_ROOTINO; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_dsize -= csfrags; sblock.fs_time = tstamp; if (Oflag <= 1) { sblock.fs_old_time = tstamp; sblock.fs_old_dsize = sblock.fs_dsize; sblock.fs_old_csaddr = sblock.fs_csaddr; sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } /* * Dump out summary information about file system. */ #define B2MBFACTOR (1 / (1024.0 * 1024.0)) printf("%s: %.1fMB (%lld sectors) block size %d, " "fragment size %d\n", fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, (long long)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, sblock.fs_fsize); printf("\tusing %d cylinder groups of %.2fMB, %d blks, " "%d inodes.\n", sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); #undef B2MBFACTOR /* * Now determine how wide each column will be, and calculate how * many columns will fit in a 76 char line. 76 is the width of the * subwindows in sysinst. */ printcolwidth = count_digits( fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); nprintcols = 76 / (printcolwidth + 2); /* * allocate space for superblock, cylinder group map, and * two sets of inode blocks. */ if (sblock.fs_bsize < SBLOCKSIZE) iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; else iobufsize = 4 * sblock.fs_bsize; iobuf = ecalloc(1, iobufsize); /* * Make a copy of the superblock into the buffer that we will be * writing out in each cylinder group. */ memcpy(writebuf, &sblock, sbsize); if (fsopts->needswap) ffs_sb_swap(&sblock, (struct fs*)writebuf); memcpy(iobuf, writebuf, SBLOCKSIZE); printf("super-block backups (for fsck -b #) at:"); for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { initcg(cylno, tstamp, fsopts); if (cylno % nprintcols == 0) printf("\n"); printf(" %*lld,", printcolwidth, (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); fflush(stdout); } printf("\n"); /* * Now construct the initial file system, * then write out the super-block. */ sblock.fs_time = tstamp; if (Oflag <= 1) { sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } if (fsopts->needswap) sblock.fs_flags |= FS_SWAPPED; ffs_write_superblock(&sblock, fsopts); return (&sblock); } /* * Write out the superblock and its duplicates, * and the cylinder group summaries */ void ffs_write_superblock(struct fs *fs, const fsinfo_t *fsopts) { int size, blks, i, saveflag; uint32_t cylno; void *space; char *wrbuf; saveflag = fs->fs_flags & FS_INTERNAL; fs->fs_flags &= ~FS_INTERNAL; memcpy(writebuf, &sblock, sbsize); if (fsopts->needswap) ffs_sb_swap(fs, (struct fs*)writebuf); ffs_wtfs(fs->fs_sblockloc / sectorsize, sbsize, writebuf, fsopts); /* Write out the duplicate super blocks */ for (cylno = 0; cylno < fs->fs_ncg; cylno++) ffs_wtfs(fsbtodb(fs, cgsblock(fs, cylno)), sbsize, writebuf, fsopts); /* Write out the cylinder group summaries */ size = fs->fs_cssize; blks = howmany(size, fs->fs_fsize); space = (void *)fs->fs_csp; wrbuf = emalloc(size); for (i = 0; i < blks; i+= fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; if (fsopts->needswap) ffs_csum_swap((struct csum *)space, (struct csum *)wrbuf, size); else memcpy(wrbuf, space, (u_int)size); ffs_wtfs(fsbtodb(fs, fs->fs_csaddr + i), size, wrbuf, fsopts); space = (char *)space + size; } free(wrbuf); fs->fs_flags |= saveflag; } /* * Initialize a cylinder group. */ static void initcg(uint32_t cylno, time_t utime, const fsinfo_t *fsopts) { daddr_t cbase, dmax; int32_t blkno; uint32_t i, j, d, dlower, dupper; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; int start; /* * Determine block bounds for cylinder group. * Allow space for super block summary information in first * cylinder group. */ cbase = cgbase(&sblock, cylno); dmax = cbase + sblock.fs_fpg; if (dmax > sblock.fs_size) dmax = sblock.fs_size; dlower = cgsblock(&sblock, cylno) - cbase; dupper = cgdmin(&sblock, cylno) - cbase; if (cylno == 0) dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); memset(&acg, 0, sblock.fs_cgsize); acg.cg_time = utime; acg.cg_magic = CG_MAGIC; acg.cg_cgx = cylno; acg.cg_niblk = sblock.fs_ipg; acg.cg_initediblk = MIN(sblock.fs_ipg, 2 * INOPB(&sblock)); acg.cg_ndblk = dmax - cbase; if (sblock.fs_contigsumsize > 0) acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift; start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); if (Oflag == 2) { acg.cg_iusedoff = start; } else { if (cylno == sblock.fs_ncg - 1) acg.cg_old_ncyl = howmany(acg.cg_ndblk, sblock.fs_fpg / sblock.fs_old_cpg); else acg.cg_old_ncyl = sblock.fs_old_cpg; acg.cg_old_time = acg.cg_time; acg.cg_time = 0; acg.cg_old_niblk = acg.cg_niblk; acg.cg_niblk = 0; acg.cg_initediblk = 0; acg.cg_old_btotoff = start; acg.cg_old_boff = acg.cg_old_btotoff + sblock.fs_old_cpg * sizeof(int32_t); acg.cg_iusedoff = acg.cg_old_boff + sblock.fs_old_cpg * sizeof(u_int16_t); } acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); if (sblock.fs_contigsumsize <= 0) { acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT); } else { acg.cg_clustersumoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t); acg.cg_clustersumoff = roundup(acg.cg_clustersumoff, sizeof(int32_t)); acg.cg_clusteroff = acg.cg_clustersumoff + (sblock.fs_contigsumsize + 1) * sizeof(int32_t); acg.cg_nextfreeoff = acg.cg_clusteroff + howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); } if (acg.cg_nextfreeoff > (uint32_t)sblock.fs_cgsize) { printf("Panic: cylinder group too big\n"); exit(37); } acg.cg_cs.cs_nifree += sblock.fs_ipg; if (cylno == 0) for (i = 0; i < UFS_ROOTINO; i++) { setbit(cg_inosused_swap(&acg, 0), i); acg.cg_cs.cs_nifree--; } if (cylno > 0) { /* * In cylno 0, beginning space is reserved * for boot and super blocks. */ for (d = 0, blkno = 0; d < dlower;) { ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); if (sblock.fs_contigsumsize > 0) setbit(cg_clustersfree_swap(&acg, 0), blkno); acg.cg_cs.cs_nbfree++; d += sblock.fs_frag; blkno++; } } if ((i = (dupper & (sblock.fs_frag - 1))) != 0) { acg.cg_frsum[sblock.fs_frag - i]++; for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { setbit(cg_blksfree_swap(&acg, 0), dupper); acg.cg_cs.cs_nffree++; } } for (d = dupper, blkno = dupper >> sblock.fs_fragshift; d + sblock.fs_frag <= acg.cg_ndblk; ) { ffs_setblock(&sblock, cg_blksfree_swap(&acg, 0), blkno); if (sblock.fs_contigsumsize > 0) setbit(cg_clustersfree_swap(&acg, 0), blkno); acg.cg_cs.cs_nbfree++; d += sblock.fs_frag; blkno++; } if (d < acg.cg_ndblk) { acg.cg_frsum[acg.cg_ndblk - d]++; for (; d < acg.cg_ndblk; d++) { setbit(cg_blksfree_swap(&acg, 0), d); acg.cg_cs.cs_nffree++; } } if (sblock.fs_contigsumsize > 0) { int32_t *sump = cg_clustersum_swap(&acg, 0); u_char *mapp = cg_clustersfree_swap(&acg, 0); int map = *mapp++; int bit = 1; int run = 0; for (i = 0; i < acg.cg_nclusterblks; i++) { if ((map & bit) != 0) { run++; } else if (run != 0) { if (run > sblock.fs_contigsumsize) run = sblock.fs_contigsumsize; sump[run]++; run = 0; } if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } if (run != 0) { if (run > sblock.fs_contigsumsize) run = sblock.fs_contigsumsize; sump[run]++; } } sblock.fs_cs(&sblock, cylno) = acg.cg_cs; /* * Write out the duplicate super block, the cylinder group map * and two blocks worth of inodes in a single write. */ start = MAX(sblock.fs_bsize, SBLOCKSIZE); memcpy(&iobuf[start], &acg, sblock.fs_cgsize); if (fsopts->needswap) ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock); start += sblock.fs_bsize; dp1 = (struct ufs1_dinode *)(&iobuf[start]); dp2 = (struct ufs2_dinode *)(&iobuf[start]); for (i = 0; i < acg.cg_initediblk; i++) { if (sblock.fs_magic == FS_UFS1_MAGIC) { /* No need to swap, it'll stay random */ dp1->di_gen = random(); dp1++; } else { dp2->di_gen = random(); dp2++; } } ffs_wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf, fsopts); /* * For the old file system, we have to initialize all the inodes. */ if (Oflag <= 1) { for (i = 2 * sblock.fs_frag; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) { dp1 = (struct ufs1_dinode *)(&iobuf[start]); for (j = 0; j < INOPB(&sblock); j++) { dp1->di_gen = random(); dp1++; } ffs_wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), sblock.fs_bsize, &iobuf[start], fsopts); } } } /* * read a block from the file system */ void ffs_rdfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) { int n; off_t offset; offset = bno * fsopts->sectorsize + fsopts->offset; if (lseek(fsopts->fd, offset, SEEK_SET) < 0) err(1, "%s: seek error for sector %lld", __func__, (long long)bno); n = read(fsopts->fd, bf, size); if (n == -1) { abort(); err(1, "%s: read error bno %lld size %d", __func__, (long long)bno, size); } else if (n != size) errx(1, "%s: read error for sector %lld", __func__, (long long)bno); } /* * write a block to the file system */ void ffs_wtfs(daddr_t bno, int size, void *bf, const fsinfo_t *fsopts) { int n; off_t offset; offset = bno * fsopts->sectorsize + fsopts->offset; if (lseek(fsopts->fd, offset, SEEK_SET) < 0) err(1, "%s: seek error for sector %lld", __func__, (long long)bno); n = write(fsopts->fd, bf, size); if (n == -1) err(1, "%s: write error for sector %lld", __func__, (long long)bno); else if (n != size) errx(1, "%s: write error for sector %lld", __func__, (long long)bno); } /* Determine how many digits are needed to print a given integer */ static int count_digits(int num) { int ndig; for(ndig = 1; num > 9; num /=10, ndig++); return (ndig); } static int ilog2(int val) { u_int n; for (n = 0; n < sizeof(n) * CHAR_BIT; n++) if (1 << n == val) return (n); errx(1, "%s: %d is not a power of 2", __func__, val); } diff --git a/usr.sbin/makefs/makefs.h b/usr.sbin/makefs/makefs.h index 25f41731fe57..68dc0362dd21 100644 --- a/usr.sbin/makefs/makefs.h +++ b/usr.sbin/makefs/makefs.h @@ -1,306 +1,306 @@ /* $NetBSD: makefs.h,v 1.20 2008/12/28 21:51:46 christos Exp $ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Luke Mewburn for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MAKEFS_H #define _MAKEFS_H #include #include /* * fsnode - * a component of the tree; contains a filename, a pointer to * fsinode, optional symlink name, and tree pointers * * fsinode - * equivalent to an inode, containing target file system inode number, * refcount (nlink), and stat buffer * * A tree of fsnodes looks like this: * * name "." "bin" "netbsd" * type S_IFDIR S_IFDIR S_IFREG * next > > NULL * parent NULL NULL NULL * child NULL v * * name "." "ls" * type S_IFDIR S_IFREG * next > NULL * parent ^ ^ (to "bin") * child NULL NULL * * Notes: * - first always points to first entry, at current level, which * must be "." when the tree has been built; during build it may * not be if "." hasn't yet been found by readdir(2). */ enum fi_flags { FI_SIZED = 1<<0, /* inode sized */ FI_ALLOCATED = 1<<1, /* fsinode->ino allocated */ FI_WRITTEN = 1<<2, /* inode written */ }; typedef struct { uint32_t ino; /* inode number used on target fs */ uint32_t nlink; /* number of links to this entry */ enum fi_flags flags; /* flags used by fs specific code */ struct stat st; /* stat entry */ } fsinode; typedef struct _fsnode { struct _fsnode *parent; /* parent (NULL if root) */ struct _fsnode *child; /* child (if type == S_IFDIR) */ struct _fsnode *next; /* next */ struct _fsnode *first; /* first node of current level (".") */ uint32_t type; /* type of entry */ fsinode *inode; /* actual inode data */ char *symlink; /* symlink target */ char *contents; /* file to provide contents */ const char *root; /* root path */ char *path; /* directory name */ char *name; /* file name */ int flags; /* misc flags */ } fsnode; #define FSNODE_F_HASSPEC 0x01 /* fsnode has a spec entry */ #define FSNODE_F_OPTIONAL 0x02 /* fsnode is optional */ /* * option_t - contains option name, description, pointer to location to store * result, and range checks for the result. Used to simplify fs specific * option setting */ typedef enum { OPT_STRARRAY, OPT_STRPTR, OPT_STRBUF, OPT_BOOL, OPT_INT8, OPT_INT16, OPT_INT32, OPT_INT64 } opttype_t; typedef struct { char letter; /* option letter NUL for none */ const char *name; /* option name */ void *value; /* where to stuff the value */ opttype_t type; /* type of entry */ long long minimum; /* minimum for value */ long long maximum; /* maximum for value */ const char *desc; /* option description */ } option_t; /* * fsinfo_t - contains various settings and parameters pertaining to * the image, including current settings, global options, and fs * specific options */ typedef struct makefs_fsinfo { /* current settings */ off_t size; /* total size */ off_t inodes; /* number of inodes */ uint32_t curinode; /* current inode */ /* image settings */ int fd; /* file descriptor of image */ void *superblock; /* superblock */ int onlyspec; /* only add entries in specfile */ /* global options */ off_t minsize; /* minimum size image should be */ off_t maxsize; /* maximum size image can be */ off_t freefiles; /* free file entries to leave */ off_t freeblocks; /* free blocks to leave */ off_t offset; /* offset from start of file */ off_t roundup; /* round image size up to this value */ int freefilepc; /* free file % */ int freeblockpc; /* free block % */ int needswap; /* non-zero if byte swapping needed */ int sectorsize; /* sector size */ int sparse; /* sparse image, don't fill it with zeros */ void *fs_specific; /* File system specific additions. */ option_t *fs_options; /* File system specific options */ } fsinfo_t; void apply_specfile(const char *, const char *, fsnode *, int); void dump_fsnodes(fsnode *); const char * inode_type(mode_t); fsnode * read_mtree(const char *, fsnode *); int set_option(const option_t *, const char *, char *, size_t); int set_option_var(const option_t *, const char *, const char *, char *, size_t); fsnode * walk_dir(const char *, const char *, fsnode *, fsnode *); void free_fsnodes(fsnode *); option_t * copy_opts(const option_t *); #define DECLARE_FUN(fs) \ void fs ## _prep_opts(fsinfo_t *); \ int fs ## _parse_opts(const char *, fsinfo_t *); \ void fs ## _cleanup_opts(fsinfo_t *); \ void fs ## _makefs(const char *, const char *, fsnode *, fsinfo_t *) DECLARE_FUN(cd9660); DECLARE_FUN(ffs); DECLARE_FUN(msdos); extern u_int debug; extern int dupsok; extern struct timespec start_time; extern struct stat stampst; /* * If -x is specified, we want to exclude nodes which do not appear * in the spec file. */ #define FSNODE_EXCLUDE_P(opts, fsnode) \ ((opts)->onlyspec != 0 && ((fsnode)->flags & FSNODE_F_HASSPEC) == 0) #define DEBUG_TIME 0x00000001 /* debug bits 1..3 unused at this time */ #define DEBUG_WALK_DIR 0x00000010 #define DEBUG_WALK_DIR_NODE 0x00000020 #define DEBUG_WALK_DIR_LINKCHECK 0x00000040 #define DEBUG_DUMP_FSNODES 0x00000080 #define DEBUG_DUMP_FSNODES_VERBOSE 0x00000100 #define DEBUG_FS_PARSE_OPTS 0x00000200 #define DEBUG_FS_MAKEFS 0x00000400 #define DEBUG_FS_VALIDATE 0x00000800 #define DEBUG_FS_CREATE_IMAGE 0x00001000 #define DEBUG_FS_SIZE_DIR 0x00002000 #define DEBUG_FS_SIZE_DIR_NODE 0x00004000 #define DEBUG_FS_SIZE_DIR_ADD_DIRENT 0x00008000 #define DEBUG_FS_POPULATE 0x00010000 #define DEBUG_FS_POPULATE_DIRBUF 0x00020000 #define DEBUG_FS_POPULATE_NODE 0x00040000 #define DEBUG_FS_WRITE_FILE 0x00080000 #define DEBUG_FS_WRITE_FILE_BLOCK 0x00100000 #define DEBUG_FS_MAKE_DIRBUF 0x00200000 #define DEBUG_FS_WRITE_INODE 0x00400000 #define DEBUG_BUF_BREAD 0x00800000 #define DEBUG_BUF_BWRITE 0x01000000 #define DEBUG_BUF_GETBLK 0x02000000 #define DEBUG_APPLY_SPECFILE 0x04000000 #define DEBUG_APPLY_SPECENTRY 0x08000000 #define DEBUG_APPLY_SPECONLY 0x10000000 #define DEBUG_MSDOSFS 0x20000000 #define TIMER_START(x) \ if (debug & DEBUG_TIME) \ gettimeofday(&(x), NULL) #define TIMER_RESULTS(x,d) \ if (debug & DEBUG_TIME) { \ struct timeval end, td; \ gettimeofday(&end, NULL); \ timersub(&end, &(x), &td); \ printf("%s took %lld.%06ld seconds\n", \ (d), (long long)td.tv_sec, \ (long)td.tv_usec); \ } #ifndef DEFAULT_FSTYPE #define DEFAULT_FSTYPE "ffs" #endif /* * ffs specific settings * --------------------- */ #define FFS_EI /* for opposite endian support in ffs headers */ /* * Write-arounds/compat shims for endian-agnostic support. * These belong in the kernel if/when it's possible to mount * filesystems w/ either byte order. */ /* * 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_ISCLEAN 1 #define DINODE1_SIZE (sizeof(struct ufs1_dinode)) #define DINODE2_SIZE (sizeof(struct ufs2_dinode)) #define UFS1_MAXSYMLINKLEN ((UFS_NDADDR + UFS_NIADDR) * sizeof(ufs1_daddr_t)) #define UFS2_MAXSYMLINKLEN ((UFS_NDADDR + UFS_NIADDR) * sizeof(ufs2_daddr_t)) #if (BYTE_ORDER == LITTLE_ENDIAN) #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)) ? \ DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen)) #endif #define cg_chkmagic_swap(cgp, ns) \ (ufs_rw32((cgp)->cg_magic, (ns)) == CG_MAGIC) #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) \ ((u_int8_t *)((u_int8_t *)(cgp) + ufs_rw32((cgp)->cg_freeoff, (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) \ ((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, uint32_t [], int, int); fsinode *link_check(fsinode *); #endif /* _MAKEFS_H */