diff --git a/sys/msdosfs/bootsect.h b/sys/msdosfs/bootsect.h index 4c31483fdfd8..89a55ea6bb7c 100644 --- a/sys/msdosfs/bootsect.h +++ b/sys/msdosfs/bootsect.h @@ -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 diff --git a/sys/msdosfs/bpb.h b/sys/msdosfs/bpb.h index 67dc787000cc..ec2ddc6ab054 100644 --- a/sys/msdosfs/bpb.h +++ b/sys/msdosfs/bpb.h @@ -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]; +}; diff --git a/sys/msdosfs/denode.h b/sys/msdosfs/denode.h index f690732ef6fe..c90e64487037 100644 --- a/sys/msdosfs/denode.h +++ b/sys/msdosfs/denode.h @@ -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); \ } diff --git a/sys/msdosfs/direntry.h b/sys/msdosfs/direntry.h index ea383527b0b9..6898bdb2efaf 100644 --- a/sys/msdosfs/direntry.h +++ b/sys/msdosfs/direntry.h @@ -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)); diff --git a/sys/msdosfs/fat.h b/sys/msdosfs/fat.h index 8832cbb553e7..c0289334d176 100644 --- a/sys/msdosfs/fat.h +++ b/sys/msdosfs/fat.h @@ -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 /* diff --git a/sys/msdosfs/msdosfs_conv.c b/sys/msdosfs/msdosfs_conv.c index 96625bd26ceb..ef02b16d978f 100644 --- a/sys/msdosfs/msdosfs_conv.c +++ b/sys/msdosfs/msdosfs_conv.c @@ -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 diff --git a/sys/msdosfs/msdosfs_denode.c b/sys/msdosfs/msdosfs_denode.c index 6dffe9b220bc..9cb3f4898012 100644 --- a/sys/msdosfs/msdosfs_denode.c +++ b/sys/msdosfs/msdosfs_denode.c @@ -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); /* diff --git a/sys/msdosfs/msdosfs_fat.c b/sys/msdosfs/msdosfs_fat.c index 05c6c5b3977a..3250037e8d0e 100644 --- a/sys/msdosfs/msdosfs_fat.c +++ b/sys/msdosfs/msdosfs_fat.c @@ -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); } diff --git a/sys/msdosfs/msdosfs_lookup.c b/sys/msdosfs/msdosfs_lookup.c index b72620f7b164..90270e04149f 100644 --- a/sys/msdosfs/msdosfs_lookup.c +++ b/sys/msdosfs/msdosfs_lookup.c @@ -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; } diff --git a/sys/msdosfs/msdosfs_vfsops.c b/sys/msdosfs/msdosfs_vfsops.c index 8d8e21385b34..a4877eb573a2 100644 --- a/sys/msdosfs/msdosfs_vfsops.c +++ b/sys/msdosfs/msdosfs_vfsops.c @@ -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. diff --git a/sys/msdosfs/msdosfs_vnops.c b/sys/msdosfs/msdosfs_vnops.c index c9fecb08f41a..766e1b9e9b5e 100644 --- a/sys/msdosfs/msdosfs_vnops.c +++ b/sys/msdosfs/msdosfs_vnops.c @@ -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), diff --git a/sys/msdosfs/msdosfsmount.h b/sys/msdosfs/msdosfsmount.h index fc8f18c89126..e581231d7a46 100644 --- a/sys/msdosfs/msdosfsmount.h +++ b/sys/msdosfs/msdosfsmount.h @@ -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