Index: head/usr.sbin/makefs/Makefile =================================================================== --- head/usr.sbin/makefs/Makefile (revision 351272) +++ head/usr.sbin/makefs/Makefile (revision 351273) @@ -1,38 +1,41 @@ # $FreeBSD$ SRCDIR:=${.PARSEDIR:tA} .include PROG= makefs CFLAGS+=-I${SRCDIR} -SRCS= cd9660.c ffs.c \ +SRCS= cd9660.c \ + ffs.c \ makefs.c \ + msdos.c \ mtree.c \ walk.c MAN= makefs.8 WARNS?= 2 .include "${SRCDIR}/cd9660/Makefile.inc" .include "${SRCDIR}/ffs/Makefile.inc" +.include "${SRCDIR}/msdos/Makefile.inc" CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1 .PATH: ${SRCTOP}/contrib/mtree CFLAGS+=-I${SRCTOP}/contrib/mtree SRCS+= getid.c misc.c spec.c .PATH: ${SRCTOP}/contrib/mknod CFLAGS+=-I${SRCTOP}/contrib/mknod SRCS+= pack_dev.c CFLAGS+= -I${SRCTOP}/lib/libnetbsd LIBADD= netbsd util sbuf HAS_TESTS= SUBDIR.${MK_TESTS}+= tests .include Index: head/usr.sbin/makefs/makefs.8 =================================================================== --- head/usr.sbin/makefs/makefs.8 (revision 351272) +++ head/usr.sbin/makefs/makefs.8 (revision 351273) @@ -1,442 +1,511 @@ .\" $NetBSD: makefs.8,v 1.33 2011/05/22 21:51:39 christos Exp $ .\" .\" Copyright (c) 2001-2003 Wasabi Systems, Inc. .\" All rights reserved. .\" .\" Written by Luke Mewburn for Wasabi Systems, Inc. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed for the NetBSD Project by .\" Wasabi Systems, Inc. .\" 4. The name of Wasabi Systems, Inc. may not be used to endorse .\" or promote products derived from this software without specific prior .\" written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED .\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR .\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR .\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF .\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS .\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN .\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD$ .\" -.Dd August 19, 2019 +.Dd August 20, 2019 .Dt MAKEFS 8 .Os .Sh NAME .Nm makefs .Nd create a file system image from a directory tree or a mtree manifest .Sh SYNOPSIS .Nm .Op Fl DxZ .Op Fl B Ar endian .Op Fl b Ar free-blocks .Op Fl d Ar debug-mask .Op Fl F Ar mtree-specfile .Op Fl f Ar free-files .Op Fl M Ar minimum-size .Op Fl m Ar maximum-size .Op Fl N Ar userdb-dir .Op Fl O Ar offset .Op Fl o Ar fs-options .Op Fl R Ar roundup-size .Op Fl S Ar sector-size .Op Fl s Ar image-size .Op Fl T Ar timestamp .Op Fl t Ar fs-type .Ar image-file .Ar directory | manifest .Op Ar extra-directory ... .Sh DESCRIPTION The utility .Nm creates a file system image into .Ar image-file from the directory tree .Ar directory or from the mtree manifest .Ar manifest . If any optional directory trees are passed in the .Ar extra-directory arguments, then the directory tree of each argument will be merged into the .Ar directory or .Ar manifest first before creating .Ar image-file . No special devices or privileges are required to perform this task. .Pp The options are as follows: .Bl -tag -width flag .It Fl B Ar endian Set the byte order of the image to .Ar endian . Valid byte orders are .Ql 4321 , .Ql big , or .Ql be for big endian, and .Ql 1234 , .Ql little , or .Ql le for little endian. Some file systems may have a fixed byte order; in those cases this argument will be ignored. .It Fl b Ar free-blocks Ensure that a minimum of .Ar free-blocks free blocks exist in the image. An optional .Ql % suffix may be provided to indicate that .Ar free-blocks indicates a percentage of the calculated image size. .It Fl D Treat duplicate paths in an mtree manifest as warnings not error. .It Fl d Ar debug-mask Enable various levels of debugging, depending upon which bits are set in .Ar debug-mask . XXX: document these .It Fl F Ar mtree-specfile .Em This is almost certainly not the option you are looking for. To create an image from a list of files in an mtree format manifest, specify it as the last argument on the command line, not as a the argument to .Fl F . .Pp Use .Ar mtree-specfile as an .Xr mtree 8 .Sq specfile specification. This option has no effect when the image is created from a mtree manifest rather than a directory. .Pp If a specfile entry exists in the underlying file system, its permissions and modification time will be used unless specifically overridden by the specfile. An error will be raised if the type of entry in the specfile conflicts with that of an existing entry. .Pp In the opposite case (where a specfile entry does not have an entry in the underlying file system) the following occurs: If the specfile entry is marked .Sy optional , the specfile entry is ignored. Otherwise, the entry will be created in the image, and it is necessary to specify at least the following parameters in the specfile: .Sy type , .Sy mode , .Sy gname , or .Sy gid , and .Sy uname or .Sy uid , and .Sy link (in the case of symbolic links). If .Sy time is not provided, the current time will be used. If .Sy flags is not provided, the current file flags will be used. Missing regular file entries will be created as zero-length files. .It Fl f Ar free-files Ensure that a minimum of .Ar free-files free files (inodes) exist in the image. An optional .Ql % suffix may be provided to indicate that .Ar free-files indicates a percentage of the calculated image size. .It Fl M Ar minimum-size Set the minimum size of the file system image to .Ar minimum-size . .It Fl m Ar maximum-size Set the maximum size of the file system image to .Ar maximum-size . An error will be raised if the target file system needs to be larger than this to accommodate the provided directory tree. .It Fl N Ar userdb-dir Use the user database text file .Pa master.passwd and group database text file .Pa group from .Ar userdb-dir , rather than using the results from the system's .Xr getpwnam 3 and .Xr getgrnam 3 (and related) library calls. .It Fl O Ar offset Instead of creating the filesystem at the beginning of the file, start at offset. Valid only for -.Sy ffs . +.Sy ffs +and +.Sy msdos . .It Fl o Ar fs-options Set file system specific options. .Ar fs-options is a comma separated list of options. Valid file system specific options are detailed below. .It Fl p Deprecated. See the .Fl Z flag. .It Fl R Ar roundup-size Round the image up to .Ar roundup-size . .Ar roundup-size should be a multiple of the file system block size. This option only applies to the .Sy ffs file system type. .It Fl S Ar sector-size Set the file system sector size to .Ar sector-size . .\" XXX: next line also true for cd9660? Defaults to 512. .It Fl s Ar image-size Set the size of the file system image to .Ar image-size . This is equivalent to setting both the minimum .Fl ( M ) and the maximum .Fl ( m ) sizes to the same value. For .Sy ffs +and +.Sy msdos the .Ar image-size does not include the .Ar offset . +.Ar offset +is not included in that size. .It Fl T Ar timestamp Specify a timestamp to be set for all filesystem files and directories created so that repeatable builds are possible. The .Ar timestamp can be a .Pa pathname , where the timestamps are derived from that file, or an integer value interpreted as the number of seconds from the Epoch. Note that timestamps specified in an .Xr mtree 5 spec file, override the default timestamp. .It Fl t Ar fs-type Create an .Ar fs-type file system image. The following file system types are supported: .Bl -tag -width cd9660 -offset indent .It Sy ffs BSD fast file system (default). .It Sy cd9660 ISO 9660 file system. +.It Sy msdos +FAT12, FAT16, or FAT32 file system. .El .It Fl x Exclude file system nodes not explicitly listed in the specfile. .It Fl Z Create a sparse file for .Sy ffs . This is useful for virtual machine images. .El .Pp Where sizes are specified, a decimal number of bytes is expected. Two or more numbers may be separated by an .Dq x to indicate a product. Each number may have one of the following optional suffixes: .Bl -tag -width 3n -offset indent -compact .It b Block; multiply by 512 .It k Kibi; multiply by 1024 (1 KiB) .It m Mebi; multiply by 1048576 (1 MiB) .It g Gibi; multiply by 1073741824 (1 GiB) .It t Tebi; multiply by 1099511627776 (1 TiB) .It w Word; multiply by the number of bytes in an integer .El .\" .\" .Ss FFS-specific options .Sy ffs images have ffs-specific optional parameters that may be provided. Each of the options consists of a keyword, an equal sign .Pq Ql = , and a value. The following keywords are supported: .Pp .Bl -tag -width optimization -offset indent -compact .It Sy avgfilesize Expected average file size. .It Sy avgfpdir Expected number of files per directory. .It Sy bsize Block size. .It Sy density Bytes per inode. .It Sy fsize Fragment size. .It Sy label Label name of the image. .It Sy maxbpg Maximum blocks per file in a cylinder group. .It Sy minfree Minimum % free. .It Sy optimization Optimization preference; one of .Ql space or .Ql time . .It Sy extent Maximum extent size. .It Sy maxbpcg Maximum total number of blocks in a cylinder group. .It Sy version UFS version. 1 for FFS (default), 2 for UFS2. .It Sy softupdates 0 for disable (default), 1 for enable .El .Ss CD9660-specific options .Sy cd9660 images have ISO9660-specific optional parameters that may be provided. The arguments consist of a keyword and, optionally, an equal sign .Pq Ql = , and a value. The following keywords are supported: .Pp .Bl -tag -width omit-trailing-period -offset indent -compact .It Sy allow-deep-trees Allow the directory structure to exceed the maximum specified in the spec. .It Sy allow-illegal-chars Allow illegal characters in filenames. This option is not implemented. .It Sy allow-lowercase Allow lowercase characters in filenames. This option is not implemented. .It Sy allow-max-name Allow 37 instead of 33 characters for filenames by omitting the version id. .It Sy allow-multidot Allow multiple dots in a filename. .It Sy applicationid Application ID of the image. .It Sy archimedes Use the .Ql ARCHIMEDES extension to encode .Tn RISC OS metadata. .It Sy bootimagedir Boot image directory. This option is not implemented. .It Sy chrp-boot Write an MBR partition table to the image to allow older CHRP hardware to boot. .It Sy boot-load-segment Set load segment for the boot image. .It Sy bootimage Filename of a boot image in the format .Dq sysid;filename , where .Dq sysid is one of .Ql i386 , .Ql mac68k , .Ql macppc , or .Ql powerpc . .It Sy generic-bootimage Load a generic boot image into the first 32K of the cd9660 image. .It Sy hard-disk-boot Boot image is a hard disk image. .It Sy isolevel An integer representing the ISO 9660 interchange level where .Dq level is either .Ql 1 or .Ql 2 . .Dq level .Ql 3 is not implemented. .It Sy keep-bad-images Do not discard images whose write was aborted due to an error. For debugging purposes. .It Sy label Label name of the image. .It Sy no-boot Boot image is not bootable. .It Sy no-emul-boot Boot image is a .Dq no emulation ElTorito image. .It Sy no-trailing-padding Do not pad the image (apparently Linux needs the padding). .It Sy omit-trailing-period Omit trailing periods in filenames. .It Sy platformid Set platform ID of section header entry of the boot image. .It Sy preparer Preparer ID of the image. .It Sy publisher Publisher ID of the image. .It Sy rockridge Use RockRidge extensions (for longer filenames, etc.). .It Sy verbose Turns on verbose output. .It Sy volumeid Volume set identifier of the image. +.El +.Ss msdos-specific options +.Sy msdos +images have MS-DOS-specific optional parameters that may be +provided. +The arguments consist of a keyword, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported (see +.Xr newfs_msdos 8 +for more details): +.Pp +.Bl -tag -width omit-trailing-period -offset indent -compact +.It Cm backup_sector +Location of the backup boot sector. +.It Cm block_size +Block size. +.It Cm bootstrap +Bootstrap file. +.It Cm bytes_per_sector +Bytes per sector. +.It Cm create_size +Create file size. +.It Cm directory_entries +Directory entries. +.It Cm drive_heads +Drive heads. +.It Cm fat_type +FAT type (12, 16, or 32). +.It Cm floppy +Preset drive parameters for standard format floppy disks +(160, 180, 320, 360, 640, 720, 1200, 1232, 1440, or 2880). +.It Cm hidden_sectors +Hidden sectors. +.It Cm info_sector +Location of the info sector. +.It Cm media_descriptor +Media descriptor. +.It Cm num_FAT +Number of FATs. +.It Cm OEM_string +OEM string. +.It Cm offset +Offset in device. +This option will be ignored if +.Fl O +is set to a positive number. +.It Cm reserved_sectors +Reserved sectors. +.It Cm sectors_per_cluster +Sectors per cluster. +.It Cm sectors_per_fat +Sectors per FAT. +.It Cm sectors_per_track +Sectors per track. +.It Cm size +File System size. +.It Cm volume_id +Volume ID. +.It Cm volume_label +Volume Label. .El .Sh SEE ALSO .Xr mtree 5 , .Xr mtree 8 , .Xr newfs 8 .Sh HISTORY The .Nm utility appeared in .Nx 1.6 . .Sh AUTHORS .An Luke Mewburn .Aq Mt lukem@NetBSD.org (original program), .An Daniel Watt , .An Walter Deignan , .An Ryan Gabrys , .An Alan Perez-Rathke , .An Ram Vedam (cd9660 support) Index: head/usr.sbin/makefs/makefs.c =================================================================== --- head/usr.sbin/makefs/makefs.c (revision 351272) +++ head/usr.sbin/makefs/makefs.c (revision 351273) @@ -1,506 +1,507 @@ /* $NetBSD: makefs.c,v 1.26 2006/10/22 21:11:56 christos Exp $ */ /*- * SPDX-License-Identifier: BSD-4-Clause * * Copyright (c) 2001-2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Luke Mewburn for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include "makefs.h" #include "mtree.h" /* * list of supported file systems and dispatch functions */ typedef struct { const char *type; void (*prepare_options)(fsinfo_t *); int (*parse_options)(const char *, fsinfo_t *); void (*cleanup_options)(fsinfo_t *); void (*make_fs)(const char *, const char *, fsnode *, fsinfo_t *); } fstype_t; static fstype_t fstypes[] = { #define ENTRY(name) { \ # name, name ## _prep_opts, name ## _parse_opts, \ name ## _cleanup_opts, name ## _makefs \ } - ENTRY(ffs), ENTRY(cd9660), + ENTRY(ffs), + ENTRY(msdos), { .type = NULL }, }; u_int debug; int dupsok; struct timespec start_time; struct stat stampst; static fstype_t *get_fstype(const char *); static int get_tstamp(const char *, struct stat *); static void usage(fstype_t *, fsinfo_t *); int main(int argc, char *argv[]) { struct stat sb; struct timeval start; fstype_t *fstype; fsinfo_t fsoptions; fsnode *root; int ch, i, len; const char *subtree; const char *specfile; setprogname(argv[0]); debug = 0; if ((fstype = get_fstype(DEFAULT_FSTYPE)) == NULL) errx(1, "Unknown default fs type `%s'.", DEFAULT_FSTYPE); /* set default fsoptions */ (void)memset(&fsoptions, 0, sizeof(fsoptions)); fsoptions.fd = -1; fsoptions.sectorsize = -1; if (fstype->prepare_options) fstype->prepare_options(&fsoptions); specfile = NULL; #ifdef CLOCK_REALTIME ch = clock_gettime(CLOCK_REALTIME, &start_time); #else ch = gettimeofday(&start, NULL); start_time.tv_sec = start.tv_sec; start_time.tv_nsec = start.tv_usec * 1000; #endif if (ch == -1) err(1, "Unable to get system time"); while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:O:o:pR:s:S:t:T:xZ")) != -1) { switch (ch) { case 'B': if (strcmp(optarg, "be") == 0 || strcmp(optarg, "4321") == 0 || strcmp(optarg, "big") == 0) { #if BYTE_ORDER == LITTLE_ENDIAN fsoptions.needswap = 1; #endif } else if (strcmp(optarg, "le") == 0 || strcmp(optarg, "1234") == 0 || strcmp(optarg, "little") == 0) { #if BYTE_ORDER == BIG_ENDIAN fsoptions.needswap = 1; #endif } else { warnx("Invalid endian `%s'.", optarg); usage(fstype, &fsoptions); } break; case 'b': len = strlen(optarg) - 1; if (optarg[len] == '%') { optarg[len] = '\0'; fsoptions.freeblockpc = strsuftoll("free block percentage", optarg, 0, 99); } else { fsoptions.freeblocks = strsuftoll("free blocks", optarg, 0, LLONG_MAX); } break; case 'D': dupsok = 1; break; case 'd': debug = strtoll(optarg, NULL, 0); break; case 'f': len = strlen(optarg) - 1; if (optarg[len] == '%') { optarg[len] = '\0'; fsoptions.freefilepc = strsuftoll("free file percentage", optarg, 0, 99); } else { fsoptions.freefiles = strsuftoll("free files", optarg, 0, LLONG_MAX); } break; case 'F': specfile = optarg; break; case 'M': fsoptions.minsize = strsuftoll("minimum size", optarg, 1LL, LLONG_MAX); break; case 'N': if (! setup_getid(optarg)) errx(1, "Unable to use user and group databases in `%s'", optarg); break; case 'm': fsoptions.maxsize = strsuftoll("maximum size", optarg, 1LL, LLONG_MAX); break; case 'O': fsoptions.offset = strsuftoll("offset", optarg, 0LL, LLONG_MAX); break; case 'o': { char *p; while ((p = strsep(&optarg, ",")) != NULL) { if (*p == '\0') errx(1, "Empty option"); if (! fstype->parse_options(p, &fsoptions)) usage(fstype, &fsoptions); } break; } case 'p': /* Deprecated in favor of 'Z' */ fsoptions.sparse = 1; break; case 'R': /* Round image size up to specified block size */ fsoptions.roundup = strsuftoll("roundup-size", optarg, 0, LLONG_MAX); break; case 's': fsoptions.minsize = fsoptions.maxsize = strsuftoll("size", optarg, 1LL, LLONG_MAX); break; case 'S': fsoptions.sectorsize = (int)strsuftoll("sector size", optarg, 1LL, INT_MAX); break; case 't': /* Check current one and cleanup if necessary. */ if (fstype->cleanup_options) fstype->cleanup_options(&fsoptions); fsoptions.fs_specific = NULL; if ((fstype = get_fstype(optarg)) == NULL) errx(1, "Unknown fs type `%s'.", optarg); fstype->prepare_options(&fsoptions); break; case 'T': if (get_tstamp(optarg, &stampst) == -1) errx(1, "Cannot get timestamp from `%s'", optarg); break; case 'x': fsoptions.onlyspec = 1; break; case 'Z': /* Superscedes 'p' for compatibility with NetBSD makefs(8) */ fsoptions.sparse = 1; break; case '?': default: usage(fstype, &fsoptions); /* NOTREACHED */ } } if (debug) { printf("debug mask: 0x%08x\n", debug); printf("start time: %ld.%ld, %s", (long)start_time.tv_sec, (long)start_time.tv_nsec, ctime(&start_time.tv_sec)); } argc -= optind; argv += optind; if (argc < 2) usage(fstype, &fsoptions); /* -x must be accompanied by -F */ if (fsoptions.onlyspec != 0 && specfile == NULL) errx(1, "-x requires -F mtree-specfile."); /* Accept '-' as meaning "read from standard input". */ if (strcmp(argv[1], "-") == 0) sb.st_mode = S_IFREG; else { if (stat(argv[1], &sb) == -1) err(1, "Can't stat `%s'", argv[1]); } switch (sb.st_mode & S_IFMT) { case S_IFDIR: /* walk the tree */ subtree = argv[1]; TIMER_START(start); root = walk_dir(subtree, ".", NULL, NULL); TIMER_RESULTS(start, "walk_dir"); break; case S_IFREG: /* read the manifest file */ subtree = "."; TIMER_START(start); root = read_mtree(argv[1], NULL); TIMER_RESULTS(start, "manifest"); break; default: errx(1, "%s: not a file or directory", argv[1]); /* NOTREACHED */ } /* append extra directory */ for (i = 2; i < argc; i++) { if (stat(argv[i], &sb) == -1) err(1, "Can't stat `%s'", argv[i]); if (!S_ISDIR(sb.st_mode)) errx(1, "%s: not a directory", argv[i]); TIMER_START(start); root = walk_dir(argv[i], ".", NULL, root); TIMER_RESULTS(start, "walk_dir2"); } if (specfile) { /* apply a specfile */ TIMER_START(start); apply_specfile(specfile, subtree, root, fsoptions.onlyspec); TIMER_RESULTS(start, "apply_specfile"); } if (debug & DEBUG_DUMP_FSNODES) { printf("\nparent: %s\n", subtree); dump_fsnodes(root); putchar('\n'); } /* build the file system */ TIMER_START(start); fstype->make_fs(argv[0], subtree, root, &fsoptions); TIMER_RESULTS(start, "make_fs"); free_fsnodes(root); exit(0); /* NOTREACHED */ } int set_option(const option_t *options, const char *option, char *buf, size_t len) { char *var, *val; int retval; assert(option != NULL); var = estrdup(option); for (val = var; *val; val++) if (*val == '=') { *val++ = '\0'; break; } retval = set_option_var(options, var, val, buf, len); free(var); return retval; } int set_option_var(const option_t *options, const char *var, const char *val, char *buf, size_t len) { char *s; size_t i; #define NUM(type) \ if (!*val) { \ *(type *)options[i].value = 1; \ break; \ } \ *(type *)options[i].value = (type)strsuftoll(options[i].desc, val, \ options[i].minimum, options[i].maximum); break for (i = 0; options[i].name != NULL; i++) { if (var[1] == '\0') { if (options[i].letter != var[0]) continue; } else if (strcmp(options[i].name, var) != 0) continue; switch (options[i].type) { case OPT_BOOL: *(bool *)options[i].value = 1; break; case OPT_STRARRAY: strlcpy((void *)options[i].value, val, (size_t) options[i].maximum); break; case OPT_STRPTR: s = estrdup(val); *(char **)options[i].value = s; break; case OPT_STRBUF: if (buf == NULL) abort(); strlcpy(buf, val, len); break; case OPT_INT64: NUM(uint64_t); case OPT_INT32: NUM(uint32_t); case OPT_INT16: NUM(uint16_t); case OPT_INT8: NUM(uint8_t); default: warnx("Unknown type %d in option %s", options[i].type, val); return 0; } return i; } warnx("Unknown option `%s'", var); return -1; } static fstype_t * get_fstype(const char *type) { int i; for (i = 0; fstypes[i].type != NULL; i++) if (strcmp(fstypes[i].type, type) == 0) return (&fstypes[i]); return (NULL); } option_t * copy_opts(const option_t *o) { size_t i; for (i = 0; o[i].name; i++) continue; i++; return memcpy(ecalloc(i, sizeof(*o)), o, i * sizeof(*o)); } static int get_tstamp(const char *b, struct stat *st) { time_t when; char *eb; long long l; if (stat(b, st) != -1) return 0; { errno = 0; l = strtoll(b, &eb, 0); if (b == eb || *eb || errno) return -1; when = (time_t)l; } st->st_ino = 1; #ifdef HAVE_STRUCT_STAT_BIRTHTIME st->st_birthtime = #endif st->st_mtime = st->st_ctime = st->st_atime = when; return 0; } static void usage(fstype_t *fstype, fsinfo_t *fsoptions) { const char *prog; prog = getprogname(); fprintf(stderr, "Usage: %s [-xZ] [-B endian] [-b free-blocks] [-d debug-mask]\n" "\t[-F mtree-specfile] [-f free-files] [-M minimum-size] [-m maximum-size]\n" "\t[-N userdb-dir] [-O offset] [-o fs-options] [-R roundup-size]\n" "\t[-S sector-size] [-s image-size] [-T ] [-t fs-type]\n" "\timage-file directory | manifest [extra-directory ...]\n", prog); if (fstype) { size_t i; option_t *o = fsoptions->fs_options; fprintf(stderr, "\n%s specific options:\n", fstype->type); for (i = 0; o[i].name != NULL; i++) fprintf(stderr, "\t%c%c%20.20s\t%s\n", o[i].letter ? o[i].letter : ' ', o[i].letter ? ',' : ' ', o[i].name, o[i].desc); } exit(1); } Index: head/usr.sbin/makefs/makefs.h =================================================================== --- head/usr.sbin/makefs/makefs.h (revision 351272) +++ head/usr.sbin/makefs/makefs.h (revision 351273) @@ -1,304 +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(ffs); 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); fsinode *link_check(fsinode *); #endif /* _MAKEFS_H */ Index: head/usr.sbin/makefs/msdos/Makefile.inc =================================================================== --- head/usr.sbin/makefs/msdos/Makefile.inc (nonexistent) +++ head/usr.sbin/makefs/msdos/Makefile.inc (revision 351273) @@ -0,0 +1,13 @@ +# $FreeBSD$ +# + +MSDOS= ${SRCTOP}/sys/fs/msdosfs +MSDOS_NEWFS= ${SRCTOP}/sbin/newfs_msdos + +.PATH: ${SRCDIR}/msdos ${MSDOS} ${MSDOS_NEWFS} + +CFLAGS+= -I${MSDOS} -I${MSDOS_NEWFS} + +SRCS+= mkfs_msdos.c +SRCS+= msdosfs_conv.c msdosfs_denode.c msdosfs_fat.c msdosfs_lookup.c +SRCS+= msdosfs_vnops.c msdosfs_vfsops.c Property changes on: head/usr.sbin/makefs/msdos/Makefile.inc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.sbin/makefs/msdos/denode.h =================================================================== --- head/usr.sbin/makefs/msdos/denode.h (nonexistent) +++ head/usr.sbin/makefs/msdos/denode.h (revision 351273) @@ -0,0 +1,237 @@ +/* $FreeBSD$ */ +/* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ +#ifndef _FS_MSDOSFS_DENODE_H_ +#define _FS_MSDOSFS_DENODE_H_ + +/* + * This is the pc filesystem specific portion of the vnode structure. + * + * To describe a file uniquely the de_dirclust, de_diroffset, and + * de_StartCluster fields are used. + * + * de_dirclust contains the cluster number of the directory cluster + * containing the entry for a file or directory. + * de_diroffset is the index into the cluster for the entry describing + * a file or directory. + * de_StartCluster is the number of the first cluster of the file or directory. + * + * Now to describe the quirks of the pc filesystem. + * - Clusters 0 and 1 are reserved. + * - The first allocatable cluster is 2. + * - The root directory is of fixed size and all blocks that make it up + * are contiguous. + * - Cluster 0 refers to the root directory when it is found in the + * startcluster field of a directory entry that points to another directory. + * - Cluster 0 implies a 0 length file when found in the start cluster field + * of a directory entry that points to a file. + * - You can't use the cluster number 0 to derive the address of the root + * directory. + * - Multiple directory entries can point to a directory. The entry in the + * parent directory points to a child directory. Any directories in the + * child directory contain a ".." entry that points back to the parent. + * The child directory itself contains a "." entry that points to itself. + * - The root directory does not contain a "." or ".." entry. + * - Directory entries for directories are never changed once they are created + * (except when removed). The size stays 0, and the last modification time + * is never changed. This is because so many directory entries can point to + * the physical clusters that make up a directory. It would lead to an + * update nightmare. + * - The length field in a directory entry pointing to a directory contains 0 + * (always). The only way to find the end of a directory is to follow the + * cluster chain until the "last cluster" marker is found. + * + * My extensions to make this house of cards work. These apply only to the in + * memory copy of the directory entry. + * - A reference count for each denode will be kept since dos doesn't keep such + * things. + */ + +/* + * Internal pseudo-offset for (nonexistent) directory entry for the root + * dir in the root dir + */ +#define MSDOSFSROOT_OFS 0x1fffffff + +/* + * The FAT cache structure. fc_fsrcn is the filesystem relative cluster + * number that corresponds to the file relative cluster number in this + * structure (fc_frcn). + */ +struct fatcache { + u_long fc_frcn; /* file relative cluster number */ + u_long fc_fsrcn; /* filesystem relative cluster number */ +}; + +/* + * The FAT entry cache as it stands helps make extending files a "quick" + * operation by avoiding having to scan the FAT to discover the last + * cluster of the file. The cache also helps sequential reads by + * remembering the last cluster read from the file. This also prevents us + * from having to rescan the FAT to find the next cluster to read. This + * cache is probably pretty worthless if a file is opened by multiple + * processes. + */ +#define FC_SIZE 3 /* number of entries in the cache */ +#define FC_LASTMAP 0 /* entry the last call to pcbmap() resolved + * to */ +#define FC_LASTFC 1 /* entry for the last cluster in the file */ +#define FC_NEXTTOLASTFC 2 /* entry for a close to the last cluster in + * the file */ + +#define FCE_EMPTY 0xffffffff /* doesn't represent an actual cluster # */ + +/* + * Set a slot in the FAT cache. + */ +#define fc_setcache(dep, slot, frcn, fsrcn) \ + (dep)->de_fc[(slot)].fc_frcn = (frcn); \ + (dep)->de_fc[(slot)].fc_fsrcn = (fsrcn); + +/* + * This is the in memory variant of a dos directory entry. It is usually + * contained within a vnode. + */ +struct denode { + struct vnode *de_vnode; /* addr of vnode we are part of */ + u_long de_flag; /* flag bits */ + u_long de_dirclust; /* cluster of the directory file containing this entry */ + u_long de_diroffset; /* offset of this entry in the directory cluster */ + u_long de_fndoffset; /* offset of found dir entry */ + int de_fndcnt; /* number of slots before de_fndoffset */ + long de_refcnt; /* reference count */ + struct msdosfsmount *de_pmp; /* addr of our mount struct */ + u_char de_Name[12]; /* name, from DOS directory entry */ + u_char de_Attributes; /* attributes, from directory entry */ + u_char de_LowerCase; /* NT VFAT lower case flags */ + u_char de_CHun; /* Hundredth of second of CTime*/ + u_short de_CTime; /* creation time */ + u_short de_CDate; /* creation date */ + u_short de_ADate; /* access date */ + u_short de_MTime; /* modification time */ + u_short de_MDate; /* modification date */ + u_long de_StartCluster; /* starting cluster of file */ + u_long de_FileSize; /* size of file in bytes */ + struct fatcache de_fc[FC_SIZE]; /* FAT cache */ + uint64_t de_inode; /* Inode number (really byte offset of direntry) */ +}; + +/* + * Values for the de_flag field of the denode. + */ +#define DE_UPDATE 0x0004 /* Modification time update request */ +#define DE_CREATE 0x0008 /* Creation time update */ +#define DE_ACCESS 0x0010 /* Access time update */ +#define DE_MODIFIED 0x0020 /* Denode has been modified */ +#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */ + +/* Maximum size of a file on a FAT filesystem */ +#define MSDOSFS_FILESIZE_MAX 0xFFFFFFFFLL + +/* + * Transfer directory entries between internal and external form. + * dep is a struct denode * (internal form), + * dp is a struct direntry * (external form). + */ +#define DE_INTERNALIZE32(dep, dp) \ + ((dep)->de_StartCluster |= getushort((dp)->deHighClust) << 16) +#define DE_INTERNALIZE(dep, dp) \ + (memcpy((dep)->de_Name, (dp)->deName, 11), \ + (dep)->de_Attributes = (dp)->deAttributes, \ + (dep)->de_LowerCase = (dp)->deLowerCase, \ + (dep)->de_CHun = (dp)->deCHundredth, \ + (dep)->de_CTime = getushort((dp)->deCTime), \ + (dep)->de_CDate = getushort((dp)->deCDate), \ + (dep)->de_ADate = getushort((dp)->deADate), \ + (dep)->de_MTime = getushort((dp)->deMTime), \ + (dep)->de_MDate = getushort((dp)->deMDate), \ + (dep)->de_StartCluster = getushort((dp)->deStartCluster), \ + (dep)->de_FileSize = getulong((dp)->deFileSize), \ + (FAT32((dep)->de_pmp) ? DE_INTERNALIZE32((dep), (dp)) : 0)) + +#define DE_EXTERNALIZE(dp, dep) \ + (memcpy((dp)->deName, (dep)->de_Name, 11), \ + (dp)->deAttributes = (dep)->de_Attributes, \ + (dp)->deLowerCase = (dep)->de_LowerCase, \ + (dp)->deCHundredth = (dep)->de_CHun, \ + putushort((dp)->deCTime, (dep)->de_CTime), \ + putushort((dp)->deCDate, (dep)->de_CDate), \ + putushort((dp)->deADate, (dep)->de_ADate), \ + putushort((dp)->deMTime, (dep)->de_MTime), \ + putushort((dp)->deMDate, (dep)->de_MDate), \ + putushort((dp)->deStartCluster, (dep)->de_StartCluster), \ + putulong((dp)->deFileSize, \ + ((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \ + putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16)) + +#define VTODE(vp) ((struct denode *)(vp)->v_data) +#define DETOV(de) ((de)->de_vnode) + +struct buf; +struct msdosfsmount; +struct direntry; +struct componentname; +struct denode; + +/* + * Internal service routine prototypes. + */ +int deget(struct msdosfsmount *, u_long, u_long, struct denode **); +int uniqdosname(struct denode *, struct componentname *, u_char *); + +int readep(struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp); +int readde(struct denode *dep, struct buf **bpp, struct direntry **epp); +int deextend(struct denode *dep, u_long length); +int fillinusemap(struct msdosfsmount *pmp); +int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp); +int removede(struct denode *pdep, struct denode *dep); +int detrunc(struct denode *dep, u_long length, int flags); +#endif /* !_FS_MSDOSFS_DENODE_H_ */ Property changes on: head/usr.sbin/makefs/msdos/denode.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos/direntry.h =================================================================== --- head/usr.sbin/makefs/msdos/direntry.h (nonexistent) +++ head/usr.sbin/makefs/msdos/direntry.h (revision 351273) @@ -0,0 +1,146 @@ +/* $FreeBSD$ */ +/* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ +#ifndef _FS_MSDOSFS_DIRENTRY_H_ +#define _FS_MSDOSFS_DIRENTRY_H_ + +/* + * Structure of a dos directory entry. + */ +struct direntry { + uint8_t deName[11]; /* filename, blank filled */ +#define SLOT_EMPTY 0x00 /* slot has never been used */ +#define SLOT_E5 0x05 /* the real value is 0xe5 */ +#define SLOT_DELETED 0xe5 /* file in this slot deleted */ + uint8_t deAttributes; /* file attributes */ +#define ATTR_NORMAL 0x00 /* normal file */ +#define ATTR_READONLY 0x01 /* file is readonly */ +#define ATTR_HIDDEN 0x02 /* file is hidden */ +#define ATTR_SYSTEM 0x04 /* file is a system file */ +#define ATTR_VOLUME 0x08 /* entry is a volume label */ +#define ATTR_DIRECTORY 0x10 /* entry is a directory name */ +#define ATTR_ARCHIVE 0x20 /* file is new or modified */ + uint8_t deLowerCase; /* NT VFAT lower case flags */ +#define LCASE_BASE 0x08 /* filename base in lower case */ +#define LCASE_EXT 0x10 /* filename extension in lower case */ + uint8_t deCHundredth; /* hundredth of seconds in CTime */ + uint8_t deCTime[2]; /* create time */ + uint8_t deCDate[2]; /* create date */ + uint8_t deADate[2]; /* access date */ + uint8_t deHighClust[2]; /* high bytes of cluster number */ + uint8_t deMTime[2]; /* last update time */ + uint8_t deMDate[2]; /* last update date */ + uint8_t deStartCluster[2]; /* starting cluster of file */ + uint8_t deFileSize[4]; /* size of file in bytes */ +}; + +/* + * Structure of a Win95 long name directory entry + */ +struct winentry { + uint8_t weCnt; +#define WIN_LAST 0x40 +#define WIN_CNT 0x3f + uint8_t wePart1[10]; + uint8_t weAttributes; +#define ATTR_WIN95 0x0f + uint8_t weReserved1; + uint8_t weChksum; + uint8_t wePart2[12]; + uint16_t weReserved2; + uint8_t wePart3[4]; +}; +#define WIN_CHARS 13 /* Number of chars per winentry */ + +/* + * Maximum number of winentries for a filename. + */ +#define WIN_MAXSUBENTRIES 20 + +/* + * Maximum filename length in Win95 + * Note: Must be < sizeof(dirent.d_name) + */ +#define WIN_MAXLEN 255 + +/* + * This is the format of the contents of the deTime field in the direntry + * structure. + * We don't use bitfields because we don't know how compilers for + * arbitrary machines will lay them out. + */ +#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ +#define DT_2SECONDS_SHIFT 0 +#define DT_MINUTES_MASK 0x7E0 /* minutes */ +#define DT_MINUTES_SHIFT 5 +#define DT_HOURS_MASK 0xF800 /* hours */ +#define DT_HOURS_SHIFT 11 + +/* + * This is the format of the contents of the deDate field in the direntry + * structure. + */ +#define DD_DAY_MASK 0x1F /* day of month */ +#define DD_DAY_SHIFT 0 +#define DD_MONTH_MASK 0x1E0 /* month */ +#define DD_MONTH_SHIFT 5 +#define DD_YEAR_MASK 0xFE00 /* year - 1980 */ +#define DD_YEAR_SHIFT 9 + +uint8_t winChksum(uint8_t *name); +int winSlotCnt(const u_char *un, size_t unlen); +int unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen); +int winChkName(const u_char *un, size_t unlen, struct winentry *wep, + int chksum); +int unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt, + int chksum); + +#endif /* !_FS_MSDOSFS_DIRENTRY_H_ */ Property changes on: head/usr.sbin/makefs/msdos/direntry.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos/fat.h =================================================================== --- head/usr.sbin/makefs/msdos/fat.h (nonexistent) +++ head/usr.sbin/makefs/msdos/fat.h (revision 351273) @@ -0,0 +1,110 @@ +/* $FreeBSD$ */ +/* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ + +#ifndef _FS_MSDOSFS_FAT_H_ +#define _FS_MSDOSFS_FAT_H_ +/* + * Some useful cluster numbers. + */ +#define MSDOSFSROOT 0 /* cluster 0 means the root dir */ +#define CLUST_FREE 0 /* cluster 0 also means a free cluster */ +#define MSDOSFSFREE CLUST_FREE +#define CLUST_FIRST 2 /* first legal cluster number */ +#define CLUST_RSRVD 0xfffffff6 /* reserved cluster range */ +#define CLUST_BAD 0xfffffff7 /* a cluster with a defect */ +#define CLUST_EOFS 0xfffffff8 /* start of eof cluster range */ +#define CLUST_EOFE 0xffffffff /* end of eof cluster range */ + +#define FAT12_MASK 0x00000fff /* mask for 12 bit cluster numbers */ +#define FAT16_MASK 0x0000ffff /* mask for 16 bit cluster numbers */ +#define FAT32_MASK 0x0fffffff /* mask for FAT32 cluster numbers */ + +/* + * MSDOSFS: + * Return true if filesystem uses 12 bit FATs. Microsoft Programmer's + * Reference says if the maximum cluster number in a filesystem is greater + * than 4084 ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK) then we've got a + * 16 bit FAT filesystem. While mounting, the result of this test is stored + * in pm_fatentrysize. + */ +#define FAT12(pmp) (pmp->pm_fatmask == FAT12_MASK) +#define FAT16(pmp) (pmp->pm_fatmask == FAT16_MASK) +#define FAT32(pmp) (pmp->pm_fatmask == FAT32_MASK) + +#define MSDOSFSEOF(pmp, cn) ((((cn) | ~(pmp)->pm_fatmask) & CLUST_EOFS) == CLUST_EOFS) + +/* + * These are the values for the function argument to the function + * fatentry(). + */ +#define FAT_GET 0x0001 /* get a FAT entry */ +#define FAT_SET 0x0002 /* set a FAT entry */ +#define FAT_GET_AND_SET (FAT_GET | FAT_SET) + +/* + * Flags to extendfile: + */ +#define DE_CLEAR 1 /* Zero out the blocks allocated */ + +struct buf; +struct denode; +struct msdosfsmount; + +int pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int* sp); +int clusterfree(struct msdosfsmount *pmp, u_long cn, u_long *oldcnp); +int clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got); +int fatentry(int function, struct msdosfsmount *pmp, u_long cluster, u_long *oldcontents, u_long newcontents); +int freeclusterchain(struct msdosfsmount *pmp, u_long startchain); +int extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags); +void fc_purge(struct denode *dep, u_int frcn); + +#endif /* !_FS_MSDOSFS_FAT_H_ */ Property changes on: head/usr.sbin/makefs/msdos/fat.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos/msdosfs_conv.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_conv.c (nonexistent) +++ head/usr.sbin/makefs/msdos/msdosfs_conv.c (revision 351273) @@ -0,0 +1,508 @@ +/*- + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/* + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include +#include + +#include + +#include "makefs.h" +#include "msdos.h" + +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + +static int char8ucs2str(const uint8_t *in, int n, uint16_t *out, int m); +static void ucs2pad(uint16_t *buf, int len, int size); +static int char8match(uint16_t *w1, uint16_t *w2, int n); + +static const u_char unix2dos[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */ + 0, '!', 0, '#', '$', '%', '&', '\'', /* 20-27 */ + '(', ')', 0, '+', 0, '-', 0, 0, /* 28-2f */ + '0', '1', '2', '3', '4', '5', '6', '7', /* 30-37 */ + '8', '9', 0, 0, 0, 0, 0, 0, /* 38-3f */ + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40-47 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 48-4f */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 50-57 */ + 'X', 'Y', 'Z', 0, 0, 0, '^', '_', /* 58-5f */ + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 60-67 */ + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 68-6f */ + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 70-77 */ + 'X', 'Y', 'Z', '{', 0, '}', '~', 0, /* 78-7f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */ + 0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */ + 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */ + 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */ + 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */ + 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */ + 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */ + 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */ + 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */ + 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */ + 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */ + 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */ + 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */ +}; + +static const u_char u2l[256] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */ + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */ + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */ + ' ', '!', '"', '#', '$', '%', '&', '\'', /* 20-27 */ + '(', ')', '*', '+', ',', '-', '.', '/', /* 28-2f */ + '0', '1', '2', '3', '4', '5', '6', '7', /* 30-37 */ + '8', '9', ':', ';', '<', '=', '>', '?', /* 38-3f */ + '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 40-47 */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 48-4f */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 50-57 */ + 'x', 'y', 'z', '[', '\\', ']', '^', '_', /* 58-5f */ + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 60-67 */ + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 68-6f */ + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 70-77 */ + 'x', 'y', 'z', '{', '|', '}', '~', 0x7f, /* 78-7f */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ +}; + +/* + * Determine the number of slots necessary for Win95 names + */ +int +winSlotCnt(const u_char *un, size_t unlen) +{ + const u_char *cp; + + /* + * Drop trailing blanks and dots + */ + for (cp = un + unlen; unlen > 0; unlen--) + if (*--cp != ' ' && *cp != '.') + break; + + return howmany(unlen, WIN_CHARS); +} + +/* + * Compare our filename to the one in the Win95 entry + * Returns the checksum or -1 if no match + */ +int +winChkName(const u_char *un, size_t unlen, struct winentry *wep, int chksum) +{ + uint16_t wn[WIN_MAXLEN], *p; + uint16_t buf[WIN_CHARS]; + int i, len; + + /* + * First compare checksums + */ + if (wep->weCnt & WIN_LAST) + chksum = wep->weChksum; + else if (chksum != wep->weChksum) + chksum = -1; + if (chksum == -1) + return -1; + + /* + * Offset of this entry + */ + i = ((wep->weCnt & WIN_CNT) - 1) * WIN_CHARS; + + /* + * Translate UNIX name to ucs-2 + */ + len = char8ucs2str(un, unlen, wn, WIN_MAXLEN); + ucs2pad(wn, len, WIN_MAXLEN); + + if (i >= len + 1) + return -1; + if ((wep->weCnt & WIN_LAST) && (len - i > WIN_CHARS)) + return -1; + + /* + * Fetch name segment from directory entry + */ + p = &buf[0]; + memcpy(p, wep->wePart1, sizeof(wep->wePart1)); + p += sizeof(wep->wePart1) / sizeof(*p); + memcpy(p, wep->wePart2, sizeof(wep->wePart2)); + p += sizeof(wep->wePart2) / sizeof(*p); + memcpy(p, wep->wePart3, sizeof(wep->wePart3)); + + /* + * And compare name segment + */ + if (!(char8match(&wn[i], buf, WIN_CHARS))) + return -1; + + return chksum; +} + +/* + * Compute the checksum of a DOS filename for Win95 use + */ +uint8_t +winChksum(uint8_t *name) +{ + int i; + uint8_t s; + + for (s = 0, i = 11; --i >= 0; s += *name++) + s = (s << 7) | (s >> 1); + return s; +} + +/* + * Create a Win95 long name directory entry + * Note: assumes that the filename is valid, + * i.e. doesn't consist solely of blanks and dots + */ +int +unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt, + int chksum) +{ + uint16_t wn[WIN_MAXLEN], *p; + int i, len; + const u_char *cp; + + /* + * Drop trailing blanks and dots + */ + for (cp = un + unlen; unlen > 0; unlen--) + if (*--cp != ' ' && *cp != '.') + break; + + /* + * Offset of this entry + */ + i = (cnt - 1) * WIN_CHARS; + + /* + * Translate UNIX name to ucs-2 + */ + len = char8ucs2str(un, unlen, wn, WIN_MAXLEN); + ucs2pad(wn, len, WIN_MAXLEN); + + /* + * Initialize winentry to some useful default + */ + memset(wep, 0xff, sizeof(*wep)); + wep->weCnt = cnt; + wep->weAttributes = ATTR_WIN95; + wep->weReserved1 = 0; + wep->weChksum = chksum; + wep->weReserved2 = 0; + + /* + * Store name segment into directory entry + */ + p = &wn[i]; + memcpy(wep->wePart1, p, sizeof(wep->wePart1)); + p += sizeof(wep->wePart1) / sizeof(*p); + memcpy(wep->wePart2, p, sizeof(wep->wePart2)); + p += sizeof(wep->wePart2) / sizeof(*p); + memcpy(wep->wePart3, p, sizeof(wep->wePart3)); + + if (len > i + WIN_CHARS) + return 1; + + wep->weCnt |= WIN_LAST; + return 0; +} + +/* + * Convert a unix filename to a DOS filename according to Win95 rules. + * If applicable and gen is not 0, it is inserted into the converted + * filename as a generation number. + * Returns + * 0 if name couldn't be converted + * 1 if the converted name is the same as the original + * (no long filename entry necessary for Win95) + * 2 if conversion was successful + * 3 if conversion was successful and generation number was inserted + */ +int +unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen) +{ + int i, j, l; + int conv = 1; + const u_char *cp, *dp, *dp1; + u_char gentext[6], *wcp; + int shortlen; + + /* + * Fill the dos filename string with blanks. These are DOS's pad + * characters. + */ + for (i = 0; i < 11; i++) + dn[i] = ' '; + dn[11] = 0; + + /* + * The filenames "." and ".." are handled specially, since they + * don't follow dos filename rules. + */ + if (un[0] == '.' && unlen == 1) { + dn[0] = '.'; + return gen <= 1; + } + if (un[0] == '.' && un[1] == '.' && unlen == 2) { + dn[0] = '.'; + dn[1] = '.'; + return gen <= 1; + } + + /* + * Filenames with only blanks and dots are not allowed! + */ + for (cp = un, i = unlen; --i >= 0; cp++) + if (*cp != ' ' && *cp != '.') + break; + if (i < 0) + return 0; + + /* + * Now find the extension + * Note: dot as first char doesn't start extension + * and trailing dots and blanks are ignored + */ + dp = dp1 = 0; + for (cp = un + 1, i = unlen - 1; --i >= 0;) { + switch (*cp++) { + case '.': + if (!dp1) + dp1 = cp; + break; + case ' ': + break; + default: + if (dp1) + dp = dp1; + dp1 = 0; + break; + } + } + + /* + * Now convert it + */ + if (dp) { + if (dp1) + l = dp1 - dp; + else + l = unlen - (dp - un); + for (i = 0, j = 8; i < l && j < 11; i++, j++) { + if (dp[i] != (dn[j] = unix2dos[dp[i]]) + && conv != 3) + conv = 2; + if (!dn[j]) { + conv = 3; + dn[j--] = ' '; + } + } + if (i < l) + conv = 3; + dp--; + } else { + for (dp = cp; *--dp == ' ' || *dp == '.';); + dp++; + } + + shortlen = (dp - un) <= 8; + + /* + * Now convert the rest of the name + */ + for (i = j = 0; un < dp && j < 8; i++, j++, un++) { + if ((*un == ' ') && shortlen) + dn[j] = ' '; + else + dn[j] = unix2dos[*un]; + if ((*un != dn[j]) + && conv != 3) + conv = 2; + if (!dn[j]) { + conv = 3; + dn[j--] = ' '; + } + } + if (un < dp) + conv = 3; + /* + * If we didn't have any chars in filename, + * generate a default + */ + if (!j) + dn[0] = '_'; + + /* + * The first character cannot be E5, + * because that means a deleted entry + */ + if (dn[0] == 0xe5) + dn[0] = SLOT_E5; + + /* + * If there wasn't any char dropped, + * there is no place for generation numbers + */ + if (conv != 3) { + if (gen > 1) + return 0; + return conv; + } + + /* + * Now insert the generation number into the filename part + */ + for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10) + *--wcp = gen % 10 + '0'; + if (gen) + return 0; + for (i = 8; dn[--i] == ' ';); + i++; + if (gentext + sizeof(gentext) - wcp + 1 > 8 - i) + i = 8 - (gentext + sizeof(gentext) - wcp + 1); + dn[i++] = '~'; + while (wcp < gentext + sizeof(gentext)) + dn[i++] = *wcp++; + return 3; +} + +/* + * Convert 8bit character string into UCS-2 string + * return total number of output chacters + */ +static int +char8ucs2str(const uint8_t *in, int n, uint16_t *out, int m) +{ + uint16_t *p; + + p = out; + while (n > 0 && in[0] != 0) { + if (m < 1) + break; + if (p) + p[0] = htole16(in[0]); + p += 1; + m -= 1; + in += 1; + n -= 1; + } + + return p - out; +} + +static void +ucs2pad(uint16_t *buf, int len, int size) +{ + + if (len < size-1) + buf[len++] = 0x0000; + while (len < size) + buf[len++] = 0xffff; +} + +/* + * Compare two 8bit char conversions case-insensitive + * + * uses the DOS case folding table + */ +static int +char8match(uint16_t *w1, uint16_t *w2, int n) +{ + uint16_t u1, u2; + + while (n > 0) { + u1 = le16toh(*w1); + u2 = le16toh(*w2); + if (u1 == 0 || u2 == 0) + return u1 == u2; + if (u1 > 255 || u2 > 255) + return 0; + u1 = u2l[u1 & 0xff]; + u2 = u2l[u2 & 0xff]; + if (u1 != u2) + return 0; + ++w1; + ++w2; + --n; + } + + return 1; +} Property changes on: head/usr.sbin/makefs/msdos/msdosfs_conv.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/usr.sbin/makefs/msdos/msdosfs_denode.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_denode.c (revision 351272) +++ head/usr.sbin/makefs/msdos/msdosfs_denode.c (revision 351273) @@ -1,363 +1,380 @@ /* $NetBSD: msdosfs_denode.c,v 1.7 2015/03/29 05:52:59 agc Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. * Copyright (C) 1994, 1995, 1997 TooLs GmbH. * All rights reserved. * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). * * 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 by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. */ /* * Written by Paul Popelka (paulp@uts.amdahl.com) * * You can do anything you want with this software, just don't say you wrote * it, and don't remove this notice. * * This software is provided "as is". * * The author supplies this software to be publicly redistributed on the * understanding that the author is not responsible for the correct * functioning of this software in any circumstances and is not liable for * any damages caused by this software. * * October 1992 */ -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif - #include __FBSDID("$FreeBSD$"); #include +#include +#include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include +#include "makefs.h" +#include "msdos.h" +#include "ffs/buf.h" + +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + /* * If deget() succeeds it returns with the gotten denode locked(). * * pmp - address of msdosfsmount structure of the filesystem containing * the denode of interest. The pm_dev field and the address of * the msdosfsmount structure are used. * dirclust - which cluster bp contains, if dirclust is 0 (root directory) * diroffset is relative to the beginning of the root directory, * otherwise it is cluster relative. * diroffset - offset past begin of cluster of denode we want * depp - returns the address of the gotten denode. */ int deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, struct denode **depp) - /* pmp: so we know the maj/min number */ - /* dirclust: cluster this dir entry came from */ - /* diroffset: index of entry within the cluster */ - /* depp: returns the addr of the gotten denode */ { int error; + uint64_t inode; struct direntry *direntptr; struct denode *ldep; struct buf *bp; -#ifdef MSDOSFS_DEBUG - printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n", - pmp, dirclust, diroffset, depp); -#endif + MSDOSFS_DPRINTF(("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n", + pmp, dirclust, diroffset, depp)); /* * On FAT32 filesystems, root is a (more or less) normal * directory */ if (FAT32(pmp) && dirclust == MSDOSFSROOT) dirclust = pmp->pm_rootdirblk; + inode = (uint64_t)pmp->pm_bpcluster * dirclust + diroffset; + ldep = ecalloc(1, sizeof(*ldep)); ldep->de_vnode = NULL; ldep->de_flag = 0; - ldep->de_devvp = 0; - ldep->de_lockf = 0; - ldep->de_dev = pmp->pm_dev; ldep->de_dirclust = dirclust; ldep->de_diroffset = diroffset; + ldep->de_inode = inode; ldep->de_pmp = pmp; - ldep->de_devvp = pmp->pm_devvp; ldep->de_refcnt = 1; - fc_purge(ldep, 0); + fc_purge(ldep, 0); /* init the FAT cache for this denode */ /* * Copy the directory entry into the denode area of the vnode. */ if ((dirclust == MSDOSFSROOT || (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)) && diroffset == MSDOSFSROOT_OFS) { /* * Directory entry for the root directory. There isn't one, * so we manufacture one. We should probably rummage * through the root directory and find a label entry (if it * exists), and then use the time and date from that entry * as the time and date for the root denode. */ ldep->de_vnode = (struct vnode *)-1; ldep->de_Attributes = ATTR_DIRECTORY; + ldep->de_LowerCase = 0; if (FAT32(pmp)) ldep->de_StartCluster = pmp->pm_rootdirblk; /* de_FileSize will be filled in further down */ else { ldep->de_StartCluster = MSDOSFSROOT; - ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec; + ldep->de_FileSize = pmp->pm_rootdirsize * DEV_BSIZE; } /* * fill in time and date so that dos2unixtime() doesn't * spit up when called from msdosfs_getattr() with root * denode */ ldep->de_CHun = 0; ldep->de_CTime = 0x0000; /* 00:00:00 */ ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT) | (1 << DD_DAY_SHIFT); /* Jan 1, 1980 */ ldep->de_ADate = ldep->de_CDate; ldep->de_MTime = ldep->de_CTime; ldep->de_MDate = ldep->de_CDate; /* leave the other fields as garbage */ } else { error = readep(pmp, dirclust, diroffset, &bp, &direntptr); if (error) { - ldep->de_devvp = NULL; ldep->de_Name[0] = SLOT_DELETED; + + *depp = NULL; return (error); } - DE_INTERNALIZE(ldep, direntptr); + (void)DE_INTERNALIZE(ldep, direntptr); brelse(bp); } /* * Fill in a few fields of the vnode and finish filling in the * denode. Then return the address of the found denode. */ if (ldep->de_Attributes & ATTR_DIRECTORY) { /* * Since DOS directory entries that describe directories * have 0 in the filesize field, we take this opportunity * to find out the length of the directory and plug it into * the denode structure. */ u_long size; + /* + * XXX it sometimes happens that the "." entry has cluster + * number 0 when it shouldn't. Use the actual cluster number + * instead of what is written in directory entry. + */ + if (diroffset == 0 && ldep->de_StartCluster != dirclust) { + MSDOSFS_DPRINTF(("deget(): \".\" entry at clust %lu != %lu\n", + dirclust, ldep->de_StartCluster)); + + ldep->de_StartCluster = dirclust; + } + if (ldep->de_StartCluster != MSDOSFSROOT) { - error = pcbmap(ldep, CLUST_END, 0, &size, 0); + error = pcbmap(ldep, 0xffff, 0, &size, 0); if (error == E2BIG) { ldep->de_FileSize = de_cn2off(pmp, size); error = 0; - } else - printf("deget(): pcbmap returned %d\n", error); + } else { + MSDOSFS_DPRINTF(("deget(): pcbmap returned %d\n", + error)); + } } } *depp = ldep; return (0); } /* * Truncate the file described by dep to the length specified by length. */ int -detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred) +detrunc(struct denode *dep, u_long length, int flags) { int error; - int allerror = 0; + int allerror; u_long eofentry; - u_long chaintofree = 0; - daddr_t bn, lastblock; + u_long chaintofree; + daddr_t bn; int boff; int isadir = dep->de_Attributes & ATTR_DIRECTORY; struct buf *bp; struct msdosfsmount *pmp = dep->de_pmp; -#ifdef MSDOSFS_DEBUG - printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags); -#endif + MSDOSFS_DPRINTF(("detrunc(): file %s, length %lu, flags %x\n", + dep->de_Name, length, flags)); /* * Disallow attempts to truncate the root directory since it is of * fixed size. That's just the way dos filesystems are. We use * the VROOT bit in the vnode because checking for the directory * bit and a startcluster of 0 in the denode is not adequate to * recognize the root directory at this point in a file or * directory's life. */ if (dep->de_vnode != NULL && !FAT32(pmp)) { - printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n", - dep->de_dirclust, dep->de_diroffset); + MSDOSFS_DPRINTF(("detrunc(): can't truncate root directory, " + "clust %ld, offset %ld\n", + dep->de_dirclust, dep->de_diroffset)); + return (EINVAL); } if (dep->de_FileSize < length) - return (deextend(dep, length, cred)); - lastblock = de_clcount(pmp, length) - 1; + return deextend(dep, length); /* * If the desired length is 0 then remember the starting cluster of * the file and set the StartCluster field in the directory entry * to 0. If the desired length is not zero, then get the number of * the last cluster in the shortened file. Then get the number of * the first cluster in the part of the file that is to be freed. * Then set the next cluster pointer in the last cluster of the * file to CLUST_EOFE. */ if (length == 0) { chaintofree = dep->de_StartCluster; dep->de_StartCluster = 0; eofentry = ~0; } else { - error = pcbmap(dep, lastblock, 0, &eofentry, 0); + error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, + &eofentry, 0); if (error) { -#ifdef MSDOSFS_DEBUG - printf("detrunc(): pcbmap fails %d\n", error); -#endif - return (error); + MSDOSFS_DPRINTF(("detrunc(): pcbmap fails %d\n", + error)); + return error; } } + fc_purge(dep, de_clcount(pmp, length)); + /* * If the new length is not a multiple of the cluster size then we * must zero the tail end of the new last cluster in case it * becomes part of the file again because of a seek. */ if ((boff = length & pmp->pm_crbomask) != 0) { if (isadir) { bn = cntobn(pmp, eofentry); - error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), - pmp->pm_bpcluster, B_MODIFY, &bp); + error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, + 0, &bp); if (error) { -#ifdef MSDOSFS_DEBUG - printf("detrunc(): bread fails %d\n", error); -#endif - return (error); + brelse(bp); + MSDOSFS_DPRINTF(("detrunc(): bread fails %d\n", + error)); + + return error; } memset((char *)bp->b_data + boff, 0, pmp->pm_bpcluster - boff); if (flags & IO_SYNC) bwrite(bp); else bdwrite(bp); } } /* * Write out the updated directory entry. Even if the update fails * we free the trailing clusters. */ dep->de_FileSize = length; if (!isadir) dep->de_flag |= DE_UPDATE|DE_MODIFIED; -#ifdef MSDOSFS_DEBUG - printf("detrunc(): allerror %d, eofentry %lu\n", - allerror, eofentry); -#endif + MSDOSFS_DPRINTF(("detrunc(): allerror %d, eofentry %lu\n", + allerror, eofentry)); /* * If we need to break the cluster chain for the file then do it * now. */ - if (eofentry != (u_long)~0) { + if (eofentry != ~0) { error = fatentry(FAT_GET_AND_SET, pmp, eofentry, &chaintofree, CLUST_EOFE); if (error) { -#ifdef MSDOSFS_DEBUG - printf("detrunc(): fatentry errors %d\n", error); -#endif + MSDOSFS_DPRINTF(("detrunc(): fatentry errors %d\n", + error)); return (error); } + fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1), + eofentry); } /* * Now free the clusters removed from the file because of the * truncation. */ - if (chaintofree != 0 && !MSDOSFSEOF(chaintofree, pmp->pm_fatmask)) + if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree)) freeclusterchain(pmp, chaintofree); - return (allerror); + return allerror; } /* * Extend the file described by dep to length specified by length. */ int -deextend(struct denode *dep, u_long length, struct kauth_cred *cred) +deextend(struct denode *dep, u_long length) { struct msdosfsmount *pmp = dep->de_pmp; u_long count; int error; /* * The root of a DOS filesystem cannot be extended. */ if (dep->de_vnode != NULL && !FAT32(pmp)) return EINVAL; /* * Directories cannot be extended. */ if (dep->de_Attributes & ATTR_DIRECTORY) return EISDIR; if (length <= dep->de_FileSize) return E2BIG; /* * Compute the number of clusters to allocate. */ count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize); if (count > 0) { if (count > pmp->pm_freeclustercount) return (ENOSPC); error = extendfile(dep, count, NULL, NULL, DE_CLEAR); if (error) { /* truncate the added clusters away again */ - (void) detrunc(dep, dep->de_FileSize, 0, cred); + (void) detrunc(dep, dep->de_FileSize, 0); return (error); } } /* * Zero extend file range; ubc_zerorange() uses ubc_alloc() and a * memset(); we set the write size so ubc won't read in file data that * is zero'd later. */ dep->de_FileSize = length; - dep->de_flag |= DE_UPDATE|DE_MODIFIED; + dep->de_flag |= DE_UPDATE | DE_MODIFIED; return 0; } Index: head/usr.sbin/makefs/msdos/msdosfs_fat.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_fat.c (nonexistent) +++ head/usr.sbin/makefs/msdos/msdosfs_fat.c (revision 351273) @@ -0,0 +1,1045 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ + +#include +#include + +#include +#include +#include +#include + +#include + +#include "ffs/buf.h" + +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + +#include "makefs.h" +#include "msdos.h" + +#define FULL_RUN ((u_int)0xffffffff) +#define SYNCHRONOUS_WRITES(pmp) 1 + +static int chainalloc(struct msdosfsmount *pmp, u_long start, + u_long count, u_long fillwith, u_long *retcluster, + u_long *got); +static int chainlength(struct msdosfsmount *pmp, u_long start, + u_long count); +static void fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, + u_long *sizep, u_long *bop); +static int fatchain(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith); +static void fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, + u_long *fsrcnp); +static void updatefats(struct msdosfsmount *pmp, struct buf *bp, + u_long fatbn); +static __inline void + usemap_alloc(struct msdosfsmount *pmp, u_long cn); +static __inline void + usemap_free(struct msdosfsmount *pmp, u_long cn); +static int clusteralloc1(struct msdosfsmount *pmp, u_long start, + u_long count, u_long fillwith, u_long *retcluster, + u_long *got); + +static void +fatblock(struct msdosfsmount *pmp, u_long ofs, u_long *bnp, u_long *sizep, + u_long *bop) +{ + u_long bn, size; + + bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; + size = MIN(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) + * DEV_BSIZE; + bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs; + + if (bnp) + *bnp = bn; + if (sizep) + *sizep = size; + if (bop) + *bop = ofs % pmp->pm_fatblocksize; +} + +/* + * Map the logical cluster number of a file into a physical disk sector + * that is filesystem relative. + * + * dep - address of denode representing the file of interest + * findcn - file relative cluster whose filesystem relative cluster number + * and/or block number are/is to be found + * bnp - address of where to place the filesystem relative block number. + * If this pointer is null then don't return this quantity. + * cnp - address of where to place the filesystem relative cluster number. + * If this pointer is null then don't return this quantity. + * sp - pointer to returned block size + * + * NOTE: Either bnp or cnp must be non-null. + * This function has one side effect. If the requested file relative cluster + * is beyond the end of file, then the actual number of clusters in the file + * is returned in *cnp. This is useful for determining how long a directory is. + * If cnp is null, nothing is returned. + */ +int +pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int *sp) +{ + int error; + u_long i; + u_long cn; + u_long prevcn = 0; /* XXX: prevcn could be used unititialized */ + u_long byteoffset; + u_long bn; + u_long bo; + struct buf *bp = NULL; + u_long bp_bn = -1; + struct msdosfsmount *pmp = dep->de_pmp; + u_long bsize; + + assert(bnp != NULL || cnp != NULL || sp != NULL); + + cn = dep->de_StartCluster; + /* + * The "file" that makes up the root directory is contiguous, + * permanently allocated, of fixed size, and is not made up of + * clusters. If the cluster number is beyond the end of the root + * directory, then return the number of clusters in the file. + */ + if (cn == MSDOSFSROOT) { + if (dep->de_Attributes & ATTR_DIRECTORY) { + if (de_cn2off(pmp, findcn) >= dep->de_FileSize) { + if (cnp) + *cnp = de_bn2cn(pmp, pmp->pm_rootdirsize); + return (E2BIG); + } + if (bnp) + *bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn); + if (cnp) + *cnp = MSDOSFSROOT; + if (sp) + *sp = MIN(pmp->pm_bpcluster, + dep->de_FileSize - de_cn2off(pmp, findcn)); + return (0); + } else { /* just an empty file */ + if (cnp) + *cnp = 0; + return (E2BIG); + } + } + + /* + * All other files do I/O in cluster sized blocks + */ + if (sp) + *sp = pmp->pm_bpcluster; + + /* + * Rummage around in the FAT cache, maybe we can avoid tromping + * through every FAT entry for the file. And, keep track of how far + * off the cache was from where we wanted to be. + */ + i = 0; + fc_lookup(dep, findcn, &i, &cn); + + /* + * Handle all other files or directories the normal way. + */ + for (; i < findcn; i++) { + /* + * Stop with all reserved clusters, not just with EOF. + */ + if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) + goto hiteof; + byteoffset = FATOFS(pmp, cn); + fatblock(pmp, byteoffset, &bn, &bsize, &bo); + if (bn != bp_bn) { + if (bp) + brelse(bp); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + bp_bn = bn; + } + prevcn = cn; + if (bo >= bsize) { + if (bp) + brelse(bp); + return (EIO); + } + if (FAT32(pmp)) + cn = getulong(&bp->b_data[bo]); + else + cn = getushort(&bp->b_data[bo]); + if (FAT12(pmp) && (prevcn & 1)) + cn >>= 4; + cn &= pmp->pm_fatmask; + + /* + * Force the special cluster numbers + * to be the same for all cluster sizes + * to let the rest of msdosfs handle + * all cases the same. + */ + if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD) + cn |= ~pmp->pm_fatmask; + } + + if (!MSDOSFSEOF(pmp, cn)) { + if (bp) + brelse(bp); + if (bnp) + *bnp = cntobn(pmp, cn); + if (cnp) + *cnp = cn; + fc_setcache(dep, FC_LASTMAP, i, cn); + return (0); + } + +hiteof:; + if (cnp) + *cnp = i; + if (bp) + brelse(bp); + /* update last file cluster entry in the FAT cache */ + fc_setcache(dep, FC_LASTFC, i - 1, prevcn); + return (E2BIG); +} + +/* + * Find the closest entry in the FAT cache to the cluster we are looking + * for. + */ +static void +fc_lookup(struct denode *dep, u_long findcn, u_long *frcnp, u_long *fsrcnp) +{ + int i; + u_long cn; + struct fatcache *closest = NULL; + + for (i = 0; i < FC_SIZE; i++) { + cn = dep->de_fc[i].fc_frcn; + if (cn != FCE_EMPTY && cn <= findcn) { + if (closest == NULL || cn > closest->fc_frcn) + closest = &dep->de_fc[i]; + } + } + if (closest) { + *frcnp = closest->fc_frcn; + *fsrcnp = closest->fc_fsrcn; + } +} + +/* + * Purge the FAT cache in denode dep of all entries relating to file + * relative cluster frcn and beyond. + */ +void +fc_purge(struct denode *dep, u_int frcn) +{ + int i; + struct fatcache *fcp; + + fcp = dep->de_fc; + for (i = 0; i < FC_SIZE; i++, fcp++) { + if (fcp->fc_frcn >= frcn) + fcp->fc_frcn = FCE_EMPTY; + } +} + +/* + * Update the FAT. + * If mirroring the FAT, update all copies, with the first copy as last. + * Else update only the current FAT (ignoring the others). + * + * pmp - msdosfsmount structure for filesystem to update + * bp - addr of modified FAT block + * fatbn - block number relative to begin of filesystem of the modified FAT block. + */ +static void +updatefats(struct msdosfsmount *pmp, struct buf *bp, u_long fatbn) +{ + struct buf *bpn; + int cleanfat, i; + +#ifdef MSDOSFS_DEBUG + printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", pmp, bp, fatbn); +#endif + + if (pmp->pm_flags & MSDOSFS_FATMIRROR) { + /* + * Now copy the block(s) of the modified FAT to the other copies of + * the FAT and write them out. This is faster than reading in the + * other FATs and then writing them back out. This could tie up + * the FAT for quite a while. Preventing others from accessing it. + * To prevent us from going after the FAT quite so much we use + * delayed writes, unless they specified "synchronous" when the + * filesystem was mounted. If synch is asked for then use + * bwrite()'s and really slow things down. + */ + if (fatbn != pmp->pm_fatblk || FAT12(pmp)) + cleanfat = 0; + else if (FAT16(pmp)) + cleanfat = 16; + else + cleanfat = 32; + for (i = 1; i < pmp->pm_FATs; i++) { + fatbn += pmp->pm_FATsecs; + /* getblk() never fails */ + bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, + 0, 0, 0); + memcpy(bpn->b_data, bp->b_data, bp->b_bcount); + /* Force the clean bit on in the other copies. */ + if (cleanfat == 16) + ((uint8_t *)bpn->b_data)[3] |= 0x80; + else if (cleanfat == 32) + ((uint8_t *)bpn->b_data)[7] |= 0x08; + if (SYNCHRONOUS_WRITES(pmp)) + bwrite(bpn); + else + bdwrite(bpn); + } + } + + /* + * Write out the first (or current) FAT last. + */ + if (SYNCHRONOUS_WRITES(pmp)) + bwrite(bp); + else + bdwrite(bp); +} + +/* + * Updating entries in 12 bit FATs is a pain in the butt. + * + * The following picture shows where nibbles go when moving from a 12 bit + * cluster number into the appropriate bytes in the FAT. + * + * byte m byte m+1 byte m+2 + * +----+----+ +----+----+ +----+----+ + * | 0 1 | | 2 3 | | 4 5 | FAT bytes + * +----+----+ +----+----+ +----+----+ + * + * +----+----+----+ +----+----+----+ + * | 3 0 1 | | 4 5 2 | + * +----+----+----+ +----+----+----+ + * cluster n cluster n+1 + * + * Where n is even. m = n + (n >> 2) + * + */ +static __inline void +usemap_alloc(struct msdosfsmount *pmp, u_long cn) +{ + + assert(cn <= pmp->pm_maxcluster); + assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0); + assert((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS))) + == 0); + assert(pmp->pm_freeclustercount > 0); + + pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS); + pmp->pm_freeclustercount--; + pmp->pm_flags |= MSDOSFS_FSIMOD; +} + +static __inline void +usemap_free(struct msdosfsmount *pmp, u_long cn) +{ + + assert(cn <= pmp->pm_maxcluster); + assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0); + assert((pmp->pm_inusemap[cn / N_INUSEBITS] & (1 << (cn % N_INUSEBITS))) + != 0); + + pmp->pm_freeclustercount++; + pmp->pm_flags |= MSDOSFS_FSIMOD; + pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1U << (cn % N_INUSEBITS)); +} + +int +clusterfree(struct msdosfsmount *pmp, u_long cluster, u_long *oldcnp) +{ + int error; + u_long oldcn; + + error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE); + if (error) + return (error); + /* + * If the cluster was successfully marked free, then update + * the count of free clusters, and turn off the "allocated" + * bit in the "in use" cluster bit map. + */ + usemap_free(pmp, cluster); + if (oldcnp) + *oldcnp = oldcn; + return (0); +} + +/* + * Get or Set or 'Get and Set' the cluster'th entry in the FAT. + * + * function - whether to get or set a FAT entry + * pmp - address of the msdosfsmount structure for the filesystem + * whose FAT is to be manipulated. + * cn - which cluster is of interest + * oldcontents - address of a word that is to receive the contents of the + * cluster'th entry if this is a get function + * newcontents - the new value to be written into the cluster'th element of + * the FAT if this is a set function. + * + * This function can also be used to free a cluster by setting the FAT entry + * for a cluster to 0. + * + * All copies of the FAT are updated if this is a set function. NOTE: If + * fatentry() marks a cluster as free it does not update the inusemap in + * the msdosfsmount structure. This is left to the caller. + */ +int +fatentry(int function, struct msdosfsmount *pmp, u_long cn, u_long *oldcontents, + u_long newcontents) +{ + int error; + u_long readcn; + u_long bn, bo, bsize, byteoffset; + struct buf *bp; + +#ifdef MSDOSFS_DEBUG + printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n", + function, pmp, cn, oldcontents, newcontents); +#endif + +#ifdef DIAGNOSTIC + /* + * Be sure they asked us to do something. + */ + if ((function & (FAT_SET | FAT_GET)) == 0) { +#ifdef MSDOSFS_DEBUG + printf("fatentry(): function code doesn't specify get or set\n"); +#endif + return (EINVAL); + } + + /* + * If they asked us to return a cluster number but didn't tell us + * where to put it, give them an error. + */ + if ((function & FAT_GET) && oldcontents == NULL) { +#ifdef MSDOSFS_DEBUG + printf("fatentry(): get function with no place to put result\n"); +#endif + return (EINVAL); + } +#endif + + /* + * Be sure the requested cluster is in the filesystem. + */ + if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) + return (EINVAL); + + byteoffset = FATOFS(pmp, cn); + fatblock(pmp, byteoffset, &bn, &bsize, &bo); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + + if (function & FAT_GET) { + if (FAT32(pmp)) + readcn = getulong(&bp->b_data[bo]); + else + readcn = getushort(&bp->b_data[bo]); + if (FAT12(pmp) & (cn & 1)) + readcn >>= 4; + readcn &= pmp->pm_fatmask; + /* map reserved FAT entries to same values for all FATs */ + if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD) + readcn |= ~pmp->pm_fatmask; + *oldcontents = readcn; + } + if (function & FAT_SET) { + switch (pmp->pm_fatmask) { + case FAT12_MASK: + readcn = getushort(&bp->b_data[bo]); + if (cn & 1) { + readcn &= 0x000f; + readcn |= newcontents << 4; + } else { + readcn &= 0xf000; + readcn |= newcontents & 0xfff; + } + putushort(&bp->b_data[bo], readcn); + break; + case FAT16_MASK: + putushort(&bp->b_data[bo], newcontents); + break; + case FAT32_MASK: + /* + * According to spec we have to retain the + * high order bits of the FAT entry. + */ + readcn = getulong(&bp->b_data[bo]); + readcn &= ~FAT32_MASK; + readcn |= newcontents & FAT32_MASK; + putulong(&bp->b_data[bo], readcn); + break; + } + updatefats(pmp, bp, bn); + bp = NULL; + pmp->pm_fmod = 1; + } + if (bp) + brelse(bp); + return (0); +} + +/* + * Update a contiguous cluster chain + * + * pmp - mount point + * start - first cluster of chain + * count - number of clusters in chain + * fillwith - what to write into FAT entry of last cluster + */ +static int +fatchain(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith) +{ + int error; + u_long bn, bo, bsize, byteoffset, readcn, newc; + struct buf *bp; + +#ifdef MSDOSFS_DEBUG + printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n", + pmp, start, count, fillwith); +#endif + /* + * Be sure the clusters are in the filesystem. + */ + if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster) + return (EINVAL); + + while (count > 0) { + byteoffset = FATOFS(pmp, start); + fatblock(pmp, byteoffset, &bn, &bsize, &bo); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + while (count > 0) { + start++; + newc = --count > 0 ? start : fillwith; + switch (pmp->pm_fatmask) { + case FAT12_MASK: + readcn = getushort(&bp->b_data[bo]); + if (start & 1) { + readcn &= 0xf000; + readcn |= newc & 0xfff; + } else { + readcn &= 0x000f; + readcn |= newc << 4; + } + putushort(&bp->b_data[bo], readcn); + bo++; + if (!(start & 1)) + bo++; + break; + case FAT16_MASK: + putushort(&bp->b_data[bo], newc); + bo += 2; + break; + case FAT32_MASK: + readcn = getulong(&bp->b_data[bo]); + readcn &= ~pmp->pm_fatmask; + readcn |= newc & pmp->pm_fatmask; + putulong(&bp->b_data[bo], readcn); + bo += 4; + break; + } + if (bo >= bsize) + break; + } + updatefats(pmp, bp, bn); + } + pmp->pm_fmod = 1; + return (0); +} + +/* + * Check the length of a free cluster chain starting at start. + * + * pmp - mount point + * start - start of chain + * count - maximum interesting length + */ +static int +chainlength(struct msdosfsmount *pmp, u_long start, u_long count) +{ + u_long idx, max_idx; + u_int map; + u_long len; + + if (start > pmp->pm_maxcluster) + return (0); + max_idx = pmp->pm_maxcluster / N_INUSEBITS; + idx = start / N_INUSEBITS; + start %= N_INUSEBITS; + map = pmp->pm_inusemap[idx]; + map &= ~((1 << start) - 1); + if (map) { + len = ffs(map) - 1 - start; + len = MIN(len, count); + if (start + len > pmp->pm_maxcluster) + len = pmp->pm_maxcluster - start + 1; + return (len); + } + len = N_INUSEBITS - start; + if (len >= count) { + len = count; + if (start + len > pmp->pm_maxcluster) + len = pmp->pm_maxcluster - start + 1; + return (len); + } + while (++idx <= max_idx) { + if (len >= count) + break; + map = pmp->pm_inusemap[idx]; + if (map) { + len += ffs(map) - 1; + break; + } + len += N_INUSEBITS; + } + len = MIN(len, count); + if (start + len > pmp->pm_maxcluster) + len = pmp->pm_maxcluster - start + 1; + return (len); +} + +/* + * Allocate contigous free clusters. + * + * pmp - mount point. + * start - start of cluster chain. + * count - number of clusters to allocate. + * fillwith - put this value into the FAT entry for the + * last allocated cluster. + * retcluster - put the first allocated cluster's number here. + * got - how many clusters were actually allocated. + */ +static int +chainalloc(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith, u_long *retcluster, u_long *got) +{ + int error; + u_long cl, n; + + assert((pmp->pm_flags & MSDOSFSMNT_RONLY) == 0); + + for (cl = start, n = count; n-- > 0;) + usemap_alloc(pmp, cl++); + pmp->pm_nxtfree = start + count; + if (pmp->pm_nxtfree > pmp->pm_maxcluster) + pmp->pm_nxtfree = CLUST_FIRST; + pmp->pm_flags |= MSDOSFS_FSIMOD; + error = fatchain(pmp, start, count, fillwith); + if (error != 0) { + for (cl = start, n = count; n-- > 0;) + usemap_free(pmp, cl++); + return (error); + } +#ifdef MSDOSFS_DEBUG + printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n", + start, count); +#endif + if (retcluster) + *retcluster = start; + if (got) + *got = count; + return (0); +} + +/* + * Allocate contiguous free clusters. + * + * pmp - mount point. + * start - preferred start of cluster chain. + * count - number of clusters requested. + * fillwith - put this value into the FAT entry for the + * last allocated cluster. + * retcluster - put the first allocated cluster's number here. + * got - how many clusters were actually allocated. + */ +int +clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith, u_long *retcluster, u_long *got) +{ + int error; + + error = clusteralloc1(pmp, start, count, fillwith, retcluster, got); + return (error); +} + +static int +clusteralloc1(struct msdosfsmount *pmp, u_long start, u_long count, + u_long fillwith, u_long *retcluster, u_long *got) +{ + u_long idx; + u_long len, newst, foundl, cn, l; + u_long foundcn = 0; /* XXX: foundcn could be used unititialized */ + u_int map; + + MSDOSFS_DPRINTF(("clusteralloc(): find %lu clusters\n", count)); + + if (start) { + if ((len = chainlength(pmp, start, count)) >= count) + return (chainalloc(pmp, start, count, fillwith, retcluster, got)); + } else + len = 0; + + newst = pmp->pm_nxtfree; + foundl = 0; + + for (cn = newst; cn <= pmp->pm_maxcluster;) { + idx = cn / N_INUSEBITS; + map = pmp->pm_inusemap[idx]; + map |= (1U << (cn % N_INUSEBITS)) - 1; + if (map != FULL_RUN) { + cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1; + if ((l = chainlength(pmp, cn, count)) >= count) + return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); + if (l > foundl) { + foundcn = cn; + foundl = l; + } + cn += l + 1; + continue; + } + cn += N_INUSEBITS - cn % N_INUSEBITS; + } + for (cn = 0; cn < newst;) { + idx = cn / N_INUSEBITS; + map = pmp->pm_inusemap[idx]; + map |= (1U << (cn % N_INUSEBITS)) - 1; + if (map != FULL_RUN) { + cn = idx * N_INUSEBITS + ffs(map ^ FULL_RUN) - 1; + if ((l = chainlength(pmp, cn, count)) >= count) + return (chainalloc(pmp, cn, count, fillwith, retcluster, got)); + if (l > foundl) { + foundcn = cn; + foundl = l; + } + cn += l + 1; + continue; + } + cn += N_INUSEBITS - cn % N_INUSEBITS; + } + + if (!foundl) + return (ENOSPC); + + if (len) + return (chainalloc(pmp, start, len, fillwith, retcluster, got)); + else + return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got)); +} + + +/* + * Free a chain of clusters. + * + * pmp - address of the msdosfs mount structure for the filesystem + * containing the cluster chain to be freed. + * startcluster - number of the 1st cluster in the chain of clusters to be + * freed. + */ +int +freeclusterchain(struct msdosfsmount *pmp, u_long cluster) +{ + int error; + struct buf *bp = NULL; + u_long bn, bo, bsize, byteoffset; + u_long readcn, lbn = -1; + + while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) { + byteoffset = FATOFS(pmp, cluster); + fatblock(pmp, byteoffset, &bn, &bsize, &bo); + if (lbn != bn) { + if (bp) + updatefats(pmp, bp, lbn); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error) { + brelse(bp); + return (error); + } + lbn = bn; + } + usemap_free(pmp, cluster); + switch (pmp->pm_fatmask) { + case FAT12_MASK: + readcn = getushort(&bp->b_data[bo]); + if (cluster & 1) { + cluster = readcn >> 4; + readcn &= 0x000f; + readcn |= MSDOSFSFREE << 4; + } else { + cluster = readcn; + readcn &= 0xf000; + readcn |= MSDOSFSFREE & 0xfff; + } + putushort(&bp->b_data[bo], readcn); + break; + case FAT16_MASK: + cluster = getushort(&bp->b_data[bo]); + putushort(&bp->b_data[bo], MSDOSFSFREE); + break; + case FAT32_MASK: + cluster = getulong(&bp->b_data[bo]); + putulong(&bp->b_data[bo], + (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK)); + break; + } + cluster &= pmp->pm_fatmask; + if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD) + cluster |= pmp->pm_fatmask; + } + if (bp) + updatefats(pmp, bp, bn); + return (0); +} + +/* + * Read in FAT blocks looking for free clusters. For every free cluster + * found turn off its corresponding bit in the pm_inusemap. + */ +int +fillinusemap(struct msdosfsmount *pmp) +{ + struct buf *bp = NULL; + u_long bn, bo, bsize, byteoffset, cn, readcn; + int error; + + /* + * Mark all clusters in use, we mark the free ones in the FAT scan + * loop further down. + */ + for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++) + pmp->pm_inusemap[cn] = FULL_RUN; + + /* + * Figure how many free clusters are in the filesystem by ripping + * through the FAT counting the number of entries whose content is + * zero. These represent free clusters. + */ + pmp->pm_freeclustercount = 0; + for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) { + byteoffset = FATOFS(pmp, cn); + bo = byteoffset % pmp->pm_fatblocksize; + if (bo == 0 || bp == NULL) { + /* Read new FAT block */ + if (bp != NULL) + brelse(bp); + fatblock(pmp, byteoffset, &bn, &bsize, NULL); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error != 0) { + brelse(bp); + return (error); + } + } + if (FAT32(pmp)) + readcn = getulong(&bp->b_data[bo]); + else + readcn = getushort(&bp->b_data[bo]); + if (FAT12(pmp) && (cn & 1)) + readcn >>= 4; + readcn &= pmp->pm_fatmask; + + if (readcn == CLUST_FREE) + usemap_free(pmp, cn); + } + if (bp != NULL) + brelse(bp); + + for (cn = pmp->pm_maxcluster + 1; cn < (pmp->pm_maxcluster + + N_INUSEBITS) / N_INUSEBITS; cn++) + pmp->pm_inusemap[cn / N_INUSEBITS] |= 1U << (cn % N_INUSEBITS); + + return (0); +} + +/* + * Allocate a new cluster and chain it onto the end of the file. + * + * dep - the file to extend + * count - number of clusters to allocate + * bpp - where to return the address of the buf header for the first new + * file block + * ncp - where to put cluster number of the first newly allocated cluster + * If this pointer is 0, do not return the cluster number. + * flags - see fat.h + * + * NOTE: This function is not responsible for turning on the DE_UPDATE bit of + * the de_flag field of the denode and it does not change the de_FileSize + * field. This is left for the caller to do. + */ +int +extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, + int flags) +{ + int error; + u_long frcn; + u_long cn, got; + struct msdosfsmount *pmp = dep->de_pmp; + struct buf *bp; + + /* + * Don't try to extend the root directory + */ + if (dep->de_StartCluster == MSDOSFSROOT + && (dep->de_Attributes & ATTR_DIRECTORY)) { +#ifdef MSDOSFS_DEBUG + printf("extendfile(): attempt to extend root directory\n"); +#endif + return (ENOSPC); + } + + /* + * If the "file's last cluster" cache entry is empty, and the file + * is not empty, then fill the cache entry by calling pcbmap(). + */ + if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY && + dep->de_StartCluster != 0) { + error = pcbmap(dep, 0xffff, 0, &cn, 0); + /* we expect it to return E2BIG */ + if (error != E2BIG) + return (error); + } + + dep->de_fc[FC_NEXTTOLASTFC].fc_frcn = + dep->de_fc[FC_LASTFC].fc_frcn; + dep->de_fc[FC_NEXTTOLASTFC].fc_fsrcn = + dep->de_fc[FC_LASTFC].fc_fsrcn; + while (count > 0) { + /* + * Allocate a new cluster chain and cat onto the end of the + * file. If the file is empty we make de_StartCluster point + * to the new block. Note that de_StartCluster being 0 is + * sufficient to be sure the file is empty since we exclude + * attempts to extend the root directory above, and the root + * dir is the only file with a startcluster of 0 that has + * blocks allocated (sort of). + */ + if (dep->de_StartCluster == 0) + cn = 0; + else + cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1; + error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got); + if (error) + return (error); + + count -= got; + + /* + * Give them the filesystem relative cluster number if they want + * it. + */ + if (ncp) { + *ncp = cn; + ncp = NULL; + } + + if (dep->de_StartCluster == 0) { + dep->de_StartCluster = cn; + frcn = 0; + } else { + error = fatentry(FAT_SET, pmp, + dep->de_fc[FC_LASTFC].fc_fsrcn, + 0, cn); + if (error) { + clusterfree(pmp, cn, NULL); + return (error); + } + frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1; + } + + /* + * Update the "last cluster of the file" entry in the + * denode's FAT cache. + */ + fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1); + + if ((flags & DE_CLEAR) && + (dep->de_Attributes & ATTR_DIRECTORY)) { + while (got-- > 0) { + bp = getblk(pmp->pm_devvp, + cntobn(pmp, cn++), + pmp->pm_bpcluster, 0, 0, 0); + clrbuf(bp); + if (bpp) { + *bpp = bp; + bpp = NULL; + } else { + bdwrite(bp); + } + } + } + } + + return (0); +} Property changes on: head/usr.sbin/makefs/msdos/msdosfs_fat.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos/msdosfs_lookup.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_lookup.c (nonexistent) +++ head/usr.sbin/makefs/msdos/msdosfs_lookup.c (revision 351273) @@ -0,0 +1,303 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ + +#include +#include + +#include +#include + +#include + +#include "ffs/buf.h" + +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + +#include "makefs.h" +#include "msdos.h" + +/* + * dep - directory entry to copy into the directory + * ddep - directory to add to + * depp - return the address of the denode for the created directory entry + * if depp != 0 + * cnp - componentname needed for Win95 long filenames + */ +int +createde(struct denode *dep, struct denode *ddep, struct denode **depp, + struct componentname *cnp) +{ + int error; + u_long dirclust, diroffset; + struct direntry *ndep; + struct msdosfsmount *pmp = ddep->de_pmp; + struct buf *bp; + daddr_t bn; + int blsize; + + MSDOSFS_DPRINTF(("createde(dep %p, ddep %p, depp %p, cnp %p)\n", + dep, ddep, depp, cnp)); + + /* + * If no space left in the directory then allocate another cluster + * and chain it onto the end of the file. There is one exception + * to this. That is, if the root directory has no more space it + * can NOT be expanded. extendfile() checks for and fails attempts + * to extend the root directory. We just return an error in that + * case. + */ + if (ddep->de_fndoffset >= ddep->de_FileSize) { + diroffset = ddep->de_fndoffset + sizeof(struct direntry) + - ddep->de_FileSize; + dirclust = de_clcount(pmp, diroffset); + error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR); + if (error) { + (void)detrunc(ddep, ddep->de_FileSize, 0); + return error; + } + + /* + * Update the size of the directory + */ + ddep->de_FileSize += de_cn2off(pmp, dirclust); + } + + /* + * We just read in the cluster with space. Copy the new directory + * entry in. Then write it to disk. NOTE: DOS directories + * do not get smaller as clusters are emptied. + */ + error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset), + &bn, &dirclust, &blsize); + if (error) + return error; + diroffset = ddep->de_fndoffset; + if (dirclust != MSDOSFSROOT) + diroffset &= pmp->pm_crbomask; + if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) { + brelse(bp); + return error; + } + ndep = bptoep(pmp, bp, ddep->de_fndoffset); + + DE_EXTERNALIZE(ndep, dep); + + /* + * Now write the Win95 long name + */ + if (ddep->de_fndcnt > 0) { + uint8_t chksum = winChksum(ndep->deName); + const u_char *un = (const u_char *)cnp->cn_nameptr; + int unlen = cnp->cn_namelen; + int cnt = 1; + + while (--ddep->de_fndcnt >= 0) { + if (!(ddep->de_fndoffset & pmp->pm_crbomask)) { + if ((error = bwrite(bp)) != 0) + return error; + + ddep->de_fndoffset -= sizeof(struct direntry); + error = pcbmap(ddep, + de_cluster(pmp, + ddep->de_fndoffset), + &bn, 0, &blsize); + if (error) + return error; + + error = bread(pmp->pm_devvp, bn, blsize, + NOCRED, &bp); + if (error) { + brelse(bp); + return error; + } + ndep = bptoep(pmp, bp, ddep->de_fndoffset); + } else { + ndep--; + ddep->de_fndoffset -= sizeof(struct direntry); + } + if (!unix2winfn(un, unlen, (struct winentry *)ndep, + cnt++, chksum)) + break; + } + } + + if ((error = bwrite(bp)) != 0) + return error; + + /* + * If they want us to return with the denode gotten. + */ + if (depp) { + if (dep->de_Attributes & ATTR_DIRECTORY) { + dirclust = dep->de_StartCluster; + if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk) + dirclust = MSDOSFSROOT; + if (dirclust == MSDOSFSROOT) + diroffset = MSDOSFSROOT_OFS; + else + diroffset = 0; + } + return deget(pmp, dirclust, diroffset, depp); + } + + return 0; +} + +/* + * Read in the disk block containing the directory entry (dirclu, dirofs) + * and return the address of the buf header, and the address of the + * directory entry within the block. + */ +int +readep(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset, + struct buf **bpp, struct direntry **epp) +{ + int error; + daddr_t bn; + int blsize; + + blsize = pmp->pm_bpcluster; + if (dirclust == MSDOSFSROOT + && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize) + blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask; + bn = detobn(pmp, dirclust, diroffset); + if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) { + brelse(*bpp); + *bpp = NULL; + return (error); + } + if (epp) + *epp = bptoep(pmp, *bpp, diroffset); + return (0); +} + +/* + * Read in the disk block containing the directory entry dep came from and + * return the address of the buf header, and the address of the directory + * entry within the block. + */ +int +readde(struct denode *dep, struct buf **bpp, struct direntry **epp) +{ + + return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, + bpp, epp)); +} + +/* + * Create a unique DOS name in dvp + */ +int +uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp) +{ + struct msdosfsmount *pmp = dep->de_pmp; + struct direntry *dentp; + int gen; + int blsize; + u_long cn; + daddr_t bn; + struct buf *bp; + int error; + + if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) + return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp, + cnp->cn_namelen, 0) ? 0 : EINVAL); + + for (gen = 1;; gen++) { + /* + * Generate DOS name with generation number + */ + if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, + cnp->cn_namelen, gen)) + return gen == 1 ? EINVAL : EEXIST; + + /* + * Now look for a dir entry with this exact name + */ + for (cn = error = 0; !error; cn++) { + if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) { + if (error == E2BIG) /* EOF reached and not found */ + return 0; + return error; + } + error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp); + if (error) { + brelse(bp); + return error; + } + for (dentp = (struct direntry *)bp->b_data; + (char *)dentp < (char *)bp->b_data + blsize; + dentp++) { + if (dentp->deName[0] == SLOT_EMPTY) { + /* + * Last used entry and not found + */ + brelse(bp); + return 0; + } + /* + * Ignore volume labels and Win95 entries + */ + if (dentp->deAttributes & ATTR_VOLUME) + continue; + if (!bcmp(dentp->deName, cp, 11)) { + error = EEXIST; + break; + } + } + brelse(bp); + } + } +} Property changes on: head/usr.sbin/makefs/msdos/msdosfs_lookup.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos/msdosfs_vfsops.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_vfsops.c (revision 351272) +++ head/usr.sbin/makefs/msdos/msdosfs_vfsops.c (revision 351273) @@ -1,432 +1,359 @@ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. * Copyright (C) 1994, 1995, 1997 TooLs GmbH. * All rights reserved. * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). * * 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 by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. */ /* * Written by Paul Popelka (paulp@uts.amdahl.com) * * You can do anything you want with this software, just don't say you wrote * it, and don't remove this notice. * * This software is provided "as is". * * The author supplies this software to be publicly redistributed on the * understanding that the author is not responsible for the correct * functioning of this software in any circumstances and is not liable for * any damages caused by this software. * * October 1992 */ -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif - #include /* $NetBSD: msdosfs_vfsops.c,v 1.10 2016/01/30 09:59:27 mlelstv Exp $ */ __FBSDID("$FreeBSD$"); #include +#include -#include - -#include -#include -#include -#include -#include -#include - -#include #include -#include +#include #include +#include #include +#include +#include + +#include + #include "makefs.h" #include "msdos.h" -#include "mkfs_msdos.h" -#ifdef MSDOSFS_DEBUG -#define DPRINTF(a) printf a -#else -#define DPRINTF(a) -#endif +#include "ffs/buf.h" +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + struct msdosfsmount * -msdosfs_mount(struct vnode *devvp, int flags) +msdosfs_mount(struct vnode *devvp) { struct msdosfsmount *pmp = NULL; struct buf *bp; union bootsector *bsp; struct byte_bpb33 *b33; struct byte_bpb50 *b50; struct byte_bpb710 *b710; uint8_t SecPerClust; - int ronly = 0, error, tmp; + int ronly = 0, error; int bsize; - struct msdos_options *m = devvp->fs->fs_specific; - uint64_t psize = m->create_size; unsigned secsize = 512; - DPRINTF(("%s(bread 0)\n", __func__)); + MSDOSFS_DPRINTF(("%s(bread 0)\n", __func__)); if ((error = bread(devvp, 0, secsize, 0, &bp)) != 0) goto error_exit; bsp = (union bootsector *)bp->b_data; b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB; - if (!(flags & MSDOSFSMNT_GEMDOSFS)) { - if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 - || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { - DPRINTF(("bootsig0 %d bootsig1 %d\n", - bsp->bs50.bsBootSectSig0, - bsp->bs50.bsBootSectSig1)); - error = EINVAL; - goto error_exit; - } - bsize = 0; - } else - bsize = 512; + if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 || + bsp->bs50.bsBootSectSig1 != BOOTSIG1) { + MSDOSFS_DPRINTF(("bootsig0 %d bootsig1 %d\n", + bsp->bs50.bsBootSectSig0, + bsp->bs50.bsBootSectSig1)); + error = EINVAL; + goto error_exit; + } + bsize = 0; - pmp = ecalloc(1, sizeof *pmp); + pmp = ecalloc(1, sizeof(*pmp)); /* * Compute several useful quantities from the bpb in the * bootsector. Copy in the dos 5 variant of the bpb then fix up * the fields that are different between dos 5 and dos 3.3. */ SecPerClust = b50->bpbSecPerClust; pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); pmp->pm_ResSectors = getushort(b50->bpbResSectors); pmp->pm_FATs = b50->bpbFATs; pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); pmp->pm_Sectors = getushort(b50->bpbSectors); pmp->pm_FATsecs = getushort(b50->bpbFATsecs); pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); pmp->pm_Heads = getushort(b50->bpbHeads); pmp->pm_Media = b50->bpbMedia; - DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, RootDirEnts=%u, " - "Sectors=%u, FATsecs=%lu, SecPerTrack=%u, Heads=%u, Media=%u)\n", - __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, pmp->pm_FATs, - pmp->pm_RootDirEnts, pmp->pm_Sectors, pmp->pm_FATsecs, - pmp->pm_SecPerTrack, pmp->pm_Heads, pmp->pm_Media)); - if (!(flags & MSDOSFSMNT_GEMDOSFS)) { - /* XXX - We should probably check more values here */ - if (!pmp->pm_BytesPerSec || !SecPerClust - || pmp->pm_SecPerTrack > 63) { - DPRINTF(("bytespersec %d secperclust %d " - "secpertrack %d\n", - pmp->pm_BytesPerSec, SecPerClust, - pmp->pm_SecPerTrack)); - error = EINVAL; - goto error_exit; - } + MSDOSFS_DPRINTF(("%s(BytesPerSec=%u, ResSectors=%u, FATs=%d, " + "RootDirEnts=%u, Sectors=%u, FATsecs=%lu, SecPerTrack=%u, " + "Heads=%u, Media=%u)\n", + __func__, pmp->pm_BytesPerSec, pmp->pm_ResSectors, + pmp->pm_FATs, pmp->pm_RootDirEnts, pmp->pm_Sectors, + pmp->pm_FATsecs, pmp->pm_SecPerTrack, pmp->pm_Heads, + pmp->pm_Media)); + + /* XXX - We should probably check more values here */ + if (!pmp->pm_BytesPerSec || !SecPerClust + || pmp->pm_SecPerTrack > 63) { + MSDOSFS_DPRINTF(("bytespersec %d secperclust %d " + "secpertrack %d\n", pmp->pm_BytesPerSec, + SecPerClust, pmp->pm_SecPerTrack)); + error = EINVAL; + goto error_exit; } - pmp->pm_flags = flags & MSDOSFSMNT_MNTOPT; - if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) - pmp->pm_flags |= MSDOSFSMNT_NOWIN95; - if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) - pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; - if (pmp->pm_Sectors == 0) { pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); } else { pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); pmp->pm_HugeSectors = pmp->pm_Sectors; } + pmp->pm_flags = 0; if (pmp->pm_RootDirEnts == 0) { unsigned short vers = getushort(b710->bpbFSVers); /* * Some say that bsBootSectSig[23] must be zero, but * Windows does not require this and some digital cameras * do not set these to zero. Therefore, do not insist. */ if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) { - DPRINTF(("sectors %d fatsecs %lu vers %d\n", + MSDOSFS_DPRINTF(("sectors %d fatsecs %lu vers %d\n", pmp->pm_Sectors, pmp->pm_FATsecs, vers)); error = EINVAL; goto error_exit; } pmp->pm_fatmask = FAT32_MASK; pmp->pm_fatmult = 4; pmp->pm_fatdiv = 1; pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); /* mirrorring is enabled if the FATMIRROR bit is not set */ if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0) pmp->pm_flags |= MSDOSFS_FATMIRROR; else pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; } else pmp->pm_flags |= MSDOSFS_FATMIRROR; - if (flags & MSDOSFSMNT_GEMDOSFS) { - if (FAT32(pmp)) { - DPRINTF(("FAT32 for GEMDOS\n")); - /* - * GEMDOS doesn't know FAT32. - */ - error = EINVAL; - goto error_exit; - } - - /* - * Check a few values (could do some more): - * - logical sector size: power of 2, >= block size - * - sectors per cluster: power of 2, >= 1 - * - number of sectors: >= 1, <= size of partition - */ - if ( (SecPerClust == 0) - || (SecPerClust & (SecPerClust - 1)) - || (pmp->pm_BytesPerSec < bsize) - || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) - || (pmp->pm_HugeSectors == 0) - || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) - > psize)) { - DPRINTF(("consistency checks for GEMDOS\n")); - error = EINVAL; - goto error_exit; - } - /* - * XXX - Many parts of the msdosfs driver seem to assume that - * the number of bytes per logical sector (BytesPerSec) will - * always be the same as the number of bytes per disk block - * Let's pretend it is. - */ - tmp = pmp->pm_BytesPerSec / bsize; - pmp->pm_BytesPerSec = bsize; - pmp->pm_HugeSectors *= tmp; - pmp->pm_HiddenSects *= tmp; - pmp->pm_ResSectors *= tmp; - pmp->pm_Sectors *= tmp; - pmp->pm_FATsecs *= tmp; - SecPerClust *= tmp; - } - /* Check that fs has nonzero FAT size */ if (pmp->pm_FATsecs == 0) { - DPRINTF(("FATsecs is 0\n")); + MSDOSFS_DPRINTF(("FATsecs is 0\n")); error = EINVAL; goto error_exit; } pmp->pm_fatblk = pmp->pm_ResSectors; if (FAT32(pmp)) { pmp->pm_rootdirblk = getulong(b710->bpbRootClust); pmp->pm_firstcluster = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_fsinfo = getushort(b710->bpbFSInfo); } else { pmp->pm_rootdirblk = pmp->pm_fatblk + (pmp->pm_FATs * pmp->pm_FATsecs); pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) + pmp->pm_BytesPerSec - 1) / pmp->pm_BytesPerSec;/* in sectors */ pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; } - pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / - SecPerClust; - pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; + pmp->pm_maxcluster = ((pmp->pm_HugeSectors - pmp->pm_firstcluster) / + SecPerClust) + 1; pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; - if (flags & MSDOSFSMNT_GEMDOSFS) { - if (pmp->pm_nmbrofclusters <= (0xff0 - 2)) { - pmp->pm_fatmask = FAT12_MASK; - pmp->pm_fatmult = 3; - pmp->pm_fatdiv = 2; - } else { - pmp->pm_fatmask = FAT16_MASK; - pmp->pm_fatmult = 2; - pmp->pm_fatdiv = 1; - } - } else if (pmp->pm_fatmask == 0) { + if (pmp->pm_fatmask == 0) { if (pmp->pm_maxcluster <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { /* * This will usually be a floppy disk. This size makes * sure that one FAT entry will not be split across * multiple blocks. */ pmp->pm_fatmask = FAT12_MASK; pmp->pm_fatmult = 3; pmp->pm_fatdiv = 2; } else { pmp->pm_fatmask = FAT16_MASK; pmp->pm_fatmult = 2; pmp->pm_fatdiv = 1; } } if (FAT12(pmp)) pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; else pmp->pm_fatblocksize = MAXBSIZE; pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; /* * Compute mask and shift value for isolating cluster relative byte * offsets and cluster numbers from a file offset. */ pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; pmp->pm_crbomask = pmp->pm_bpcluster - 1; pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; - DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, fatblocksize=%lu, " - "fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, crbomask=%lu, " - "cnshift=%lu)\n", - __func__, pmp->pm_fatmask, pmp->pm_fatmult, pmp->pm_fatdiv, - pmp->pm_fatblocksize, pmp->pm_fatblocksec, pmp->pm_bnshift, - pmp->pm_bpcluster, pmp->pm_crbomask, pmp->pm_cnshift)); + MSDOSFS_DPRINTF(("%s(fatmask=%lu, fatmult=%u, fatdiv=%u, " + "fatblocksize=%lu, fatblocksec=%lu, bnshift=%lu, pbcluster=%lu, " + "crbomask=%lu, cnshift=%lu)\n", + __func__, (unsigned long)pmp->pm_fatmask, pmp->pm_fatmult, + pmp->pm_fatdiv, pmp->pm_fatblocksize, pmp->pm_fatblocksec, + pmp->pm_bnshift, pmp->pm_bpcluster, pmp->pm_crbomask, + pmp->pm_cnshift)); /* * Check for valid cluster size * must be a power of 2 */ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { - DPRINTF(("bpcluster %lu cnshift %lu\n", + MSDOSFS_DPRINTF(("bpcluster %lu cnshift %lu\n", pmp->pm_bpcluster, pmp->pm_cnshift)); error = EINVAL; goto error_exit; } /* * Release the bootsector buffer. */ brelse(bp); bp = NULL; /* * Check FSInfo. */ if (pmp->pm_fsinfo) { struct fsinfo *fp; /* * XXX If the fsinfo block is stored on media with * 2KB or larger sectors, is the fsinfo structure * padded at the end or in the middle? */ - DPRINTF(("%s(bread %lu)\n", __func__, - (unsigned long)de_bn2kb(pmp, pmp->pm_fsinfo))); - if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo), - pmp->pm_BytesPerSec, 0, &bp)) != 0) + if ((error = bread(devvp, pmp->pm_fsinfo, pmp->pm_BytesPerSec, + 0, &bp)) != 0) goto error_exit; fp = (struct fsinfo *)bp->b_data; if (!memcmp(fp->fsisig1, "RRaA", 4) && !memcmp(fp->fsisig2, "rrAa", 4) - && !memcmp(fp->fsisig3, "\0\0\125\252", 4) - && !memcmp(fp->fsisig4, "\0\0\125\252", 4)) + && !memcmp(fp->fsisig3, "\0\0\125\252", 4)) pmp->pm_nxtfree = getulong(fp->fsinxtfree); else pmp->pm_fsinfo = 0; brelse(bp); bp = NULL; } /* * Check and validate (or perhaps invalidate?) the fsinfo structure? * XXX */ if (pmp->pm_fsinfo) { if ((pmp->pm_nxtfree == 0xffffffffUL) || (pmp->pm_nxtfree > pmp->pm_maxcluster)) pmp->pm_fsinfo = 0; } /* * Allocate memory for the bitmap of allocated clusters, and then * fill it in. */ pmp->pm_inusemap = ecalloc(sizeof(*pmp->pm_inusemap), ((pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS)); /* * fillinusemap() needs pm_devvp. */ pmp->pm_dev = 0; pmp->pm_devvp = devvp; /* * Have the inuse map filled in. */ if ((error = fillinusemap(pmp)) != 0) { - DPRINTF(("fillinusemap %d\n", error)); + MSDOSFS_DPRINTF(("fillinusemap %d\n", error)); goto error_exit; } /* * Finish up. */ if (ronly) pmp->pm_flags |= MSDOSFSMNT_RONLY; else pmp->pm_fmod = 1; /* * If we ever do quotas for DOS filesystems this would be a place * to fill in the info in the msdosfsmount structure. You dolt, * quotas on dos filesystems make no sense because files have no * owners on dos filesystems. of course there is some empty space * in the directory entry where we could put uid's and gid's. */ return pmp; error_exit: if (bp) - brelse(bp, BC_AGE); + brelse(bp); if (pmp) { if (pmp->pm_inusemap) free(pmp->pm_inusemap); free(pmp); } errno = error; return NULL; } int msdosfs_root(struct msdosfsmount *pmp, struct vnode *vp) { struct denode *ndep; int error; *vp = *pmp->pm_devvp; if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0) { errno = error; return -1; } vp->v_data = ndep; return 0; } Index: head/usr.sbin/makefs/msdos/msdosfs_vnops.c =================================================================== --- head/usr.sbin/makefs/msdos/msdosfs_vnops.c (revision 351272) +++ head/usr.sbin/makefs/msdos/msdosfs_vnops.c (revision 351273) @@ -1,647 +1,640 @@ /* $NetBSD: msdosfs_vnops.c,v 1.19 2017/04/13 17:10:12 christos Exp $ */ /*- * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. * Copyright (C) 1994, 1995, 1997 TooLs GmbH. * All rights reserved. * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). * * 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 by TooLs GmbH. * 4. The name of TooLs GmbH may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. */ /* * Written by Paul Popelka (paulp@uts.amdahl.com) * * You can do anything you want with this software, just don't say you wrote * it, and don't remove this notice. * * This software is provided "as is". * * The author supplies this software to be publicly redistributed on the * understanding that the author is not responsible for the correct * functioning of this software in any circumstances and is not liable for * any damages caused by this software. * * October 1992 */ -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif #include __FBSDID("$FreeBSD$"); #include +#include +#include #include +#include + #include +#include +#include +#include #include -#include - #include -#include -#include -#include -#include #include "makefs.h" #include "msdos.h" -#ifdef MSDOSFS_DEBUG -#define DPRINTF(a) printf a -#else -#define DPRINTF(a) -#endif +#include "ffs/buf.h" + +#include "msdos/denode.h" +#include "msdos/direntry.h" +#include "msdos/fat.h" +#include "msdos/msdosfsmount.h" + /* * Some general notes: * * In the ufs filesystem the inodes, superblocks, and indirect blocks are * read/written using the vnode for the filesystem. Blocks that represent * the contents of a file are read/written using the vnode for the file * (including directories when they are read/written as files). This * presents problems for the dos filesystem because data that should be in * an inode (if dos had them) resides in the directory itself. Since we * must update directory entries without the benefit of having the vnode * for the directory we must use the vnode for the filesystem. This means * that when a directory is actually read/written (via read, write, or * readdir, or seek) we must use the vnode for the filesystem instead of * the vnode for the directory as would happen in ufs. This is to insure we * retrieve the correct block from the buffer cache since the hash value is * based upon the vnode address and the desired block number. */ static int msdosfs_wfile(const char *, struct denode *, fsnode *); +static void unix2fattime(const struct timespec *tsp, uint16_t *ddp, + uint16_t *dtp); static void -msdosfs_times(struct msdosfsmount *pmp, struct denode *dep, - const struct stat *st) +msdosfs_times(struct denode *dep, const struct stat *st) { - struct timespec at; - struct timespec mt; - if (stampst.st_ino) - st = &stampst; + st = &stampst; -#ifndef HAVE_NBTOOL_CONFIG_H - at = st->st_atimespec; - mt = st->st_mtimespec; -#else - at.tv_sec = st->st_atime; - at.tv_nsec = 0; - mt.tv_sec = st->st_mtime; - mt.tv_nsec = 0; -#endif - unix2dostime(&at, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL); - unix2dostime(&mt, pmp->pm_gmtoff, &dep->de_MDate, &dep->de_MTime, NULL); + unix2fattime(&st->st_birthtim, &dep->de_CDate, &dep->de_CTime); + unix2fattime(&st->st_atim, &dep->de_ADate, NULL); + unix2fattime(&st->st_mtim, &dep->de_MDate, &dep->de_MTime); } +static void +unix2fattime(const struct timespec *tsp, uint16_t *ddp, uint16_t *dtp) +{ + time_t t1; + struct tm lt = {0}; + + t1 = tsp->tv_sec; + localtime_r(&t1, <); + + unsigned long fat_time = ((lt.tm_year - 80) << 25) | + ((lt.tm_mon + 1) << 21) | + (lt.tm_mday << 16) | + (lt.tm_hour << 11) | + (lt.tm_min << 5) | + (lt.tm_sec >> 1); + + if (ddp != NULL) + *ddp = (uint16_t)(fat_time >> 16); + if (dtp != NULL) + *dtp = (uint16_t)fat_time; +} + /* * When we search a directory the blocks containing directory entries are * read and examined. The directory entries contain information that would * normally be in the inode of a unix filesystem. This means that some of * a directory's contents may also be in memory resident denodes (sort of * an inode). This can cause problems if we are searching while some other * process is modifying a directory. To prevent one process from accessing * incompletely modified directory information we depend upon being the * sole owner of a directory block. bread/brelse provide this service. * This being the case, when a process modifies a directory it must first * acquire the disk block that contains the directory entry to be modified. * Then update the disk block and the denode, and then write the disk block * out to disk. This way disk blocks containing directory entries and in * memory denode's will be in synch. */ static int msdosfs_findslot(struct denode *dp, struct componentname *cnp) { daddr_t bn; int error; int slotcount; int slotoffset = 0; int frcn; u_long cluster; int blkoff; u_int diroff; int blsize; struct msdosfsmount *pmp; struct buf *bp = 0; struct direntry *dep; u_char dosfilename[12]; int wincnt = 1; int chksum = -1, chksum_ok; int olddos = 1; pmp = dp->de_pmp; switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0)) { case 0: return (EINVAL); case 1: break; case 2: wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, - cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1; + cnp->cn_namelen) + 1; break; case 3: olddos = 0; wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr, - cnp->cn_namelen, pmp->pm_flags & MSDOSFSMNT_UTF8) + 1; + cnp->cn_namelen) + 1; break; } if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) wincnt = 1; /* * Suppress search for slots unless creating * file and at end of pathname, in which case * we watch for a place to put the new file in * case it doesn't already exist. */ slotcount = 0; - DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename)); + MSDOSFS_DPRINTF(("%s(): dos filename: %s\n", __func__, dosfilename)); /* * Search the directory pointed at by vdp for the name pointed at * by cnp->cn_nameptr. */ /* * The outer loop ranges over the clusters that make up the * directory. Note that the root directory is different from all * other directories. It has a fixed number of blocks that are not * part of the pool of allocatable clusters. So, we treat it a * little differently. The root directory starts at "cluster" 0. */ diroff = 0; for (frcn = 0; diroff < dp->de_FileSize; frcn++) { if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) { if (error == E2BIG) break; return (error); } - error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, - 0, &bp); + error = bread(pmp->pm_devvp, bn, blsize, 0, &bp); if (error) { return (error); } for (blkoff = 0; blkoff < blsize; blkoff += sizeof(struct direntry), diroff += sizeof(struct direntry)) { dep = (struct direntry *)((char *)bp->b_data + blkoff); /* * If the slot is empty and we are still looking * for an empty then remember this one. If the * slot is not empty then check to see if it * matches what we are looking for. If the slot * has never been filled with anything, then the * remainder of the directory has never been used, * so there is no point in searching it. */ if (dep->deName[0] == SLOT_EMPTY || dep->deName[0] == SLOT_DELETED) { /* * Drop memory of previous long matches */ chksum = -1; if (slotcount < wincnt) { slotcount++; slotoffset = diroff; } if (dep->deName[0] == SLOT_EMPTY) { brelse(bp); goto notfound; } } else { /* * If there wasn't enough space for our * winentries, forget about the empty space */ if (slotcount < wincnt) slotcount = 0; /* * Check for Win95 long filename entry */ if (dep->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; - chksum = winChkName((const u_char *)cnp->cn_nameptr, - cnp->cn_namelen, - (struct winentry *)dep, - chksum, - pmp->pm_flags & MSDOSFSMNT_UTF8); + chksum = winChkName( + (const u_char *)cnp->cn_nameptr, + cnp->cn_namelen, + (struct winentry *)dep, chksum); continue; } /* * Ignore volume labels (anywhere, not just * the root directory). */ if (dep->deAttributes & ATTR_VOLUME) { chksum = -1; continue; } /* * Check for a checksum or name match */ chksum_ok = (chksum == winChksum(dep->deName)); if (!chksum_ok && (!olddos || memcmp(dosfilename, dep->deName, 11))) { chksum = -1; continue; } - DPRINTF(("%s(): match blkoff %d, diroff %d\n", + MSDOSFS_DPRINTF(("%s(): match blkoff %d, diroff %u\n", __func__, blkoff, diroff)); /* * Remember where this directory * entry came from for whoever did * this lookup. */ dp->de_fndoffset = diroff; dp->de_fndcnt = 0; return EEXIST; } } /* for (blkoff = 0; .... */ /* * Release the buffer holding the directory cluster just * searched. */ brelse(bp); } /* for (frcn = 0; ; frcn++) */ notfound: /* * We hold no disk buffers at this point. */ /* * If we get here we didn't find the entry we were looking for. But * that's ok if we are creating or renaming and are at the end of * the pathname and the directory hasn't been removed. */ - DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n", + MSDOSFS_DPRINTF(("%s(): refcnt %ld, slotcount %d, slotoffset %d\n", __func__, dp->de_refcnt, slotcount, slotoffset)); /* * Fixup the slot description to point to the place where * we might put the new DOS direntry (putting the Win95 * long name entries before that) */ if (!slotcount) { slotcount = 1; slotoffset = diroff; } if (wincnt > slotcount) { slotoffset += sizeof(struct direntry) * (wincnt - slotcount); } /* * Return an indication of where the new directory * entry should be put. */ dp->de_fndoffset = slotoffset; dp->de_fndcnt = wincnt - 1; /* * We return with the directory locked, so that * the parameters we set up above will still be * valid if we actually decide to do a direnter(). * We return ni_vp == NULL to indicate that the entry * does not currently exist; we leave a pointer to * the (locked) directory inode in ndp->ni_dvp. * * NB - if the directory is unlocked, then this * information cannot be used. */ return 0; } /* * Create a regular file. On entry the directory to contain the file being * created is locked. We must release before we return. */ struct denode * msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node) { struct componentname cn; struct denode ndirent; struct denode *dep; int error; struct stat *st = &node->inode->st; - struct msdosfsmount *pmp = pdep->de_pmp; cn.cn_nameptr = node->name; cn.cn_namelen = strlen(node->name); - DPRINTF(("%s(name %s, mode 0%o size %zu)\n", __func__, node->name, - st->st_mode, (size_t)st->st_size)); + MSDOSFS_DPRINTF(("%s(name %s, mode 0%o size %zu)\n", + __func__, node->name, st->st_mode, (size_t)st->st_size)); /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not * change size. */ if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndoffset >= pdep->de_FileSize) { error = ENOSPC; goto bad; } /* * Create a directory entry for the file, then call createde() to * have it installed. NOTE: DOS files are always executable. We * use the absence of the owner write bit to make the file * readonly. */ memset(&ndirent, 0, sizeof(ndirent)); if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0) goto bad; ndirent.de_Attributes = (st->st_mode & S_IWUSR) ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY; ndirent.de_StartCluster = 0; ndirent.de_FileSize = 0; - ndirent.de_dev = pdep->de_dev; - ndirent.de_devvp = pdep->de_devvp; ndirent.de_pmp = pdep->de_pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; - msdosfs_times(pmp, &ndirent, st); + msdosfs_times(&ndirent, &node->inode->st); + if ((error = msdosfs_findslot(pdep, &cn)) != 0) goto bad; if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) goto bad; if ((error = msdosfs_wfile(path, dep, node)) != 0) goto bad; return dep; bad: errno = error; return NULL; } static int msdosfs_updatede(struct denode *dep) { struct buf *bp; struct direntry *dirp; int error; dep->de_flag &= ~DE_MODIFIED; error = readde(dep, &bp, &dirp); if (error) return error; DE_EXTERNALIZE(dirp, dep); error = bwrite(bp); return error; } /* * Write data to a file or directory. */ static int msdosfs_wfile(const char *path, struct denode *dep, fsnode *node) { int error, fd; size_t osize = dep->de_FileSize; struct stat *st = &node->inode->st; size_t nsize, offs; struct msdosfsmount *pmp = dep->de_pmp; struct buf *bp; char *dat; u_long cn = 0; error = 0; /* XXX: gcc/vax */ - DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", __func__, - dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster)); + MSDOSFS_DPRINTF(("%s(diroff %lu, dirclust %lu, startcluster %lu)\n", + __func__, dep->de_diroffset, dep->de_dirclust, + dep->de_StartCluster)); if (st->st_size == 0) return 0; /* Don't bother to try to write files larger than the fs limit */ if (st->st_size > MSDOSFS_FILESIZE_MAX) return EFBIG; nsize = st->st_size; - DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize)); + MSDOSFS_DPRINTF(("%s(nsize=%zu, osize=%zu)\n", __func__, nsize, osize)); if (nsize > osize) { - if ((error = deextend(dep, nsize, NULL)) != 0) + if ((error = deextend(dep, nsize)) != 0) return error; if ((error = msdosfs_updatede(dep)) != 0) return error; } if ((fd = open(path, O_RDONLY)) == -1) { error = errno; - DPRINTF((1, "open %s: %s", path, strerror(error))); + MSDOSFS_DPRINTF(("open %s: %s", path, strerror(error))); return error; } if ((dat = mmap(0, nsize, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) { error = errno; - DPRINTF(("%s: mmap %s: %s", __func__, node->name, + MSDOSFS_DPRINTF(("%s: mmap %s: %s", __func__, node->name, strerror(error))); close(fd); goto out; } close(fd); for (offs = 0; offs < nsize;) { int blsize, cpsize; daddr_t bn; u_long on = offs & pmp->pm_crbomask; -#ifdef HACK - cn = dep->de_StartCluster; - if (cn == MSDOSFSROOT) { - DPRINTF(("%s: bad lbn %lu", __func__, cn)); - error = EINVAL; - goto out; - } - bn = cntobn(pmp, cn); - blsize = pmp->pm_bpcluster; -#else + if ((error = pcbmap(dep, cn++, &bn, NULL, &blsize)) != 0) { - DPRINTF(("%s: pcbmap %lu", __func__, bn)); + MSDOSFS_DPRINTF(("%s: pcbmap %lu", + __func__, (unsigned long)bn)); goto out; } -#endif - DPRINTF(("%s(cn=%lu, bn=%llu/%llu, blsize=%d)\n", __func__, - cn, (unsigned long long)bn, - (unsigned long long)de_bn2kb(pmp, bn), blsize)); - if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), blsize, - 0, &bp)) != 0) { - DPRINTF(("bread %d\n", error)); + + MSDOSFS_DPRINTF(("%s(cn=%lu, bn=%llu, blsize=%d)\n", + __func__, cn, (unsigned long long)bn, blsize)); + if ((error = bread(pmp->pm_devvp, bn, blsize, 0, &bp)) != 0) { + MSDOSFS_DPRINTF(("bread %d\n", error)); goto out; } cpsize = MIN((nsize - offs), blsize - on); memcpy((char *)bp->b_data + on, dat + offs, cpsize); bwrite(bp); offs += cpsize; } munmap(dat, nsize); return 0; out: munmap(dat, nsize); return error; } - static const struct { struct direntry dot; struct direntry dotdot; } dosdirtemplate = { - { ". ", " ", /* the . entry */ + { ". ", /* the . entry */ ATTR_DIRECTORY, /* file attribute */ 0, /* reserved */ 0, { 0, 0 }, { 0, 0 }, /* create time & date */ { 0, 0 }, /* access date */ { 0, 0 }, /* high bits of start cluster */ { 210, 4 }, { 210, 4 }, /* modify time & date */ { 0, 0 }, /* startcluster */ { 0, 0, 0, 0 } /* filesize */ }, - { ".. ", " ", /* the .. entry */ + { ".. ", /* the .. entry */ ATTR_DIRECTORY, /* file attribute */ 0, /* reserved */ 0, { 0, 0 }, { 0, 0 }, /* create time & date */ { 0, 0 }, /* access date */ { 0, 0 }, /* high bits of start cluster */ { 210, 4 }, { 210, 4 }, /* modify time & date */ { 0, 0 }, /* startcluster */ { 0, 0, 0, 0 } /* filesize */ } }; struct denode * msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) { struct denode ndirent; struct denode *dep; struct componentname cn; - struct stat *st = &node->inode->st; struct msdosfsmount *pmp = pdep->de_pmp; int error; u_long newcluster, pcl, bn; - daddr_t lbn; struct direntry *denp; struct buf *bp; cn.cn_nameptr = node->name; cn.cn_namelen = strlen(node->name); /* * If this is the root directory and there is no space left we * can't do anything. This is because the root directory can not * change size. */ if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndoffset >= pdep->de_FileSize) { error = ENOSPC; goto bad2; } /* * Allocate a cluster to hold the about to be created directory. */ - error = clusteralloc(pmp, 0, 1, &newcluster, NULL); + error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL); if (error) goto bad2; memset(&ndirent, 0, sizeof(ndirent)); ndirent.de_pmp = pmp; ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE; - msdosfs_times(pmp, &ndirent, st); + msdosfs_times(&ndirent, &node->inode->st); /* * Now fill the cluster with the "." and ".." entries. And write * the cluster to disk. This way it is there for the parent * directory to be pointing at if there were a crash. */ bn = cntobn(pmp, newcluster); - lbn = de_bn2kb(pmp, bn); - DPRINTF(("%s(newcluster %lu, bn=%lu, lbn=%lu)\n", __func__, newcluster, - bn, lbn)); + MSDOSFS_DPRINTF(("%s(newcluster %lu, bn=%lu)\n", + __func__, newcluster, bn)); /* always succeeds */ - bp = getblk(pmp->pm_devvp, lbn, pmp->pm_bpcluster, 0, 0); + bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0); memset(bp->b_data, 0, pmp->pm_bpcluster); memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate); denp = (struct direntry *)bp->b_data; putushort(denp[0].deStartCluster, newcluster); putushort(denp[0].deCDate, ndirent.de_CDate); putushort(denp[0].deCTime, ndirent.de_CTime); denp[0].deCHundredth = ndirent.de_CHun; putushort(denp[0].deADate, ndirent.de_ADate); putushort(denp[0].deMDate, ndirent.de_MDate); putushort(denp[0].deMTime, ndirent.de_MTime); pcl = pdep->de_StartCluster; - DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl, + MSDOSFS_DPRINTF(("%s(pcl %lu, rootdirblk=%lu)\n", __func__, pcl, pmp->pm_rootdirblk)); if (FAT32(pmp) && pcl == pmp->pm_rootdirblk) pcl = 0; putushort(denp[1].deStartCluster, pcl); putushort(denp[1].deCDate, ndirent.de_CDate); putushort(denp[1].deCTime, ndirent.de_CTime); denp[1].deCHundredth = ndirent.de_CHun; putushort(denp[1].deADate, ndirent.de_ADate); putushort(denp[1].deMDate, ndirent.de_MDate); putushort(denp[1].deMTime, ndirent.de_MTime); if (FAT32(pmp)) { putushort(denp[0].deHighClust, newcluster >> 16); putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16); } else { putushort(denp[0].deHighClust, 0); putushort(denp[1].deHighClust, 0); } if ((error = bwrite(bp)) != 0) goto bad; /* * Now build up a directory entry pointing to the newly allocated * cluster. This will be written to an empty slot in the parent * directory. */ if ((error = uniqdosname(pdep, &cn, ndirent.de_Name)) != 0) goto bad; ndirent.de_Attributes = ATTR_DIRECTORY; ndirent.de_StartCluster = newcluster; ndirent.de_FileSize = 0; - ndirent.de_dev = pdep->de_dev; - ndirent.de_devvp = pdep->de_devvp; ndirent.de_pmp = pdep->de_pmp; if ((error = msdosfs_findslot(pdep, &cn)) != 0) goto bad; if ((error = createde(&ndirent, pdep, &dep, &cn)) != 0) goto bad; if ((error = msdosfs_updatede(dep)) != 0) goto bad; return dep; bad: clusterfree(pmp, newcluster, NULL); bad2: errno = error; return NULL; } Index: head/usr.sbin/makefs/msdos/msdosfsmount.h =================================================================== --- head/usr.sbin/makefs/msdos/msdosfsmount.h (nonexistent) +++ head/usr.sbin/makefs/msdos/msdosfsmount.h (revision 351273) @@ -0,0 +1,199 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-4-Clause + * + * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. + * Copyright (C) 1994, 1995, 1997 TooLs GmbH. + * All rights reserved. + * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). + * + * 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 by TooLs GmbH. + * 4. The name of TooLs GmbH may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``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 TOOLS GMBH 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. + */ +/*- + * Written by Paul Popelka (paulp@uts.amdahl.com) + * + * You can do anything you want with this software, just don't say you wrote + * it, and don't remove this notice. + * + * This software is provided "as is". + * + * The author supplies this software to be publicly redistributed on the + * understanding that the author is not responsible for the correct + * functioning of this software in any circumstances and is not liable for + * any damages caused by this software. + * + * October 1992 + */ + +#ifndef _MSDOSFS_MSDOSFSMOUNT_H_ +#define _MSDOSFS_MSDOSFSMOUNT_H_ + +#include + +struct vnode; +struct cdev; +struct bpb50; + +/* + * Layout of the mount control block for a MSDOSFS filesystem. + */ +struct msdosfsmount { + struct vnode *pm_devvp; /* vnode for character device mounted */ + struct cdev *pm_dev; /* character device mounted */ + struct bpb50 pm_bpb; /* BIOS parameter blk for this fs */ + u_long pm_FATsecs; /* actual number of FAT sectors */ + u_long pm_fatblk; /* block # of first FAT */ + u_long pm_rootdirblk; /* block # (cluster # for FAT32) of root directory number */ + u_long pm_rootdirsize; /* size in blocks (not clusters) */ + u_long pm_firstcluster; /* block number of first cluster */ + u_long pm_maxcluster; /* maximum cluster number */ + u_long pm_freeclustercount; /* number of free clusters */ + u_long pm_cnshift; /* shift file offset right this amount to get a cluster number */ + u_long pm_crbomask; /* and a file offset with this mask to get cluster rel offset */ + u_long pm_bnshift; /* shift file offset right this amount to get a block number */ + u_long pm_bpcluster; /* bytes per cluster */ + u_long pm_fmod; /* ~0 if fs is modified, this can rollover to 0 */ + u_long pm_fatblocksize; /* size of FAT blocks in bytes */ + u_long pm_fatblocksec; /* size of FAT blocks in sectors */ + u_long pm_fatsize; /* size of FAT in bytes */ + uint32_t pm_fatmask; /* mask to use for FAT numbers */ + u_long pm_fsinfo; /* fsinfo block number */ + u_long pm_nxtfree; /* next place to search for a free cluster */ + u_int pm_fatmult; /* these 2 values are used in FAT */ + u_int pm_fatdiv; /* offset computation */ + u_int pm_curfat; /* current FAT for FAT32 (0 otherwise) */ + u_int *pm_inusemap; /* ptr to bitmap of in-use clusters */ + uint64_t pm_flags; /* see below */ +}; + +/* Byte offset in FAT on filesystem pmp, cluster cn */ +#define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv) + +/* Number of bits in one pm_inusemap item: */ +#define N_INUSEBITS (8 * sizeof(u_int)) + +/* + * Shorthand for fields in the bpb contained in the msdosfsmount structure. + */ +#define pm_BytesPerSec pm_bpb.bpbBytesPerSec +#define pm_ResSectors pm_bpb.bpbResSectors +#define pm_FATs pm_bpb.bpbFATs +#define pm_RootDirEnts pm_bpb.bpbRootDirEnts +#define pm_Sectors pm_bpb.bpbSectors +#define pm_Media pm_bpb.bpbMedia +#define pm_SecPerTrack pm_bpb.bpbSecPerTrack +#define pm_Heads pm_bpb.bpbHeads +#define pm_HiddenSects pm_bpb.bpbHiddenSecs +#define pm_HugeSectors pm_bpb.bpbHugeSectors + +/* + * Convert pointer to buffer -> pointer to direntry + */ +#define bptoep(pmp, bp, dirofs) \ + ((struct direntry *)(((bp)->b_data) \ + + ((dirofs) & (pmp)->pm_crbomask))) + +/* + * Convert block number to cluster number + */ +#define de_bn2cn(pmp, bn) \ + ((bn) >> ((pmp)->pm_cnshift - (pmp)->pm_bnshift)) + +/* + * Convert cluster number to block number + */ +#define de_cn2bn(pmp, cn) \ + ((cn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift)) + +/* + * Convert file offset to cluster number + */ +#define de_cluster(pmp, off) \ + ((off) >> (pmp)->pm_cnshift) + +/* + * Clusters required to hold size bytes + */ +#define de_clcount(pmp, size) \ + (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift) + +/* + * Convert file offset to block number + */ +#define de_blk(pmp, off) \ + (de_cn2bn(pmp, de_cluster((pmp), (off)))) + +/* + * Convert cluster number to file offset + */ +#define de_cn2off(pmp, cn) \ + ((cn) << (pmp)->pm_cnshift) + +/* + * Convert block number to file offset + */ +#define de_bn2off(pmp, bn) \ + ((bn) << (pmp)->pm_bnshift) +/* + * Map a cluster number into a filesystem relative block number. + */ +#define cntobn(pmp, cn) \ + (de_cn2bn((pmp), (cn)-CLUST_FIRST) + (pmp)->pm_firstcluster) + +/* + * Calculate block number for directory entry in root dir, offset dirofs + */ +#define roottobn(pmp, dirofs) \ + (de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk) + +/* + * Calculate block number for directory entry at cluster dirclu, offset + * dirofs + */ +#define detobn(pmp, dirclu, dirofs) \ + ((dirclu) == MSDOSFSROOT \ + ? roottobn((pmp), (dirofs)) \ + : cntobn((pmp), (dirclu))) + +/* + * Msdosfs mount options: + */ +#define MSDOSFSMNT_SHORTNAME 1 /* Force old DOS short names only */ +#define MSDOSFSMNT_LONGNAME 2 /* Force Win'95 long names */ +#define MSDOSFSMNT_NOWIN95 4 /* Completely ignore Win95 entries */ +#define MSDOSFSMNT_KICONV 0x10 /* Use libiconv to convert chars */ +/* All flags above: */ +#define MSDOSFSMNT_MNTOPT \ + (MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \ + |MSDOSFSMNT_KICONV) +#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */ +#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */ +#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */ +#define MSDOSFS_FSIMOD 0x01000000 + +#endif /* !_MSDOSFS_MSDOSFSMOUNT_H_ */ Property changes on: head/usr.sbin/makefs/msdos/msdosfsmount.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Index: head/usr.sbin/makefs/msdos.c =================================================================== --- head/usr.sbin/makefs/msdos.c (revision 351272) +++ head/usr.sbin/makefs/msdos.c (revision 351273) @@ -1,272 +1,271 @@ /* $NetBSD: msdos.c,v 1.20 2017/04/14 15:40:35 christos Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ #if HAVE_NBTOOL_CONFIG_H #include "nbtool_config.h" #endif #include #if defined(__RCSID) && !defined(__lint) __FBSDID("$FreeBSD$"); #endif /* !__lint */ #include #if !HAVE_NBTOOL_CONFIG_H #include #endif #include #include #include #include #include #include #include +#include #include #include #include -#include -#include -#include -#include #include "makefs.h" #include "msdos.h" -#include "mkfs_msdos.h" +#include +#include + +#include "ffs/buf.h" + +#include "msdos/msdosfsmount.h" +#include "msdos/direntry.h" +#include "msdos/denode.h" + static int msdos_populate_dir(const char *, struct denode *, fsnode *, fsnode *, fsinfo_t *); struct msdos_options_ex { struct msdos_options options; - bool utf8; }; void msdos_prep_opts(fsinfo_t *fsopts) { struct msdos_options_ex *msdos_opt = ecalloc(1, sizeof(*msdos_opt)); const option_t msdos_options[] = { #define AOPT(_opt, _type, _name, _min, _desc) { \ .letter = _opt, \ .name = # _name, \ .type = _min == -1 ? OPT_STRPTR : \ (_min == -2 ? OPT_BOOL : \ (sizeof(_type) == 1 ? OPT_INT8 : \ (sizeof(_type) == 2 ? OPT_INT16 : \ (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))), \ .value = &msdos_opt->options._name, \ .minimum = _min, \ - .maximum = sizeof(_type) == 1 ? 0xff : \ - (sizeof(_type) == 2 ? 0xffff : \ - (sizeof(_type) == 4 ? 0xffffffff : 0xffffffffffffffffLL)), \ - .desc = _desc, \ + .maximum = sizeof(_type) == 1 ? UINT8_MAX : \ + (sizeof(_type) == 2 ? UINT16_MAX : \ + (sizeof(_type) == 4 ? UINT32_MAX : INT64_MAX)), \ + .desc = _desc, \ }, ALLOPTS #undef AOPT - { 'U', "utf8", &msdos_opt->utf8, OPT_BOOL, - 0, 1, "Use UTF8 names" }, { .name = NULL } }; fsopts->fs_specific = msdos_opt; fsopts->fs_options = copy_opts(msdos_options); } void msdos_cleanup_opts(fsinfo_t *fsopts) { free(fsopts->fs_specific); free(fsopts->fs_options); } int msdos_parse_opts(const char *option, fsinfo_t *fsopts) { struct msdos_options *msdos_opt = fsopts->fs_specific; option_t *msdos_options = fsopts->fs_options; - int rv; assert(option != NULL); assert(fsopts != NULL); assert(msdos_opt != NULL); if (debug & DEBUG_FS_PARSE_OPTS) printf("msdos_parse_opts: got `%s'\n", option); rv = set_option(msdos_options, option, NULL, 0); if (rv == -1) return rv; if (strcmp(msdos_options[rv].name, "volume_id") == 0) msdos_opt->volume_id_set = 1; else if (strcmp(msdos_options[rv].name, "media_descriptor") == 0) msdos_opt->media_descriptor_set = 1; else if (strcmp(msdos_options[rv].name, "hidden_sectors") == 0) msdos_opt->hidden_sectors_set = 1; if (stampst.st_ino) { msdos_opt->timestamp_set = 1; msdos_opt->timestamp = stampst.st_mtime; } return 1; } void msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) { struct msdos_options_ex *msdos_opt = fsopts->fs_specific; struct vnode vp, rootvp; - struct timeval start; + struct timeval start; struct msdosfsmount *pmp; uint32_t flags; assert(image != NULL); assert(dir != NULL); assert(root != NULL); assert(fsopts != NULL); fsopts->size = fsopts->maxsize; msdos_opt->options.create_size = MAX(msdos_opt->options.create_size, fsopts->offset + fsopts->size); - msdos_opt->options.offset = fsopts->offset; + if (fsopts->offset > 0) + msdos_opt->options.offset = fsopts->offset; if (msdos_opt->options.bytes_per_sector == 0) { if (fsopts->sectorsize == -1) fsopts->sectorsize = 512; msdos_opt->options.bytes_per_sector = fsopts->sectorsize; } else if (fsopts->sectorsize == -1) { fsopts->sectorsize = msdos_opt->options.bytes_per_sector; } else if (fsopts->sectorsize != msdos_opt->options.bytes_per_sector) { err(1, "inconsistent sectorsize -S %u" "!= -o bytes_per_sector %u", fsopts->sectorsize, msdos_opt->options.bytes_per_sector); } - /* create image */ + /* create image */ printf("Creating `%s'\n", image); TIMER_START(start); if (mkfs_msdos(image, NULL, &msdos_opt->options) == -1) return; TIMER_RESULTS(start, "mkfs_msdos"); fsopts->fd = open(image, O_RDWR); vp.fs = fsopts; flags = 0; - if (msdos_opt->utf8) - flags |= MSDOSFSMNT_UTF8; - - if ((pmp = msdosfs_mount(&vp, flags)) == NULL) + if ((pmp = msdosfs_mount(&vp)) == NULL) err(1, "msdosfs_mount"); if (msdosfs_root(pmp, &rootvp) != 0) err(1, "msdosfs_root"); if (debug & DEBUG_FS_MAKEFS) printf("msdos_makefs: image %s directory %s root %p\n", image, dir, root); - /* populate image */ + /* populate image */ printf("Populating `%s'\n", image); TIMER_START(start); if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1) errx(1, "Image file `%s' not created.", image); TIMER_RESULTS(start, "msdos_populate_dir"); if (debug & DEBUG_FS_MAKEFS) putchar('\n'); - /* ensure no outstanding buffers remain */ + /* ensure no outstanding buffers remain */ if (debug & DEBUG_FS_MAKEFS) bcleanup(); printf("Image `%s' complete\n", image); } static int msdos_populate_dir(const char *path, struct denode *dir, fsnode *root, fsnode *parent, fsinfo_t *fsopts) { fsnode *cur; char pbuf[MAXPATHLEN]; assert(dir != NULL); assert(root != NULL); assert(fsopts != NULL); for (cur = root->next; cur != NULL; cur = cur->next) { if ((size_t)snprintf(pbuf, sizeof(pbuf), "%s/%s", path, cur->name) >= sizeof(pbuf)) { warnx("path %s too long", pbuf); return -1; } if ((cur->inode->flags & FI_ALLOCATED) == 0) { cur->inode->flags |= FI_ALLOCATED; if (cur != root) { fsopts->curinode++; cur->inode->ino = fsopts->curinode; cur->parent = parent; } } if (cur->inode->flags & FI_WRITTEN) { continue; // hard link } cur->inode->flags |= FI_WRITTEN; if (cur->child) { struct denode *de; if ((de = msdosfs_mkdire(pbuf, dir, cur)) == NULL) { warn("msdosfs_mkdire %s", pbuf); return -1; } if (msdos_populate_dir(pbuf, de, cur->child, cur, fsopts) == -1) { warn("msdos_populate_dir %s", pbuf); return -1; } continue; } else if (!S_ISREG(cur->type)) { warnx("skipping non-regular file %s/%s", cur->path, cur->name); continue; } if (msdosfs_mkfile(pbuf, dir, cur) == NULL) { warn("msdosfs_mkfile %s", pbuf); return -1; } } return 0; } Index: head/usr.sbin/makefs/msdos.h =================================================================== --- head/usr.sbin/makefs/msdos.h (revision 351272) +++ head/usr.sbin/makefs/msdos.h (revision 351273) @@ -1,40 +1,60 @@ /* $FreeBSD$ */ /* $NetBSD: msdos.h,v 1.3 2015/10/16 16:40:02 christos Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ +#ifndef _MAKEFS_MSDOS_H +#define _MAKEFS_MSDOS_H + +#define NOCRED NULL + +#define MSDOSFS_DPRINTF(args) do { \ + if (debug & DEBUG_MSDOSFS) \ + printf args; \ +} while (0); + + struct vnode; struct denode; +struct fsnode; +struct msdosfsmount; -struct msdosfsmount *msdosfs_mount(struct vnode *, int); +struct componentname { + char *cn_nameptr; + size_t cn_namelen; +}; + +struct msdosfsmount *msdosfs_mount(struct vnode *); int msdosfs_root(struct msdosfsmount *, struct vnode *); struct denode *msdosfs_mkfile(const char *, struct denode *, fsnode *); struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *); + +#endif