Add support for FAT32

Don't panic if renaming a file to itself
Don't try to keep access times, there is no place for them
While being here, fix some minor bugs with VFAT handling
This commit is contained in:
ws 1997-10-17 11:23:29 +00:00
parent d445160e23
commit 9c1b7cfa37
12 changed files with 644 additions and 242 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bootsect.h,v 1.7 1995/07/24 06:36:23 leo Exp $ */
/* $NetBSD: bootsect.h,v 1.8 1997/10/17 11:23:29 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -27,24 +27,48 @@ struct bootsector33 {
int8_t bsBPB[19]; /* BIOS parameter block */
int8_t bsDriveNumber; /* drive number (0x80) */
int8_t bsBootCode[479]; /* pad so struct is 512b */
u_int16_t bsBootSectSig;
#define BOOTSIG 0xaa55
u_int8_t bsBootSectSig0;
u_int8_t bsBootSectSig1;
#define BOOTSIG0 0x55
#define BOOTSIG1 0xaa
};
struct extboot {
int8_t exDriveNumber; /* drive number (0x80) */
int8_t exReserved1; /* reserved */
int8_t exBootSignature; /* ext. boot signature (0x29) */
#define EXBOOTSIG 0x29
int8_t exVolumeID[4]; /* volume ID number */
int8_t exVolumeLabel[11]; /* volume label */
int8_t exFileSysType[8]; /* fs type (FAT12 or FAT16) */
};
struct bootsector50 {
u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
int8_t bsOemName[8]; /* OEM name and version */
int8_t bsBPB[25]; /* BIOS parameter block */
int8_t bsDriveNumber; /* drive number (0x80) */
int8_t bsReserved1; /* reserved */
int8_t bsBootSignature; /* ext. boot signature (0x29) */
#define EXBOOTSIG 0x29
int8_t bsVolumeID[4]; /* volume ID number */
int8_t bsVolumeLabel[11]; /* volume label */
int8_t bsFileSysType[8]; /* fs type (FAT12 or FAT16) */
int8_t bsExt[26]; /* Bootsector Extension */
int8_t bsBootCode[448]; /* pad so structure is 512b */
u_int16_t bsBootSectSig;
#define BOOTSIG 0xaa55
u_int8_t bsBootSectSig0;
u_int8_t bsBootSectSig1;
#define BOOTSIG0 0x55
#define BOOTSIG1 0xaa
};
struct bootsector710 {
u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
int8_t bsOEMName[8]; /* OEM name and version */
int8_t bsPBP[53]; /* BIOS parameter block */
int8_t bsExt[26]; /* Bootsector Extension */
int8_t bsBootCode[418]; /* pad so structure is 512b */
u_int8_t bsBootSectSig2; /* 2 & 3 are only defined for FAT32? */
u_int8_t bsBootSectSig3;
u_int8_t bsBootSectSig0;
u_int8_t bsBootSectSig1;
#define BOOTSIG0 0x55
#define BOOTSIG1 0xaa
#define BOOTSIG2 0
#define BOOTSIG3 0
};
#ifdef atari
/*
@ -66,8 +90,10 @@ struct bootsec_atari {
union bootsector {
struct bootsector33 bs33;
struct bootsector50 bs50;
struct bootsector710 bs710;
};
#if 0
/*
* Shorthand for fields in the bpb.
*/
@ -83,3 +109,4 @@ union bootsector {
#define bsHeads bsBPB.bpbHeads
#define bsHiddenSecs bsBPB.bpbHiddenSecs
#define bsHugeSectors bsBPB.bpbHugeSectors
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: bpb.h,v 1.5 1995/07/24 06:37:15 leo Exp $ */
/* $NetBSD: bpb.h,v 1.6 1997/10/17 11:23:35 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -52,6 +52,34 @@ struct bpb50 {
u_int32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */
};
/*
* BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50.
*/
struct bpb710 {
u_int16_t bpbBytesPerSec; /* bytes per sector */
u_int8_t bpbSecPerClust; /* sectors per cluster */
u_int16_t bpbResSectors; /* number of reserved sectors */
u_int8_t bpbFATs; /* number of FATs */
u_int16_t bpbRootDirEnts; /* number of root directory entries */
u_int16_t bpbSectors; /* total number of sectors */
u_int8_t bpbMedia; /* media descriptor */
u_int16_t bpbFATsecs; /* number of sectors per FAT */
u_int16_t bpbSecPerTrack; /* sectors per track */
u_int16_t bpbHeads; /* number of heads */
u_int32_t bpbHiddenSecs; /* # of hidden sectors */
u_int32_t bpbHugeSectors; /* # of sectors if bpbSectors == 0 */
u_int32_t bpbBigFATsecs; /* like bpbFATsecs for FAT32 */
u_int16_t bpbExtFlags; /* extended flags: */
#define FATNUM 0xf /* mask for numbering active FAT */
#define FATMIRROR 0x80 /* FAT is mirrored (like it always was) */
u_int16_t bpbFSVers; /* filesystem version */
#define FSVERS 0 /* currently only 0 is understood */
u_int32_t bpbRootClust; /* start cluster for root directory */
u_int16_t bpbFSInfo; /* filesystem info structure sector */
u_int16_t bpbBackup; /* backup boot sector */
/* There is a 12 byte filler here, but we ignore it */
};
#ifdef atari
/*
* BPB for gemdos filesystems. Atari leaves the obsolete stuff undefined.
@ -138,3 +166,43 @@ struct byte_bpb50 {
int8_t bpbHiddenSecs[4]; /* number of hidden sectors */
int8_t bpbHugeSectors[4]; /* # of sectors if bpbSectors == 0 */
};
/*
* BPB for DOS 7.10 (FAT32). This one has a few extensions to bpb50.
*/
struct byte_bpb710 {
u_int8_t bpbBytesPerSec[2]; /* bytes per sector */
u_int8_t bpbSecPerClust; /* sectors per cluster */
u_int8_t bpbResSectors[2]; /* number of reserved sectors */
u_int8_t bpbFATs; /* number of FATs */
u_int8_t bpbRootDirEnts[2]; /* number of root directory entries */
u_int8_t bpbSectors[2]; /* total number of sectors */
u_int8_t bpbMedia; /* media descriptor */
u_int8_t bpbFATsecs[2]; /* number of sectors per FAT */
u_int8_t bpbSecPerTrack[2]; /* sectors per track */
u_int8_t bpbHeads[2]; /* number of heads */
u_int8_t bpbHiddenSecs[4]; /* # of hidden sectors */
u_int8_t bpbHugeSectors[4]; /* # of sectors if bpbSectors == 0 */
u_int8_t bpbBigFATsecs[4]; /* like bpbFATsecs for FAT32 */
u_int8_t bpbExtFlags[2]; /* extended flags: */
u_int8_t bpbFSVers[2]; /* filesystem version */
u_int8_t bpbRootClust[4]; /* start cluster for root directory */
u_int8_t bpbFSInfo[2]; /* filesystem info structure sector */
u_int8_t bpbBackup[2]; /* backup boot sector */
/* There is a 12 byte filler here, but we ignore it */
};
/*
* FAT32 FSInfo block.
*/
struct fsinfo {
u_int8_t fsisig1[4];
u_int8_t fsifill1[480];
u_int8_t fsisig2[4];
u_int8_t fsinfree[4];
u_int8_t fsinxtfree[4];
u_int8_t fsifill2[12];
u_int8_t fsisig3[4];
u_int8_t fsifill3[508];
u_int8_t fsisig4[4];
};

View File

@ -1,8 +1,8 @@
/* $NetBSD: denode.h,v 1.23 1997/04/11 21:52:06 kleink Exp $ */
/* $NetBSD: denode.h,v 1.24 1997/10/17 11:23:39 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -102,8 +102,8 @@
* structure (fc_frcn).
*/
struct fatcache {
u_short fc_frcn; /* file relative cluster number */
u_short fc_fsrcn; /* filesystem relative cluster number */
u_long fc_frcn; /* file relative cluster number */
u_long fc_fsrcn; /* filesystem relative cluster number */
};
/*
@ -120,7 +120,7 @@ struct fatcache {
* to */
#define FC_LASTFC 1 /* entry for the last cluster in the file */
#define FCE_EMPTY 0xffff /* doesn't represent an actual cluster # */
#define FCE_EMPTY 0xffffffff /* doesn't represent an actual cluster # */
/*
* Set a slot in the fat cache.
@ -151,13 +151,13 @@ struct denode {
pid_t de_lockwaiter; /* lock wanter */
u_char de_Name[12]; /* name, from DOS directory entry */
u_char de_Attributes; /* attributes, from directory entry */
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_ATime; /* access time */
u_short de_MTime; /* modification time */
u_short de_MDate; /* modification date */
u_short de_StartCluster; /* starting cluster of file */
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 */
};
@ -184,30 +184,36 @@ struct denode {
* dep is a struct denode * (internal form),
* dp is a struct direntry * (external form).
*/
#define DE_INTERNALIZE(dep, dp) \
#define DE_INTERNALIZE32(dep, dp) \
((dep)->de_StartCluster |= getushort((dp)->deHighClust) << 16)
#define DE_INTERNALIZE(dep, dp) \
(bcopy((dp)->deName, (dep)->de_Name, 11), \
(dep)->de_Attributes = (dp)->deAttributes, \
(dep)->de_CHun = (dp)->deCHundredth, \
(dep)->de_CTime = getushort((dp)->deCTime), \
(dep)->de_CDate = getushort((dp)->deCDate), \
(dep)->de_ATime = getushort((dp)->deATime), \
(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))
(dep)->de_FileSize = getulong((dp)->deFileSize), \
(FAT32((dep)->de_pmp) ? DE_INTERNALIZE32((dep), (dp)) : 0))
#define DE_EXTERNALIZE32(dp, dep) \
putushort((dp)->deHighClust, (dep)->de_StartCluster >> 16)
#define DE_EXTERNALIZE(dp, dep) \
(bcopy((dep)->de_Name, (dp)->deName, 11), \
(dp)->deAttributes = (dep)->de_Attributes, \
(dp)->deCHundredth = (dep)->de_CHun, \
putushort((dp)->deCTime, (dep)->de_CTime), \
putushort((dp)->deCDate, (dep)->de_CDate), \
putushort((dp)->deATime, (dep)->de_ATime), \
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))
putulong((dp)->deFileSize, \
((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize), \
(FAT32((dep)->de_pmp) ? DE_EXTERNALIZE32((dp), (dep)) : 0))
#define de_forw de_chain[0]
#define de_back de_chain[1]
@ -221,14 +227,14 @@ struct denode {
if ((dep)->de_flag & (DE_UPDATE | DE_CREATE | DE_ACCESS)) { \
(dep)->de_flag |= DE_MODIFIED; \
if ((dep)->de_flag & DE_UPDATE) { \
unix2dostime((mod), &(dep)->de_MDate, &(dep)->de_MTime); \
unix2dostime((mod), &(dep)->de_MDate, &(dep)->de_MTime, NULL); \
(dep)->de_Attributes |= ATTR_ARCHIVE; \
} \
if (!((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)) { \
if ((dep)->de_flag & DE_ACCESS) \
unix2dostime((acc), &(dep)->de_ADate, &(dep)->de_ATime); \
unix2dostime((acc), &(dep)->de_ADate, NULL, NULL); \
if ((dep)->de_flag & DE_CREATE) \
unix2dostime((cre), &(dep)->de_CDate, &(dep)->de_CTime); \
unix2dostime((cre), &(dep)->de_CDate, &(dep)->de_CTime, &(dep)->de_CHun); \
} \
(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \
}

View File

@ -1,8 +1,8 @@
/* $NetBSD: direntry.h,v 1.12 1996/10/25 23:14:05 cgd Exp $ */
/* $NetBSD: direntry.h,v 1.13 1997/10/17 11:23:45 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -64,11 +64,12 @@ struct direntry {
#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 */
u_int8_t deReserved[2]; /* reserved */
u_int8_t deReserved; /* reserved */
u_int8_t deCHundredth; /* hundredth of seconds in CTime */
u_int8_t deCTime[2]; /* create time */
u_int8_t deCDate[2]; /* create date */
u_int8_t deADate[2]; /* access date */
u_int8_t deATime[2]; /* access time */
u_int8_t deHighClust[2]; /* high bytes of cluster number */
u_int8_t deMTime[2]; /* last update time */
u_int8_t deMDate[2]; /* last update date */
u_int8_t deStartCluster[2]; /* starting cluster of file */
@ -119,8 +120,8 @@ struct winentry {
#ifdef _KERNEL
void unix2dostime __P((struct timespec *tsp, u_int16_t *ddp,
u_int16_t *dtp));
void dos2unixtime __P((u_int dd, u_int dt, struct timespec *tsp));
u_int16_t *dtp, u_int8_t *dhp));
void dos2unixtime __P((u_int dd, u_int dt, u_int dh, struct timespec *tsp));
int dos2unixfn __P((u_char dn[11], u_char *un, int lower));
int unix2dosfn __P((const u_char *un, u_char dn[12], int unlen,
u_int gen));

View File

@ -1,8 +1,8 @@
/* $NetBSD: fat.h,v 1.10 1996/02/11 22:48:14 ws Exp $ */
/* $NetBSD: fat.h,v 1.11 1997/10/17 11:23:49 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 TooLs GmbH.
* 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).
*
@ -50,18 +50,18 @@
/*
* 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 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_RSRVS 0xfff0 /* start of reserved cluster range */
#define CLUST_RSRVE 0xfff6 /* end of reserved cluster range */
#define CLUST_BAD 0xfff7 /* a cluster with a defect */
#define CLUST_EOFS 0xfff8 /* start of eof cluster range */
#define CLUST_EOFE 0xffff /* end of eof cluster range */
#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 0x0fff /* mask for 12 bit cluster numbers */
#define FAT16_MASK 0xffff /* mask for 16 bit cluster numbers */
#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:
@ -76,10 +76,11 @@
* and store the result in the pm_fatentrysize. Note that this kind of
* detection gets flakey when mounting a vnd-device.
*/
#define FAT12(pmp) (pmp->pm_fatentrysize == 12)
#define FAT16(pmp) (pmp->pm_fatentrysize == 16)
#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(cn) (((cn) & 0xfff8) == 0xfff8)
#define MSDOSFSEOF(pmp, cn) ((((cn) | ~(pmp)->pm_fatmask) & CLUST_EOFS) == CLUST_EOFS)
#ifdef _KERNEL
/*

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_conv.c,v 1.23 1997/01/15 01:37:54 perry Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.24 1997/10/17 11:23:54 ws Exp $ */
/*-
* Copyright (C) 1995 Wolfgang Solfrank.
* Copyright (C) 1995 TooLs GmbH.
* Copyright (C) 1995, 1997 Wolfgang Solfrank.
* Copyright (C) 1995, 1997 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
@ -93,10 +93,11 @@ u_short lastdtime;
* file timestamps. The passed in unix time is assumed to be in GMT.
*/
void
unix2dostime(tsp, ddp, dtp)
unix2dostime(tsp, ddp, dtp, dhp)
struct timespec *tsp;
u_int16_t *ddp;
u_int16_t *dtp;
u_int8_t *dhp;
{
u_long t;
u_long days;
@ -112,6 +113,7 @@ unix2dostime(tsp, ddp, dtp)
/* XXX NOTE: Removed tz, which is obsolete. Must replace!!! */
t = tsp->tv_sec /* - (tz.tz_minuteswest * 60) */
/* +- daylight savings time correction */ ;
t &= ~1;
if (lasttime != t) {
lasttime = t;
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
@ -150,7 +152,11 @@ unix2dostime(tsp, ddp, dtp)
lastddate += (year - 1980) << DD_YEAR_SHIFT;
}
}
*dtp = lastdtime;
if (dtp)
*dtp = lastdtime;
if (dhp)
*dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000;
*ddp = lastddate;
}
@ -169,9 +175,10 @@ u_long lastseconds;
* not be too efficient.
*/
void
dos2unixtime(dd, dt, tsp)
dos2unixtime(dd, dt, dh, tsp)
u_int dd;
u_int dt;
u_int dh;
struct timespec *tsp;
{
u_long seconds;
@ -190,7 +197,8 @@ dos2unixtime(dd, dt, tsp)
}
seconds = ((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) * 2
+ ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60
+ ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600;
+ ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600
+ dh / 100;
/*
* If the year, month, and day from the last conversion are the
* same then use the saved value.
@ -220,7 +228,7 @@ dos2unixtime(dd, dt, tsp)
/* XXX NOTE: Removed tz, which is obsolete. Must replace!!! */
tsp->tv_sec = seconds + lastseconds /* + (tz.tz_minuteswest * 60) */
/* -+ daylight savings time correction */ ;
tsp->tv_nsec = 0;
tsp->tv_nsec = (dh % 100) * 10000000;
}
static u_char

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_denode.c,v 1.22 1996/10/13 04:16:31 christos Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.23 1997/10/17 11:23:58 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -171,11 +171,18 @@ deget(pmp, dirclust, diroffset, depp)
pmp, dirclust, diroffset, depp);
#endif
/*
* On FAT32 filesystems, root is a (more or less) normal
* directory
*/
if (FAT32(pmp) && dirclust == MSDOSFSROOT)
dirclust = pmp->pm_rootdirblk;
/*
* See if the denode is in the denode cache. Use the location of
* the directory entry to compute the hash value. For subdir use
* address of "." entry. for root dir use cluster MSDOSFSROOT,
* offset MSDOSFSROOT_OFS
* address of "." entry. For root dir (if not FAT32) use cluster
* MSDOSFSROOT, offset MSDOSFSROOT_OFS
*
* NOTE: The check for de_refcnt > 0 below insures the denode being
* examined does not represent an unlinked but still open file.
@ -220,10 +227,15 @@ deget(pmp, dirclust, diroffset, depp)
VOP_LOCK(nvp);
msdosfs_hashins(ldep);
ldep->de_pmp = pmp;
ldep->de_devvp = pmp->pm_devvp;
ldep->de_refcnt = 1;
/*
* Copy the directory entry into the denode area of the vnode.
*/
if (dirclust == MSDOSFSROOT && diroffset == MSDOSFSROOT_OFS) {
if ((dirclust == MSDOSFSROOT
|| (FAT32(pmp) && dirclust == pmp->pm_rootdirblk))
&& diroffset == MSDOSFSROOT_OFS) {
/*
* Directory entry for the root directory. There isn't one,
* so we manufacture one. We should probably rummage
@ -231,19 +243,26 @@ deget(pmp, dirclust, diroffset, depp)
* exists), and then use the time and date from that entry
* as the time and date for the root denode.
*/
nvp->v_flag |= VROOT; /* should be further down XXX */
ldep->de_Attributes = ATTR_DIRECTORY;
ldep->de_StartCluster = MSDOSFSROOT;
ldep->de_FileSize = pmp->pm_rootdirsize * pmp->pm_BytesPerSec;
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;
}
/*
* fill in time and date so that dos2unixtime() doesn't
* spit up when called from msdosfs_getattr() with root
* denode
*/
ldep->de_CHun = 0;
ldep->de_CTime = 0x0000; /* 00:00:00 */
ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
| (1 << DD_DAY_SHIFT);
/* Jan 1, 1980 */
ldep->de_ATime = ldep->de_CTime;
ldep->de_ADate = ldep->de_CDate;
ldep->de_MTime = ldep->de_CTime;
ldep->de_MDate = ldep->de_CDate;
@ -260,9 +279,6 @@ deget(pmp, dirclust, diroffset, depp)
* Fill in a few fields of the vnode and finish filling in the
* denode. Then return the address of the found denode.
*/
ldep->de_pmp = pmp;
ldep->de_devvp = pmp->pm_devvp;
ldep->de_refcnt = 1;
if (ldep->de_Attributes & ATTR_DIRECTORY) {
/*
* Since DOS directory entries that describe directories
@ -273,9 +289,7 @@ deget(pmp, dirclust, diroffset, depp)
u_long size;
nvp->v_type = VDIR;
if (ldep->de_StartCluster == MSDOSFSROOT)
nvp->v_flag |= VROOT;
else {
if (ldep->de_StartCluster != MSDOSFSROOT) {
error = pcbmap(ldep, 0xffff, 0, &size, 0);
if (error == E2BIG) {
ldep->de_FileSize = de_cn2off(pmp, size);
@ -335,7 +349,7 @@ detrunc(dep, length, flags, cred, p)
* recognize the root directory at this point in a file or
* directory's life.
*/
if (DETOV(dep)->v_flag & VROOT) {
if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp)) {
printf("detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
dep->de_dirclust, dep->de_diroffset);
return (EINVAL);
@ -441,7 +455,7 @@ detrunc(dep, length, flags, cred, p)
* Now free the clusters removed from the file because of the
* truncation.
*/
if (chaintofree != 0 && !MSDOSFSEOF(chaintofree))
if (chaintofree != 0 && !MSDOSFSEOF(pmp, chaintofree))
freeclusterchain(pmp, chaintofree);
return (allerror);
@ -463,7 +477,7 @@ deextend(dep, length, cred)
/*
* The root of a DOS filesystem cannot be extended.
*/
if (DETOV(dep)->v_flag & VROOT)
if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
return (EINVAL);
/*

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_fat.c,v 1.25 1997/05/17 20:33:57 pk Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.26 1997/10/17 11:24:02 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -82,9 +82,6 @@ int fc_lmdistance[LMMAX]; /* counters for how far off the last
* cluster mapped entry was. */
int fc_largedistance; /* off by more than LMMAX */
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
static void fatblock __P((struct msdosfsmount *, u_long, u_long *, u_long *,
u_long *));
void updatefats __P((struct msdosfsmount *, struct buf *, u_long));
@ -108,7 +105,8 @@ fatblock(pmp, ofs, bnp, sizep, bop)
bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
* pmp->pm_BytesPerSec;
bn += pmp->pm_fatblk;
bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs;
if (bnp)
*bnp = bn;
if (sizep)
@ -154,7 +152,6 @@ pcbmap(dep, findcn, bnp, cnp, sp)
u_long bp_bn = -1;
struct msdosfsmount *pmp = dep->de_pmp;
u_long bsize;
int fat12 = FAT12(pmp); /* 12 bit fat */
fc_bmapcalls++;
@ -216,7 +213,10 @@ pcbmap(dep, findcn, bnp, cnp, sp)
* Handle all other files or directories the normal way.
*/
for (; i < findcn; i++) {
if (MSDOSFSEOF(cn))
/*
* Stop with all reserved clusters, not just with EOF.
*/
if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
goto hiteof;
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
@ -231,23 +231,25 @@ pcbmap(dep, findcn, bnp, cnp, sp)
bp_bn = bn;
}
prevcn = cn;
cn = getushort(&bp->b_data[bo]);
if (fat12) {
if (prevcn & 1)
cn >>= 4;
cn &= 0x0fff;
/*
* Force the special cluster numbers in the range
* 0x0ff0-0x0fff to be the same as for 16 bit
* cluster numbers to let the rest of msdosfs think
* it is always dealing with 16 bit fats.
*/
if ((cn & 0x0ff0) == 0x0ff0)
cn |= 0xf000;
}
if (FAT32(pmp))
cn = getulong(&bp->b_data[bo]);
else
cn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) && (prevcn & 1))
cn >>= 4;
cn &= pmp->pm_fatmask;
/*
* Force the special cluster numbers
* to be the same for all cluster sizes
* to let the rest of msdosfs handle
* all cases the same.
*/
if ((cn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
cn |= ~pmp->pm_fatmask;
}
if (!MSDOSFSEOF(cn)) {
if (!MSDOSFSEOF(pmp, cn)) {
if (bp)
brelse(bp);
if (bnp)
@ -316,7 +318,9 @@ fc_purge(dep, frcn)
}
/*
* Update all copies of the fat. The first copy is updated last.
* Update the fat.
* If mirroring the fat, update all copies, with the first copy as last.
* Else update only the current fat (ignoring the others).
*
* pmp - msdosfsmount structure for filesystem to update
* bp - addr of modified fat block
@ -337,32 +341,76 @@ updatefats(pmp, bp, fatbn)
#endif
/*
* Now copy the block(s) of the modified fat to the other copies of
* the fat and write them out. This is faster than reading in the
* other fats and then writing them back out. This could tie up
* the fat for quite a while. Preventing others from accessing it.
* To prevent us from going after the fat quite so much we use
* delayed writes, unless they specfied "synchronous" when the
* filesystem was mounted. If synch is asked for then use
* bwrite()'s and really slow things down.
* If we have an FSInfo block, update it.
*/
for (i = 1; i < pmp->pm_FATs; i++) {
fatbn += pmp->pm_FATsecs;
/* getblk() never fails */
bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, 0, 0);
bcopy(bp->b_data, bpn->b_data, bp->b_bcount);
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bpn);
else
bdwrite(bpn);
if (pmp->pm_fsinfo) {
u_long cn = pmp->pm_nxtfree;
if (pmp->pm_freeclustercount
&& (pmp->pm_inusemap[cn / N_INUSEBITS]
& (1 << (cn % N_INUSEBITS)))) {
/*
* The cluster indicated in FSInfo isn't free
* any longer. Got get a new free one.
*/
for (cn = 0; cn < pmp->pm_maxcluster;)
if (pmp->pm_inusemap[cn / N_INUSEBITS] != (u_int)-1)
break;
pmp->pm_nxtfree = cn
+ ffs(pmp->pm_inusemap[cn / N_INUSEBITS]
^ (u_int)-1) - 1;
}
if (bread(pmp->pm_devvp, pmp->pm_fsinfo, 1024, NOCRED, &bpn) != 0) {
/*
* Ignore the error, but turn off FSInfo update for the future.
*/
pmp->pm_fsinfo = 0;
brelse(bpn);
} else {
struct fsinfo *fp = (struct fsinfo *)bpn->b_data;
putulong(fp->fsinfree, pmp->pm_freeclustercount);
putulong(fp->fsinxtfree, pmp->pm_nxtfree);
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bpn);
else
bdwrite(bpn);
}
}
if (pmp->pm_flags & MSDOSFS_FATMIRROR) {
/*
* Now copy the block(s) of the modified fat to the other copies of
* the fat and write them out. This is faster than reading in the
* other fats and then writing them back out. This could tie up
* the fat for quite a while. Preventing others from accessing it.
* To prevent us from going after the fat quite so much we use
* delayed writes, unless they specfied "synchronous" when the
* filesystem was mounted. If synch is asked for then use
* bwrite()'s and really slow things down.
*/
for (i = 1; i < pmp->pm_FATs; i++) {
fatbn += pmp->pm_FATsecs;
/* getblk() never fails */
bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount, 0, 0);
bcopy(bp->b_data, bpn->b_data, bp->b_bcount);
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bpn);
else
bdwrite(bpn);
}
}
/*
* Write out the first fat last.
* Write out the first (or current) fat last.
*/
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bp);
else
bdwrite(bp);
/*
* Maybe update fsinfo sector here?
*/
}
/*
@ -413,15 +461,17 @@ clusterfree(pmp, cluster, oldcnp)
int error;
u_long oldcn;
usemap_free(pmp, cluster);
error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
if (error)
if (error) {
usemap_alloc(pmp, cluster);
return (error);
}
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
usemap_free(pmp, cluster);
if (oldcnp)
*oldcnp = oldcn;
return (0);
@ -459,7 +509,7 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
u_long bn, bo, bsize, byteoffset;
struct buf *bp;
#if 0
#ifdef MSDOSFS_DEBUG
printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
function, pmp, cluster, oldcontents, newcontents);
#endif
@ -497,19 +547,21 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
}
if (function & FAT_GET) {
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp)) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
/* map certain 12 bit fat entries to 16 bit */
if ((readcn & 0x0ff0) == 0x0ff0)
readcn |= 0xf000;
}
if (FAT32(pmp))
readcn = getulong(&bp->b_data[bo]);
else
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) & (cn & 1))
readcn >>= 4;
readcn &= pmp->pm_fatmask;
/* map reserved fat entries to same values for all fats */
if ((readcn | ~pmp->pm_fatmask) >= CLUST_RSRVD)
readcn |= ~pmp->pm_fatmask;
*oldcontents = readcn;
}
if (function & FAT_SET) {
if (FAT12(pmp)) {
switch (pmp->pm_fatmask) {
case FAT12_MASK:
readcn = getushort(&bp->b_data[bo]);
if (cn & 1) {
readcn &= 0x000f;
@ -519,8 +571,21 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
readcn |= newcontents & 0xfff;
}
putushort(&bp->b_data[bo], readcn);
} else
break;
case FAT16_MASK:
putushort(&bp->b_data[bo], newcontents);
break;
case FAT32_MASK:
/*
* According to spec we have to retain the
* high order bits of the fat entry.
*/
readcn = getulong(&bp->b_data[bo]);
readcn &= ~FAT32_MASK;
readcn |= newcontents & FAT32_MASK;
putulong(&bp->b_data[bo], readcn);
break;
}
updatefats(pmp, bp, bn);
bp = NULL;
pmp->pm_fmod = 1;
@ -570,7 +635,8 @@ fatchain(pmp, start, count, fillwith)
while (count > 0) {
start++;
newc = --count > 0 ? start : fillwith;
if (FAT12(pmp)) {
switch (pmp->pm_fatmask) {
case FAT12_MASK:
readcn = getushort(&bp->b_data[bo]);
if (start & 1) {
readcn &= 0xf000;
@ -583,9 +649,18 @@ fatchain(pmp, start, count, fillwith)
bo++;
if (!(start & 1))
bo++;
} else {
break;
case FAT16_MASK:
putushort(&bp->b_data[bo], newc);
bo += 2;
break;
case FAT32_MASK:
readcn = getulong(&bp->b_data[bo]);
readcn &= ~pmp->pm_fatmask;
readcn |= newc & pmp->pm_fatmask;
putulong(&bp->b_data[bo], readcn);
bo += 4;
break;
}
if (bo >= bsize)
break;
@ -658,7 +733,10 @@ chainalloc(pmp, start, count, fillwith, retcluster, got)
u_long *got;
{
int error;
u_long cl, n;
for (cl = start, n = count; n-- > 0;)
usemap_alloc(pmp, cl++);
if ((error = fatchain(pmp, start, count, fillwith)) != 0)
return (error);
#ifdef MSDOSFS_DEBUG
@ -669,8 +747,6 @@ chainalloc(pmp, start, count, fillwith, retcluster, got)
*retcluster = start;
if (got)
*got = count;
while (count-- > 0)
usemap_alloc(pmp, start++);
return (0);
}
@ -800,8 +876,9 @@ freeclusterchain(pmp, cluster)
lbn = bn;
}
usemap_free(pmp, cluster);
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp)) {
switch (pmp->pm_fatmask) {
case FAT12_MASK:
readcn = getushort(&bp->b_data[bo]);
if (cluster & 1) {
cluster = readcn >> 4;
readcn &= 0x000f;
@ -812,13 +889,20 @@ freeclusterchain(pmp, cluster)
readcn |= MSDOSFSFREE & 0xfff;
}
putushort(&bp->b_data[bo], readcn);
cluster &= 0x0fff;
if ((cluster&0x0ff0) == 0x0ff0)
cluster |= 0xf000;
} else {
cluster = readcn;
break;
case FAT16_MASK:
cluster = getushort(&bp->b_data[bo]);
putushort(&bp->b_data[bo], MSDOSFSFREE);
break;
case FAT32_MASK:
cluster = getulong(&bp->b_data[bo]);
putulong(&bp->b_data[bo],
(MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK));
break;
}
cluster &= pmp->pm_fatmask;
if ((cluster | ~pmp->pm_fatmask) >= CLUST_RSRVD)
cluster |= pmp->pm_fatmask;
}
if (bp)
updatefats(pmp, bp, bn);
@ -836,7 +920,6 @@ fillinusemap(pmp)
struct buf *bp = NULL;
u_long cn, readcn;
int error;
int fat12 = FAT12(pmp);
u_long bn, bo, bsize, byteoffset;
/*
@ -866,12 +949,13 @@ fillinusemap(pmp)
return (error);
}
}
readcn = getushort(&bp->b_data[bo]);
if (fat12) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
}
if (FAT32(pmp))
readcn = getulong(&bp->b_data[bo]);
else
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) && (cn & 1))
readcn >>= 4;
readcn &= pmp->pm_fatmask;
if (readcn == 0)
usemap_free(pmp, cn);
@ -912,7 +996,8 @@ extendfile(dep, count, bpp, ncp, flags)
/*
* Don't try to extend the root directory
*/
if (DETOV(dep)->v_flag & VROOT) {
if (dep->de_StartCluster == MSDOSFSROOT
&& (dep->de_Attributes & ATTR_DIRECTORY)) {
printf("extendfile(): attempt to extend root directory\n");
return (ENOSPC);
}

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_lookup.c,v 1.32 1997/05/08 16:20:25 mycroft Exp $ */
/* $NetBSD: msdosfs_lookup.c,v 1.33 1997/10/17 11:24:08 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -431,9 +431,24 @@ found:;
*/
isadir = dep->deAttributes & ATTR_DIRECTORY;
scn = getushort(dep->deStartCluster);
if (FAT32(pmp)) {
scn |= getushort(dep->deHighClust) << 16;
if (scn == pmp->pm_rootdirblk) {
/*
* There should actually be 0 here.
* Just ignore the error.
*/
scn = MSDOSFSROOT;
}
}
if (cluster == MSDOSFSROOT)
if (cluster == MSDOSFSROOT) {
/*
* Force root to be a directory.
*/
isadir = ATTR_DIRECTORY;
blkoff = diroff;
}
if (isadir) {
cluster = scn;
if (cluster == MSDOSFSROOT)
@ -455,6 +470,8 @@ foundroot:;
* entry of the filesystems root directory. isadir and scn were
* setup before jumping here. And, bp is already null.
*/
if (FAT32(pmp) && scn == MSDOSFSROOT)
scn = pmp->pm_rootdirblk;
/*
* If deleting, and at end of pathname, return
@ -464,6 +481,12 @@ foundroot:;
* on and lock the inode, being careful with ".".
*/
if (nameiop == DELETE && (flags & ISLASTCN)) {
/*
* Don't allow deleting the root.
*/
if (blkoff == MSDOSFSROOT_OFS)
return EROFS; /* really? XXX */
/*
* Write access to directory required to delete files.
*/
@ -496,6 +519,9 @@ foundroot:;
*/
if (nameiop == RENAME && wantparent &&
(flags & ISLASTCN)) {
if (blkoff == MSDOSFSROOT_OFS)
return EROFS; /* really? XXX */
error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
if (error)
return (error);
@ -636,7 +662,7 @@ createde(dep, ddep, depp, cnp)
ndep = bptoep(pmp, bp, ddep->de_fndoffset);
DE_EXTERNALIZE(ndep, dep);
/*
* Now write the Win95 long name
*/
@ -684,6 +710,8 @@ createde(dep, ddep, depp, cnp)
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
@ -800,12 +828,19 @@ doscheckpath(source, target)
}
if (dep->de_StartCluster == MSDOSFSROOT)
goto out;
pmp = dep->de_pmp;
#ifdef DIAGNOSTIC
if (pmp != source->de_pmp)
panic("doscheckpath: source and target on different filesystems");
#endif
if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
goto out;
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
break;
}
pmp = dep->de_pmp;
scn = dep->de_StartCluster;
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
pmp->pm_bpcluster, NOCRED, &bp);
@ -819,12 +854,23 @@ doscheckpath(source, target)
break;
}
scn = getushort(ep->deStartCluster);
if (FAT32(pmp))
scn |= getushort(ep->deHighClust) << 16;
if (scn == source->de_StartCluster) {
error = EINVAL;
break;
}
if (scn == MSDOSFSROOT)
break;
if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
/*
* scn should be 0 in this case,
* but we silently ignore the error.
*/
break;
}
vput(DETOV(dep));
brelse(bp);
bp = NULL;
@ -893,7 +939,7 @@ readde(dep, bpp, epp)
/*
* Remove a directory entry. At this point the file represented by the
* directory entry to be removed is still full length until no one has it
* directory entry to be removed is still full length until noone has it
* open. When the file no longer being used msdosfs_inactive() is called
* and will truncate the file to 0 length. When the vnode containing the
* denode is needed for some other purpose by VFS it will call
@ -918,7 +964,9 @@ removede(pdep, dep)
#endif
dep->de_refcnt--;
offset += sizeof(struct direntry);
do {
offset -= sizeof(struct direntry);
error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
if (error)
return error;
@ -928,6 +976,17 @@ removede(pdep, dep)
return error;
}
ep = bptoep(pmp, bp, offset);
/*
* Check whether, if we came here the second time, i.e.
* when underflowing into the previous block, the last
* entry in this block is a longfilename entry, too.
*/
if (ep->deAttributes != ATTR_WIN95
&& offset != pdep->de_fndoffset) {
brelse(bp);
break;
}
offset += sizeof(struct direntry);
while (1) {
/*
* We are a bit agressive here in that we delete any Win95
@ -935,18 +994,18 @@ removede(pdep, dep)
* Since these presumably aren't valid anyway,
* there should be no harm.
*/
ep--->deName[0] = SLOT_DELETED;
offset -= sizeof(struct direntry);
ep--->deName[0] = SLOT_DELETED;
if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
|| !((offset + sizeof(struct direntry)) & pmp->pm_crbomask)
|| !(offset & pmp->pm_crbomask)
|| ep->deAttributes != ATTR_WIN95)
break;
}
if ((error = bwrite(bp)) != 0)
return error;
} while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
&& offset
&& !(offset & pmp->pm_crbomask));
&& !(offset & pmp->pm_crbomask)
&& offset);
return 0;
}

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_vfsops.c,v 1.46 1997/07/28 23:41:04 christos Exp $ */
/* $NetBSD: msdosfs_vfsops.c,v 1.47 1997/10/17 11:24:13 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -136,12 +136,16 @@ update_mp(mp, argp)
/*
* Try to divine whether to support Win'95 long filenames
*/
if ((error = msdosfs_root(mp, &rootvp)) != 0)
return error;
pmp->pm_flags |= findwin95(VTODE(rootvp))
? MSDOSFSMNT_LONGNAME
: MSDOSFSMNT_SHORTNAME;
vput(rootvp);
if (FAT32(pmp))
pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
else {
if ((error = msdosfs_root(mp, &rootvp)) != 0)
return error;
pmp->pm_flags |= findwin95(VTODE(rootvp))
? MSDOSFSMNT_LONGNAME
: MSDOSFSMNT_SHORTNAME;
vput(rootvp);
}
}
return 0;
}
@ -360,6 +364,7 @@ msdosfs_mountfs(devvp, mp, p, argp)
union bootsector *bsp;
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
struct byte_bpb710 *b710;
extern struct vnode *rootvp;
u_int8_t SecPerClust;
int ronly, error;
@ -420,13 +425,15 @@ msdosfs_mountfs(devvp, mp, p, argp)
bsp = (union bootsector *)bp->b_data;
b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
#ifdef MSDOSFS_CHECKSIG
if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)
&& (bsp->bs50.bsBootSectSig != BOOTSIG)) {
error = EINVAL;
goto error_exit;
b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;
if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
|| bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
error = EINVAL;
goto error_exit;
}
}
#endif
pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
bzero((caddr_t)pmp, sizeof *pmp);
@ -464,8 +471,45 @@ msdosfs_mountfs(devvp, mp, p, argp)
pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
pmp->pm_HugeSectors = pmp->pm_Sectors;
}
if (pmp->pm_HugeSectors > 0xffffffff / pmp->pm_BytesPerSec + 1) {
/*
* We cannot deal currently with this size of disk
* due to fileid limitations (see msdosfs_getattr and
* msdosfs_readdir)
*/
error = EINVAL;
goto error_exit;
}
if (pmp->pm_RootDirEnts == 0) {
if (bsp->bs710.bsBootSectSig2 != BOOTSIG2
|| bsp->bs710.bsBootSectSig3 != BOOTSIG3
|| pmp->pm_Sectors
|| pmp->pm_FATsecs
|| getushort(b710->bpbFSVers)) {
error = EINVAL;
goto error_exit;
}
pmp->pm_fatmask = FAT32_MASK;
pmp->pm_fatmult = 4;
pmp->pm_fatdiv = 1;
pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
if (getushort(b710->bpbExtFlags) & FATMIRROR)
pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
else
pmp->pm_flags |= MSDOSFS_FATMIRROR;
} else
pmp->pm_flags |= MSDOSFS_FATMIRROR;
if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
if (FAT32(pmp)) {
/*
* 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
@ -499,12 +543,20 @@ msdosfs_mountfs(devvp, mp, p, argp)
SecPerClust *= tmp;
}
pmp->pm_fatblk = pmp->pm_ResSectors;
pmp->pm_rootdirblk = pmp->pm_fatblk +
(pmp->pm_FATs * pmp->pm_FATsecs);
pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
+ pmp->pm_BytesPerSec - 1)
/ pmp->pm_BytesPerSec;/* in sectors */
pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
if (FAT32(pmp)) {
pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
pmp->pm_firstcluster = pmp->pm_fatblk
+ (pmp->pm_FATs * pmp->pm_FATsecs);
pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
} else {
pmp->pm_rootdirblk = pmp->pm_fatblk +
(pmp->pm_FATs * pmp->pm_FATsecs);
pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
+ pmp->pm_BytesPerSec - 1)
/ pmp->pm_BytesPerSec;/* in sectors */
pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
}
pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
SecPerClust;
pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
@ -514,21 +566,31 @@ msdosfs_mountfs(devvp, mp, p, argp)
if ((pmp->pm_nmbrofclusters <= (0xff0 - 2))
&& ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE)
&& ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2))))
)
pmp->pm_fatentrysize = 12;
else
pmp->pm_fatentrysize = 16;
} else {
) {
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_maxcluster
<= ((CLUST_RSRVS - CLUST_FIRST) & FAT12_MASK))
<= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
/*
* This will usually be a floppy disk. This size makes
* sure that one fat entry will not be split across
* multiple blocks.
*/
pmp->pm_fatentrysize = 12;
else
pmp->pm_fatentrysize = 16;
pmp->pm_fatmask = FAT12_MASK;
pmp->pm_fatmult = 3;
pmp->pm_fatdiv = 2;
} else {
pmp->pm_fatmask = FAT16_MASK;
pmp->pm_fatmult = 2;
pmp->pm_fatdiv = 1;
}
}
if (FAT12(pmp))
pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
@ -561,6 +623,30 @@ msdosfs_mountfs(devvp, mp, p, argp)
brelse(bp);
bp = NULL;
/*
* Check FSInfo.
*/
if (pmp->pm_fsinfo) {
struct fsinfo *fp;
if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &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))
pmp->pm_nxtfree = getulong(fp->fsinxtfree);
else
pmp->pm_fsinfo = 0;
brelse(bp);
bp = NULL;
}
/*
* Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
*/
/*
* Allocate memory for the bitmap of allocated clusters, and then
* fill it in.

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfs_vnops.c,v 1.62 1997/10/16 23:58:05 christos Exp $ */
/* $NetBSD: msdosfs_vnops.c,v 1.63 1997/10/17 11:24:19 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -265,12 +265,13 @@ msdosfs_getattr(v)
struct ucred *a_cred;
struct proc *a_p;
} */ *ap = v;
u_int cn;
struct denode *dep = VTODE(ap->a_vp);
struct msdosfsmount *pmp = dep->de_pmp;
struct vattr *vap = ap->a_vap;
mode_t mode;
struct timespec ts;
u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
u_long fileid;
TIMEVAL_TO_TIMESPEC(&time, &ts);
DETIMES(dep, &ts, &ts, &ts);
@ -281,15 +282,16 @@ msdosfs_getattr(v)
* doesn't work.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
if ((cn = dep->de_StartCluster) == MSDOSFSROOT)
cn = 1;
fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
if (dep->de_StartCluster == MSDOSFSROOT)
fileid = 1;
} else {
if ((cn = dep->de_dirclust) == MSDOSFSROOT)
cn = 1;
cn = (cn << 16)
| ((dep->de_diroffset / sizeof(struct direntry)) & 0xffff);
fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
if (dep->de_dirclust == MSDOSFSROOT)
fileid = roottobn(pmp, 0) * dirsperblk;
fileid += dep->de_diroffset / sizeof(struct direntry);
}
vap->va_fileid = cn;
vap->va_fileid = fileid;
if ((dep->de_Attributes & ATTR_READONLY) == 0)
mode = S_IRWXU|S_IRWXG|S_IRWXO;
else
@ -300,10 +302,10 @@ msdosfs_getattr(v)
vap->va_nlink = 1;
vap->va_rdev = 0;
vap->va_size = dep->de_FileSize;
dos2unixtime(dep->de_MDate, dep->de_MTime, &vap->va_mtime);
dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
dos2unixtime(dep->de_ADate, dep->de_ATime, &vap->va_atime);
dos2unixtime(dep->de_CDate, dep->de_CTime, &vap->va_ctime);
dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
} else {
vap->va_atime = vap->va_mtime;
vap->va_ctime = vap->va_mtime;
@ -374,9 +376,9 @@ msdosfs_setattr(v)
return (error);
if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
vap->va_atime.tv_sec != VNOVAL)
unix2dostime(&vap->va_atime, &dep->de_ADate, &dep->de_ATime);
unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
if (vap->va_mtime.tv_sec != VNOVAL)
unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime);
unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
dep->de_Attributes |= ATTR_ARCHIVE;
dep->de_flag |= DE_MODIFIED;
}
@ -926,6 +928,14 @@ abortit:
return (error);
}
/*
* If source and dest are the same, do nothing.
*/
if (tvp == fvp) {
error = 0;
goto abortit;
}
/* */
if ((error = VOP_LOCK(fvp)) != 0)
goto abortit;
@ -1176,18 +1186,20 @@ struct {
} dosdirtemplate = {
{ ". ", " ", /* the . entry */
ATTR_DIRECTORY, /* file attribute */
{ 0, 0 }, /* reserved */
{ 0, 0 }, { 0, 0 }, /* create time & date */
{ 0, 0 }, { 0, 0 }, /* access time & date */
0, /* reserved */
0, { 0, 0 }, { 0, 0 }, /* create time & date */
{ 0, 0 }, /* access date */
{ 0, 0 }, /* high bits of start cluster */
{ 210, 4 }, { 210, 4 }, /* modify time & date */
{ 0, 0 }, /* startcluster */
{ 0, 0, 0, 0 } /* filesize */
},
{ ".. ", " ", /* the .. entry */
ATTR_DIRECTORY, /* file attribute */
{ 0, 0 }, /* reserved */
{ 0, 0 }, { 0, 0 }, /* create time & date */
{ 0, 0 }, { 0, 0 }, /* access time & date */
0, /* reserved */
0, { 0, 0 }, { 0, 0 }, /* create time & date */
{ 0, 0 }, /* access date */
{ 0, 0 }, /* high bits of start cluster */
{ 210, 4 }, { 210, 4 }, /* modify time & date */
{ 0, 0 }, /* startcluster */
{ 0, 0, 0, 0 } /* filesize */
@ -1210,7 +1222,7 @@ msdosfs_mkdir(v)
struct denode *pdep = VTODE(ap->a_dvp);
int error;
int bn;
u_long newcluster;
u_long newcluster, pcl;
struct direntry *denp;
struct msdosfsmount *pmp = pdep->de_pmp;
struct buf *bp;
@ -1254,17 +1266,25 @@ msdosfs_mkdir(v)
putushort(denp[0].deStartCluster, newcluster);
putushort(denp[0].deCDate, ndirent.de_CDate);
putushort(denp[0].deCTime, ndirent.de_CTime);
denp[0].deCHundredth = ndirent.de_CHun;
putushort(denp[0].deADate, ndirent.de_ADate);
putushort(denp[0].deATime, ndirent.de_ATime);
putushort(denp[0].deMDate, ndirent.de_MDate);
putushort(denp[0].deMTime, ndirent.de_MTime);
putushort(denp[1].deStartCluster, pdep->de_StartCluster);
pcl = pdep->de_StartCluster;
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
pcl = 0;
putushort(denp[1].deStartCluster, pcl);
putushort(denp[1].deCDate, ndirent.de_CDate);
putushort(denp[1].deCTime, ndirent.de_CTime);
denp[1].deCHundredth = ndirent.de_CHun;
putushort(denp[1].deADate, ndirent.de_ADate);
putushort(denp[1].deATime, ndirent.de_ATime);
putushort(denp[1].deMDate, ndirent.de_MDate);
putushort(denp[1].deMTime, ndirent.de_MTime);
if (FAT32(pmp)) {
putushort(denp[0].deHighClust, newcluster >> 16);
putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
}
if ((error = bwrite(bp)) != 0)
goto bad;
@ -1409,6 +1429,7 @@ msdosfs_readdir(v)
long count;
u_long cn;
u_long fileno;
u_long dirsperblk;
long bias = 0;
daddr_t bn, lbn;
struct buf *bp;
@ -1456,7 +1477,9 @@ msdosfs_readdir(v)
cookies = ap->a_cookies;
ncookies = ap->a_ncookies;
dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
/*
* If they are reading from the root directory then, we simulate
* the . and .. entries since these don't exist in the root
@ -1464,7 +1487,8 @@ msdosfs_readdir(v)
* simulate these entries. By this I mean that at file offset 64 we
* read the first entry in the root directory that lives on disk.
*/
if (dep->de_StartCluster == MSDOSFSROOT) {
if (dep->de_StartCluster == MSDOSFSROOT
|| (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
#if 0
printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
offset);
@ -1473,7 +1497,12 @@ msdosfs_readdir(v)
if (offset < bias) {
for (n = (int)offset / sizeof(struct direntry);
n < 2; n++) {
dirbuf.d_fileno = 1;
if (FAT32(pmp))
dirbuf.d_fileno = cntobn(pmp,
pmp->pm_rootdirblk)
* dirsperblk;
else
dirbuf.d_fileno = 1;
dirbuf.d_type = DT_DIR;
switch (n) {
case 0:
@ -1569,23 +1598,33 @@ msdosfs_readdir(v)
* msdosfs_getattr.
*/
if (dentp->deAttributes & ATTR_DIRECTORY) {
/* if this is the root directory */
fileno = getushort(dentp->deStartCluster);
if (FAT32(pmp))
fileno |= getushort(dentp->deHighClust) << 16;
/* if this is the root directory */
if (fileno == MSDOSFSROOT)
fileno = 1;
if (FAT32(pmp))
fileno = cntobn(pmp,
pmp->pm_rootdirblk)
* dirsperblk;
else
fileno = 1;
else
fileno = cntobn(pmp, fileno) * dirsperblk;
dirbuf.d_fileno = fileno;
dirbuf.d_type = DT_DIR;
} else {
/*
* If the file's dirent lives in
* root dir.
*/
if ((fileno = cn) == MSDOSFSROOT)
fileno = 1;
fileno = (fileno << 16) |
((dentp - (struct direntry *)bp->b_data) & 0xffff);
fileno = cntobn(pmp, cn) * dirsperblk;
if (cn == MSDOSFSROOT)
fileno = roottobn(pmp, 0) * dirsperblk;
fileno += dentp - (struct direntry *)bp->b_data;
dirbuf.d_fileno = fileno;
dirbuf.d_type = DT_REG;
}
dirbuf.d_fileno = fileno;
dirbuf.d_type =
(dentp->deAttributes & ATTR_DIRECTORY) ? DT_DIR : DT_REG;
if (chksum != winChksum(dentp->deName))
dirbuf.d_namlen = dos2unixfn(dentp->deName,
(u_char *)dirbuf.d_name,
@ -1837,7 +1876,7 @@ msdosfs_print(v)
struct denode *dep = VTODE(ap->a_vp);
printf(
"tag VT_MSDOSFS, startcluster %d, dircluster %ld, diroffset %ld ",
"tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
printf(" dev %d, %d, %s\n",
major(dep->de_dev), minor(dep->de_dev),

View File

@ -1,8 +1,8 @@
/* $NetBSD: msdosfsmount.h,v 1.15 1996/12/22 10:31:41 cgd Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.16 1997/10/17 11:24:24 ws Exp $ */
/*-
* Copyright (C) 1994, 1995 Wolfgang Solfrank.
* Copyright (C) 1994, 1995 TooLs GmbH.
* 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).
*
@ -58,8 +58,9 @@ struct msdosfsmount {
mode_t pm_mask; /* mask to and with file protection bits */
struct vnode *pm_devvp; /* vnode for block device mntd */
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 # of root directory */
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_nmbrofclusters; /* # of clusters in filesystem */
@ -73,11 +74,18 @@ struct msdosfsmount {
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 */
u_long pm_fatmask; /* mask to use for fat numbers */
u_long pm_fsinfo; /* fsinfo block number */
u_long pm_nxtfree; /* next free cluster in fsinfo block */
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 */
u_int pm_flags; /* see below */
struct netexport pm_export; /* export information */
u_int pm_fatentrysize; /* size of fat entry (12/16) */
};
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv)
/*
* Mount point flags:
@ -96,6 +104,7 @@ struct msdosfsmount {
|MSDOSFSMNT_GEMDOSFS)
#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */
#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */
#define VFSTOMSDOSFS(mp) ((struct msdosfsmount *)mp->mnt_data)
@ -111,7 +120,6 @@ struct msdosfsmount {
#define pm_RootDirEnts pm_bpb.bpbRootDirEnts
#define pm_Sectors pm_bpb.bpbSectors
#define pm_Media pm_bpb.bpbMedia
#define pm_FATsecs pm_bpb.bpbFATsecs
#define pm_SecPerTrack pm_bpb.bpbSecPerTrack
#define pm_Heads pm_bpb.bpbHeads
#define pm_HiddenSects pm_bpb.bpbHiddenSecs