Author: emaste Date: Tue Aug 20 18:20:45 2019 New Revision: 351273 URL: https://svnweb.freebsd.org/changeset/base/351273
Log: makefs: add msdosfs (FAT) support Add FAT support to makefs by copying some files from sys/fs/msdosfs/ and updating others with changes from NetBSD. The six files copied from sys/fs/msdosfs at r348251 and modified are: denode.h direntry.h fat.h msdosfs_fat.c msdosfs_lookup.c msdosfsmount.h I would prefer to avoid the duplication, but reluctance to doing so was expressed in a previous review (D11197); for now copy the files and revisit in the future. Submitted by: Siva Mahadevan Discussed with: cem, imp MFC after: 1 month Relnotes: Yes Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D16438 Added: head/usr.sbin/makefs/msdos/Makefile.inc (contents, props changed) head/usr.sbin/makefs/msdos/denode.h - copied, changed from r351251, head/sys/fs/msdosfs/denode.h head/usr.sbin/makefs/msdos/direntry.h - copied, changed from r351251, head/sys/fs/msdosfs/direntry.h head/usr.sbin/makefs/msdos/fat.h - copied, changed from r351251, head/sys/fs/msdosfs/fat.h head/usr.sbin/makefs/msdos/msdosfs_conv.c (contents, props changed) head/usr.sbin/makefs/msdos/msdosfs_fat.c - copied, changed from r351251, head/sys/fs/msdosfs/msdosfs_fat.c head/usr.sbin/makefs/msdos/msdosfs_lookup.c - copied, changed from r351251, head/sys/fs/msdosfs/msdosfs_lookup.c head/usr.sbin/makefs/msdos/msdosfsmount.h - copied, changed from r351251, head/sys/fs/msdosfs/msdosfsmount.h Modified: head/usr.sbin/makefs/Makefile head/usr.sbin/makefs/makefs.8 head/usr.sbin/makefs/makefs.c head/usr.sbin/makefs/makefs.h head/usr.sbin/makefs/msdos.c head/usr.sbin/makefs/msdos.h head/usr.sbin/makefs/msdos/msdosfs_denode.c head/usr.sbin/makefs/msdos/msdosfs_vfsops.c head/usr.sbin/makefs/msdos/msdosfs_vnops.c Modified: head/usr.sbin/makefs/Makefile ============================================================================== --- head/usr.sbin/makefs/Makefile Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/Makefile Tue Aug 20 18:20:45 2019 (r351273) @@ -8,8 +8,10 @@ PROG= makefs CFLAGS+=-I${SRCDIR} -SRCS= cd9660.c ffs.c \ +SRCS= cd9660.c \ + ffs.c \ makefs.c \ + msdos.c \ mtree.c \ walk.c MAN= makefs.8 @@ -18,6 +20,7 @@ WARNS?= 2 .include "${SRCDIR}/cd9660/Makefile.inc" .include "${SRCDIR}/ffs/Makefile.inc" +.include "${SRCDIR}/msdos/Makefile.inc" CFLAGS+=-DHAVE_STRUCT_STAT_ST_FLAGS=1 Modified: head/usr.sbin/makefs/makefs.8 ============================================================================== --- head/usr.sbin/makefs/makefs.8 Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/makefs.8 Tue Aug 20 18:20:45 2019 (r351273) @@ -35,7 +35,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 19, 2019 +.Dd August 20, 2019 .Dt MAKEFS 8 .Os .Sh NAME @@ -198,7 +198,9 @@ and 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 @@ -232,10 +234,14 @@ and the maximum sizes to the same value. For .Sy ffs +and +.Sy msdos the .Ar image-size does not include the .Ar offset . +.Ar offset +is not included in that size. .It Fl T Ar timestamp Specify a timestamp to be set for all filesystem files and directories created so that repeatable builds are possible. @@ -258,6 +264,8 @@ The following file system types are supported: 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. @@ -420,6 +428,67 @@ Use RockRidge extensions (for longer filenames, etc.). Turns on verbose output. .It Sy volumeid Volume set identifier of the image. +.El +.Ss msdos-specific options +.Sy msdos +images have MS-DOS-specific optional parameters that may be +provided. +The arguments consist of a keyword, an equal sign +.Pq Ql = , +and a value. +The following keywords are supported (see +.Xr newfs_msdos 8 +for more details): +.Pp +.Bl -tag -width omit-trailing-period -offset indent -compact +.It Cm backup_sector +Location of the backup boot sector. +.It Cm block_size +Block size. +.It Cm bootstrap +Bootstrap file. +.It Cm bytes_per_sector +Bytes per sector. +.It Cm create_size +Create file size. +.It Cm directory_entries +Directory entries. +.It Cm drive_heads +Drive heads. +.It Cm fat_type +FAT type (12, 16, or 32). +.It Cm floppy +Preset drive parameters for standard format floppy disks +(160, 180, 320, 360, 640, 720, 1200, 1232, 1440, or 2880). +.It Cm hidden_sectors +Hidden sectors. +.It Cm info_sector +Location of the info sector. +.It Cm media_descriptor +Media descriptor. +.It Cm num_FAT +Number of FATs. +.It Cm OEM_string +OEM string. +.It Cm offset +Offset in device. +This option will be ignored if +.Fl O +is set to a positive number. +.It Cm reserved_sectors +Reserved sectors. +.It Cm sectors_per_cluster +Sectors per cluster. +.It Cm sectors_per_fat +Sectors per FAT. +.It Cm sectors_per_track +Sectors per track. +.It Cm size +File System size. +.It Cm volume_id +Volume ID. +.It Cm volume_label +Volume Label. .El .Sh SEE ALSO .Xr mtree 5 , Modified: head/usr.sbin/makefs/makefs.c ============================================================================== --- head/usr.sbin/makefs/makefs.c Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/makefs.c Tue Aug 20 18:20:45 2019 (r351273) @@ -74,8 +74,9 @@ static fstype_t fstypes[] = { # name, name ## _prep_opts, name ## _parse_opts, \ name ## _cleanup_opts, name ## _makefs \ } - ENTRY(ffs), ENTRY(cd9660), + ENTRY(ffs), + ENTRY(msdos), { .type = NULL }, }; Modified: head/usr.sbin/makefs/makefs.h ============================================================================== --- head/usr.sbin/makefs/makefs.h Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/makefs.h Tue Aug 20 18:20:45 2019 (r351273) @@ -183,8 +183,9 @@ int fs ## _parse_opts(const char *, fsinfo_t *); \ void fs ## _cleanup_opts(fsinfo_t *); \ void fs ## _makefs(const char *, const char *, fsnode *, fsinfo_t *) -DECLARE_FUN(ffs); DECLARE_FUN(cd9660); +DECLARE_FUN(ffs); +DECLARE_FUN(msdos); extern u_int debug; extern int dupsok; @@ -225,6 +226,7 @@ extern struct stat stampst; #define DEBUG_APPLY_SPECFILE 0x04000000 #define DEBUG_APPLY_SPECENTRY 0x08000000 #define DEBUG_APPLY_SPECONLY 0x10000000 +#define DEBUG_MSDOSFS 0x20000000 #define TIMER_START(x) \ Modified: head/usr.sbin/makefs/msdos.c ============================================================================== --- head/usr.sbin/makefs/msdos.c Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/msdos.c Tue Aug 20 18:20:45 2019 (r351273) @@ -50,24 +50,28 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <stdint.h> #include <unistd.h> #include <dirent.h> #include <util.h> -#include <ffs/buf.h> -#include <fs/msdosfs/bpb.h> -#include <fs/msdosfs/denode.h> -#include <fs/msdosfs/msdosfsmount.h> #include "makefs.h" #include "msdos.h" -#include "mkfs_msdos.h" +#include <mkfs_msdos.h> +#include <fs/msdosfs/bpb.h> + +#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 @@ -85,15 +89,13 @@ msdos_prep_opts(fsinfo_t *fsopts) (sizeof(_type) == 4 ? OPT_INT32 : OPT_INT64)))), \ .value = &msdos_opt->options._name, \ .minimum = _min, \ - .maximum = sizeof(_type) == 1 ? 0xff : \ - (sizeof(_type) == 2 ? 0xffff : \ - (sizeof(_type) == 4 ? 0xffffffff : 0xffffffffffffffffLL)), \ - .desc = _desc, \ + .maximum = sizeof(_type) == 1 ? UINT8_MAX : \ + (sizeof(_type) == 2 ? UINT16_MAX : \ + (sizeof(_type) == 4 ? UINT32_MAX : INT64_MAX)), \ + .desc = _desc, \ }, ALLOPTS #undef AOPT - { 'U', "utf8", &msdos_opt->utf8, OPT_BOOL, - 0, 1, "Use UTF8 names" }, { .name = NULL } }; @@ -113,7 +115,6 @@ msdos_parse_opts(const char *option, fsinfo_t *fsopts) { struct msdos_options *msdos_opt = fsopts->fs_specific; option_t *msdos_options = fsopts->fs_options; - int rv; assert(option != NULL); @@ -148,7 +149,7 @@ msdos_makefs(const char *image, const char *dir, fsnod { struct msdos_options_ex *msdos_opt = fsopts->fs_specific; struct vnode vp, rootvp; - struct timeval start; + struct timeval start; struct msdosfsmount *pmp; uint32_t flags; @@ -160,7 +161,8 @@ msdos_makefs(const char *image, const char *dir, fsnod fsopts->size = fsopts->maxsize; msdos_opt->options.create_size = MAX(msdos_opt->options.create_size, fsopts->offset + fsopts->size); - msdos_opt->options.offset = fsopts->offset; + if (fsopts->offset > 0) + msdos_opt->options.offset = fsopts->offset; if (msdos_opt->options.bytes_per_sector == 0) { if (fsopts->sectorsize == -1) fsopts->sectorsize = 512; @@ -173,7 +175,7 @@ msdos_makefs(const char *image, const char *dir, fsnod fsopts->sectorsize, msdos_opt->options.bytes_per_sector); } - /* create image */ + /* create image */ printf("Creating `%s'\n", image); TIMER_START(start); if (mkfs_msdos(image, NULL, &msdos_opt->options) == -1) @@ -184,10 +186,7 @@ msdos_makefs(const char *image, const char *dir, fsnod 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,7 +196,7 @@ msdos_makefs(const char *image, const char *dir, fsnod printf("msdos_makefs: image %s directory %s root %p\n", image, dir, root); - /* populate image */ + /* populate image */ printf("Populating `%s'\n", image); TIMER_START(start); if (msdos_populate_dir(dir, VTODE(&rootvp), root, root, fsopts) == -1) @@ -207,7 +206,7 @@ msdos_makefs(const char *image, const char *dir, fsnod if (debug & DEBUG_FS_MAKEFS) putchar('\n'); - /* ensure no outstanding buffers remain */ + /* ensure no outstanding buffers remain */ if (debug & DEBUG_FS_MAKEFS) bcleanup(); Modified: head/usr.sbin/makefs/msdos.h ============================================================================== --- head/usr.sbin/makefs/msdos.h Tue Aug 20 18:02:37 2019 (r351272) +++ head/usr.sbin/makefs/msdos.h Tue Aug 20 18:20:45 2019 (r351273) @@ -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 msdosfsmount *msdosfs_mount(struct vnode *, int); +struct componentname { + char *cn_nameptr; + size_t cn_namelen; +}; + +struct msdosfsmount *msdosfs_mount(struct vnode *); int msdosfs_root(struct msdosfsmount *, struct vnode *); struct denode *msdosfs_mkfile(const char *, struct denode *, fsnode *); struct denode *msdosfs_mkdire(const char *, struct denode *, fsnode *); + +#endif Added: head/usr.sbin/makefs/msdos/Makefile.inc ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.sbin/makefs/msdos/Makefile.inc Tue Aug 20 18:20:45 2019 (r351273) @@ -0,0 +1,13 @@ +# $FreeBSD$ +# + +MSDOS= ${SRCTOP}/sys/fs/msdosfs +MSDOS_NEWFS= ${SRCTOP}/sbin/newfs_msdos + +.PATH: ${SRCDIR}/msdos ${MSDOS} ${MSDOS_NEWFS} + +CFLAGS+= -I${MSDOS} -I${MSDOS_NEWFS} + +SRCS+= mkfs_msdos.c +SRCS+= msdosfs_conv.c msdosfs_denode.c msdosfs_fat.c msdosfs_lookup.c +SRCS+= msdosfs_vnops.c msdosfs_vfsops.c Copied and modified: head/usr.sbin/makefs/msdos/denode.h (from r351251, head/sys/fs/msdosfs/denode.h) ============================================================================== --- head/sys/fs/msdosfs/denode.h Tue Aug 20 16:07:17 2019 (r351251, copy source) +++ head/usr.sbin/makefs/msdos/denode.h Tue Aug 20 18:20:45 2019 (r351273) @@ -161,7 +161,6 @@ struct denode { 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 */ - u_quad_t de_modrev; /* Revision level for lease. */ uint64_t de_inode; /* Inode number (really byte offset of direntry) */ }; @@ -213,60 +212,16 @@ struct denode { ((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \ putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16)) -#ifdef _KERNEL - #define VTODE(vp) ((struct denode *)(vp)->v_data) #define DETOV(de) ((de)->de_vnode) -#define DETIMES(dep, acc, mod, cre) do { \ - if ((dep)->de_flag & DE_UPDATE) { \ - (dep)->de_flag |= DE_MODIFIED; \ - timespec2fattime((mod), 0, &(dep)->de_MDate, \ - &(dep)->de_MTime, NULL); \ - (dep)->de_Attributes |= ATTR_ARCHIVE; \ - } \ - if ((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95) { \ - (dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \ - break; \ - } \ - if ((dep)->de_flag & DE_ACCESS) { \ - uint16_t adate; \ - \ - timespec2fattime((acc), 0, &adate, NULL, NULL); \ - if (adate != (dep)->de_ADate) { \ - (dep)->de_flag |= DE_MODIFIED; \ - (dep)->de_ADate = adate; \ - } \ - } \ - if ((dep)->de_flag & DE_CREATE) { \ - timespec2fattime((cre), 0, &(dep)->de_CDate, \ - &(dep)->de_CTime, &(dep)->de_CHun); \ - (dep)->de_flag |= DE_MODIFIED; \ - } \ - (dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \ -} while (0) +struct buf; +struct msdosfsmount; +struct direntry; +struct componentname; +struct denode; /* - * This overlays the fid structure (see mount.h) - */ -struct defid { - u_short defid_len; /* length of structure */ - u_short defid_pad; /* force long alignment */ - - uint32_t defid_dirclust; /* cluster this dir entry came from */ - uint32_t defid_dirofs; /* offset of entry within the cluster */ -#if 0 - uint32_t defid_gen; /* generation number */ -#endif -}; - -extern struct vop_vector msdosfs_vnodeops; - -int msdosfs_lookup(struct vop_cachedlookup_args *); -int msdosfs_inactive(struct vop_inactive_args *); -int msdosfs_reclaim(struct vop_reclaim_args *); - -/* * Internal service routine prototypes. */ int deget(struct msdosfsmount *, u_long, u_long, struct denode **); @@ -274,14 +229,9 @@ int uniqdosname(struct denode *, struct componentname 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, struct ucred *cred); +int deextend(struct denode *dep, u_long length); int fillinusemap(struct msdosfsmount *pmp); -void reinsert(struct denode *dep); -int dosdirempty(struct denode *dep); int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp); -int deupdat(struct denode *dep, int waitfor); int removede(struct denode *pdep, struct denode *dep); -int detrunc(struct denode *dep, u_long length, int flags, struct ucred *cred); -int doscheckpath( struct denode *source, struct denode *target); -#endif /* _KERNEL */ +int detrunc(struct denode *dep, u_long length, int flags); #endif /* !_FS_MSDOSFS_DENODE_H_ */ Copied and modified: head/usr.sbin/makefs/msdos/direntry.h (from r351251, head/sys/fs/msdosfs/direntry.h) ============================================================================== --- head/sys/fs/msdosfs/direntry.h Tue Aug 20 16:07:17 2019 (r351251, copy source) +++ head/usr.sbin/makefs/msdos/direntry.h Tue Aug 20 18:20:45 2019 (r351273) @@ -135,31 +135,12 @@ struct winentry { #define DD_YEAR_MASK 0xFE00 /* year - 1980 */ #define DD_YEAR_SHIFT 9 -#ifdef _KERNEL -struct mbnambuf { - size_t nb_len; - int nb_last_id; - char nb_buf[WIN_MAXLEN + 1]; -}; - -struct dirent; -struct msdosfsmount; - -char *mbnambuf_flush(struct mbnambuf *nbp, struct dirent *dp); -void mbnambuf_init(struct mbnambuf *nbp); -int mbnambuf_write(struct mbnambuf *nbp, char *name, int id); -int dos2unixfn(u_char dn[11], u_char *un, int lower, - struct msdosfsmount *pmp); -int unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen, - struct msdosfsmount *pmp); -int unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt, - int chksum, struct msdosfsmount *pmp); -int winChkName(struct mbnambuf *nbp, const u_char *un, size_t unlen, - int chksum, struct msdosfsmount *pmp); -int win2unixfn(struct mbnambuf *nbp, struct winentry *wep, int chksum, - struct msdosfsmount *pmp); uint8_t winChksum(uint8_t *name); -int winSlotCnt(const u_char *un, size_t unlen, struct msdosfsmount *pmp); -size_t winLenFixup(const u_char *un, size_t unlen); -#endif /* _KERNEL */ +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_ */ Copied and modified: head/usr.sbin/makefs/msdos/fat.h (from r351251, head/sys/fs/msdosfs/fat.h) ============================================================================== --- head/sys/fs/msdosfs/fat.h Tue Aug 20 16:07:17 2019 (r351251, copy source) +++ head/usr.sbin/makefs/msdos/fat.h Tue Aug 20 18:20:45 2019 (r351273) @@ -82,7 +82,6 @@ #define MSDOSFSEOF(pmp, cn) ((((cn) | ~(pmp)->pm_fatmask) & CLUST_EOFS) == CLUST_EOFS) -#ifdef _KERNEL /* * These are the values for the function argument to the function * fatentry(). @@ -96,6 +95,10 @@ */ #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); @@ -103,7 +106,5 @@ int fatentry(int function, struct msdosfsmount *pmp, u 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); -int markvoldirty(struct msdosfsmount *pmp, int dirty); -#endif /* _KERNEL */ #endif /* !_FS_MSDOSFS_FAT_H_ */ Added: head/usr.sbin/makefs/msdos/msdosfs_conv.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.sbin/makefs/msdos/msdosfs_conv.c Tue Aug 20 18:20:45 2019 (r351273) @@ -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 (pa...@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 (pa...@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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/endian.h> + +#include <dirent.h> +#include <stdio.h> +#include <string.h> + +#include <fs/msdosfs/bpb.h> + +#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; + *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"