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
This commit is contained in:
Ed Maste 2019-08-20 18:20:45 +00:00
parent 35fd0fc409
commit 98dc8da58c
17 changed files with 2906 additions and 314 deletions

View File

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

View File

@ -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.
@ -421,6 +429,67 @@ Turns on verbose output.
.It Sy volumeid
Volume set identifier of the image.
.El
.Ss msdos-specific options
.Sy msdos
images have MS-DOS-specific optional parameters that may be
provided.
The arguments consist of a keyword, an equal sign
.Pq Ql = ,
and a value.
The following keywords are supported (see
.Xr newfs_msdos 8
for more details):
.Pp
.Bl -tag -width omit-trailing-period -offset indent -compact
.It Cm backup_sector
Location of the backup boot sector.
.It Cm block_size
Block size.
.It Cm bootstrap
Bootstrap file.
.It Cm bytes_per_sector
Bytes per sector.
.It Cm create_size
Create file size.
.It Cm directory_entries
Directory entries.
.It Cm drive_heads
Drive heads.
.It Cm fat_type
FAT type (12, 16, or 32).
.It Cm floppy
Preset drive parameters for standard format floppy disks
(160, 180, 320, 360, 640, 720, 1200, 1232, 1440, or 2880).
.It Cm hidden_sectors
Hidden sectors.
.It Cm info_sector
Location of the info sector.
.It Cm media_descriptor
Media descriptor.
.It Cm num_FAT
Number of FATs.
.It Cm OEM_string
OEM string.
.It Cm offset
Offset in device.
This option will be ignored if
.Fl O
is set to a positive number.
.It Cm reserved_sectors
Reserved sectors.
.It Cm sectors_per_cluster
Sectors per cluster.
.It Cm sectors_per_fat
Sectors per FAT.
.It Cm sectors_per_track
Sectors per track.
.It Cm size
File System size.
.It Cm volume_id
Volume ID.
.It Cm volume_label
Volume Label.
.El
.Sh SEE ALSO
.Xr mtree 5 ,
.Xr mtree 8 ,

View File

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

View File

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

View File

@ -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, fsnode *root, fsinfo_t *fsopts)
{
struct msdos_options_ex *msdos_opt = fsopts->fs_specific;
struct vnode vp, rootvp;
struct timeval start;
struct timeval start;
struct msdosfsmount *pmp;
uint32_t flags;
@ -160,7 +161,8 @@ msdos_makefs(const char *image, const char *dir, fsnode *root, fsinfo_t *fsopts)
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, fsnode *root, fsinfo_t *fsopts)
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, fsnode *root, fsinfo_t *fsopts)
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, fsnode *root, fsinfo_t *fsopts)
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, fsnode *root, fsinfo_t *fsopts)
if (debug & DEBUG_FS_MAKEFS)
putchar('\n');
/* ensure no outstanding buffers remain */
/* ensure no outstanding buffers remain */
if (debug & DEBUG_FS_MAKEFS)
bcleanup();

View File

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

View File

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

View File

@ -0,0 +1,237 @@
/* $FreeBSD$ */
/* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
#ifndef _FS_MSDOSFS_DENODE_H_
#define _FS_MSDOSFS_DENODE_H_
/*
* This is the pc filesystem specific portion of the vnode structure.
*
* To describe a file uniquely the de_dirclust, de_diroffset, and
* de_StartCluster fields are used.
*
* de_dirclust contains the cluster number of the directory cluster
* containing the entry for a file or directory.
* de_diroffset is the index into the cluster for the entry describing
* a file or directory.
* de_StartCluster is the number of the first cluster of the file or directory.
*
* Now to describe the quirks of the pc filesystem.
* - Clusters 0 and 1 are reserved.
* - The first allocatable cluster is 2.
* - The root directory is of fixed size and all blocks that make it up
* are contiguous.
* - Cluster 0 refers to the root directory when it is found in the
* startcluster field of a directory entry that points to another directory.
* - Cluster 0 implies a 0 length file when found in the start cluster field
* of a directory entry that points to a file.
* - You can't use the cluster number 0 to derive the address of the root
* directory.
* - Multiple directory entries can point to a directory. The entry in the
* parent directory points to a child directory. Any directories in the
* child directory contain a ".." entry that points back to the parent.
* The child directory itself contains a "." entry that points to itself.
* - The root directory does not contain a "." or ".." entry.
* - Directory entries for directories are never changed once they are created
* (except when removed). The size stays 0, and the last modification time
* is never changed. This is because so many directory entries can point to
* the physical clusters that make up a directory. It would lead to an
* update nightmare.
* - The length field in a directory entry pointing to a directory contains 0
* (always). The only way to find the end of a directory is to follow the
* cluster chain until the "last cluster" marker is found.
*
* My extensions to make this house of cards work. These apply only to the in
* memory copy of the directory entry.
* - A reference count for each denode will be kept since dos doesn't keep such
* things.
*/
/*
* Internal pseudo-offset for (nonexistent) directory entry for the root
* dir in the root dir
*/
#define MSDOSFSROOT_OFS 0x1fffffff
/*
* The FAT cache structure. fc_fsrcn is the filesystem relative cluster
* number that corresponds to the file relative cluster number in this
* structure (fc_frcn).
*/
struct fatcache {
u_long fc_frcn; /* file relative cluster number */
u_long fc_fsrcn; /* filesystem relative cluster number */
};
/*
* The FAT entry cache as it stands helps make extending files a "quick"
* operation by avoiding having to scan the FAT to discover the last
* cluster of the file. The cache also helps sequential reads by
* remembering the last cluster read from the file. This also prevents us
* from having to rescan the FAT to find the next cluster to read. This
* cache is probably pretty worthless if a file is opened by multiple
* processes.
*/
#define FC_SIZE 3 /* number of entries in the cache */
#define FC_LASTMAP 0 /* entry the last call to pcbmap() resolved
* to */
#define FC_LASTFC 1 /* entry for the last cluster in the file */
#define FC_NEXTTOLASTFC 2 /* entry for a close to the last cluster in
* the file */
#define FCE_EMPTY 0xffffffff /* doesn't represent an actual cluster # */
/*
* Set a slot in the FAT cache.
*/
#define fc_setcache(dep, slot, frcn, fsrcn) \
(dep)->de_fc[(slot)].fc_frcn = (frcn); \
(dep)->de_fc[(slot)].fc_fsrcn = (fsrcn);
/*
* This is the in memory variant of a dos directory entry. It is usually
* contained within a vnode.
*/
struct denode {
struct vnode *de_vnode; /* addr of vnode we are part of */
u_long de_flag; /* flag bits */
u_long de_dirclust; /* cluster of the directory file containing this entry */
u_long de_diroffset; /* offset of this entry in the directory cluster */
u_long de_fndoffset; /* offset of found dir entry */
int de_fndcnt; /* number of slots before de_fndoffset */
long de_refcnt; /* reference count */
struct msdosfsmount *de_pmp; /* addr of our mount struct */
u_char de_Name[12]; /* name, from DOS directory entry */
u_char de_Attributes; /* attributes, from directory entry */
u_char de_LowerCase; /* NT VFAT lower case flags */
u_char de_CHun; /* Hundredth of second of CTime*/
u_short de_CTime; /* creation time */
u_short de_CDate; /* creation date */
u_short de_ADate; /* access date */
u_short de_MTime; /* modification time */
u_short de_MDate; /* modification date */
u_long de_StartCluster; /* starting cluster of file */
u_long de_FileSize; /* size of file in bytes */
struct fatcache de_fc[FC_SIZE]; /* FAT cache */
uint64_t de_inode; /* Inode number (really byte offset of direntry) */
};
/*
* Values for the de_flag field of the denode.
*/
#define DE_UPDATE 0x0004 /* Modification time update request */
#define DE_CREATE 0x0008 /* Creation time update */
#define DE_ACCESS 0x0010 /* Access time update */
#define DE_MODIFIED 0x0020 /* Denode has been modified */
#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */
/* Maximum size of a file on a FAT filesystem */
#define MSDOSFS_FILESIZE_MAX 0xFFFFFFFFLL
/*
* Transfer directory entries between internal and external form.
* dep is a struct denode * (internal form),
* dp is a struct direntry * (external form).
*/
#define DE_INTERNALIZE32(dep, dp) \
((dep)->de_StartCluster |= getushort((dp)->deHighClust) << 16)
#define DE_INTERNALIZE(dep, dp) \
(memcpy((dep)->de_Name, (dp)->deName, 11), \
(dep)->de_Attributes = (dp)->deAttributes, \
(dep)->de_LowerCase = (dp)->deLowerCase, \
(dep)->de_CHun = (dp)->deCHundredth, \
(dep)->de_CTime = getushort((dp)->deCTime), \
(dep)->de_CDate = getushort((dp)->deCDate), \
(dep)->de_ADate = getushort((dp)->deADate), \
(dep)->de_MTime = getushort((dp)->deMTime), \
(dep)->de_MDate = getushort((dp)->deMDate), \
(dep)->de_StartCluster = getushort((dp)->deStartCluster), \
(dep)->de_FileSize = getulong((dp)->deFileSize), \
(FAT32((dep)->de_pmp) ? DE_INTERNALIZE32((dep), (dp)) : 0))
#define DE_EXTERNALIZE(dp, dep) \
(memcpy((dp)->deName, (dep)->de_Name, 11), \
(dp)->deAttributes = (dep)->de_Attributes, \
(dp)->deLowerCase = (dep)->de_LowerCase, \
(dp)->deCHundredth = (dep)->de_CHun, \
putushort((dp)->deCTime, (dep)->de_CTime), \
putushort((dp)->deCDate, (dep)->de_CDate), \
putushort((dp)->deADate, (dep)->de_ADate), \
putushort((dp)->deMTime, (dep)->de_MTime), \
putushort((dp)->deMDate, (dep)->de_MDate), \
putushort((dp)->deStartCluster, (dep)->de_StartCluster), \
putulong((dp)->deFileSize, \
((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \
putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16))
#define VTODE(vp) ((struct denode *)(vp)->v_data)
#define DETOV(de) ((de)->de_vnode)
struct buf;
struct msdosfsmount;
struct direntry;
struct componentname;
struct denode;
/*
* Internal service routine prototypes.
*/
int deget(struct msdosfsmount *, u_long, u_long, struct denode **);
int uniqdosname(struct denode *, struct componentname *, u_char *);
int readep(struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp);
int readde(struct denode *dep, struct buf **bpp, struct direntry **epp);
int deextend(struct denode *dep, u_long length);
int fillinusemap(struct msdosfsmount *pmp);
int createde(struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp);
int removede(struct denode *pdep, struct denode *dep);
int detrunc(struct denode *dep, u_long length, int flags);
#endif /* !_FS_MSDOSFS_DENODE_H_ */

View File

@ -0,0 +1,146 @@
/* $FreeBSD$ */
/* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
#ifndef _FS_MSDOSFS_DIRENTRY_H_
#define _FS_MSDOSFS_DIRENTRY_H_
/*
* Structure of a dos directory entry.
*/
struct direntry {
uint8_t deName[11]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
uint8_t deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
uint8_t deLowerCase; /* NT VFAT lower case flags */
#define LCASE_BASE 0x08 /* filename base in lower case */
#define LCASE_EXT 0x10 /* filename extension in lower case */
uint8_t deCHundredth; /* hundredth of seconds in CTime */
uint8_t deCTime[2]; /* create time */
uint8_t deCDate[2]; /* create date */
uint8_t deADate[2]; /* access date */
uint8_t deHighClust[2]; /* high bytes of cluster number */
uint8_t deMTime[2]; /* last update time */
uint8_t deMDate[2]; /* last update date */
uint8_t deStartCluster[2]; /* starting cluster of file */
uint8_t deFileSize[4]; /* size of file in bytes */
};
/*
* Structure of a Win95 long name directory entry
*/
struct winentry {
uint8_t weCnt;
#define WIN_LAST 0x40
#define WIN_CNT 0x3f
uint8_t wePart1[10];
uint8_t weAttributes;
#define ATTR_WIN95 0x0f
uint8_t weReserved1;
uint8_t weChksum;
uint8_t wePart2[12];
uint16_t weReserved2;
uint8_t wePart3[4];
};
#define WIN_CHARS 13 /* Number of chars per winentry */
/*
* Maximum number of winentries for a filename.
*/
#define WIN_MAXSUBENTRIES 20
/*
* Maximum filename length in Win95
* Note: Must be < sizeof(dirent.d_name)
*/
#define WIN_MAXLEN 255
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
* We don't use bitfields because we don't know how compilers for
* arbitrary machines will lay them out.
*/
#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
#define DT_2SECONDS_SHIFT 0
#define DT_MINUTES_MASK 0x7E0 /* minutes */
#define DT_MINUTES_SHIFT 5
#define DT_HOURS_MASK 0xF800 /* hours */
#define DT_HOURS_SHIFT 11
/*
* This is the format of the contents of the deDate field in the direntry
* structure.
*/
#define DD_DAY_MASK 0x1F /* day of month */
#define DD_DAY_SHIFT 0
#define DD_MONTH_MASK 0x1E0 /* month */
#define DD_MONTH_SHIFT 5
#define DD_YEAR_MASK 0xFE00 /* year - 1980 */
#define DD_YEAR_SHIFT 9
uint8_t winChksum(uint8_t *name);
int winSlotCnt(const u_char *un, size_t unlen);
int unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen);
int winChkName(const u_char *un, size_t unlen, struct winentry *wep,
int chksum);
int unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt,
int chksum);
#endif /* !_FS_MSDOSFS_DIRENTRY_H_ */

110
usr.sbin/makefs/msdos/fat.h Normal file
View File

@ -0,0 +1,110 @@
/* $FreeBSD$ */
/* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 ws Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (C) 1994, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
#ifndef _FS_MSDOSFS_FAT_H_
#define _FS_MSDOSFS_FAT_H_
/*
* Some useful cluster numbers.
*/
#define MSDOSFSROOT 0 /* cluster 0 means the root dir */
#define CLUST_FREE 0 /* cluster 0 also means a free cluster */
#define MSDOSFSFREE CLUST_FREE
#define CLUST_FIRST 2 /* first legal cluster number */
#define CLUST_RSRVD 0xfffffff6 /* reserved cluster range */
#define CLUST_BAD 0xfffffff7 /* a cluster with a defect */
#define CLUST_EOFS 0xfffffff8 /* start of eof cluster range */
#define CLUST_EOFE 0xffffffff /* end of eof cluster range */
#define FAT12_MASK 0x00000fff /* mask for 12 bit cluster numbers */
#define FAT16_MASK 0x0000ffff /* mask for 16 bit cluster numbers */
#define FAT32_MASK 0x0fffffff /* mask for FAT32 cluster numbers */
/*
* MSDOSFS:
* Return true if filesystem uses 12 bit FATs. Microsoft Programmer's
* Reference says if the maximum cluster number in a filesystem is greater
* than 4084 ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK) then we've got a
* 16 bit FAT filesystem. While mounting, the result of this test is stored
* in pm_fatentrysize.
*/
#define FAT12(pmp) (pmp->pm_fatmask == FAT12_MASK)
#define FAT16(pmp) (pmp->pm_fatmask == FAT16_MASK)
#define FAT32(pmp) (pmp->pm_fatmask == FAT32_MASK)
#define MSDOSFSEOF(pmp, cn) ((((cn) | ~(pmp)->pm_fatmask) & CLUST_EOFS) == CLUST_EOFS)
/*
* These are the values for the function argument to the function
* fatentry().
*/
#define FAT_GET 0x0001 /* get a FAT entry */
#define FAT_SET 0x0002 /* set a FAT entry */
#define FAT_GET_AND_SET (FAT_GET | FAT_SET)
/*
* Flags to extendfile:
*/
#define DE_CLEAR 1 /* Zero out the blocks allocated */
struct buf;
struct denode;
struct msdosfsmount;
int pcbmap(struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int* sp);
int clusterfree(struct msdosfsmount *pmp, u_long cn, u_long *oldcnp);
int clusteralloc(struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got);
int fatentry(int function, struct msdosfsmount *pmp, u_long cluster, u_long *oldcontents, u_long newcontents);
int freeclusterchain(struct msdosfsmount *pmp, u_long startchain);
int extendfile(struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags);
void fc_purge(struct denode *dep, u_int frcn);
#endif /* !_FS_MSDOSFS_FAT_H_ */

View File

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

View File

@ -47,24 +47,29 @@
* October 1992
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/vnode.h>
#include <ffs/buf.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <util.h>
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
#include <fs/msdosfs/fat.h>
#include <util.h>
#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 @@ __FBSDID("$FreeBSD$");
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 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
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 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
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 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
} 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 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
*/
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 @@ deget(struct msdosfsmount *pmp, u_long dirclust, u_long diroffset,
* 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 @@ detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred)
* 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 @@ detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred)
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 @@ detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred)
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 @@ detrunc(struct denode *dep, u_long length, int flags, struct kauth_cred *cred)
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 @@ deextend(struct denode *dep, u_long length, struct kauth_cred *cred)
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 @@ deextend(struct denode *dep, u_long length, struct kauth_cred *cred)
* is zero'd later.
*/
dep->de_FileSize = length;
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
dep->de_flag |= DE_UPDATE | DE_MODIFIED;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,303 @@
/* $FreeBSD$ */
/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 ws Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
#include <sys/param.h>
#include <sys/errno.h>
#include <stdio.h>
#include <string.h>
#include <fs/msdosfs/bpb.h>
#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);
}
}
}

View File

@ -45,43 +45,36 @@
* October 1992
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
/* $NetBSD: msdosfs_vfsops.c,v 1.10 2016/01/30 09:59:27 mlelstv Exp $ */
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/mount.h>
#include <ffs/buf.h>
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/bootsect.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/fat.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <util.h>
#include <fs/msdosfs/bootsect.h>
#include <fs/msdosfs/bpb.h>
#include <mkfs_msdos.h>
#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 +83,11 @@ msdosfs_mount(struct vnode *devvp, int flags)
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 +96,17 @@ msdosfs_mount(struct vnode *devvp, int flags)
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,29 +123,23 @@ msdosfs_mount(struct vnode *devvp, int flags)
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));
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;
/* 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;
}
if (pmp->pm_Sectors == 0) {
pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
@ -167,6 +149,7 @@ msdosfs_mount(struct vnode *devvp, int flags)
pmp->pm_HugeSectors = pmp->pm_Sectors;
}
pmp->pm_flags = 0;
if (pmp->pm_RootDirEnts == 0) {
unsigned short vers = getushort(b710->bpbFSVers);
/*
@ -175,7 +158,7 @@ msdosfs_mount(struct vnode *devvp, int flags)
* 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 +176,9 @@ msdosfs_mount(struct vnode *devvp, int flags)
} 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 +198,11 @@ msdosfs_mount(struct vnode *devvp, int flags)
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 +235,19 @@ msdosfs_mount(struct vnode *devvp, int flags)
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 +270,13 @@ msdosfs_mount(struct vnode *devvp, int flags)
* 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 +310,7 @@ msdosfs_mount(struct vnode *devvp, int flags)
* 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 +334,7 @@ msdosfs_mount(struct vnode *devvp, int flags)
error_exit:
if (bp)
brelse(bp, BC_AGE);
brelse(bp);
if (pmp) {
if (pmp->pm_inusemap)
free(pmp->pm_inusemap);

View File

@ -46,34 +46,34 @@
*
* October 1992
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/clock.h>
#include <sys/errno.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <ffs/buf.h>
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/fat.h>
#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 @@ __FBSDID("$FreeBSD$");
*/
static int msdosfs_wfile(const char *, struct denode *, fsnode *);
static void unix2fattime(const struct timespec *tsp, uint16_t *ddp,
uint16_t *dtp);
static void
msdosfs_times(struct msdosfsmount *pmp, struct denode *dep,
const struct stat *st)
msdosfs_times(struct denode *dep, const struct stat *st)
{
struct timespec at;
struct timespec mt;
if (stampst.st_ino)
st = &stampst;
st = &stampst;
#ifndef HAVE_NBTOOL_CONFIG_H
at = st->st_atimespec;
mt = st->st_mtimespec;
#else
at.tv_sec = st->st_atime;
at.tv_nsec = 0;
mt.tv_sec = st->st_mtime;
mt.tv_nsec = 0;
#endif
unix2dostime(&at, pmp->pm_gmtoff, &dep->de_ADate, NULL, NULL);
unix2dostime(&mt, pmp->pm_gmtoff, &dep->de_MDate, &dep->de_MTime, NULL);
unix2fattime(&st->st_birthtim, &dep->de_CDate, &dep->de_CTime);
unix2fattime(&st->st_atim, &dep->de_ADate, NULL);
unix2fattime(&st->st_mtim, &dep->de_MDate, &dep->de_MTime);
}
static void
unix2fattime(const struct timespec *tsp, uint16_t *ddp, uint16_t *dtp)
{
time_t t1;
struct tm lt = {0};
t1 = tsp->tv_sec;
localtime_r(&t1, &lt);
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;
}
/*
@ -162,12 +174,12 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
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 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
* 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 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
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 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
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 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
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 @@ msdosfs_findslot(struct denode *dp, struct componentname *cnp)
* 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 @@ msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
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 @@ msdosfs_mkfile(const char *path, struct denode *pdep, fsnode *node)
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 @@ msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
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 @@ msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
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 @@ msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
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,27 +481,17 @@ msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
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);
@ -508,12 +507,11 @@ msdosfs_wfile(const char *path, struct denode *dep, fsnode *node)
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 @@ static const struct {
{ 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 @@ msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
struct denode ndirent;
struct denode *dep;
struct componentname cn;
struct stat *st = &node->inode->st;
struct msdosfsmount *pmp = pdep->de_pmp;
int error;
u_long newcluster, pcl, bn;
daddr_t lbn;
struct direntry *denp;
struct buf *bp;
@ -564,14 +560,14 @@ msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
/*
* 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 @@ msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
* 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 @@ msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
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 @@ msdosfs_mkdire(const char *path, struct denode *pdep, fsnode *node) {
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;

View File

@ -0,0 +1,199 @@
/* $FreeBSD$ */
/* $NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1994, 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software, just don't say you wrote
* it, and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly redistributed on the
* understanding that the author is not responsible for the correct
* functioning of this software in any circumstances and is not liable for
* any damages caused by this software.
*
* October 1992
*/
#ifndef _MSDOSFS_MSDOSFSMOUNT_H_
#define _MSDOSFS_MSDOSFSMOUNT_H_
#include <sys/types.h>
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_ */