Index: usr.sbin/makefs/Makefile =================================================================== --- usr.sbin/makefs/Makefile +++ usr.sbin/makefs/Makefile @@ -8,7 +8,7 @@ CFLAGS+=-I${SRCDIR} -SRCS= cd9660.c ffs.c \ +SRCS= cd9660.c ffs.c msdos.c \ makefs.c \ mtree.c \ walk.c @@ -18,6 +18,7 @@ .include "${SRCDIR}/cd9660/Makefile.inc" .include "${SRCDIR}/ffs/Makefile.inc" +.include "${SRCDIR}/msdos/Makefile.inc" CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1 Index: usr.sbin/makefs/ffs/buf.h =================================================================== --- usr.sbin/makefs/ffs/buf.h +++ usr.sbin/makefs/ffs/buf.h @@ -45,6 +45,9 @@ #include #include +#define bdwrite(bp) bwrite(bp) +#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount) + struct makefs_fsinfo; struct ucred; @@ -54,24 +57,20 @@ }; struct buf { - void * b_data; - long b_bufsize; - long b_bcount; - daddr_t b_blkno; - daddr_t b_lblkno; + void *b_data; + long b_bufsize; + long b_bcount; + daddr_t b_blkno; + daddr_t b_lblkno; struct makefs_fsinfo *b_fs; - - TAILQ_ENTRY(buf) b_tailq; + TAILQ_ENTRY(buf) b_tailq; }; -void bcleanup(void); -int bread(struct vnode *, daddr_t, int, struct ucred *, +void bcleanup(void); +void brelse(struct buf *); +int bwrite(struct buf *); +struct buf *getblk(struct vnode *, daddr_t, int, int, int, int); +int bread(struct vnode *, daddr_t, int, struct ucred *, struct buf **); -void brelse(struct buf *, int); -int bwrite(struct buf *); -struct buf * getblk(struct vnode *, daddr_t, int, int, int, int); - -#define bdwrite(bp) bwrite(bp) -#define clrbuf(bp) memset((bp)->b_data, 0, (u_int)(bp)->b_bcount) #endif /* _FFS_BUF_H */ Index: usr.sbin/makefs/makefs.h =================================================================== --- usr.sbin/makefs/makefs.h +++ usr.sbin/makefs/makefs.h @@ -185,6 +185,7 @@ DECLARE_FUN(ffs); DECLARE_FUN(cd9660); +DECLARE_FUN(msdos); extern u_int debug; extern int dupsok; @@ -225,7 +226,7 @@ #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) \ Index: usr.sbin/makefs/makefs.8 =================================================================== --- usr.sbin/makefs/makefs.8 +++ usr.sbin/makefs/makefs.8 @@ -200,7 +200,9 @@ 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 @@ -229,6 +231,19 @@ Set the size of the file system image to .Ar image-size bytes. +This is equivalent of setting both the minimum +.Fl ( m ) +and the maximum +.Fl ( M ) +sizes to +.Ar image-size . +For +.Sy ffs +and +.Sy msdos +the +.Ar offset +is not included on 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. @@ -251,6 +266,8 @@ 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. @@ -411,6 +428,66 @@ .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 , Index: usr.sbin/makefs/makefs.c =================================================================== --- usr.sbin/makefs/makefs.c +++ usr.sbin/makefs/makefs.c @@ -75,6 +75,7 @@ name ## _cleanup_opts, name ## _makefs \ } ENTRY(ffs), + ENTRY(msdos), ENTRY(cd9660), { .type = NULL }, }; Index: usr.sbin/makefs/msdos.h =================================================================== --- usr.sbin/makefs/msdos.h +++ usr.sbin/makefs/msdos.h @@ -30,11 +30,31 @@ * 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 componentname { + char *cn_nameptr; + size_t cn_namelen; +}; -struct msdosfsmount *msdosfs_mount(struct vnode *, int); +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 Index: usr.sbin/makefs/msdos.c =================================================================== --- usr.sbin/makefs/msdos.c +++ usr.sbin/makefs/msdos.c @@ -28,20 +28,13 @@ * 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 @@ -50,32 +43,32 @@ #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) { \ + struct msdos_options *msdos_spec = ecalloc(1, sizeof(*msdos_spec)); + const option_t msdos_opts[] = { +#define AOPT(_opt, _type, _name, _min, _desc) { \ .letter = _opt, \ .name = # _name, \ .type = _min == -1 ? OPT_STRPTR : \ @@ -83,22 +76,20 @@ (sizeof(_type) == 1 ? OPT_INT8 : \ (sizeof(_type) == 2 ? OPT_INT16 : \ (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))), \ - .value = &msdos_opt->options._name, \ + .value = &msdos_spec->_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" }, +#undef AOPT { .name = NULL } }; - fsopts->fs_specific = msdos_opt; - fsopts->fs_options = copy_opts(msdos_options); + fsopts->fs_specific = msdos_spec; + fsopts->fs_options = copy_opts(msdos_opts); } void @@ -111,32 +102,31 @@ 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; - + struct msdos_options *msdos_spec = fsopts->fs_specific; + option_t *msdos_opts = fsopts->fs_options; int rv; assert(option != NULL); assert(fsopts != NULL); - assert(msdos_opt != NULL); + assert(msdos_spec != NULL); if (debug & DEBUG_FS_PARSE_OPTS) - printf("msdos_parse_opts: got `%s'\n", option); + printf("msdos_parse_opts: got '%s'\n", option); - rv = set_option(msdos_options, option, NULL, 0); + rv = set_option(msdos_opts, 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 (strcmp(msdos_opts[rv].name, "volume_id") == 0) + msdos_spec->volume_id_set = 1; + else if (strcmp(msdos_opts[rv].name, "media_descriptor") == 0) + msdos_spec->media_descriptor_set = 1; + else if (strcmp(msdos_opts[rv].name, "hidden_sectors") == 0) + msdos_spec->hidden_sectors_set = 1; if (stampst.st_ino) { - msdos_opt->timestamp_set = 1; - msdos_opt->timestamp = stampst.st_mtime; + msdos_spec->timestamp_set = 1; + msdos_spec->timestamp = stampst.st_mtime; } return 1; @@ -146,9 +136,9 @@ void msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts) { - struct msdos_options_ex *msdos_opt = fsopts->fs_specific; + struct msdos_options *msdos_spec = fsopts->fs_specific; struct vnode vp, rootvp; - struct timeval start; + struct timeval start; struct msdosfsmount *pmp; uint32_t flags; @@ -158,25 +148,26 @@ assert(fsopts != NULL); fsopts->size = fsopts->maxsize; - msdos_opt->options.create_size = MAX(msdos_opt->options.create_size, + msdos_spec->create_size = MAX(msdos_spec->create_size, fsopts->offset + fsopts->size); - msdos_opt->options.offset = fsopts->offset; - if (msdos_opt->options.bytes_per_sector == 0) { + if (fsopts->offset > 0) + msdos_spec->offset = fsopts->offset; + if (msdos_spec->bytes_per_sector == 0) { if (fsopts->sectorsize == -1) fsopts->sectorsize = 512; - msdos_opt->options.bytes_per_sector = fsopts->sectorsize; + msdos_spec->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) { + fsopts->sectorsize = msdos_spec->bytes_per_sector; + } else if (fsopts->sectorsize != msdos_spec->bytes_per_sector) { err(1, "inconsistent sectorsize -S %u" - "!= -o bytes_per_sector %u", - fsopts->sectorsize, msdos_opt->options.bytes_per_sector); + "!= -o bytes_per_sector %u", + fsopts->sectorsize, msdos_spec->bytes_per_sector); } - /* create image */ - printf("Creating `%s'\n", image); + /* create image */ + printf("Creating '%s'\n", image); TIMER_START(start); - if (mkfs_msdos(image, NULL, &msdos_opt->options) == -1) + if (mkfs_msdos(image, NULL, msdos_spec) == -1) return; TIMER_RESULTS(start, "mkfs_msdos"); @@ -184,10 +175,7 @@ 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) @@ -197,21 +185,22 @@ printf("msdos_makefs: image %s directory %s root %p\n", image, dir, root); - /* populate image */ - printf("Populating `%s'\n", 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); + 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); + printf("Image '%s' complete\n", image); } static int @@ -223,8 +212,8 @@ assert(dir != NULL); assert(root != NULL); - assert(fsopts != 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)) { Index: usr.sbin/makefs/msdos/Makefile.inc =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/Makefile.inc @@ -0,0 +1,13 @@ +# $NetBSD: Makefile.inc,v 1.7 2016/02/06 10:40:58 mlelstv Exp $ +# + +MSDOS= ${SRCTOP}/sys/fs/msdosfs +MSDOS_NEWFS= ${SRCTOP}/sbin/newfs_msdos + +.PATH: ${SRCDIR}/msdos ${MSDOS} ${MSDOS_NEWFS} + +CFLAGS+= -I${MSDOS} -I${MSDOS_NEWFS} + +SRCS+= msdosfs_denode.c msdosfs_vnops.c msdosfs_vfsops.c msdosfs_conv.c +SRCS+= msdosfs_fat.c msdosfs_lookup.c +SRCS+= mkfs_msdos.c Index: usr.sbin/makefs/msdos/denode.h =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/denode.h @@ -0,0 +1,236 @@ +/* $FreeBSD$ */ +/* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws 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 + */ +#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_ */ Index: usr.sbin/makefs/msdos/direntry.h =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/direntry.h @@ -0,0 +1,144 @@ +/* $FreeBSD$ */ +/* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws 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 + */ +#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_ */ Index: usr.sbin/makefs/msdos/fat.h =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/fat.h @@ -0,0 +1,108 @@ +/* $FreeBSD$ */ +/* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 ws Exp $ */ + +/*- + * 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_ */ Index: usr.sbin/makefs/msdos/msdosfs_conv.c =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/msdosfs_conv.c @@ -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; +} Index: usr.sbin/makefs/msdos/msdosfs_denode.c =================================================================== --- usr.sbin/makefs/msdos/msdosfs_denode.c +++ usr.sbin/makefs/msdos/msdosfs_denode.c @@ -47,24 +47,29 @@ * 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(). @@ -81,20 +86,15 @@ 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 @@ -103,18 +103,17 @@ 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. */ @@ -131,12 +130,13 @@ 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 @@ -155,11 +155,12 @@ } 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); } @@ -176,13 +177,27 @@ */ 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; @@ -193,21 +208,20 @@ * 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 @@ -218,14 +232,15 @@ * 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 @@ -241,15 +256,17 @@ 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 @@ -258,13 +275,14 @@ 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); @@ -282,41 +300,40 @@ 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; @@ -347,7 +364,7 @@ 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); } } @@ -358,6 +375,6 @@ * 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: usr.sbin/makefs/msdos/msdosfs_fat.c =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/msdosfs_fat.c @@ -0,0 +1,1044 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws 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 + */ + +#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] |= 1 << (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] &= ~(1 << (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 |= (1 << (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 |= (1 << (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 cn, readcn; + int error; + u_long bn, bo, bsize, byteoffset; + + /* + * 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 || !bp) { + /* Read new FAT block */ + if (bp) + brelse(bp); + fatblock(pmp, byteoffset, &bn, &bsize, NULL); + error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); + if (error) { + 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] |= 1 << (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); +} Index: usr.sbin/makefs/msdos/msdosfs_lookup.c =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/msdosfs_lookup.c @@ -0,0 +1,301 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws 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 + */ + +#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); + } + } +} Index: usr.sbin/makefs/msdos/msdosfs_vfsops.c =================================================================== --- usr.sbin/makefs/msdos/msdosfs_vfsops.c +++ usr.sbin/makefs/msdos/msdosfs_vfsops.c @@ -45,43 +45,35 @@ * 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; @@ -90,13 +82,11 @@ 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; @@ -105,20 +95,17 @@ 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 @@ -135,30 +122,24 @@ 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); @@ -167,6 +148,7 @@ pmp->pm_HugeSectors = pmp->pm_Sectors; } + pmp->pm_flags = 0; if (pmp->pm_RootDirEnts == 0) { unsigned short vers = getushort(b710->bpbFSVers); /* @@ -175,7 +157,7 @@ * 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; @@ -193,52 +175,9 @@ } 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; } @@ -258,22 +197,11 @@ 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)) { /* @@ -306,18 +234,19 @@ 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; @@ -340,16 +269,13 @@ * 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; @@ -383,7 +309,7 @@ * 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; } @@ -407,7 +333,7 @@ error_exit: if (bp) - brelse(bp, BC_AGE); + brelse(bp); if (pmp) { if (pmp->pm_inusemap) free(pmp->pm_inusemap); Index: usr.sbin/makefs/msdos/msdosfs_vnops.c =================================================================== --- usr.sbin/makefs/msdos/msdosfs_vnops.c +++ usr.sbin/makefs/msdos/msdosfs_vnops.c @@ -46,34 +46,34 @@ * * 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: * @@ -93,28 +93,40 @@ */ 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 denode *dep, const struct stat *st) +{ + if (stampst.st_ino) + st = &stampst; + + 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 -msdosfs_times(struct msdosfsmount *pmp, struct denode *dep, - const struct stat *st) +unix2fattime(const struct timespec *tsp, uint16_t *ddp, uint16_t *dtp) { - struct timespec at; - struct timespec mt; - - if (stampst.st_ino) - 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); + 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; } /* @@ -133,7 +145,7 @@ * memory denode's will be in synch. */ static int -msdosfs_findslot(struct denode *dp, struct componentname *cnp) +msdosfs_findslot(struct denode *dp, struct componentname *cnp) { daddr_t bn; int error; @@ -162,12 +174,12 @@ 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; } @@ -181,7 +193,7 @@ * 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. @@ -200,8 +212,7 @@ 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); } @@ -248,11 +259,10 @@ 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; } @@ -274,7 +284,7 @@ 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 @@ -304,7 +314,7 @@ * 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 @@ -352,13 +362,12 @@ 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 @@ -385,11 +394,10 @@ 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) @@ -434,8 +442,9 @@ 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; @@ -444,9 +453,9 @@ 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; @@ -454,14 +463,14 @@ 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; @@ -472,29 +481,19 @@ 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); @@ -508,12 +507,11 @@ 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 */ @@ -523,7 +521,7 @@ { 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 */ @@ -540,11 +538,9 @@ 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; @@ -564,14 +560,14 @@ /* * 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 @@ -579,11 +575,10 @@ * 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; @@ -595,7 +590,7 @@ 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; @@ -628,8 +623,6 @@ 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; Index: usr.sbin/makefs/msdos/msdosfsmount.h =================================================================== --- /dev/null +++ usr.sbin/makefs/msdos/msdosfsmount.h @@ -0,0 +1,197 @@ +/* $FreeBSD$ */ +/* $NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws 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 + */ + +#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_ */