Update MSDOSFS code using NetBSD's msdosfs as a guide to support

FAT32 partitions.  Unfortunately, we looked around here at
Walnut Creek CDROM for any newer FAT32-supporting versions
of Win95 and we were unsuccessful; only the older stuff here.
So this is untested beyond simply making sure it compiles and
someone with access to an actual FAT32 fs will have
to let us know how well it actually works.
Submitted by:	Dmitrij Tejblum <dima@tejblum.dnttm.rssi.ru>
Obtained from:	NetBSD
This commit is contained in:
Jordan K. Hubbard 1998-02-18 09:28:47 +00:00
parent 24b687b8de
commit 952a6212d9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=33548
24 changed files with 6778 additions and 3908 deletions

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* $NetBSD: bootsect.h,v 1.4 1994/06/29 06:35:28 cgd Exp $ */
/* $Id: bootsect.h,v 1.5 1997/02/22 09:40:43 peter Exp $ */
/* $NetBSD: bootsect.h,v 1.9 1997/11/17 15:36:17 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -23,36 +23,78 @@
* first sector of a partitioned hard disk.
*/
struct bootsector33 {
u_char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[19]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsBootCode[479]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
int8_t bsOemName[8]; /* OEM name and version */
int8_t bsBPB[19]; /* BIOS parameter block */
int8_t bsDriveNumber; /* drive number (0x80) */
int8_t bsBootCode[479]; /* pad so struct is 512b */
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_char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[25]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsReserved1; /* reserved */
char bsBootSignature; /* extended boot signature (0x29) */
#define EXBOOTSIG 0x29
char bsVolumeID[4]; /* volume ID number */
char bsVolumeLabel[11]; /* volume label */
char bsFileSysType[8]; /* file system type (FAT12 or FAT16) */
char bsBootCode[448]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
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 bsExt[26]; /* Bootsector Extension */
int8_t bsBootCode[448]; /* pad so structure is 512b */
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
/*
* The boot sector on a gemdos fs is a little bit different from the msdos fs
* format. Currently there is no need to declare a seperate structure, the
* bootsector33 struct will do.
*/
#if 0
struct bootsec_atari {
u_int8_t bsBranch[2]; /* branch inst if auto-boot */
int8_t bsFiller[6]; /* anything or nothing */
int8_t bsSerial[3]; /* serial no. for mediachange */
int8_t bsBPB[19]; /* BIOS parameter block */
int8_t bsBootCode[482]; /* pad so struct is 512b */
};
#endif
#endif /* atari */
union bootsector {
struct bootsector33 bs33;
struct bootsector50 bs50;
struct bootsector710 bs710;
};
#if 0
/*
* Shorthand for fields in the bpb.
*/
@ -68,3 +110,4 @@ union bootsector {
#define bsHeads bsBPB.bpbHeads
#define bsHiddenSecs bsBPB.bpbHiddenSecs
#define bsHugeSectors bsBPB.bpbHugeSectors
#endif

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* $NetBSD: bpb.h,v 1.3 1994/06/29 06:35:29 cgd Exp $ */
/* $Id: bpb.h,v 1.5 1997/02/22 09:40:44 peter Exp $ */
/* $NetBSD: bpb.h,v 1.7 1997/11/17 15:36:24 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -21,17 +21,17 @@
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct bpb33 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_short bpbHiddenSecs; /* number of hidden sectors */
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_int16_t bpbHiddenSecs; /* number of hidden sectors */
};
/*
@ -39,20 +39,70 @@ struct bpb33 {
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct bpb50 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_long bpbHiddenSecs; /* number of hidden sectors */
u_long bpbHugeSectors; /* number of sectors if bpbSectors == 0 */
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 */
};
/*
* 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.
* Currently there is no need for a separate BPB structure.
*/
#if 0
struct bpb_a {
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 bpbUseless1; /* meaningless on gemdos fs */
u_int16_t bpbFATsecs; /* number of sectors per FAT */
u_int16_t bpbUseless2; /* meaningless for harddisk fs */
u_int16_t bpbUseless3; /* meaningless for harddisk fs */
u_int16_t bpbHiddenSecs; /* the TOS-BIOS ignores this */
};
#endif
#endif /* atari */
/*
* The following structures represent how the bpb's look on disk. shorts
* and longs are just character arrays of the appropriate length. This is
@ -64,40 +114,39 @@ struct bpb50 {
* use the macros for the big-endian case.
*/
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN /* && can do unaligned accesses */
#define getushort(x) *((u_short *)(x))
#define getulong(x) *((u_long *)(x))
#define putushort(p, v) (*((u_short *)(p)) = (v))
#define putulong(p, v) (*((u_long *)(p)) = (v))
#if (BYTE_ORDER == LITTLE_ENDIAN) /* && defined(UNALIGNED_ACCESS) */
#define getushort(x) *((u_int16_t *)(x))
#define getulong(x) *((u_int32_t *)(x))
#define putushort(p, v) (*((u_int16_t *)(p)) = (v))
#define putulong(p, v) (*((u_int32_t *)(p)) = (v))
#else
#define getushort(x) (((u_char *)(x))[0] + (((u_char *)(x))[1] << 8))
#define getulong(x) (((u_char *)(x))[0] + (((u_char *)(x))[1] << 8) \
+ (((u_char *)(x))[2] << 16) \
+ (((u_char *)(x))[3] << 24))
#define putushort(p, v) (((u_char *)(p))[0] = (v), \
((u_char *)(p))[1] = (v) >> 8)
#define putulong(p, v) (((u_char *)(p))[0] = (v), \
((u_char *)(p))[1] = (v) >> 8, \
((u_char *)(p))[2] = (v) >> 16,\
((u_char *)(p))[3] = (v) >> 24)
#define getushort(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8))
#define getulong(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8) \
+ (((u_int8_t *)(x))[2] << 16) \
+ (((u_int8_t *)(x))[3] << 24))
#define putushort(p, v) (((u_int8_t *)(p))[0] = (v), \
((u_int8_t *)(p))[1] = (v) >> 8)
#define putulong(p, v) (((u_int8_t *)(p))[0] = (v), \
((u_int8_t *)(p))[1] = (v) >> 8, \
((u_int8_t *)(p))[2] = (v) >> 16,\
((u_int8_t *)(p))[3] = (v) >> 24)
#endif
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct byte_bpb33 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[2]; /* number of hidden sectors */
int8_t bpbBytesPerSec[2]; /* bytes per sector */
int8_t bpbSecPerClust; /* sectors per cluster */
int8_t bpbResSectors[2]; /* number of reserved sectors */
int8_t bpbFATs; /* number of FATs */
int8_t bpbRootDirEnts[2]; /* number of root directory entries */
int8_t bpbSectors[2]; /* total number of sectors */
int8_t bpbMedia; /* media descriptor */
int8_t bpbFATsecs[2]; /* number of sectors per FAT */
int8_t bpbSecPerTrack[2]; /* sectors per track */
int8_t bpbHeads[2]; /* number of heads */
int8_t bpbHiddenSecs[2]; /* number of hidden sectors */
};
/*
@ -105,16 +154,56 @@ struct byte_bpb33 {
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct byte_bpb50 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[4]; /* number of hidden sectors */
char bpbHugeSectors[4]; /* number of sectors if bpbSectors == 0 */
int8_t bpbBytesPerSec[2]; /* bytes per sector */
int8_t bpbSecPerClust; /* sectors per cluster */
int8_t bpbResSectors[2]; /* number of reserved sectors */
int8_t bpbFATs; /* number of FATs */
int8_t bpbRootDirEnts[2]; /* number of root directory entries */
int8_t bpbSectors[2]; /* total number of sectors */
int8_t bpbMedia; /* media descriptor */
int8_t bpbFATsecs[2]; /* number of sectors per FAT */
int8_t bpbSecPerTrack[2]; /* sectors per track */
int8_t bpbHeads[2]; /* number of heads */
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,9 +1,9 @@
/* $Id: denode.h,v 1.13 1997/08/26 07:32:36 phk Exp $ */
/* $NetBSD: denode.h,v 1.8 1994/08/21 18:43:49 ws Exp $ */
/* $Id: denode.h,v 1.14 1997/10/17 12:36:16 phk Exp $ */
/* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -103,8 +103,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 */
};
/*
@ -121,7 +121,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.
@ -143,19 +143,21 @@ struct denode {
u_long de_flag; /* flag bits */
dev_t de_dev; /* device where direntry lives */
u_long de_dirclust; /* cluster of the directory file containing this entry */
u_long de_diroffset; /* ordinal of this entry in the directory */
u_long de_fndclust; /* cluster of found dir entry */
u_long de_diroffset; /* offset of this entry in the directory cluster */
u_long de_fndoffset; /* offset of found dir entry */
int de_fndcnt; /* number of slots before de_fndoffset */
long de_refcnt; /* reference count */
struct msdosfsmount *de_pmp; /* addr of our mount struct */
struct lockf *de_lockf; /* byte level lock list */
/* the next two fields must be contiguous in memory... */
u_char de_Name[8]; /* name, from directory entry */
u_char de_Extension[3]; /* extension, from directory entry */
u_char de_Name[12]; /* name, from DOS directory entry */
u_char de_Attributes; /* attributes, from directory entry */
u_short de_Time; /* creation time */
u_short de_Date; /* creation date */
u_short de_StartCluster; /* starting cluster of file */
u_char de_CHun; /* Hundredth of second of CTime*/
u_short de_CTime; /* creation time */
u_short de_CDate; /* creation date */
u_short de_ADate; /* access date */
u_short de_MTime; /* modification time */
u_short de_MDate; /* modification date */
u_long de_StartCluster; /* starting cluster of file */
u_long de_FileSize; /* size of file in bytes */
struct fatcache de_fc[FC_SIZE]; /* fat cache */
u_quad_t de_modrev; /* Revision level for lease. */
@ -164,31 +166,49 @@ struct denode {
/*
* Values for the de_flag field of the denode.
*/
#define DE_UPDATE 0x0004 /* modification time update request */
#define DE_MODIFIED 0x0080 /* denode has been modified, but DE_UPDATE
* isn't set */
#define DE_UPDATE 0x0004 /* Modification time update request */
#define DE_CREATE 0x0008 /* Creation time update */
#define DE_ACCESS 0x0010 /* Access time update */
#define DE_MODIFIED 0x0020 /* Denode has been modified */
#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */
/*
* Transfer directory entries between internal and external form.
* 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_Time = getushort((dp)->deTime), \
(dep)->de_Date = getushort((dp)->deDate), \
(dep)->de_CHun = (dp)->deCHundredth, \
(dep)->de_CTime = getushort((dp)->deCTime), \
(dep)->de_CDate = getushort((dp)->deCDate), \
(dep)->de_ADate = getushort((dp)->deADate), \
(dep)->de_MTime = getushort((dp)->deMTime), \
(dep)->de_MDate = getushort((dp)->deMDate), \
(dep)->de_StartCluster = getushort((dp)->deStartCluster), \
(dep)->de_FileSize = getulong((dp)->deFileSize))
(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), \
bzero((dp)->deReserved, 10), \
(dp)->deAttributes = (dep)->de_Attributes, \
putushort((dp)->deTime, (dep)->de_Time), \
putushort((dp)->deDate, (dep)->de_Date), \
(dp)->deCHundredth = (dep)->de_CHun, \
putushort((dp)->deCTime, (dep)->de_CTime), \
putushort((dp)->deCDate, (dep)->de_CDate), \
putushort((dp)->deADate, (dep)->de_ADate), \
putushort((dp)->deMTime, (dep)->de_MTime), \
putushort((dp)->deMDate, (dep)->de_MDate), \
putushort((dp)->deStartCluster, (dep)->de_StartCluster), \
putulong((dp)->deFileSize, (dep)->de_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]
@ -198,17 +218,20 @@ struct denode {
#define VTODE(vp) ((struct denode *)(vp)->v_data)
#define DETOV(de) ((de)->de_vnode)
#define DE_TIMES(dep, t) \
if ((dep)->de_flag & DE_UPDATE) { \
if (!((dep)->de_Attributes & ATTR_DIRECTORY)) { \
struct timespec DE_TIMES_ts; \
(dep)->de_flag |= DE_MODIFIED; \
TIMEVAL_TO_TIMESPEC((t), &DE_TIMES_ts); \
unix2dostime(&DE_TIMES_ts, &(dep)->de_Date, \
&(dep)->de_Time); \
#define DETIMES(dep, acc, mod, cre) \
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, NULL); \
(dep)->de_Attributes |= ATTR_ARCHIVE; \
} \
(dep)->de_flag &= ~DE_UPDATE; \
if (!((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)) { \
if ((dep)->de_flag & DE_ACCESS) \
unix2dostime((acc), &(dep)->de_ADate, NULL, NULL); \
if ((dep)->de_flag & DE_CREATE) \
unix2dostime((cre), &(dep)->de_CDate, &(dep)->de_CTime, &(dep)->de_CHun); \
} \
(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \
}
/*
@ -219,9 +242,10 @@ struct defid {
u_short defid_pad; /* force long alignment */
u_long defid_dirclust; /* cluster this dir entry came from */
u_long defid_dirofs; /* index of entry within the cluster */
/* u_long defid_gen; generation number */
u_long defid_dirofs; /* offset of entry within the cluster */
#if 0
u_long defid_gen; /* generation number */
#endif
};
extern vop_t **msdosfs_vnodeop_p;
@ -233,5 +257,19 @@ int msdosfs_reclaim __P((struct vop_reclaim_args *));
/*
* Internal service routine prototypes.
*/
int deget __P((struct msdosfsmount * pmp, u_long dirclust, u_long diroffset, struct direntry * direntptr, struct denode ** depp));
int deget __P((struct msdosfsmount *, u_long, u_long, struct denode **));
int uniqdosname __P((struct denode *, struct componentname *, u_char *));
int findwin95 __P((struct denode *));
int readep __P((struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp));
int readde __P((struct denode *dep, struct buf **bpp, struct direntry **epp));
int deextend __P((struct denode *dep, u_long length, struct ucred *cred));
int fillinusemap __P((struct msdosfsmount *pmp));
void reinsert __P((struct denode *dep));
int dosdirempty __P((struct denode *dep));
int createde __P((struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp));
int deupdat __P((struct denode *dep, int waitfor));
int removede __P((struct denode *pdep, struct denode *dep));
int detrunc __P((struct denode *dep, u_long length, int flags, struct ucred *cred, struct proc *p));
int doscheckpath __P(( struct denode *source, struct denode *target));
#endif /* KERNEL */

View File

@ -1,9 +1,9 @@
/* $Id$ */
/* $NetBSD: direntry.h,v 1.7 1994/08/21 18:43:54 ws Exp $ */
/* $Id: direntry.h,v 1.4 1997/02/22 09:40:45 peter Exp $ */
/* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -52,26 +52,55 @@
* Structure of a dos directory entry.
*/
struct direntry {
u_char deName[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
u_char deExtension[3]; /* extension, blank filled */
u_char deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
u_char deReserved[10]; /* reserved */
u_char deTime[2]; /* create/last update time */
u_char deDate[2]; /* create/last update date */
u_char deStartCluster[2]; /* starting cluster of file */
u_char deFileSize[4]; /* size of file in bytes */
u_int8_t deName[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
u_int8_t deExtension[3]; /* extension, blank filled */
u_int8_t deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
u_int8_t deReserved[1]; /* 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 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 */
u_int8_t deFileSize[4]; /* size of file in bytes */
};
/*
* Structure of a Win95 long name directory entry
*/
struct winentry {
u_int8_t weCnt;
#define WIN_LAST 0x40
#define WIN_CNT 0x3f
u_int8_t wePart1[10];
u_int8_t weAttributes;
#define ATTR_WIN95 0x0f
u_int8_t weReserved1;
u_int8_t weChksum;
u_int8_t wePart2[12];
u_int16_t weReserved2;
u_int8_t wePart3[4];
};
#define WIN_CHARS 13 /* Number of chars per winentry */
/*
* Maximum filename length in Win95
* Note: Must be < sizeof(dirent.d_name)
*/
#define WIN_MAXLEN 255
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
@ -97,8 +126,15 @@ struct direntry {
#define DD_YEAR_SHIFT 9
#ifdef KERNEL
void unix2dostime __P((struct timespec * tsp, u_short * ddp, u_short * dtp));
void dos2unixtime __P((u_short dd, u_short dt, struct timespec * tsp));
int dos2unixfn __P((u_char dn[11], u_char * un));
void unix2dosfn __P((u_char * un, u_char dn[11], int unlen));
struct dirent;
void unix2dostime __P((struct timespec *tsp, u_int16_t *ddp,
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));
int unix2winfn __P((const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum));
int winChkName __P((const u_char *un, int unlen, struct winentry *wep, int chksum));
int win2unixfn __P((struct winentry *wep, struct dirent *dp, int chksum));
u_int8_t winChksum __P((u_int8_t *name));
int winSlotCnt __P((const u_char *un, int unlen));
#endif /* KERNEL */

View File

@ -1,9 +1,9 @@
/* $Id$ */
/* $NetBSD: fat.h,v 1.4 1994/08/21 18:43:57 ws Exp $ */
/* $Id: fat.h,v 1.6 1997/02/22 09:40:45 peter Exp $ */
/* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 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).
*
@ -51,28 +51,37 @@
/*
* 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:
* Return true if filesystem uses 12 bit fats. Microsoft Programmer's
* Reference says if the maximum cluster number in a filesystem is greater
* than 4086 then we've got a 16 bit fat filesystem.
* than 4078 ((CLUST_RSRVS - CLUST_FIRST) & FAT12_MASK) then we've got a
* 16 bit fat filesystem. While mounting, the result of this test is stored
* in pm_fatentrysize.
* GEMDOS-flavour (atari):
* If the filesystem is on floppy we've got a 12 bit fat filesystem, otherwise
* 16 bit. We check the d_type field in the disklabel struct while mounting
* 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_maxcluster <= 4086)
#define FAT16(pmp) (pmp->pm_maxcluster > 4086)
#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
/*
@ -88,7 +97,7 @@
*/
#define DE_CLEAR 1 /* Zero out the blocks allocated */
int pcbmap __P((struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp));
int pcbmap __P((struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int* sp));
int clusterfree __P((struct msdosfsmount *pmp, u_long cn, u_long *oldcnp));
int clusteralloc __P((struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got));
int fatentry __P((int function, struct msdosfsmount *pmp, u_long cluster, u_long *oldcontents, u_long newcontents));
@ -96,15 +105,4 @@ int freeclusterchain __P((struct msdosfsmount *pmp, u_long startchain));
int extendfile __P((struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags));
void fc_purge __P((struct denode *dep, u_int frcn));
int readep __P((struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp));
int readde __P((struct denode *dep, struct buf **bpp, struct direntry **epp));
int deextend __P((struct denode *dep, off_t length, struct ucred *cred));
int fillinusemap __P((struct msdosfsmount *pmp));
int reinsert __P((struct denode *dep));
int dosdirempty __P((struct denode *dep));
int createde __P((struct denode *dep, struct denode *ddep, struct denode **depp));
int deupdat __P((struct denode *dep, struct timespec *tp, int waitfor));
int removede __P((struct denode *pdep, struct denode *dep));
int detrunc __P((struct denode *dep, u_long length, int flags, struct ucred *cred, struct proc *p));
int doscheckpath __P(( struct denode *source, struct denode *target));
#endif /* KERNEL */

View File

@ -1,6 +1,37 @@
/* $Id: msdosfs_conv.c,v 1.13 1997/02/22 09:40:46 peter Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.6.2.1 1994/08/30 02:27:57 cgd Exp $ */
/* $Id: msdosfs_conv.c,v 1.14 1998/02/09 06:09:50 eivind Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.25 1997/11/17 15:36:40 ws Exp $ */
/*-
* 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).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
@ -23,8 +54,9 @@
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h> /* defines tz */
#include <sys/systm.h> /* defines tz */
#include <sys/systm.h>
#include <machine/clock.h>
#include <sys/dirent.h>
/*
* MSDOSFS include files.
@ -61,10 +93,11 @@ static 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_short *ddp;
u_short *dtp;
u_int16_t *ddp;
u_int16_t *dtp;
u_int8_t *dhp;
{
u_long t;
u_long days;
@ -80,9 +113,10 @@ unix2dostime(tsp, ddp, dtp)
t = tsp->tv_sec - (tz.tz_minuteswest * 60)
- (wall_cmos_clock ? adjkerntz : 0);
/* - daylight savings time correction */
t &= ~1;
if (lasttime != t) {
lasttime = t;
lastdtime = (((t % 60) >> 1) << DT_2SECONDS_SHIFT)
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
@ -117,7 +151,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;
}
@ -136,9 +174,10 @@ static u_long lastseconds;
* not be too efficient.
*/
void
dos2unixtime(dd, dt, tsp)
u_short dd;
u_short dt;
dos2unixtime(dd, dt, dh, tsp)
u_int dd;
u_int dt;
u_int dh;
struct timespec *tsp;
{
u_long seconds;
@ -147,9 +186,18 @@ dos2unixtime(dd, dt, tsp)
u_long days;
u_short *months;
if (dd == 0) {
/*
* Uninitialized field, return the epoch.
*/
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
return;
}
seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ ((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.
@ -165,8 +213,7 @@ dos2unixtime(dd, dt, tsp)
months = year & 0x03 ? regyear : leapyear;
month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
if (month < 1 || month > 12) {
printf(
"dos2unixtime(): month value out of range (%ld)\n",
printf("dos2unixtime(): month value out of range (%ld)\n",
month);
month = 1;
}
@ -178,17 +225,116 @@ dos2unixtime(dd, dt, tsp)
tsp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
+ adjkerntz;
/* + daylight savings time correction */
tsp->tv_nsec = 0;
tsp->tv_nsec = (dh % 100) * 10000000;
}
/*
* Cheezy macros to do case detection and conversion for the ascii
* character set. DOESN'T work for ebcdic.
*/
#define isupper(c) (c >= 'A' && c <= 'Z')
#define islower(c) (c >= 'a' && c <= 'z')
#define toupper(c) (c & ~' ')
#define tolower(c) (c | ' ')
static u_char
unix2dos[256] = {
0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */
0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */
0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */
0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */
0, 0x21, 0, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0, 0, 0, 0x2d, 0, 0, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0, 0, 0, 0, 0, 0, /* 38-3f */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
0x58, 0x59, 0x5a, 0, 0, 0, 0x5e, 0x5f, /* 58-5f */
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 68-6f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */
0x58, 0x59, 0x5a, 0x7b, 0, 0x7d, 0x7e, 0, /* 78-7f */
0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */
0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */
0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */
0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */
0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
};
static u_char
dos2unix[256] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 00-07 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 08-0f */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 10-17 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 18-1f */
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7, /* 80-87 */
0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5, /* 88-8f */
0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9, /* 90-97 */
0xff, 0xd6, 0xdc, 0xf8, 0xa3, 0xd8, 0xd7, 0x3f, /* 98-9f */
0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba, /* a0-a7 */
0xbf, 0xae, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb, /* a8-af */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xc1, 0xc2, 0xc0, /* b0-b7 */
0xa9, 0x3f, 0x3f, 0x3f, 0x3f, 0xa2, 0xa5, 0x3f, /* b8-bf */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xe3, 0xc3, /* c0-c7 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xa4, /* c8-cf */
0xf0, 0xd0, 0xca, 0xcb, 0xc8, 0x3f, 0xcd, 0xce, /* d0-d7 */
0xcf, 0x3f, 0x3f, 0x3f, 0x3f, 0xa6, 0xcc, 0x3f, /* d8-df */
0xd3, 0xdf, 0xd4, 0xd2, 0xf5, 0xd5, 0xb5, 0xfe, /* e0-e7 */
0xde, 0xda, 0xdb, 0xd9, 0xfd, 0xdd, 0xaf, 0x3f, /* e8-ef */
0xad, 0xb1, 0x3f, 0xbe, 0xb6, 0xa7, 0xf7, 0xb8, /* f0-f7 */
0xb0, 0xa8, 0xb7, 0xb9, 0xb3, 0xb2, 0x3f, 0x3f, /* f8-ff */
};
static u_char
u2l[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */
};
/*
* DOS filenames are made of 2 parts, the name part and the extension part.
@ -203,58 +349,14 @@ dos2unixtime(dd, dt, tsp)
* null.
*/
int
dos2unixfn(dn, un)
dos2unixfn(dn, un, lower)
u_char dn[11];
u_char *un;
int lower;
{
int i;
int ni;
int ei;
int thislong = 0;
int thislong = 1;
u_char c;
u_char *origun = un;
/*
* Find the last character in the name portion of the dos filename.
*/
for (ni = 7; ni >= 0; ni--)
if (dn[ni] != ' ')
break;
/*
* Find the last character in the extension portion of the
* filename.
*/
for (ei = 10; ei >= 8; ei--)
if (dn[ei] != ' ')
break;
/*
* Copy the name portion into the unix filename string. NOTE: DOS
* filenames are usually kept in upper case. To make it more unixy
* we convert all DOS filenames to lower case. Some may like this,
* some may not.
*/
for (i = 0; i <= ni; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
/*
* Now, if there is an extension then put in a period and copy in
* the extension.
*/
if (ei >= 8) {
*un++ = '.';
thislong++;
for (i = 8; i <= ei; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
}
*un++ = 0;
/*
* If first char of the filename is SLOT_E5 (0x05), then the real
@ -262,31 +364,71 @@ dos2unixfn(dn, un)
* just have a 0xe5 mean 0xe5 because that is used to mean a freed
* directory slot. Another dos quirk.
*/
if (*origun == SLOT_E5)
*origun = 0xe5;
if (*dn == SLOT_E5)
c = dos2unix[0xe5];
else
c = dos2unix[*dn];
*un++ = lower ? u2l[c] : c;
dn++;
return thislong;
/*
* Copy the name portion into the unix filename string.
*/
for (i = 1; i < 8 && *dn != ' '; i++) {
c = dos2unix[*dn++];
*un++ = lower ? u2l[c] : c;
thislong++;
}
dn += 8 - i;
/*
* Now, if there is an extension then put in a period and copy in
* the extension.
*/
if (*dn != ' ') {
*un++ = '.';
thislong++;
for (i = 0; i < 3 && *dn != ' '; i++) {
c = dos2unix[*dn++];
*un++ = lower ? u2l[c] : c;
thislong++;
}
}
*un++ = 0;
return (thislong);
}
/*
* Convert a unix filename to a DOS filename. This function does not ensure
* that valid characters for a dos filename are supplied.
* Convert a unix filename to a DOS filename according to Win95 rules.
* If applicable and gen is not 0, it is inserted into the converted
* filename as a generation number.
* Returns
* 0 if name couldn't be converted
* 1 if the converted name is the same as the original
* (no long filename entry necessary for Win95)
* 2 if conversion was successful
* 3 if conversion was successful and generation number was inserted
*/
void
unix2dosfn(un, dn, unlen)
u_char *un;
u_char dn[11];
int
unix2dosfn(un, dn, unlen, gen)
const u_char *un;
u_char dn[12];
int unlen;
u_int gen;
{
int i;
u_char c;
int i, j, l;
int conv = 1;
const u_char *cp, *dp, *dp1;
u_char gentext[6], *wcp;
/*
* Fill the dos filename string with blanks. These are DOS's pad
* characters.
*/
for (i = 0; i <= 10; i++)
for (i = 0; i < 11; i++)
dn[i] = ' ';
dn[11] = 0;
/*
* The filenames "." and ".." are handled specially, since they
@ -294,65 +436,393 @@ unix2dosfn(un, dn, unlen)
*/
if (un[0] == '.' && unlen == 1) {
dn[0] = '.';
return;
return gen <= 1;
}
if (un[0] == '.' && un[1] == '.' && unlen == 2) {
dn[0] = '.';
dn[1] = '.';
return;
return gen <= 1;
}
/*
* Copy the unix filename into the dos filename string upto the end
* of string, a '.', or 8 characters. Whichever happens first stops
* us. This forms the name portion of the dos filename. Fold to
* upper case.
* Filenames with only blanks and dots are not allowed!
*/
for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
for (cp = un, i = unlen; --i >= 0; cp++)
if (*cp != ' ' && *cp != '.')
break;
if (i < 0)
return 0;
/*
* Now find the extension
* Note: dot as first char doesn't start extension
* and trailing dots and blanks are ignored
*/
dp = dp1 = 0;
for (cp = un + 1, i = unlen - 1; --i >= 0;) {
switch (*cp++) {
case '.':
if (!dp1)
dp1 = cp;
break;
case ' ':
break;
default:
if (dp1)
dp = dp1;
dp1 = 0;
break;
}
}
/*
* If the first char of the filename is 0xe5, then translate it to
* 0x05. This is because 0xe5 is the marker for a deleted
* directory slot. I guess this means you can't have filenames
* that start with 0x05. I suppose we should check for this and
* doing something about it.
* Now convert it
*/
if (dn[0] == SLOT_DELETED)
if (dp) {
if (dp1)
l = dp1 - dp;
else
l = unlen - (dp - un);
for (i = 0, j = 8; i < l && j < 11; i++, j++) {
if (dp[i] != (dn[j] = unix2dos[dp[i]])
&& conv != 3)
conv = 2;
if (!dn[j]) {
conv = 3;
dn[j--] = ' ';
}
}
if (i < l)
conv = 3;
dp--;
} else {
for (dp = cp; *--dp == ' ' || *dp == '.';);
dp++;
}
/*
* Now convert the rest of the name
*/
for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
if (*un != (dn[j] = unix2dos[*un])
&& conv != 3)
conv = 2;
if (!dn[j]) {
conv = 3;
dn[j--] = ' ';
}
}
if (un < dp)
conv = 3;
/*
* If we didn't have any chars in filename,
* generate a default
*/
if (!j)
dn[0] = '_';
/*
* The first character cannot be E5,
* because that means a deleted entry
*/
if (dn[0] == 0xe5)
dn[0] = SLOT_E5;
/*
* Strip any further characters up to a '.' or the end of the
* string.
* If there wasn't any char dropped,
* there is no place for generation numbers
*/
while (unlen && (c = *un)) {
un++;
unlen--;
/* Make sure we've skipped over the dot before stopping. */
if (c == '.')
break;
if (conv != 3) {
if (gen > 1)
return 0;
return conv;
}
/*
* Copy in the extension part of the name, if any. Force to upper
* case. Note that the extension is allowed to contain '.'s.
* Filenames in this form are probably inaccessable under dos.
* Now insert the generation number into the filename part
*/
for (i = 8; i <= 10 && unlen && (c = *un); i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
}
for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
*--wcp = gen % 10 + '0';
if (gen)
return 0;
for (i = 8; dn[--i] == ' ';);
i++;
if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
i = 8 - (gentext + sizeof(gentext) - wcp + 1);
dn[i++] = '~';
while (wcp < gentext + sizeof(gentext))
dn[i++] = *wcp++;
return 3;
}
/*
* Get rid of these macros before someone discovers we are using such
* hideous things.
* Create a Win95 long name directory entry
* Note: assumes that the filename is valid,
* i.e. doesn't consist solely of blanks and dots
*/
#undef isupper
#undef islower
#undef toupper
#undef tolower
int
unix2winfn(un, unlen, wep, cnt, chksum)
const u_char *un;
int unlen;
struct winentry *wep;
int cnt;
int chksum;
{
const u_int8_t *cp;
u_int8_t *wcp;
int i;
/*
* Drop trailing blanks and dots
*/
for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
un += (cnt - 1) * WIN_CHARS;
unlen -= (cnt - 1) * WIN_CHARS;
/*
* Initialize winentry to some useful default
*/
for (wcp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *wcp++ = 0xff);
wep->weCnt = cnt;
wep->weAttributes = ATTR_WIN95;
wep->weReserved1 = 0;
wep->weChksum = chksum;
wep->weReserved2 = 0;
/*
* Now convert the filename parts
*/
for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
if (!unlen)
wep->weCnt |= WIN_LAST;
return unlen;
done:
*wcp++ = 0;
*wcp++ = 0;
wep->weCnt |= WIN_LAST;
return 0;
}
/*
* Compare our filename to the one in the Win95 entry
* Returns the checksum or -1 if no match
*/
int
winChkName(un, unlen, wep, chksum)
const u_char *un;
int unlen;
struct winentry *wep;
int chksum;
{
u_int8_t *cp;
int i;
/*
* First compare checksums
*/
if (wep->weCnt&WIN_LAST)
chksum = wep->weChksum;
else if (chksum != wep->weChksum)
chksum = -1;
if (chksum == -1)
return -1;
/*
* Offset of this entry
*/
i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
un += i;
if ((unlen -= i) <= 0)
return -1;
if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS)
return -1;
/*
* Compare the name parts
*/
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
return chksum;
}
/*
* Convert Win95 filename to dirbuf.
* Returns the checksum or -1 if impossible
*/
int
win2unixfn(wep, dp, chksum)
struct winentry *wep;
struct dirent *dp;
int chksum;
{
u_int8_t *cp;
u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
int i;
if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
|| !(wep->weCnt&WIN_CNT))
return -1;
/*
* First compare checksums
*/
if (wep->weCnt&WIN_LAST) {
chksum = wep->weChksum;
/*
* This works even though d_namlen is one byte!
*/
dp->d_namlen = (wep->weCnt&WIN_CNT) * WIN_CHARS;
} else if (chksum != wep->weChksum)
chksum = -1;
if (chksum == -1)
return -1;
/*
* Offset of this entry
*/
i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
np = (u_int8_t *)dp->d_name + i;
/*
* Convert the name parts
*/
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= sizeof(wep->wePart2)/2
+ sizeof(wep->wePart3)/2 + i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* The size comparison should result in the compiler
* optimizing the whole if away
*/
if (WIN_MAXLEN % WIN_CHARS < sizeof(wep->wePart1) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* The size comparisons should be optimized away
*/
if (WIN_MAXLEN % WIN_CHARS >= sizeof(wep->wePart1) / 2
&& WIN_MAXLEN % WIN_CHARS < (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* See above
*/
if (WIN_MAXLEN % WIN_CHARS >= (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
return chksum;
}
/*
* Compute the checksum of a DOS filename for Win95 use
*/
u_int8_t
winChksum(name)
u_int8_t *name;
{
int i;
u_int8_t s;
for (s = 0, i = 11; --i >= 0; s += *name++)
s = (s << 7)|(s >> 1);
return s;
}
/*
* Determine the number of slots necessary for Win95 names
*/
int
winSlotCnt(un, unlen)
const u_char *un;
int unlen;
{
for (un += unlen; unlen > 0; unlen--)
if (*--un != ' ' && *un != '.')
break;
if (unlen > WIN_MAXLEN)
return 0;
return howmany(unlen, WIN_CHARS);
}

View File

@ -1,9 +1,9 @@
/* $Id: msdosfs_denode.c,v 1.30 1998/02/06 12:13:46 eivind Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.9 1994/08/21 18:44:00 ws Exp $ */
/* $Id: msdosfs_denode.c,v 1.31 1998/02/09 06:09:51 eivind Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -69,8 +69,9 @@
static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");
static struct denode **dehashtbl;
static u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, deno) (dehashtbl[((dev) + (deno)) & dehash])
static u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, dcl, doff) (dehashtbl[((dev) + (dcl) + (doff) / \
sizeof(struct direntry)) & dehash])
static struct simplelock dehash_slock;
union _qcvt {
@ -96,12 +97,14 @@ static struct denode *
static void msdosfs_hashins __P((struct denode *dep));
static void msdosfs_hashrem __P((struct denode *dep));
int msdosfs_init(vfsp)
/*ARGSUSED*/
int
msdosfs_init(vfsp)
struct vfsconf *vfsp;
{
dehashtbl = hashinit(desiredvnodes/2, M_MSDOSFSMNT, &dehash);
simple_lock_init(&dehash_slock);
return 0;
return (0);
}
static struct denode *
@ -116,7 +119,7 @@ msdosfs_hashget(dev, dirclust, diroff)
loop:
simple_lock(&dehash_slock);
for (dep = DEHASH(dev, dirclust + diroff); dep; dep = dep->de_next) {
for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next) {
if (dirclust == dep->de_dirclust
&& diroff == dep->de_diroffset
&& dev == dep->de_dev
@ -140,7 +143,7 @@ msdosfs_hashins(dep)
struct denode **depp, *deq;
simple_lock(&dehash_slock);
depp = &DEHASH(dep->de_dev, dep->de_dirclust + dep->de_diroffset);
depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
deq = *depp;
if (deq)
deq->de_prev = &dep->de_next;
@ -178,48 +181,41 @@ msdosfs_hashrem(dep)
* diroffset is relative to the beginning of the root directory,
* otherwise it is cluster relative.
* diroffset - offset past begin of cluster of denode we want
* direntptr - address of the direntry structure of interest. If direntptr is
* NULL, the block is read if necessary.
* depp - returns the address of the gotten denode.
*/
int
deget(pmp, dirclust, diroffset, direntptr, depp)
deget(pmp, dirclust, diroffset, depp)
struct msdosfsmount *pmp; /* so we know the maj/min number */
u_long dirclust; /* cluster this dir entry came from */
u_long diroffset; /* index of entry within the cluster */
struct direntry *direntptr;
struct denode **depp; /* returns the addr of the gotten denode */
{
int error;
dev_t dev = pmp->pm_dev;
struct mount *mntp = pmp->pm_mountp;
struct direntry *direntptr;
struct denode *ldep;
struct vnode *nvp;
struct buf *bp;
struct proc *p = curproc; /* XXX */
#ifdef MSDOSFS_DEBUG
printf("deget(pmp %p, dirclust %ld, diroffset %x, direntptr %p, depp %p)\n",
pmp, dirclust, diroffset, direntptr, depp);
printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
pmp, dirclust, diroffset, depp);
#endif
/*
* If dir entry is given and refers to a directory, convert to
* canonical form
* On FAT32 filesystems, root is a (more or less) normal
* directory
*/
if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) {
dirclust = getushort(direntptr->deStartCluster);
if (dirclust == MSDOSFSROOT)
diroffset = MSDOSFSROOT_OFS;
else
diroffset = 0;
}
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.
@ -230,7 +226,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
ldep = msdosfs_hashget(dev, dirclust, diroffset);
if (ldep) {
*depp = ldep;
return 0;
return (0);
}
/*
@ -277,10 +273,15 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
*/
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
@ -288,39 +289,42 @@ deget(pmp, dirclust, diroffset, direntptr, 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_Time = 0x0000; /* 00:00:00 */
ldep->de_Date = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
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_ADate = ldep->de_CDate;
ldep->de_MTime = ldep->de_CTime;
ldep->de_MDate = ldep->de_CDate;
/* leave the other fields as garbage */
} else {
bp = NULL;
if (!direntptr) {
error = readep(pmp, dirclust, diroffset, &bp,
&direntptr);
if (error)
return error;
}
error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
if (error)
return (error);
DE_INTERNALIZE(ldep, direntptr);
if (bp)
brelse(bp);
brelse(bp);
}
/*
* 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
@ -331,12 +335,10 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
u_long size;
nvp->v_type = VDIR;
if (ldep->de_StartCluster == MSDOSFSROOT)
nvp->v_flag |= VROOT;
else {
error = pcbmap(ldep, 0xffff, 0, &size);
if (ldep->de_StartCluster != MSDOSFSROOT) {
error = pcbmap(ldep, 0xffff, 0, &size, 0);
if (error == E2BIG) {
ldep->de_FileSize = size << pmp->pm_cnshift;
ldep->de_FileSize = de_cn2off(pmp, size);
error = 0;
} else
printf("deget(): pcbmap returned %d\n", error);
@ -347,78 +349,40 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
SETLOW(ldep->de_modrev, mono_time.tv_usec * 4294);
VREF(ldep->de_devvp);
*depp = ldep;
return 0;
return (0);
}
int
deupdat(dep, tp, waitfor)
deupdat(dep, waitfor)
struct denode *dep;
struct timespec *tp;
int waitfor;
{
int error;
struct buf *bp;
struct direntry *dirp;
struct vnode *vp = DETOV(dep);
struct timespec ts;
#ifdef MSDOSFS_DEBUG
printf("deupdat(): dep %p\n", dep);
#endif
/*
* If the denode-modified and update-mtime bits are off,
* or this denode is from a readonly filesystem,
* or this denode is for a directory,
* or the denode represents an open but unlinked file,
* then don't do anything. DOS directory
* entries that describe a directory do not ever get
* updated. This is the way DOS treats them.
*/
if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 ||
vp->v_mount->mnt_flag & MNT_RDONLY ||
dep->de_Attributes & ATTR_DIRECTORY ||
dep->de_refcnt <= 0)
return 0;
/*
* Read in the cluster containing the directory entry we want to
* update.
*/
if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY)
return (0);
TIMEVAL_TO_TIMESPEC(&time, &ts);
DETIMES(dep, &ts, &ts, &ts);
if ((dep->de_flag & DE_MODIFIED) == 0)
return (0);
dep->de_flag &= ~DE_MODIFIED;
if (dep->de_Attributes & ATTR_DIRECTORY)
return (0);
if (dep->de_refcnt <= 0)
return (0);
error = readde(dep, &bp, &dirp);
if (error)
return error;
/*
* If the mtime is to be updated, put the passed in time into the
* directory entry.
*/
if (dep->de_flag & DE_UPDATE) {
dep->de_Attributes |= ATTR_ARCHIVE;
unix2dostime(tp, &dep->de_Date, &dep->de_Time);
}
/*
* The mtime is now up to date. The denode will be unmodifed soon.
*/
dep->de_flag &= ~(DE_MODIFIED | DE_UPDATE);
/*
* Copy the directory entry out of the denode into the cluster it
* came from.
*/
return (error);
DE_EXTERNALIZE(dirp, dep);
/*
* Write the cluster back to disk. If they asked for us to wait
* for the write to complete, then use bwrite() otherwise use
* bdwrite().
*/
error = 0; /* note that error is 0 from above, but ... */
if (waitfor)
error = bwrite(bp);
else
return (bwrite(bp));
else {
bdwrite(bp);
return error;
return (0);
}
}
/*
@ -445,7 +409,7 @@ detrunc(dep, length, flags, cred, p)
struct timespec ts;
#ifdef MSDOSFS_DEBUG
printf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags);
printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
#endif
/*
@ -456,11 +420,10 @@ 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) {
printf(
"detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
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;
return (EINVAL);
}
@ -483,16 +446,17 @@ detrunc(dep, length, flags, cred, p)
dep->de_StartCluster = 0;
eofentry = ~0;
} else {
error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, &eofentry);
error = pcbmap(dep, de_clcount(pmp, length) - 1, 0,
&eofentry, 0);
if (error) {
#ifdef MSDOSFS_DEBUG
printf("detrunc(): pcbmap fails %d\n", error);
#endif
return error;
return (error);
}
}
fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift);
fc_purge(dep, de_clcount(pmp, length));
/*
* If the new length is not a multiple of the cluster size then we
@ -500,10 +464,6 @@ detrunc(dep, length, flags, cred, p)
* becomes part of the file again because of a seek.
*/
if ((boff = length & pmp->pm_crbomask) != 0) {
/*
* should read from file vnode or filesystem vnode
* depending on if file or dir
*/
if (isadir) {
bn = cntobn(pmp, eofentry);
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
@ -521,10 +481,11 @@ detrunc(dep, length, flags, cred, p)
NOCRED, &bp);
}
if (error) {
brelse(bp);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): bread fails %d\n", error);
#endif
return error;
return (error);
}
/*
* is this the right place for it?
@ -541,14 +502,14 @@ detrunc(dep, length, flags, cred, p)
* we free the trailing clusters.
*/
dep->de_FileSize = length;
dep->de_flag |= DE_UPDATE;
if (!isadir)
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
vflags = (length > 0 ? V_SAVE : 0) | V_SAVEMETA;
vinvalbuf(DETOV(dep), vflags, cred, p, 0, 0);
vnode_pager_setsize(DETOV(dep), length);
TIMEVAL_TO_TIMESPEC(&time, &ts);
allerror = deupdat(dep, &ts, 1);
allerror = deupdat(dep, 1);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): allerror %d, eofentry %d\n",
printf("detrunc(): allerror %d, eofentry %lu\n",
allerror, eofentry);
#endif
@ -563,9 +524,9 @@ detrunc(dep, length, flags, cred, p)
#ifdef MSDOSFS_DEBUG
printf("detrunc(): fatentry errors %d\n", error);
#endif
return error;
return (error);
}
fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
eofentry);
}
@ -573,10 +534,10 @@ 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;
return (allerror);
}
/*
@ -585,7 +546,7 @@ detrunc(dep, length, flags, cred, p)
int
deextend(dep, length, cred)
struct denode *dep;
off_t length;
u_long length;
struct ucred *cred;
{
struct msdosfsmount *pmp = dep->de_pmp;
@ -596,18 +557,14 @@ deextend(dep, length, cred)
/*
* The root of a DOS filesystem cannot be extended.
*/
if (DETOV(dep)->v_flag & VROOT)
return EINVAL;
if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
return (EINVAL);
/*
* Directories can only be extended by the superuser.
* Is this really important?
* Directories cannot be extended.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
error = suser(cred, NULL);
if (error)
return error;
}
if (dep->de_Attributes & ATTR_DIRECTORY)
return (EISDIR);
if (length <= dep->de_FileSize)
panic("deextend: file too large");
@ -618,26 +575,25 @@ deextend(dep, length, cred)
count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
if (count > 0) {
if (count > pmp->pm_freeclustercount)
return ENOSPC;
return (ENOSPC);
error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
if (error) {
/* truncate the added clusters away again */
(void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
return error;
return (error);
}
}
dep->de_flag |= DE_UPDATE;
dep->de_FileSize = length;
TIMEVAL_TO_TIMESPEC(&time, &ts);
return deupdat(dep, &ts, 1);
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
return (deupdat(dep, 1));
}
/*
* Move a denode to its correct hash queue after the file it represents has
* been moved to a new directory.
*/
int reinsert(dep)
void
reinsert(dep)
struct denode *dep;
{
/*
@ -648,11 +604,10 @@ int reinsert(dep)
* so we must remove it from the cache and re-enter it with the
* hash based on the new location of the directory entry.
*/
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
msdosfs_hashrem(dep);
msdosfs_hashins(dep);
}
return 0;
if (dep->de_Attributes & ATTR_DIRECTORY)
return;
msdosfs_hashrem(dep);
msdosfs_hashins(dep);
}
int
@ -671,27 +626,25 @@ msdosfs_reclaim(ap)
if (prtactive && vp->v_usecount != 0)
vprint("msdosfs_reclaim(): pushing active", vp);
/*
* Remove the denode from the denode hash chain we are in.
* Remove the denode from its hash chain.
*/
msdosfs_hashrem(dep);
cache_purge(vp);
/*
* Indicate that one less file on the filesystem is open.
* Purge old data structures associated with the denode.
*/
cache_purge(vp);
if (dep->de_devvp) {
vrele(dep->de_devvp);
dep->de_devvp = 0;
}
#if 0 /* XXX */
dep->de_flag = 0;
#endif
FREE(dep, M_MSDOSFSNODE);
vp->v_data = NULL;
return 0;
return (0);
}
int
@ -715,7 +668,7 @@ msdosfs_inactive(ap)
vprint("msdosfs_inactive(): pushing active", vp);
/*
* Ignore inodes related to stale file handles.
* Ignore denodes related to stale file handles.
*/
if (dep->de_Name[0] == SLOT_DELETED)
goto out;
@ -734,17 +687,13 @@ msdosfs_inactive(ap)
dep->de_flag |= DE_UPDATE;
dep->de_Name[0] = SLOT_DELETED;
}
if (dep->de_flag & (DE_MODIFIED | DE_UPDATE)) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
deupdat(dep, &ts, 0);
}
deupdat(dep, 0);
out:
VOP_UNLOCK(vp, 0, p);
dep->de_flag = 0;
/*
* If we are done with the denode, then reclaim it so that it can
* be reused now.
* If we are done with the denode, reclaim it
* so that it can be reused immediately.
*/
#ifdef MSDOSFS_DEBUG
printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount,
@ -752,5 +701,5 @@ msdosfs_inactive(ap)
#endif
if (dep->de_Name[0] == SLOT_DELETED)
vrecycle(vp, (struct simplelock *)0, p);
return error;
return (error);
}

View File

@ -1,9 +1,9 @@
/* $Id: msdosfs_fat.c,v 1.15 1998/02/06 12:13:46 eivind Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.12 1994/08/21 18:44:04 ws Exp $ */
/* $Id: msdosfs_fat.c,v 1.16 1998/02/09 06:09:52 eivind Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -56,6 +56,7 @@
#include <sys/buf.h>
#include <sys/mount.h> /* to define statfs structure */
#include <sys/vnode.h> /* to define vattr structure */
#include <sys/errno.h>
/*
* msdosfs include files.
@ -79,9 +80,6 @@ static int fc_lmdistance[LMMAX];/* counters for how far off the last
* cluster mapped entry was. */
static 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 int chainalloc __P((struct msdosfsmount *pmp, u_long start,
u_long count, u_long fillwith,
u_long *retcluster, u_long *got));
@ -111,7 +109,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)
@ -139,16 +138,17 @@ fatblock(pmp, ofs, bnp, sizep, bop)
* If cnp is null, nothing is returned.
*/
int
pcbmap(dep, findcn, bnp, cnp)
pcbmap(dep, findcn, bnp, cnp, sp)
struct denode *dep;
u_long findcn; /* file relative cluster to get */
daddr_t *bnp; /* returned filesys relative blk number */
u_long *cnp; /* returned cluster number */
int *sp; /* returned block size */
{
int error;
u_long i;
u_long cn;
u_long prevcn;
u_long prevcn = 0; /* XXX: prevcn could be used unititialized */
u_long byteoffset;
u_long bn;
u_long bo;
@ -156,7 +156,6 @@ pcbmap(dep, findcn, bnp, cnp)
u_long bp_bn = -1;
struct msdosfsmount *pmp = dep->de_pmp;
u_long bsize;
int fat12 = FAT12(pmp); /* 12 bit fat */
fc_bmapcalls++;
@ -164,8 +163,8 @@ pcbmap(dep, findcn, bnp, cnp)
* If they don't give us someplace to return a value then don't
* bother doing anything.
*/
if (bnp == NULL && cnp == NULL)
return 0;
if (bnp == NULL && cnp == NULL && sp == NULL)
return (0);
cn = dep->de_StartCluster;
/*
@ -176,23 +175,32 @@ pcbmap(dep, findcn, bnp, cnp)
*/
if (cn == MSDOSFSROOT) {
if (dep->de_Attributes & ATTR_DIRECTORY) {
if (findcn * pmp->pm_SectPerClust >= pmp->pm_rootdirsize) {
if (de_cn2off(pmp, findcn) >= dep->de_FileSize) {
if (cnp)
*cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
return E2BIG;
*cnp = de_bn2cn(pmp, pmp->pm_rootdirsize);
return (E2BIG);
}
if (bnp)
*bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
*bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn);
if (cnp)
*cnp = MSDOSFSROOT;
return 0;
if (sp)
*sp = min(pmp->pm_bpcluster,
dep->de_FileSize - de_cn2off(pmp, findcn));
return (0);
} else { /* just an empty file */
if (cnp)
*cnp = 0;
return E2BIG;
return (E2BIG);
}
}
/*
* All other files do I/O in cluster sized blocks
*/
if (sp)
*sp = pmp->pm_bpcluster;
/*
* Rummage around in the fat cache, maybe we can avoid tromping
* thru every fat entry for the file. And, keep track of how far
@ -208,9 +216,11 @@ pcbmap(dep, findcn, bnp, cnp)
/*
* Handle all other files or directories the normal way.
*/
prevcn = 0;
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);
@ -218,28 +228,32 @@ pcbmap(dep, findcn, bnp, cnp)
if (bp)
brelse(bp);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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)
@ -247,7 +261,7 @@ pcbmap(dep, findcn, bnp, cnp)
if (cnp)
*cnp = cn;
fc_setcache(dep, FC_LASTMAP, i, cn);
return 0;
return (0);
}
hiteof:;
@ -257,7 +271,7 @@ hiteof:;
brelse(bp);
/* update last file cluster entry in the fat cache */
fc_setcache(dep, FC_LASTFC, i - 1, prevcn);
return E2BIG;
return (E2BIG);
}
/*
@ -292,7 +306,8 @@ fc_lookup(dep, findcn, frcnp, fsrcnp)
* Purge the fat cache in denode dep of all entries relating to file
* relative cluster frcn and beyond.
*/
void fc_purge(dep, frcn)
void
fc_purge(dep, frcn)
struct denode *dep;
u_int frcn;
{
@ -307,7 +322,9 @@ void 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
@ -323,36 +340,80 @@ updatefats(pmp, bp, fatbn)
struct buf *bpn;
#ifdef MSDOSFS_DEBUG
printf("updatefats(pmp %p, bp %p, fatbn %ld)\n", pmp, bp, fatbn);
printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", 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_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_waitonfat)
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bp);
else
bdwrite(bp);
/*
* Maybe update fsinfo sector here?
*/
}
/*
@ -379,8 +440,8 @@ usemap_alloc(pmp, cn)
struct msdosfsmount *pmp;
u_long cn;
{
pmp->pm_inusemap[cn / N_INUSEBITS]
|= 1 << (cn % N_INUSEBITS);
pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
pmp->pm_freeclustercount--;
}
@ -389,6 +450,7 @@ usemap_free(pmp, cn)
struct msdosfsmount *pmp;
u_long cn;
{
pmp->pm_freeclustercount++;
pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
}
@ -402,18 +464,20 @@ 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 == 0) {
/*
* 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;
if (error) {
usemap_alloc(pmp, cluster);
return (error);
}
return error;
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
if (oldcnp)
*oldcnp = oldcn;
return (0);
}
/*
@ -448,10 +512,10 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
u_long bn, bo, bsize, byteoffset;
struct buf *bp;
/*
* printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
* function, pmp, cluster, oldcontents, newcontents);
*/
#ifdef MSDOSFS_DEBUG
printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
function, pmp, cn, oldcontents, newcontents);
#endif
#ifdef DIAGNOSTIC
/*
@ -459,7 +523,7 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
*/
if ((function & (FAT_SET | FAT_GET)) == 0) {
printf("fatentry(): function code doesn't specify get or set\n");
return EINVAL;
return (EINVAL);
}
/*
@ -468,7 +532,7 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
*/
if ((function & FAT_GET) && oldcontents == NULL) {
printf("fatentry(): get function with no place to put result\n");
return EINVAL;
return (EINVAL);
}
#endif
@ -476,28 +540,32 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
* Be sure the requested cluster is in the filesystem.
*/
if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
return EINVAL;
return (EINVAL);
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -507,15 +575,28 @@ 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;
}
if (bp)
brelse(bp);
return 0;
return (0);
}
/*
@ -538,25 +619,28 @@ fatchain(pmp, start, count, fillwith)
struct buf *bp;
#ifdef MSDOSFS_DEBUG
printf("fatchain(pmp %p, start %ld, count %ld, fillwith %ld)\n",
pmp, start, count, fillwith);
printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
pmp, start, count, fillwith);
#endif
/*
* Be sure the clusters are in the filesystem.
*/
if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
return EINVAL;
return (EINVAL);
while (count > 0) {
byteoffset = FATOFS(pmp, start);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -569,9 +653,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;
@ -579,7 +672,7 @@ fatchain(pmp, start, count, fillwith)
updatefats(pmp, bp, bn);
}
pmp->pm_fmod = 1;
return 0;
return (0);
}
/*
@ -606,11 +699,11 @@ chainlength(pmp, start, count)
map &= ~((1 << start) - 1);
if (map) {
len = ffs(map) - 1 - start;
return len > count ? count : len;
return (len > count ? count : len);
}
len = N_INUSEBITS - start;
if (len >= count)
return count;
return (count);
while (++idx <= max_idx) {
if (len >= count)
break;
@ -621,7 +714,7 @@ chainlength(pmp, start, count)
}
len += N_INUSEBITS;
}
return len > count ? count : len;
return (len > count ? count : len);
}
/*
@ -645,21 +738,23 @@ 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++);
error = fatchain(pmp, start, count, fillwith);
if (error == 0) {
if (error != 0)
return (error);
#ifdef MSDOSFS_DEBUG
printf("clusteralloc(): allocated cluster chain at %ld (%ld clusters)\n",
start, count);
printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
start, count);
#endif
if (retcluster)
*retcluster = start;
if (got)
*got = count;
while (count-- > 0)
usemap_alloc(pmp, start++);
}
return error;
if (retcluster)
*retcluster = start;
if (got)
*got = count;
return (0);
}
/*
@ -683,15 +778,16 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
u_long *got;
{
u_long idx;
u_long len, newst, foundcn, foundl, cn, l;
u_long len, newst, foundl, cn, l;
u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
u_int map;
#ifdef MSDOSFS_DEBUG
printf("clusteralloc(): find %d clusters\n",count);
printf("clusteralloc(): find %lu clusters\n",count);
#endif
if (start) {
if ((len = chainlength(pmp, start, count)) >= count)
return chainalloc(pmp, start, count, fillwith, retcluster, got);
return (chainalloc(pmp, start, count, fillwith, retcluster, got));
} else {
/*
* This is a new file, initialize start
@ -699,7 +795,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
struct timeval tv;
microtime(&tv);
start = (tv.tv_usec >> 10)|tv.tv_usec;
start = (tv.tv_usec >> 10) | tv.tv_usec;
len = 0;
}
@ -707,7 +803,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
* Start at a (pseudo) random place to maximize cluster runs
* under multiple writers.
*/
foundcn = newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
foundl = 0;
for (cn = newst; cn <= pmp->pm_maxcluster;) {
@ -717,7 +813,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
if (map != (u_int)-1) {
cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
if ((l = chainlength(pmp, cn, count)) >= count)
return chainalloc(pmp, cn, count, fillwith, retcluster, got);
return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
if (l > foundl) {
foundcn = cn;
foundl = l;
@ -734,7 +830,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
if (map != (u_int)-1) {
cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
if ((l = chainlength(pmp, cn, count)) >= count)
return chainalloc(pmp, cn, count, fillwith, retcluster, got);
return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
if (l > foundl) {
foundcn = cn;
foundl = l;
@ -746,12 +842,12 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
}
if (!foundl)
return ENOSPC;
return (ENOSPC);
if (len)
return chainalloc(pmp, start, len, fillwith, retcluster, got);
return (chainalloc(pmp, start, len, fillwith, retcluster, got));
else
return chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got);
return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got));
}
@ -768,7 +864,7 @@ freeclusterchain(pmp, cluster)
struct msdosfsmount *pmp;
u_long cluster;
{
int error = 0;
int error;
struct buf *bp = NULL;
u_long bn, bo, bsize, byteoffset;
u_long readcn, lbn = -1;
@ -780,13 +876,16 @@ freeclusterchain(pmp, cluster)
if (bp)
updatefats(pmp, bp, lbn);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -797,17 +896,24 @@ 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);
return error;
return (0);
}
/*
@ -821,7 +927,6 @@ fillinusemap(pmp)
struct buf *bp = NULL;
u_long cn, readcn;
int error;
int fat12 = FAT12(pmp);
u_long bn, bo, bsize, byteoffset;
/*
@ -846,21 +951,24 @@ fillinusemap(pmp)
brelse(bp);
fatblock(pmp, byteoffset, &bn, &bsize, NULL);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
}
readcn = getushort(&bp->b_data[bo]);
if (fat12) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
if (error) {
brelse(bp);
return (error);
}
}
if (FAT32(pmp))
readcn = getulong(&bp->b_data[bo]);
else
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) && (cn & 1))
readcn >>= 4;
readcn &= pmp->pm_fatmask;
if (readcn == 0)
usemap_free(pmp, cn);
}
brelse(bp);
return 0;
return (0);
}
/*
@ -886,7 +994,7 @@ extendfile(dep, count, bpp, ncp, flags)
u_long *ncp;
int flags;
{
int error = 0;
int error;
u_long frcn;
u_long cn, got;
struct msdosfsmount *pmp = dep->de_pmp;
@ -895,9 +1003,10 @@ 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;
return (ENOSPC);
}
/*
@ -908,21 +1017,21 @@ extendfile(dep, count, bpp, ncp, flags)
if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
dep->de_StartCluster != 0) {
fc_lfcempty++;
error = pcbmap(dep, 0xffff, 0, &cn);
error = pcbmap(dep, 0xffff, 0, &cn, 0);
/* we expect it to return E2BIG */
if (error != E2BIG)
return error;
error = 0;
return (error);
}
while (count > 0) {
/*
* Allocate a new cluster chain and cat onto the end of the file.
* If the file is empty we make de_StartCluster point to the new
* block. Note that de_StartCluster being 0 is sufficient to be
* sure the file is empty since we exclude attempts to extend the
* root directory above, and the root dir is the only file with a
* startcluster of 0 that has blocks allocated (sort of).
* Allocate a new cluster chain and cat onto the end of the
* file. * If the file is empty we make de_StartCluster point
* to the new block. Note that de_StartCluster being 0 is
* sufficient to be sure the file is empty since we exclude
* attempts to extend the root directory above, and the root
* dir is the only file with a startcluster of 0 that has
* blocks allocated (sort of).
*/
if (dep->de_StartCluster == 0)
cn = 0;
@ -930,7 +1039,7 @@ extendfile(dep, count, bpp, ncp, flags)
cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got);
if (error)
return error;
return (error);
count -= got;
@ -947,13 +1056,13 @@ extendfile(dep, count, bpp, ncp, flags)
dep->de_StartCluster = cn;
frcn = 0;
} else {
error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
error = fatentry(FAT_SET, pmp,
dep->de_fc[FC_LASTFC].fc_fsrcn,
0, cn);
if (error) {
clusterfree(pmp, cn, NULL);
return error;
return (error);
}
frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
}
@ -972,11 +1081,14 @@ extendfile(dep, count, bpp, ncp, flags)
bp = getblk(pmp->pm_devvp, cntobn(pmp, cn++),
pmp->pm_bpcluster, 0, 0);
else {
bp = getblk(DETOV(dep), frcn++, pmp->pm_bpcluster, 0, 0);
bp = getblk(DETOV(dep), de_cn2bn(pmp, frcn++),
pmp->pm_bpcluster, 0, 0);
/*
* Do the bmap now, as in msdosfs_write
*/
if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
if (pcbmap(dep,
de_bn2cn(pmp, bp->b_lblkno),
&bp->b_blkno, 0, 0))
bp->b_blkno = -1;
if (bp->b_blkno == -1)
panic("extendfile: pcbmap");
@ -985,13 +1097,11 @@ extendfile(dep, count, bpp, ncp, flags)
if (bpp) {
*bpp = bp;
bpp = NULL;
} else {
bp->b_flags |= B_AGE;
bawrite(bp);
}
} else
bdwrite(bp);
}
}
}
return 0;
return (0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/* $Id: msdosfsmount.h,v 1.11 1997/03/03 17:36:11 bde Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.7 1994/08/21 18:44:17 ws Exp $ */
/* $Id: msdosfsmount.h,v 1.12 1997/10/12 20:25:02 phk Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -63,90 +63,119 @@ MALLOC_DECLARE(M_MSDOSFSMNT);
struct msdosfsmount {
struct mount *pm_mountp;/* vfs mount struct for this fs */
dev_t pm_dev; /* block special device mounted */
uid_t pm_mounter; /* uid of the user who mounted the FS */
uid_t pm_uid; /* uid to set as owner of the files */
gid_t pm_gid; /* gid to set as owner of the files */
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 */
u_long pm_maxcluster; /* maximum cluster number */
u_long pm_freeclustercount; /* number of free clusters */
u_long pm_bnshift; /* shift file offset right this amount to get a block number */
u_long pm_brbomask; /* and a file offset with this mask to get block rel offset */
u_long pm_cnshift; /* shift file offset right this amount to get a cluster number */
u_long pm_crbomask; /* and a file offset with this mask to get cluster rel offset */
u_long pm_bnshift; /* shift file offset right this amount to get a block number */
u_long pm_bpcluster; /* bytes per cluster */
u_long pm_depclust; /* directory entries per cluster */
u_long pm_fmod; /* ~0 if fs is modified, this can rollover to 0 */
u_long pm_fatblocksize; /* size of fat blocks in bytes */
u_long pm_fatblocksec; /* size of fat blocks in sectors */
u_long pm_fatsize; /* size of fat in bytes */
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 */
char pm_ronly; /* read only if non-zero */
char pm_waitonfat; /* wait for writes of the fat to complete, when 0 use bdwrite, else use bwrite */
u_int pm_flags; /* see below */
struct netexport pm_export; /* export information */
};
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv)
#define VFSTOMSDOSFS(mp) ((struct msdosfsmount *)mp->mnt_data)
/* Number of bits in one pm_inusemap item: */
#define N_INUSEBITS (8 * sizeof(u_int))
/*
* How to compute pm_cnshift and pm_crbomask.
*
* pm_crbomask = (pm_SectPerClust * pm_BytesPerSect) - 1
* if (bytesperclust == * 0)
* return EBADBLKSZ;
* bit = 1;
* for (i = 0; i < 32; i++) {
* if (bit & bytesperclust) {
* if (bit ^ bytesperclust)
* return EBADBLKSZ;
* pm_cnshift = * i;
* break;
* }
* bit <<= 1;
* }
*/
/*
* Shorthand for fields in the bpb contained in the msdosfsmount structure.
*/
#define pm_BytesPerSec pm_bpb.bpbBytesPerSec
#define pm_SectPerClust pm_bpb.bpbSecPerClust
#define pm_ResSectors pm_bpb.bpbResSectors
#define pm_FATs pm_bpb.bpbFATs
#define pm_RootDirEnts pm_bpb.bpbRootDirEnts
#define pm_Sectors pm_bpb.bpbSectors
#define pm_Media pm_bpb.bpbMedia
#define pm_FATsecs pm_bpb.bpbFATsecs
#define pm_SecPerTrack pm_bpb.bpbSecPerTrack
#define pm_Heads pm_bpb.bpbHeads
#define pm_HiddenSects pm_bpb.bpbHiddenSecs
#define pm_HugeSectors pm_bpb.bpbHugeSectors
/*
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)(((bp)->b_data) \
+ ((dirofs) & (pmp)->pm_crbomask)))
/*
* Convert block number to cluster number
*/
#define de_bn2cn(pmp, bn) \
((bn) >> ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
* Convert cluster number to block number
*/
#define de_cn2bn(pmp, cn) \
((cn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
* Convert file offset to cluster number
*/
#define de_cluster(pmp, off) \
((off) >> (pmp)->pm_cnshift)
/*
* Clusters required to hold size bytes
*/
#define de_clcount(pmp, size) \
(((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
/*
* Convert file offset to block number
*/
#define de_blk(pmp, off) \
(de_cn2bn(pmp, de_cluster((pmp), (off))))
/*
* Convert cluster number to file offset
*/
#define de_cn2off(pmp, cn) \
((cn) << (pmp)->pm_cnshift)
/*
* Convert block number to file offset
*/
#define de_bn2off(pmp, bn) \
((bn) << (pmp)->pm_bnshift)
/*
* Map a cluster number into a filesystem relative block number.
*/
#define cntobn(pmp, cn) \
((((cn)-CLUST_FIRST) * (pmp)->pm_SectPerClust) + (pmp)->pm_firstcluster)
/*
* Map a filesystem relative block number back into a cluster number.
*/
#define bntocn(pmp, bn) \
((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
(de_cn2bn((pmp), (cn)-CLUST_FIRST) + (pmp)->pm_firstcluster)
/*
* Calculate block number for directory entry in root dir, offset dirofs
*/
#define roottobn(pmp, dirofs) \
(((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
+ (pmp)->pm_rootdirblk)
(de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk)
/*
* Calculate block number for directory entry at cluster dirclu, offset
@ -157,27 +186,8 @@ struct msdosfsmount {
? roottobn((pmp), (dirofs)) \
: cntobn((pmp), (dirclu)))
/*
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)((bp)->b_data) \
+ (dirofs) % (pmp)->pm_depclust)
/*
* Convert filesize to block number
*/
#define de_blk(pmp, off) \
((off) >> (pmp)->pm_cnshift)
/*
* Clusters required to hold size bytes
*/
#define de_clcount(pmp, size) \
(((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
int msdosfs_init __P((struct vfsconf *vfsp));
int msdosfs_mountroot __P((void));
#endif /* KERNEL */
@ -190,6 +200,27 @@ struct msdosfs_args {
uid_t uid; /* uid that owns msdosfs files */
gid_t gid; /* gid that owns msdosfs files */
mode_t mask; /* mask to be applied for msdosfs perms */
int flags; /* see below */
int magic; /* version number */
};
/*
* Msdosfs mount options:
*/
#define MSDOSFSMNT_SHORTNAME 1 /* Force old DOS short names only */
#define MSDOSFSMNT_LONGNAME 2 /* Force Win'95 long names */
#define MSDOSFSMNT_NOWIN95 4 /* Completely ignore Win95 entries */
#ifndef __FreeBSD__
#define MSDOSFSMNT_GEMDOSFS 8 /* This is a gemdos-flavour */
#endif
/* All flags above: */
#define MSDOSFSMNT_MNTOPT \
(MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \
/*|MSDOSFSMNT_GEMDOSFS*/)
#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */
#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */
#define MSDOSFS_ARGSMAGIC 0xe4eff300
#endif /* !_MSDOSFS_MSDOSFSMOUNT_H_ */

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* $NetBSD: bootsect.h,v 1.4 1994/06/29 06:35:28 cgd Exp $ */
/* $Id: bootsect.h,v 1.5 1997/02/22 09:40:43 peter Exp $ */
/* $NetBSD: bootsect.h,v 1.9 1997/11/17 15:36:17 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -23,36 +23,78 @@
* first sector of a partitioned hard disk.
*/
struct bootsector33 {
u_char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[19]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsBootCode[479]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
int8_t bsOemName[8]; /* OEM name and version */
int8_t bsBPB[19]; /* BIOS parameter block */
int8_t bsDriveNumber; /* drive number (0x80) */
int8_t bsBootCode[479]; /* pad so struct is 512b */
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_char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[25]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsReserved1; /* reserved */
char bsBootSignature; /* extended boot signature (0x29) */
#define EXBOOTSIG 0x29
char bsVolumeID[4]; /* volume ID number */
char bsVolumeLabel[11]; /* volume label */
char bsFileSysType[8]; /* file system type (FAT12 or FAT16) */
char bsBootCode[448]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
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 bsExt[26]; /* Bootsector Extension */
int8_t bsBootCode[448]; /* pad so structure is 512b */
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
/*
* The boot sector on a gemdos fs is a little bit different from the msdos fs
* format. Currently there is no need to declare a seperate structure, the
* bootsector33 struct will do.
*/
#if 0
struct bootsec_atari {
u_int8_t bsBranch[2]; /* branch inst if auto-boot */
int8_t bsFiller[6]; /* anything or nothing */
int8_t bsSerial[3]; /* serial no. for mediachange */
int8_t bsBPB[19]; /* BIOS parameter block */
int8_t bsBootCode[482]; /* pad so struct is 512b */
};
#endif
#endif /* atari */
union bootsector {
struct bootsector33 bs33;
struct bootsector50 bs50;
struct bootsector710 bs710;
};
#if 0
/*
* Shorthand for fields in the bpb.
*/
@ -68,3 +110,4 @@ union bootsector {
#define bsHeads bsBPB.bpbHeads
#define bsHiddenSecs bsBPB.bpbHiddenSecs
#define bsHugeSectors bsBPB.bpbHugeSectors
#endif

View File

@ -1,5 +1,5 @@
/* $Id$ */
/* $NetBSD: bpb.h,v 1.3 1994/06/29 06:35:29 cgd Exp $ */
/* $Id: bpb.h,v 1.5 1997/02/22 09:40:44 peter Exp $ */
/* $NetBSD: bpb.h,v 1.7 1997/11/17 15:36:24 ws Exp $ */
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
@ -21,17 +21,17 @@
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct bpb33 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_short bpbHiddenSecs; /* number of hidden sectors */
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_int16_t bpbHiddenSecs; /* number of hidden sectors */
};
/*
@ -39,20 +39,70 @@ struct bpb33 {
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct bpb50 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_long bpbHiddenSecs; /* number of hidden sectors */
u_long bpbHugeSectors; /* number of sectors if bpbSectors == 0 */
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 */
};
/*
* 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.
* Currently there is no need for a separate BPB structure.
*/
#if 0
struct bpb_a {
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 bpbUseless1; /* meaningless on gemdos fs */
u_int16_t bpbFATsecs; /* number of sectors per FAT */
u_int16_t bpbUseless2; /* meaningless for harddisk fs */
u_int16_t bpbUseless3; /* meaningless for harddisk fs */
u_int16_t bpbHiddenSecs; /* the TOS-BIOS ignores this */
};
#endif
#endif /* atari */
/*
* The following structures represent how the bpb's look on disk. shorts
* and longs are just character arrays of the appropriate length. This is
@ -64,40 +114,39 @@ struct bpb50 {
* use the macros for the big-endian case.
*/
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN /* && can do unaligned accesses */
#define getushort(x) *((u_short *)(x))
#define getulong(x) *((u_long *)(x))
#define putushort(p, v) (*((u_short *)(p)) = (v))
#define putulong(p, v) (*((u_long *)(p)) = (v))
#if (BYTE_ORDER == LITTLE_ENDIAN) /* && defined(UNALIGNED_ACCESS) */
#define getushort(x) *((u_int16_t *)(x))
#define getulong(x) *((u_int32_t *)(x))
#define putushort(p, v) (*((u_int16_t *)(p)) = (v))
#define putulong(p, v) (*((u_int32_t *)(p)) = (v))
#else
#define getushort(x) (((u_char *)(x))[0] + (((u_char *)(x))[1] << 8))
#define getulong(x) (((u_char *)(x))[0] + (((u_char *)(x))[1] << 8) \
+ (((u_char *)(x))[2] << 16) \
+ (((u_char *)(x))[3] << 24))
#define putushort(p, v) (((u_char *)(p))[0] = (v), \
((u_char *)(p))[1] = (v) >> 8)
#define putulong(p, v) (((u_char *)(p))[0] = (v), \
((u_char *)(p))[1] = (v) >> 8, \
((u_char *)(p))[2] = (v) >> 16,\
((u_char *)(p))[3] = (v) >> 24)
#define getushort(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8))
#define getulong(x) (((u_int8_t *)(x))[0] + (((u_int8_t *)(x))[1] << 8) \
+ (((u_int8_t *)(x))[2] << 16) \
+ (((u_int8_t *)(x))[3] << 24))
#define putushort(p, v) (((u_int8_t *)(p))[0] = (v), \
((u_int8_t *)(p))[1] = (v) >> 8)
#define putulong(p, v) (((u_int8_t *)(p))[0] = (v), \
((u_int8_t *)(p))[1] = (v) >> 8, \
((u_int8_t *)(p))[2] = (v) >> 16,\
((u_int8_t *)(p))[3] = (v) >> 24)
#endif
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct byte_bpb33 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[2]; /* number of hidden sectors */
int8_t bpbBytesPerSec[2]; /* bytes per sector */
int8_t bpbSecPerClust; /* sectors per cluster */
int8_t bpbResSectors[2]; /* number of reserved sectors */
int8_t bpbFATs; /* number of FATs */
int8_t bpbRootDirEnts[2]; /* number of root directory entries */
int8_t bpbSectors[2]; /* total number of sectors */
int8_t bpbMedia; /* media descriptor */
int8_t bpbFATsecs[2]; /* number of sectors per FAT */
int8_t bpbSecPerTrack[2]; /* sectors per track */
int8_t bpbHeads[2]; /* number of heads */
int8_t bpbHiddenSecs[2]; /* number of hidden sectors */
};
/*
@ -105,16 +154,56 @@ struct byte_bpb33 {
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct byte_bpb50 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[4]; /* number of hidden sectors */
char bpbHugeSectors[4]; /* number of sectors if bpbSectors == 0 */
int8_t bpbBytesPerSec[2]; /* bytes per sector */
int8_t bpbSecPerClust; /* sectors per cluster */
int8_t bpbResSectors[2]; /* number of reserved sectors */
int8_t bpbFATs; /* number of FATs */
int8_t bpbRootDirEnts[2]; /* number of root directory entries */
int8_t bpbSectors[2]; /* total number of sectors */
int8_t bpbMedia; /* media descriptor */
int8_t bpbFATsecs[2]; /* number of sectors per FAT */
int8_t bpbSecPerTrack[2]; /* sectors per track */
int8_t bpbHeads[2]; /* number of heads */
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,9 +1,9 @@
/* $Id: denode.h,v 1.13 1997/08/26 07:32:36 phk Exp $ */
/* $NetBSD: denode.h,v 1.8 1994/08/21 18:43:49 ws Exp $ */
/* $Id: denode.h,v 1.14 1997/10/17 12:36:16 phk Exp $ */
/* $NetBSD: denode.h,v 1.25 1997/11/17 15:36:28 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -103,8 +103,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 */
};
/*
@ -121,7 +121,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.
@ -143,19 +143,21 @@ struct denode {
u_long de_flag; /* flag bits */
dev_t de_dev; /* device where direntry lives */
u_long de_dirclust; /* cluster of the directory file containing this entry */
u_long de_diroffset; /* ordinal of this entry in the directory */
u_long de_fndclust; /* cluster of found dir entry */
u_long de_diroffset; /* offset of this entry in the directory cluster */
u_long de_fndoffset; /* offset of found dir entry */
int de_fndcnt; /* number of slots before de_fndoffset */
long de_refcnt; /* reference count */
struct msdosfsmount *de_pmp; /* addr of our mount struct */
struct lockf *de_lockf; /* byte level lock list */
/* the next two fields must be contiguous in memory... */
u_char de_Name[8]; /* name, from directory entry */
u_char de_Extension[3]; /* extension, from directory entry */
u_char de_Name[12]; /* name, from DOS directory entry */
u_char de_Attributes; /* attributes, from directory entry */
u_short de_Time; /* creation time */
u_short de_Date; /* creation date */
u_short de_StartCluster; /* starting cluster of file */
u_char de_CHun; /* Hundredth of second of CTime*/
u_short de_CTime; /* creation time */
u_short de_CDate; /* creation date */
u_short de_ADate; /* access date */
u_short de_MTime; /* modification time */
u_short de_MDate; /* modification date */
u_long de_StartCluster; /* starting cluster of file */
u_long de_FileSize; /* size of file in bytes */
struct fatcache de_fc[FC_SIZE]; /* fat cache */
u_quad_t de_modrev; /* Revision level for lease. */
@ -164,31 +166,49 @@ struct denode {
/*
* Values for the de_flag field of the denode.
*/
#define DE_UPDATE 0x0004 /* modification time update request */
#define DE_MODIFIED 0x0080 /* denode has been modified, but DE_UPDATE
* isn't set */
#define DE_UPDATE 0x0004 /* Modification time update request */
#define DE_CREATE 0x0008 /* Creation time update */
#define DE_ACCESS 0x0010 /* Access time update */
#define DE_MODIFIED 0x0020 /* Denode has been modified */
#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */
/*
* Transfer directory entries between internal and external form.
* 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_Time = getushort((dp)->deTime), \
(dep)->de_Date = getushort((dp)->deDate), \
(dep)->de_CHun = (dp)->deCHundredth, \
(dep)->de_CTime = getushort((dp)->deCTime), \
(dep)->de_CDate = getushort((dp)->deCDate), \
(dep)->de_ADate = getushort((dp)->deADate), \
(dep)->de_MTime = getushort((dp)->deMTime), \
(dep)->de_MDate = getushort((dp)->deMDate), \
(dep)->de_StartCluster = getushort((dp)->deStartCluster), \
(dep)->de_FileSize = getulong((dp)->deFileSize))
(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), \
bzero((dp)->deReserved, 10), \
(dp)->deAttributes = (dep)->de_Attributes, \
putushort((dp)->deTime, (dep)->de_Time), \
putushort((dp)->deDate, (dep)->de_Date), \
(dp)->deCHundredth = (dep)->de_CHun, \
putushort((dp)->deCTime, (dep)->de_CTime), \
putushort((dp)->deCDate, (dep)->de_CDate), \
putushort((dp)->deADate, (dep)->de_ADate), \
putushort((dp)->deMTime, (dep)->de_MTime), \
putushort((dp)->deMDate, (dep)->de_MDate), \
putushort((dp)->deStartCluster, (dep)->de_StartCluster), \
putulong((dp)->deFileSize, (dep)->de_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]
@ -198,17 +218,20 @@ struct denode {
#define VTODE(vp) ((struct denode *)(vp)->v_data)
#define DETOV(de) ((de)->de_vnode)
#define DE_TIMES(dep, t) \
if ((dep)->de_flag & DE_UPDATE) { \
if (!((dep)->de_Attributes & ATTR_DIRECTORY)) { \
struct timespec DE_TIMES_ts; \
(dep)->de_flag |= DE_MODIFIED; \
TIMEVAL_TO_TIMESPEC((t), &DE_TIMES_ts); \
unix2dostime(&DE_TIMES_ts, &(dep)->de_Date, \
&(dep)->de_Time); \
#define DETIMES(dep, acc, mod, cre) \
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, NULL); \
(dep)->de_Attributes |= ATTR_ARCHIVE; \
} \
(dep)->de_flag &= ~DE_UPDATE; \
if (!((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)) { \
if ((dep)->de_flag & DE_ACCESS) \
unix2dostime((acc), &(dep)->de_ADate, NULL, NULL); \
if ((dep)->de_flag & DE_CREATE) \
unix2dostime((cre), &(dep)->de_CDate, &(dep)->de_CTime, &(dep)->de_CHun); \
} \
(dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \
}
/*
@ -219,9 +242,10 @@ struct defid {
u_short defid_pad; /* force long alignment */
u_long defid_dirclust; /* cluster this dir entry came from */
u_long defid_dirofs; /* index of entry within the cluster */
/* u_long defid_gen; generation number */
u_long defid_dirofs; /* offset of entry within the cluster */
#if 0
u_long defid_gen; /* generation number */
#endif
};
extern vop_t **msdosfs_vnodeop_p;
@ -233,5 +257,19 @@ int msdosfs_reclaim __P((struct vop_reclaim_args *));
/*
* Internal service routine prototypes.
*/
int deget __P((struct msdosfsmount * pmp, u_long dirclust, u_long diroffset, struct direntry * direntptr, struct denode ** depp));
int deget __P((struct msdosfsmount *, u_long, u_long, struct denode **));
int uniqdosname __P((struct denode *, struct componentname *, u_char *));
int findwin95 __P((struct denode *));
int readep __P((struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp));
int readde __P((struct denode *dep, struct buf **bpp, struct direntry **epp));
int deextend __P((struct denode *dep, u_long length, struct ucred *cred));
int fillinusemap __P((struct msdosfsmount *pmp));
void reinsert __P((struct denode *dep));
int dosdirempty __P((struct denode *dep));
int createde __P((struct denode *dep, struct denode *ddep, struct denode **depp, struct componentname *cnp));
int deupdat __P((struct denode *dep, int waitfor));
int removede __P((struct denode *pdep, struct denode *dep));
int detrunc __P((struct denode *dep, u_long length, int flags, struct ucred *cred, struct proc *p));
int doscheckpath __P(( struct denode *source, struct denode *target));
#endif /* KERNEL */

View File

@ -1,9 +1,9 @@
/* $Id$ */
/* $NetBSD: direntry.h,v 1.7 1994/08/21 18:43:54 ws Exp $ */
/* $Id: direntry.h,v 1.4 1997/02/22 09:40:45 peter Exp $ */
/* $NetBSD: direntry.h,v 1.14 1997/11/17 15:36:32 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -52,26 +52,55 @@
* Structure of a dos directory entry.
*/
struct direntry {
u_char deName[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
u_char deExtension[3]; /* extension, blank filled */
u_char deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
u_char deReserved[10]; /* reserved */
u_char deTime[2]; /* create/last update time */
u_char deDate[2]; /* create/last update date */
u_char deStartCluster[2]; /* starting cluster of file */
u_char deFileSize[4]; /* size of file in bytes */
u_int8_t deName[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
u_int8_t deExtension[3]; /* extension, blank filled */
u_int8_t deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
u_int8_t deReserved[1]; /* 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 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 */
u_int8_t deFileSize[4]; /* size of file in bytes */
};
/*
* Structure of a Win95 long name directory entry
*/
struct winentry {
u_int8_t weCnt;
#define WIN_LAST 0x40
#define WIN_CNT 0x3f
u_int8_t wePart1[10];
u_int8_t weAttributes;
#define ATTR_WIN95 0x0f
u_int8_t weReserved1;
u_int8_t weChksum;
u_int8_t wePart2[12];
u_int16_t weReserved2;
u_int8_t wePart3[4];
};
#define WIN_CHARS 13 /* Number of chars per winentry */
/*
* Maximum filename length in Win95
* Note: Must be < sizeof(dirent.d_name)
*/
#define WIN_MAXLEN 255
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
@ -97,8 +126,15 @@ struct direntry {
#define DD_YEAR_SHIFT 9
#ifdef KERNEL
void unix2dostime __P((struct timespec * tsp, u_short * ddp, u_short * dtp));
void dos2unixtime __P((u_short dd, u_short dt, struct timespec * tsp));
int dos2unixfn __P((u_char dn[11], u_char * un));
void unix2dosfn __P((u_char * un, u_char dn[11], int unlen));
struct dirent;
void unix2dostime __P((struct timespec *tsp, u_int16_t *ddp,
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));
int unix2winfn __P((const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum));
int winChkName __P((const u_char *un, int unlen, struct winentry *wep, int chksum));
int win2unixfn __P((struct winentry *wep, struct dirent *dp, int chksum));
u_int8_t winChksum __P((u_int8_t *name));
int winSlotCnt __P((const u_char *un, int unlen));
#endif /* KERNEL */

View File

@ -1,9 +1,9 @@
/* $Id$ */
/* $NetBSD: fat.h,v 1.4 1994/08/21 18:43:57 ws Exp $ */
/* $Id: fat.h,v 1.6 1997/02/22 09:40:45 peter Exp $ */
/* $NetBSD: fat.h,v 1.12 1997/11/17 15:36:36 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).
*
@ -51,28 +51,37 @@
/*
* 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:
* Return true if filesystem uses 12 bit fats. Microsoft Programmer's
* Reference says if the maximum cluster number in a filesystem is greater
* than 4086 then we've got a 16 bit fat filesystem.
* than 4078 ((CLUST_RSRVS - CLUST_FIRST) & FAT12_MASK) then we've got a
* 16 bit fat filesystem. While mounting, the result of this test is stored
* in pm_fatentrysize.
* GEMDOS-flavour (atari):
* If the filesystem is on floppy we've got a 12 bit fat filesystem, otherwise
* 16 bit. We check the d_type field in the disklabel struct while mounting
* 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_maxcluster <= 4086)
#define FAT16(pmp) (pmp->pm_maxcluster > 4086)
#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
/*
@ -88,7 +97,7 @@
*/
#define DE_CLEAR 1 /* Zero out the blocks allocated */
int pcbmap __P((struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp));
int pcbmap __P((struct denode *dep, u_long findcn, daddr_t *bnp, u_long *cnp, int* sp));
int clusterfree __P((struct msdosfsmount *pmp, u_long cn, u_long *oldcnp));
int clusteralloc __P((struct msdosfsmount *pmp, u_long start, u_long count, u_long fillwith, u_long *retcluster, u_long *got));
int fatentry __P((int function, struct msdosfsmount *pmp, u_long cluster, u_long *oldcontents, u_long newcontents));
@ -96,15 +105,4 @@ int freeclusterchain __P((struct msdosfsmount *pmp, u_long startchain));
int extendfile __P((struct denode *dep, u_long count, struct buf **bpp, u_long *ncp, int flags));
void fc_purge __P((struct denode *dep, u_int frcn));
int readep __P((struct msdosfsmount *pmp, u_long dirclu, u_long dirofs, struct buf **bpp, struct direntry **epp));
int readde __P((struct denode *dep, struct buf **bpp, struct direntry **epp));
int deextend __P((struct denode *dep, off_t length, struct ucred *cred));
int fillinusemap __P((struct msdosfsmount *pmp));
int reinsert __P((struct denode *dep));
int dosdirempty __P((struct denode *dep));
int createde __P((struct denode *dep, struct denode *ddep, struct denode **depp));
int deupdat __P((struct denode *dep, struct timespec *tp, int waitfor));
int removede __P((struct denode *pdep, struct denode *dep));
int detrunc __P((struct denode *dep, u_long length, int flags, struct ucred *cred, struct proc *p));
int doscheckpath __P(( struct denode *source, struct denode *target));
#endif /* KERNEL */

View File

@ -1,6 +1,37 @@
/* $Id: msdosfs_conv.c,v 1.13 1997/02/22 09:40:46 peter Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.6.2.1 1994/08/30 02:27:57 cgd Exp $ */
/* $Id: msdosfs_conv.c,v 1.14 1998/02/09 06:09:50 eivind Exp $ */
/* $NetBSD: msdosfs_conv.c,v 1.25 1997/11/17 15:36:40 ws Exp $ */
/*-
* 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).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by TooLs GmbH.
* 4. The name of TooLs GmbH may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
@ -23,8 +54,9 @@
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h> /* defines tz */
#include <sys/systm.h> /* defines tz */
#include <sys/systm.h>
#include <machine/clock.h>
#include <sys/dirent.h>
/*
* MSDOSFS include files.
@ -61,10 +93,11 @@ static 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_short *ddp;
u_short *dtp;
u_int16_t *ddp;
u_int16_t *dtp;
u_int8_t *dhp;
{
u_long t;
u_long days;
@ -80,9 +113,10 @@ unix2dostime(tsp, ddp, dtp)
t = tsp->tv_sec - (tz.tz_minuteswest * 60)
- (wall_cmos_clock ? adjkerntz : 0);
/* - daylight savings time correction */
t &= ~1;
if (lasttime != t) {
lasttime = t;
lastdtime = (((t % 60) >> 1) << DT_2SECONDS_SHIFT)
lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT)
+ (((t / 60) % 60) << DT_MINUTES_SHIFT)
+ (((t / 3600) % 24) << DT_HOURS_SHIFT);
@ -117,7 +151,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;
}
@ -136,9 +174,10 @@ static u_long lastseconds;
* not be too efficient.
*/
void
dos2unixtime(dd, dt, tsp)
u_short dd;
u_short dt;
dos2unixtime(dd, dt, dh, tsp)
u_int dd;
u_int dt;
u_int dh;
struct timespec *tsp;
{
u_long seconds;
@ -147,9 +186,18 @@ dos2unixtime(dd, dt, tsp)
u_long days;
u_short *months;
if (dd == 0) {
/*
* Uninitialized field, return the epoch.
*/
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
return;
}
seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1)
+ ((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.
@ -165,8 +213,7 @@ dos2unixtime(dd, dt, tsp)
months = year & 0x03 ? regyear : leapyear;
month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT;
if (month < 1 || month > 12) {
printf(
"dos2unixtime(): month value out of range (%ld)\n",
printf("dos2unixtime(): month value out of range (%ld)\n",
month);
month = 1;
}
@ -178,17 +225,116 @@ dos2unixtime(dd, dt, tsp)
tsp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
+ adjkerntz;
/* + daylight savings time correction */
tsp->tv_nsec = 0;
tsp->tv_nsec = (dh % 100) * 10000000;
}
/*
* Cheezy macros to do case detection and conversion for the ascii
* character set. DOESN'T work for ebcdic.
*/
#define isupper(c) (c >= 'A' && c <= 'Z')
#define islower(c) (c >= 'a' && c <= 'z')
#define toupper(c) (c & ~' ')
#define tolower(c) (c | ' ')
static u_char
unix2dos[256] = {
0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */
0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */
0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */
0, 0, 0, 0, 0, 0, 0, 0, /* 18-1f */
0, 0x21, 0, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0, 0, 0, 0x2d, 0, 0, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0, 0, 0, 0, 0, 0, /* 38-3f */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
0x58, 0x59, 0x5a, 0, 0, 0, 0x5e, 0x5f, /* 58-5f */
0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 60-67 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 68-6f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 70-77 */
0x58, 0x59, 0x5a, 0x7b, 0, 0x7d, 0x7e, 0, /* 78-7f */
0, 0, 0, 0, 0, 0, 0, 0, /* 80-87 */
0, 0, 0, 0, 0, 0, 0, 0, /* 88-8f */
0, 0, 0, 0, 0, 0, 0, 0, /* 90-97 */
0, 0, 0, 0, 0, 0, 0, 0, /* 98-9f */
0, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
};
static u_char
dos2unix[256] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 00-07 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 08-0f */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 10-17 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 18-1f */
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
0xc7, 0xfc, 0xe9, 0xe2, 0xe4, 0xe0, 0xe5, 0xe7, /* 80-87 */
0xea, 0xeb, 0xe8, 0xef, 0xee, 0xec, 0xc4, 0xc5, /* 88-8f */
0xc9, 0xe6, 0xc6, 0xf4, 0xf6, 0xf2, 0xfb, 0xf9, /* 90-97 */
0xff, 0xd6, 0xdc, 0xf8, 0xa3, 0xd8, 0xd7, 0x3f, /* 98-9f */
0xe1, 0xed, 0xf3, 0xfa, 0xf1, 0xd1, 0xaa, 0xba, /* a0-a7 */
0xbf, 0xae, 0xac, 0xbd, 0xbc, 0xa1, 0xab, 0xbb, /* a8-af */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xc1, 0xc2, 0xc0, /* b0-b7 */
0xa9, 0x3f, 0x3f, 0x3f, 0x3f, 0xa2, 0xa5, 0x3f, /* b8-bf */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xe3, 0xc3, /* c0-c7 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0xa4, /* c8-cf */
0xf0, 0xd0, 0xca, 0xcb, 0xc8, 0x3f, 0xcd, 0xce, /* d0-d7 */
0xcf, 0x3f, 0x3f, 0x3f, 0x3f, 0xa6, 0xcc, 0x3f, /* d8-df */
0xd3, 0xdf, 0xd4, 0xd2, 0xf5, 0xd5, 0xb5, 0xfe, /* e0-e7 */
0xde, 0xda, 0xdb, 0xd9, 0xfd, 0xdd, 0xaf, 0x3f, /* e8-ef */
0xad, 0xb1, 0x3f, 0xbe, 0xb6, 0xa7, 0xf7, 0xb8, /* f0-f7 */
0xb0, 0xa8, 0xb7, 0xb9, 0xb3, 0xb2, 0x3f, 0x3f, /* f8-ff */
};
static u_char
u2l[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */
};
/*
* DOS filenames are made of 2 parts, the name part and the extension part.
@ -203,58 +349,14 @@ dos2unixtime(dd, dt, tsp)
* null.
*/
int
dos2unixfn(dn, un)
dos2unixfn(dn, un, lower)
u_char dn[11];
u_char *un;
int lower;
{
int i;
int ni;
int ei;
int thislong = 0;
int thislong = 1;
u_char c;
u_char *origun = un;
/*
* Find the last character in the name portion of the dos filename.
*/
for (ni = 7; ni >= 0; ni--)
if (dn[ni] != ' ')
break;
/*
* Find the last character in the extension portion of the
* filename.
*/
for (ei = 10; ei >= 8; ei--)
if (dn[ei] != ' ')
break;
/*
* Copy the name portion into the unix filename string. NOTE: DOS
* filenames are usually kept in upper case. To make it more unixy
* we convert all DOS filenames to lower case. Some may like this,
* some may not.
*/
for (i = 0; i <= ni; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
/*
* Now, if there is an extension then put in a period and copy in
* the extension.
*/
if (ei >= 8) {
*un++ = '.';
thislong++;
for (i = 8; i <= ei; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
}
*un++ = 0;
/*
* If first char of the filename is SLOT_E5 (0x05), then the real
@ -262,31 +364,71 @@ dos2unixfn(dn, un)
* just have a 0xe5 mean 0xe5 because that is used to mean a freed
* directory slot. Another dos quirk.
*/
if (*origun == SLOT_E5)
*origun = 0xe5;
if (*dn == SLOT_E5)
c = dos2unix[0xe5];
else
c = dos2unix[*dn];
*un++ = lower ? u2l[c] : c;
dn++;
return thislong;
/*
* Copy the name portion into the unix filename string.
*/
for (i = 1; i < 8 && *dn != ' '; i++) {
c = dos2unix[*dn++];
*un++ = lower ? u2l[c] : c;
thislong++;
}
dn += 8 - i;
/*
* Now, if there is an extension then put in a period and copy in
* the extension.
*/
if (*dn != ' ') {
*un++ = '.';
thislong++;
for (i = 0; i < 3 && *dn != ' '; i++) {
c = dos2unix[*dn++];
*un++ = lower ? u2l[c] : c;
thislong++;
}
}
*un++ = 0;
return (thislong);
}
/*
* Convert a unix filename to a DOS filename. This function does not ensure
* that valid characters for a dos filename are supplied.
* Convert a unix filename to a DOS filename according to Win95 rules.
* If applicable and gen is not 0, it is inserted into the converted
* filename as a generation number.
* Returns
* 0 if name couldn't be converted
* 1 if the converted name is the same as the original
* (no long filename entry necessary for Win95)
* 2 if conversion was successful
* 3 if conversion was successful and generation number was inserted
*/
void
unix2dosfn(un, dn, unlen)
u_char *un;
u_char dn[11];
int
unix2dosfn(un, dn, unlen, gen)
const u_char *un;
u_char dn[12];
int unlen;
u_int gen;
{
int i;
u_char c;
int i, j, l;
int conv = 1;
const u_char *cp, *dp, *dp1;
u_char gentext[6], *wcp;
/*
* Fill the dos filename string with blanks. These are DOS's pad
* characters.
*/
for (i = 0; i <= 10; i++)
for (i = 0; i < 11; i++)
dn[i] = ' ';
dn[11] = 0;
/*
* The filenames "." and ".." are handled specially, since they
@ -294,65 +436,393 @@ unix2dosfn(un, dn, unlen)
*/
if (un[0] == '.' && unlen == 1) {
dn[0] = '.';
return;
return gen <= 1;
}
if (un[0] == '.' && un[1] == '.' && unlen == 2) {
dn[0] = '.';
dn[1] = '.';
return;
return gen <= 1;
}
/*
* Copy the unix filename into the dos filename string upto the end
* of string, a '.', or 8 characters. Whichever happens first stops
* us. This forms the name portion of the dos filename. Fold to
* upper case.
* Filenames with only blanks and dots are not allowed!
*/
for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
for (cp = un, i = unlen; --i >= 0; cp++)
if (*cp != ' ' && *cp != '.')
break;
if (i < 0)
return 0;
/*
* Now find the extension
* Note: dot as first char doesn't start extension
* and trailing dots and blanks are ignored
*/
dp = dp1 = 0;
for (cp = un + 1, i = unlen - 1; --i >= 0;) {
switch (*cp++) {
case '.':
if (!dp1)
dp1 = cp;
break;
case ' ':
break;
default:
if (dp1)
dp = dp1;
dp1 = 0;
break;
}
}
/*
* If the first char of the filename is 0xe5, then translate it to
* 0x05. This is because 0xe5 is the marker for a deleted
* directory slot. I guess this means you can't have filenames
* that start with 0x05. I suppose we should check for this and
* doing something about it.
* Now convert it
*/
if (dn[0] == SLOT_DELETED)
if (dp) {
if (dp1)
l = dp1 - dp;
else
l = unlen - (dp - un);
for (i = 0, j = 8; i < l && j < 11; i++, j++) {
if (dp[i] != (dn[j] = unix2dos[dp[i]])
&& conv != 3)
conv = 2;
if (!dn[j]) {
conv = 3;
dn[j--] = ' ';
}
}
if (i < l)
conv = 3;
dp--;
} else {
for (dp = cp; *--dp == ' ' || *dp == '.';);
dp++;
}
/*
* Now convert the rest of the name
*/
for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
if (*un != (dn[j] = unix2dos[*un])
&& conv != 3)
conv = 2;
if (!dn[j]) {
conv = 3;
dn[j--] = ' ';
}
}
if (un < dp)
conv = 3;
/*
* If we didn't have any chars in filename,
* generate a default
*/
if (!j)
dn[0] = '_';
/*
* The first character cannot be E5,
* because that means a deleted entry
*/
if (dn[0] == 0xe5)
dn[0] = SLOT_E5;
/*
* Strip any further characters up to a '.' or the end of the
* string.
* If there wasn't any char dropped,
* there is no place for generation numbers
*/
while (unlen && (c = *un)) {
un++;
unlen--;
/* Make sure we've skipped over the dot before stopping. */
if (c == '.')
break;
if (conv != 3) {
if (gen > 1)
return 0;
return conv;
}
/*
* Copy in the extension part of the name, if any. Force to upper
* case. Note that the extension is allowed to contain '.'s.
* Filenames in this form are probably inaccessable under dos.
* Now insert the generation number into the filename part
*/
for (i = 8; i <= 10 && unlen && (c = *un); i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
}
for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
*--wcp = gen % 10 + '0';
if (gen)
return 0;
for (i = 8; dn[--i] == ' ';);
i++;
if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
i = 8 - (gentext + sizeof(gentext) - wcp + 1);
dn[i++] = '~';
while (wcp < gentext + sizeof(gentext))
dn[i++] = *wcp++;
return 3;
}
/*
* Get rid of these macros before someone discovers we are using such
* hideous things.
* Create a Win95 long name directory entry
* Note: assumes that the filename is valid,
* i.e. doesn't consist solely of blanks and dots
*/
#undef isupper
#undef islower
#undef toupper
#undef tolower
int
unix2winfn(un, unlen, wep, cnt, chksum)
const u_char *un;
int unlen;
struct winentry *wep;
int cnt;
int chksum;
{
const u_int8_t *cp;
u_int8_t *wcp;
int i;
/*
* Drop trailing blanks and dots
*/
for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
un += (cnt - 1) * WIN_CHARS;
unlen -= (cnt - 1) * WIN_CHARS;
/*
* Initialize winentry to some useful default
*/
for (wcp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *wcp++ = 0xff);
wep->weCnt = cnt;
wep->weAttributes = ATTR_WIN95;
wep->weReserved1 = 0;
wep->weChksum = chksum;
wep->weReserved2 = 0;
/*
* Now convert the filename parts
*/
for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
if (--unlen < 0)
goto done;
*wcp++ = *un++;
*wcp++ = 0;
}
if (!unlen)
wep->weCnt |= WIN_LAST;
return unlen;
done:
*wcp++ = 0;
*wcp++ = 0;
wep->weCnt |= WIN_LAST;
return 0;
}
/*
* Compare our filename to the one in the Win95 entry
* Returns the checksum or -1 if no match
*/
int
winChkName(un, unlen, wep, chksum)
const u_char *un;
int unlen;
struct winentry *wep;
int chksum;
{
u_int8_t *cp;
int i;
/*
* First compare checksums
*/
if (wep->weCnt&WIN_LAST)
chksum = wep->weChksum;
else if (chksum != wep->weChksum)
chksum = -1;
if (chksum == -1)
return -1;
/*
* Offset of this entry
*/
i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
un += i;
if ((unlen -= i) <= 0)
return -1;
if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS)
return -1;
/*
* Compare the name parts
*/
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
if (--unlen < 0) {
if (!*cp++ && !*cp)
return chksum;
return -1;
}
if (u2l[*cp++] != u2l[*un++] || *cp++)
return -1;
}
return chksum;
}
/*
* Convert Win95 filename to dirbuf.
* Returns the checksum or -1 if impossible
*/
int
win2unixfn(wep, dp, chksum)
struct winentry *wep;
struct dirent *dp;
int chksum;
{
u_int8_t *cp;
u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
int i;
if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
|| !(wep->weCnt&WIN_CNT))
return -1;
/*
* First compare checksums
*/
if (wep->weCnt&WIN_LAST) {
chksum = wep->weChksum;
/*
* This works even though d_namlen is one byte!
*/
dp->d_namlen = (wep->weCnt&WIN_CNT) * WIN_CHARS;
} else if (chksum != wep->weChksum)
chksum = -1;
if (chksum == -1)
return -1;
/*
* Offset of this entry
*/
i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
np = (u_int8_t *)dp->d_name + i;
/*
* Convert the name parts
*/
for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= sizeof(wep->wePart2)/2
+ sizeof(wep->wePart3)/2 + i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* The size comparison should result in the compiler
* optimizing the whole if away
*/
if (WIN_MAXLEN % WIN_CHARS < sizeof(wep->wePart1) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* The size comparisons should be optimized away
*/
if (WIN_MAXLEN % WIN_CHARS >= sizeof(wep->wePart1) / 2
&& WIN_MAXLEN % WIN_CHARS < (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
switch (*np++ = *cp++) {
case 0:
dp->d_namlen -= i + 1;
return chksum;
case '/':
np[-1] = 0;
return -1;
}
/*
* See above
*/
if (WIN_MAXLEN % WIN_CHARS >= (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
&& np > ep) {
np[-1] = 0;
return -1;
}
if (*cp++)
return -1;
}
return chksum;
}
/*
* Compute the checksum of a DOS filename for Win95 use
*/
u_int8_t
winChksum(name)
u_int8_t *name;
{
int i;
u_int8_t s;
for (s = 0, i = 11; --i >= 0; s += *name++)
s = (s << 7)|(s >> 1);
return s;
}
/*
* Determine the number of slots necessary for Win95 names
*/
int
winSlotCnt(un, unlen)
const u_char *un;
int unlen;
{
for (un += unlen; unlen > 0; unlen--)
if (*--un != ' ' && *un != '.')
break;
if (unlen > WIN_MAXLEN)
return 0;
return howmany(unlen, WIN_CHARS);
}

View File

@ -1,9 +1,9 @@
/* $Id: msdosfs_denode.c,v 1.30 1998/02/06 12:13:46 eivind Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.9 1994/08/21 18:44:00 ws Exp $ */
/* $Id: msdosfs_denode.c,v 1.31 1998/02/09 06:09:51 eivind Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.28 1998/02/10 14:10:00 mrg Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -69,8 +69,9 @@
static MALLOC_DEFINE(M_MSDOSFSNODE, "MSDOSFS node", "MSDOSFS vnode private part");
static struct denode **dehashtbl;
static u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, deno) (dehashtbl[((dev) + (deno)) & dehash])
static u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, dcl, doff) (dehashtbl[((dev) + (dcl) + (doff) / \
sizeof(struct direntry)) & dehash])
static struct simplelock dehash_slock;
union _qcvt {
@ -96,12 +97,14 @@ static struct denode *
static void msdosfs_hashins __P((struct denode *dep));
static void msdosfs_hashrem __P((struct denode *dep));
int msdosfs_init(vfsp)
/*ARGSUSED*/
int
msdosfs_init(vfsp)
struct vfsconf *vfsp;
{
dehashtbl = hashinit(desiredvnodes/2, M_MSDOSFSMNT, &dehash);
simple_lock_init(&dehash_slock);
return 0;
return (0);
}
static struct denode *
@ -116,7 +119,7 @@ msdosfs_hashget(dev, dirclust, diroff)
loop:
simple_lock(&dehash_slock);
for (dep = DEHASH(dev, dirclust + diroff); dep; dep = dep->de_next) {
for (dep = DEHASH(dev, dirclust, diroff); dep; dep = dep->de_next) {
if (dirclust == dep->de_dirclust
&& diroff == dep->de_diroffset
&& dev == dep->de_dev
@ -140,7 +143,7 @@ msdosfs_hashins(dep)
struct denode **depp, *deq;
simple_lock(&dehash_slock);
depp = &DEHASH(dep->de_dev, dep->de_dirclust + dep->de_diroffset);
depp = &DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset);
deq = *depp;
if (deq)
deq->de_prev = &dep->de_next;
@ -178,48 +181,41 @@ msdosfs_hashrem(dep)
* diroffset is relative to the beginning of the root directory,
* otherwise it is cluster relative.
* diroffset - offset past begin of cluster of denode we want
* direntptr - address of the direntry structure of interest. If direntptr is
* NULL, the block is read if necessary.
* depp - returns the address of the gotten denode.
*/
int
deget(pmp, dirclust, diroffset, direntptr, depp)
deget(pmp, dirclust, diroffset, depp)
struct msdosfsmount *pmp; /* so we know the maj/min number */
u_long dirclust; /* cluster this dir entry came from */
u_long diroffset; /* index of entry within the cluster */
struct direntry *direntptr;
struct denode **depp; /* returns the addr of the gotten denode */
{
int error;
dev_t dev = pmp->pm_dev;
struct mount *mntp = pmp->pm_mountp;
struct direntry *direntptr;
struct denode *ldep;
struct vnode *nvp;
struct buf *bp;
struct proc *p = curproc; /* XXX */
#ifdef MSDOSFS_DEBUG
printf("deget(pmp %p, dirclust %ld, diroffset %x, direntptr %p, depp %p)\n",
pmp, dirclust, diroffset, direntptr, depp);
printf("deget(pmp %p, dirclust %lu, diroffset %lx, depp %p)\n",
pmp, dirclust, diroffset, depp);
#endif
/*
* If dir entry is given and refers to a directory, convert to
* canonical form
* On FAT32 filesystems, root is a (more or less) normal
* directory
*/
if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) {
dirclust = getushort(direntptr->deStartCluster);
if (dirclust == MSDOSFSROOT)
diroffset = MSDOSFSROOT_OFS;
else
diroffset = 0;
}
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.
@ -230,7 +226,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
ldep = msdosfs_hashget(dev, dirclust, diroffset);
if (ldep) {
*depp = ldep;
return 0;
return (0);
}
/*
@ -277,10 +273,15 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
*/
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
@ -288,39 +289,42 @@ deget(pmp, dirclust, diroffset, direntptr, 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_Time = 0x0000; /* 00:00:00 */
ldep->de_Date = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
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_ADate = ldep->de_CDate;
ldep->de_MTime = ldep->de_CTime;
ldep->de_MDate = ldep->de_CDate;
/* leave the other fields as garbage */
} else {
bp = NULL;
if (!direntptr) {
error = readep(pmp, dirclust, diroffset, &bp,
&direntptr);
if (error)
return error;
}
error = readep(pmp, dirclust, diroffset, &bp, &direntptr);
if (error)
return (error);
DE_INTERNALIZE(ldep, direntptr);
if (bp)
brelse(bp);
brelse(bp);
}
/*
* 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
@ -331,12 +335,10 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
u_long size;
nvp->v_type = VDIR;
if (ldep->de_StartCluster == MSDOSFSROOT)
nvp->v_flag |= VROOT;
else {
error = pcbmap(ldep, 0xffff, 0, &size);
if (ldep->de_StartCluster != MSDOSFSROOT) {
error = pcbmap(ldep, 0xffff, 0, &size, 0);
if (error == E2BIG) {
ldep->de_FileSize = size << pmp->pm_cnshift;
ldep->de_FileSize = de_cn2off(pmp, size);
error = 0;
} else
printf("deget(): pcbmap returned %d\n", error);
@ -347,78 +349,40 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
SETLOW(ldep->de_modrev, mono_time.tv_usec * 4294);
VREF(ldep->de_devvp);
*depp = ldep;
return 0;
return (0);
}
int
deupdat(dep, tp, waitfor)
deupdat(dep, waitfor)
struct denode *dep;
struct timespec *tp;
int waitfor;
{
int error;
struct buf *bp;
struct direntry *dirp;
struct vnode *vp = DETOV(dep);
struct timespec ts;
#ifdef MSDOSFS_DEBUG
printf("deupdat(): dep %p\n", dep);
#endif
/*
* If the denode-modified and update-mtime bits are off,
* or this denode is from a readonly filesystem,
* or this denode is for a directory,
* or the denode represents an open but unlinked file,
* then don't do anything. DOS directory
* entries that describe a directory do not ever get
* updated. This is the way DOS treats them.
*/
if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 ||
vp->v_mount->mnt_flag & MNT_RDONLY ||
dep->de_Attributes & ATTR_DIRECTORY ||
dep->de_refcnt <= 0)
return 0;
/*
* Read in the cluster containing the directory entry we want to
* update.
*/
if (DETOV(dep)->v_mount->mnt_flag & MNT_RDONLY)
return (0);
TIMEVAL_TO_TIMESPEC(&time, &ts);
DETIMES(dep, &ts, &ts, &ts);
if ((dep->de_flag & DE_MODIFIED) == 0)
return (0);
dep->de_flag &= ~DE_MODIFIED;
if (dep->de_Attributes & ATTR_DIRECTORY)
return (0);
if (dep->de_refcnt <= 0)
return (0);
error = readde(dep, &bp, &dirp);
if (error)
return error;
/*
* If the mtime is to be updated, put the passed in time into the
* directory entry.
*/
if (dep->de_flag & DE_UPDATE) {
dep->de_Attributes |= ATTR_ARCHIVE;
unix2dostime(tp, &dep->de_Date, &dep->de_Time);
}
/*
* The mtime is now up to date. The denode will be unmodifed soon.
*/
dep->de_flag &= ~(DE_MODIFIED | DE_UPDATE);
/*
* Copy the directory entry out of the denode into the cluster it
* came from.
*/
return (error);
DE_EXTERNALIZE(dirp, dep);
/*
* Write the cluster back to disk. If they asked for us to wait
* for the write to complete, then use bwrite() otherwise use
* bdwrite().
*/
error = 0; /* note that error is 0 from above, but ... */
if (waitfor)
error = bwrite(bp);
else
return (bwrite(bp));
else {
bdwrite(bp);
return error;
return (0);
}
}
/*
@ -445,7 +409,7 @@ detrunc(dep, length, flags, cred, p)
struct timespec ts;
#ifdef MSDOSFS_DEBUG
printf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags);
printf("detrunc(): file %s, length %lu, flags %x\n", dep->de_Name, length, flags);
#endif
/*
@ -456,11 +420,10 @@ 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) {
printf(
"detrunc(): can't truncate root directory, clust %ld, offset %ld\n",
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;
return (EINVAL);
}
@ -483,16 +446,17 @@ detrunc(dep, length, flags, cred, p)
dep->de_StartCluster = 0;
eofentry = ~0;
} else {
error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, &eofentry);
error = pcbmap(dep, de_clcount(pmp, length) - 1, 0,
&eofentry, 0);
if (error) {
#ifdef MSDOSFS_DEBUG
printf("detrunc(): pcbmap fails %d\n", error);
#endif
return error;
return (error);
}
}
fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift);
fc_purge(dep, de_clcount(pmp, length));
/*
* If the new length is not a multiple of the cluster size then we
@ -500,10 +464,6 @@ detrunc(dep, length, flags, cred, p)
* becomes part of the file again because of a seek.
*/
if ((boff = length & pmp->pm_crbomask) != 0) {
/*
* should read from file vnode or filesystem vnode
* depending on if file or dir
*/
if (isadir) {
bn = cntobn(pmp, eofentry);
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
@ -521,10 +481,11 @@ detrunc(dep, length, flags, cred, p)
NOCRED, &bp);
}
if (error) {
brelse(bp);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): bread fails %d\n", error);
#endif
return error;
return (error);
}
/*
* is this the right place for it?
@ -541,14 +502,14 @@ detrunc(dep, length, flags, cred, p)
* we free the trailing clusters.
*/
dep->de_FileSize = length;
dep->de_flag |= DE_UPDATE;
if (!isadir)
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
vflags = (length > 0 ? V_SAVE : 0) | V_SAVEMETA;
vinvalbuf(DETOV(dep), vflags, cred, p, 0, 0);
vnode_pager_setsize(DETOV(dep), length);
TIMEVAL_TO_TIMESPEC(&time, &ts);
allerror = deupdat(dep, &ts, 1);
allerror = deupdat(dep, 1);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): allerror %d, eofentry %d\n",
printf("detrunc(): allerror %d, eofentry %lu\n",
allerror, eofentry);
#endif
@ -563,9 +524,9 @@ detrunc(dep, length, flags, cred, p)
#ifdef MSDOSFS_DEBUG
printf("detrunc(): fatentry errors %d\n", error);
#endif
return error;
return (error);
}
fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
eofentry);
}
@ -573,10 +534,10 @@ 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;
return (allerror);
}
/*
@ -585,7 +546,7 @@ detrunc(dep, length, flags, cred, p)
int
deextend(dep, length, cred)
struct denode *dep;
off_t length;
u_long length;
struct ucred *cred;
{
struct msdosfsmount *pmp = dep->de_pmp;
@ -596,18 +557,14 @@ deextend(dep, length, cred)
/*
* The root of a DOS filesystem cannot be extended.
*/
if (DETOV(dep)->v_flag & VROOT)
return EINVAL;
if ((DETOV(dep)->v_flag & VROOT) && !FAT32(pmp))
return (EINVAL);
/*
* Directories can only be extended by the superuser.
* Is this really important?
* Directories cannot be extended.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
error = suser(cred, NULL);
if (error)
return error;
}
if (dep->de_Attributes & ATTR_DIRECTORY)
return (EISDIR);
if (length <= dep->de_FileSize)
panic("deextend: file too large");
@ -618,26 +575,25 @@ deextend(dep, length, cred)
count = de_clcount(pmp, length) - de_clcount(pmp, dep->de_FileSize);
if (count > 0) {
if (count > pmp->pm_freeclustercount)
return ENOSPC;
return (ENOSPC);
error = extendfile(dep, count, NULL, NULL, DE_CLEAR);
if (error) {
/* truncate the added clusters away again */
(void) detrunc(dep, dep->de_FileSize, 0, cred, NULL);
return error;
return (error);
}
}
dep->de_flag |= DE_UPDATE;
dep->de_FileSize = length;
TIMEVAL_TO_TIMESPEC(&time, &ts);
return deupdat(dep, &ts, 1);
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
return (deupdat(dep, 1));
}
/*
* Move a denode to its correct hash queue after the file it represents has
* been moved to a new directory.
*/
int reinsert(dep)
void
reinsert(dep)
struct denode *dep;
{
/*
@ -648,11 +604,10 @@ int reinsert(dep)
* so we must remove it from the cache and re-enter it with the
* hash based on the new location of the directory entry.
*/
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
msdosfs_hashrem(dep);
msdosfs_hashins(dep);
}
return 0;
if (dep->de_Attributes & ATTR_DIRECTORY)
return;
msdosfs_hashrem(dep);
msdosfs_hashins(dep);
}
int
@ -671,27 +626,25 @@ msdosfs_reclaim(ap)
if (prtactive && vp->v_usecount != 0)
vprint("msdosfs_reclaim(): pushing active", vp);
/*
* Remove the denode from the denode hash chain we are in.
* Remove the denode from its hash chain.
*/
msdosfs_hashrem(dep);
cache_purge(vp);
/*
* Indicate that one less file on the filesystem is open.
* Purge old data structures associated with the denode.
*/
cache_purge(vp);
if (dep->de_devvp) {
vrele(dep->de_devvp);
dep->de_devvp = 0;
}
#if 0 /* XXX */
dep->de_flag = 0;
#endif
FREE(dep, M_MSDOSFSNODE);
vp->v_data = NULL;
return 0;
return (0);
}
int
@ -715,7 +668,7 @@ msdosfs_inactive(ap)
vprint("msdosfs_inactive(): pushing active", vp);
/*
* Ignore inodes related to stale file handles.
* Ignore denodes related to stale file handles.
*/
if (dep->de_Name[0] == SLOT_DELETED)
goto out;
@ -734,17 +687,13 @@ msdosfs_inactive(ap)
dep->de_flag |= DE_UPDATE;
dep->de_Name[0] = SLOT_DELETED;
}
if (dep->de_flag & (DE_MODIFIED | DE_UPDATE)) {
TIMEVAL_TO_TIMESPEC(&time, &ts);
deupdat(dep, &ts, 0);
}
deupdat(dep, 0);
out:
VOP_UNLOCK(vp, 0, p);
dep->de_flag = 0;
/*
* If we are done with the denode, then reclaim it so that it can
* be reused now.
* If we are done with the denode, reclaim it
* so that it can be reused immediately.
*/
#ifdef MSDOSFS_DEBUG
printf("msdosfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount,
@ -752,5 +701,5 @@ msdosfs_inactive(ap)
#endif
if (dep->de_Name[0] == SLOT_DELETED)
vrecycle(vp, (struct simplelock *)0, p);
return error;
return (error);
}

View File

@ -1,9 +1,9 @@
/* $Id: msdosfs_fat.c,v 1.15 1998/02/06 12:13:46 eivind Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.12 1994/08/21 18:44:04 ws Exp $ */
/* $Id: msdosfs_fat.c,v 1.16 1998/02/09 06:09:52 eivind Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.28 1997/11/17 15:36:49 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -56,6 +56,7 @@
#include <sys/buf.h>
#include <sys/mount.h> /* to define statfs structure */
#include <sys/vnode.h> /* to define vattr structure */
#include <sys/errno.h>
/*
* msdosfs include files.
@ -79,9 +80,6 @@ static int fc_lmdistance[LMMAX];/* counters for how far off the last
* cluster mapped entry was. */
static 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 int chainalloc __P((struct msdosfsmount *pmp, u_long start,
u_long count, u_long fillwith,
u_long *retcluster, u_long *got));
@ -111,7 +109,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)
@ -139,16 +138,17 @@ fatblock(pmp, ofs, bnp, sizep, bop)
* If cnp is null, nothing is returned.
*/
int
pcbmap(dep, findcn, bnp, cnp)
pcbmap(dep, findcn, bnp, cnp, sp)
struct denode *dep;
u_long findcn; /* file relative cluster to get */
daddr_t *bnp; /* returned filesys relative blk number */
u_long *cnp; /* returned cluster number */
int *sp; /* returned block size */
{
int error;
u_long i;
u_long cn;
u_long prevcn;
u_long prevcn = 0; /* XXX: prevcn could be used unititialized */
u_long byteoffset;
u_long bn;
u_long bo;
@ -156,7 +156,6 @@ pcbmap(dep, findcn, bnp, cnp)
u_long bp_bn = -1;
struct msdosfsmount *pmp = dep->de_pmp;
u_long bsize;
int fat12 = FAT12(pmp); /* 12 bit fat */
fc_bmapcalls++;
@ -164,8 +163,8 @@ pcbmap(dep, findcn, bnp, cnp)
* If they don't give us someplace to return a value then don't
* bother doing anything.
*/
if (bnp == NULL && cnp == NULL)
return 0;
if (bnp == NULL && cnp == NULL && sp == NULL)
return (0);
cn = dep->de_StartCluster;
/*
@ -176,23 +175,32 @@ pcbmap(dep, findcn, bnp, cnp)
*/
if (cn == MSDOSFSROOT) {
if (dep->de_Attributes & ATTR_DIRECTORY) {
if (findcn * pmp->pm_SectPerClust >= pmp->pm_rootdirsize) {
if (de_cn2off(pmp, findcn) >= dep->de_FileSize) {
if (cnp)
*cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
return E2BIG;
*cnp = de_bn2cn(pmp, pmp->pm_rootdirsize);
return (E2BIG);
}
if (bnp)
*bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
*bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn);
if (cnp)
*cnp = MSDOSFSROOT;
return 0;
if (sp)
*sp = min(pmp->pm_bpcluster,
dep->de_FileSize - de_cn2off(pmp, findcn));
return (0);
} else { /* just an empty file */
if (cnp)
*cnp = 0;
return E2BIG;
return (E2BIG);
}
}
/*
* All other files do I/O in cluster sized blocks
*/
if (sp)
*sp = pmp->pm_bpcluster;
/*
* Rummage around in the fat cache, maybe we can avoid tromping
* thru every fat entry for the file. And, keep track of how far
@ -208,9 +216,11 @@ pcbmap(dep, findcn, bnp, cnp)
/*
* Handle all other files or directories the normal way.
*/
prevcn = 0;
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);
@ -218,28 +228,32 @@ pcbmap(dep, findcn, bnp, cnp)
if (bp)
brelse(bp);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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)
@ -247,7 +261,7 @@ pcbmap(dep, findcn, bnp, cnp)
if (cnp)
*cnp = cn;
fc_setcache(dep, FC_LASTMAP, i, cn);
return 0;
return (0);
}
hiteof:;
@ -257,7 +271,7 @@ hiteof:;
brelse(bp);
/* update last file cluster entry in the fat cache */
fc_setcache(dep, FC_LASTFC, i - 1, prevcn);
return E2BIG;
return (E2BIG);
}
/*
@ -292,7 +306,8 @@ fc_lookup(dep, findcn, frcnp, fsrcnp)
* Purge the fat cache in denode dep of all entries relating to file
* relative cluster frcn and beyond.
*/
void fc_purge(dep, frcn)
void
fc_purge(dep, frcn)
struct denode *dep;
u_int frcn;
{
@ -307,7 +322,9 @@ void 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
@ -323,36 +340,80 @@ updatefats(pmp, bp, fatbn)
struct buf *bpn;
#ifdef MSDOSFS_DEBUG
printf("updatefats(pmp %p, bp %p, fatbn %ld)\n", pmp, bp, fatbn);
printf("updatefats(pmp %p, bp %p, fatbn %lu)\n", 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_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_waitonfat)
if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bp);
else
bdwrite(bp);
/*
* Maybe update fsinfo sector here?
*/
}
/*
@ -379,8 +440,8 @@ usemap_alloc(pmp, cn)
struct msdosfsmount *pmp;
u_long cn;
{
pmp->pm_inusemap[cn / N_INUSEBITS]
|= 1 << (cn % N_INUSEBITS);
pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
pmp->pm_freeclustercount--;
}
@ -389,6 +450,7 @@ usemap_free(pmp, cn)
struct msdosfsmount *pmp;
u_long cn;
{
pmp->pm_freeclustercount++;
pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
}
@ -402,18 +464,20 @@ 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 == 0) {
/*
* 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;
if (error) {
usemap_alloc(pmp, cluster);
return (error);
}
return error;
/*
* If the cluster was successfully marked free, then update
* the count of free clusters, and turn off the "allocated"
* bit in the "in use" cluster bit map.
*/
if (oldcnp)
*oldcnp = oldcn;
return (0);
}
/*
@ -448,10 +512,10 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
u_long bn, bo, bsize, byteoffset;
struct buf *bp;
/*
* printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
* function, pmp, cluster, oldcontents, newcontents);
*/
#ifdef MSDOSFS_DEBUG
printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
function, pmp, cn, oldcontents, newcontents);
#endif
#ifdef DIAGNOSTIC
/*
@ -459,7 +523,7 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
*/
if ((function & (FAT_SET | FAT_GET)) == 0) {
printf("fatentry(): function code doesn't specify get or set\n");
return EINVAL;
return (EINVAL);
}
/*
@ -468,7 +532,7 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
*/
if ((function & FAT_GET) && oldcontents == NULL) {
printf("fatentry(): get function with no place to put result\n");
return EINVAL;
return (EINVAL);
}
#endif
@ -476,28 +540,32 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
* Be sure the requested cluster is in the filesystem.
*/
if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
return EINVAL;
return (EINVAL);
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -507,15 +575,28 @@ 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;
}
if (bp)
brelse(bp);
return 0;
return (0);
}
/*
@ -538,25 +619,28 @@ fatchain(pmp, start, count, fillwith)
struct buf *bp;
#ifdef MSDOSFS_DEBUG
printf("fatchain(pmp %p, start %ld, count %ld, fillwith %ld)\n",
pmp, start, count, fillwith);
printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
pmp, start, count, fillwith);
#endif
/*
* Be sure the clusters are in the filesystem.
*/
if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
return EINVAL;
return (EINVAL);
while (count > 0) {
byteoffset = FATOFS(pmp, start);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -569,9 +653,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;
@ -579,7 +672,7 @@ fatchain(pmp, start, count, fillwith)
updatefats(pmp, bp, bn);
}
pmp->pm_fmod = 1;
return 0;
return (0);
}
/*
@ -606,11 +699,11 @@ chainlength(pmp, start, count)
map &= ~((1 << start) - 1);
if (map) {
len = ffs(map) - 1 - start;
return len > count ? count : len;
return (len > count ? count : len);
}
len = N_INUSEBITS - start;
if (len >= count)
return count;
return (count);
while (++idx <= max_idx) {
if (len >= count)
break;
@ -621,7 +714,7 @@ chainlength(pmp, start, count)
}
len += N_INUSEBITS;
}
return len > count ? count : len;
return (len > count ? count : len);
}
/*
@ -645,21 +738,23 @@ 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++);
error = fatchain(pmp, start, count, fillwith);
if (error == 0) {
if (error != 0)
return (error);
#ifdef MSDOSFS_DEBUG
printf("clusteralloc(): allocated cluster chain at %ld (%ld clusters)\n",
start, count);
printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
start, count);
#endif
if (retcluster)
*retcluster = start;
if (got)
*got = count;
while (count-- > 0)
usemap_alloc(pmp, start++);
}
return error;
if (retcluster)
*retcluster = start;
if (got)
*got = count;
return (0);
}
/*
@ -683,15 +778,16 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
u_long *got;
{
u_long idx;
u_long len, newst, foundcn, foundl, cn, l;
u_long len, newst, foundl, cn, l;
u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
u_int map;
#ifdef MSDOSFS_DEBUG
printf("clusteralloc(): find %d clusters\n",count);
printf("clusteralloc(): find %lu clusters\n",count);
#endif
if (start) {
if ((len = chainlength(pmp, start, count)) >= count)
return chainalloc(pmp, start, count, fillwith, retcluster, got);
return (chainalloc(pmp, start, count, fillwith, retcluster, got));
} else {
/*
* This is a new file, initialize start
@ -699,7 +795,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
struct timeval tv;
microtime(&tv);
start = (tv.tv_usec >> 10)|tv.tv_usec;
start = (tv.tv_usec >> 10) | tv.tv_usec;
len = 0;
}
@ -707,7 +803,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
* Start at a (pseudo) random place to maximize cluster runs
* under multiple writers.
*/
foundcn = newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
foundl = 0;
for (cn = newst; cn <= pmp->pm_maxcluster;) {
@ -717,7 +813,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
if (map != (u_int)-1) {
cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
if ((l = chainlength(pmp, cn, count)) >= count)
return chainalloc(pmp, cn, count, fillwith, retcluster, got);
return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
if (l > foundl) {
foundcn = cn;
foundl = l;
@ -734,7 +830,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
if (map != (u_int)-1) {
cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
if ((l = chainlength(pmp, cn, count)) >= count)
return chainalloc(pmp, cn, count, fillwith, retcluster, got);
return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
if (l > foundl) {
foundcn = cn;
foundl = l;
@ -746,12 +842,12 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
}
if (!foundl)
return ENOSPC;
return (ENOSPC);
if (len)
return chainalloc(pmp, start, len, fillwith, retcluster, got);
return (chainalloc(pmp, start, len, fillwith, retcluster, got));
else
return chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got);
return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got));
}
@ -768,7 +864,7 @@ freeclusterchain(pmp, cluster)
struct msdosfsmount *pmp;
u_long cluster;
{
int error = 0;
int error;
struct buf *bp = NULL;
u_long bn, bo, bsize, byteoffset;
u_long readcn, lbn = -1;
@ -780,13 +876,16 @@ freeclusterchain(pmp, cluster)
if (bp)
updatefats(pmp, bp, lbn);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
if (error) {
brelse(bp);
return (error);
}
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;
@ -797,17 +896,24 @@ 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);
return error;
return (0);
}
/*
@ -821,7 +927,6 @@ fillinusemap(pmp)
struct buf *bp = NULL;
u_long cn, readcn;
int error;
int fat12 = FAT12(pmp);
u_long bn, bo, bsize, byteoffset;
/*
@ -846,21 +951,24 @@ fillinusemap(pmp)
brelse(bp);
fatblock(pmp, byteoffset, &bn, &bsize, NULL);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
}
readcn = getushort(&bp->b_data[bo]);
if (fat12) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
if (error) {
brelse(bp);
return (error);
}
}
if (FAT32(pmp))
readcn = getulong(&bp->b_data[bo]);
else
readcn = getushort(&bp->b_data[bo]);
if (FAT12(pmp) && (cn & 1))
readcn >>= 4;
readcn &= pmp->pm_fatmask;
if (readcn == 0)
usemap_free(pmp, cn);
}
brelse(bp);
return 0;
return (0);
}
/*
@ -886,7 +994,7 @@ extendfile(dep, count, bpp, ncp, flags)
u_long *ncp;
int flags;
{
int error = 0;
int error;
u_long frcn;
u_long cn, got;
struct msdosfsmount *pmp = dep->de_pmp;
@ -895,9 +1003,10 @@ 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;
return (ENOSPC);
}
/*
@ -908,21 +1017,21 @@ extendfile(dep, count, bpp, ncp, flags)
if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
dep->de_StartCluster != 0) {
fc_lfcempty++;
error = pcbmap(dep, 0xffff, 0, &cn);
error = pcbmap(dep, 0xffff, 0, &cn, 0);
/* we expect it to return E2BIG */
if (error != E2BIG)
return error;
error = 0;
return (error);
}
while (count > 0) {
/*
* Allocate a new cluster chain and cat onto the end of the file.
* If the file is empty we make de_StartCluster point to the new
* block. Note that de_StartCluster being 0 is sufficient to be
* sure the file is empty since we exclude attempts to extend the
* root directory above, and the root dir is the only file with a
* startcluster of 0 that has blocks allocated (sort of).
* Allocate a new cluster chain and cat onto the end of the
* file. * If the file is empty we make de_StartCluster point
* to the new block. Note that de_StartCluster being 0 is
* sufficient to be sure the file is empty since we exclude
* attempts to extend the root directory above, and the root
* dir is the only file with a startcluster of 0 that has
* blocks allocated (sort of).
*/
if (dep->de_StartCluster == 0)
cn = 0;
@ -930,7 +1039,7 @@ extendfile(dep, count, bpp, ncp, flags)
cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
error = clusteralloc(pmp, cn, count, CLUST_EOFE, &cn, &got);
if (error)
return error;
return (error);
count -= got;
@ -947,13 +1056,13 @@ extendfile(dep, count, bpp, ncp, flags)
dep->de_StartCluster = cn;
frcn = 0;
} else {
error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
error = fatentry(FAT_SET, pmp,
dep->de_fc[FC_LASTFC].fc_fsrcn,
0, cn);
if (error) {
clusterfree(pmp, cn, NULL);
return error;
return (error);
}
frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
}
@ -972,11 +1081,14 @@ extendfile(dep, count, bpp, ncp, flags)
bp = getblk(pmp->pm_devvp, cntobn(pmp, cn++),
pmp->pm_bpcluster, 0, 0);
else {
bp = getblk(DETOV(dep), frcn++, pmp->pm_bpcluster, 0, 0);
bp = getblk(DETOV(dep), de_cn2bn(pmp, frcn++),
pmp->pm_bpcluster, 0, 0);
/*
* Do the bmap now, as in msdosfs_write
*/
if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
if (pcbmap(dep,
de_bn2cn(pmp, bp->b_lblkno),
&bp->b_blkno, 0, 0))
bp->b_blkno = -1;
if (bp->b_blkno == -1)
panic("extendfile: pcbmap");
@ -985,13 +1097,11 @@ extendfile(dep, count, bpp, ncp, flags)
if (bpp) {
*bpp = bp;
bpp = NULL;
} else {
bp->b_flags |= B_AGE;
bawrite(bp);
}
} else
bdwrite(bp);
}
}
}
return 0;
return (0);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
/* $Id: msdosfsmount.h,v 1.11 1997/03/03 17:36:11 bde Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.7 1994/08/21 18:44:17 ws Exp $ */
/* $Id: msdosfsmount.h,v 1.12 1997/10/12 20:25:02 phk Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.17 1997/11/17 15:37:07 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
* Copyright (C) 1994 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).
*
@ -63,90 +63,119 @@ MALLOC_DECLARE(M_MSDOSFSMNT);
struct msdosfsmount {
struct mount *pm_mountp;/* vfs mount struct for this fs */
dev_t pm_dev; /* block special device mounted */
uid_t pm_mounter; /* uid of the user who mounted the FS */
uid_t pm_uid; /* uid to set as owner of the files */
gid_t pm_gid; /* gid to set as owner of the files */
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 */
u_long pm_maxcluster; /* maximum cluster number */
u_long pm_freeclustercount; /* number of free clusters */
u_long pm_bnshift; /* shift file offset right this amount to get a block number */
u_long pm_brbomask; /* and a file offset with this mask to get block rel offset */
u_long pm_cnshift; /* shift file offset right this amount to get a cluster number */
u_long pm_crbomask; /* and a file offset with this mask to get cluster rel offset */
u_long pm_bnshift; /* shift file offset right this amount to get a block number */
u_long pm_bpcluster; /* bytes per cluster */
u_long pm_depclust; /* directory entries per cluster */
u_long pm_fmod; /* ~0 if fs is modified, this can rollover to 0 */
u_long pm_fatblocksize; /* size of fat blocks in bytes */
u_long pm_fatblocksec; /* size of fat blocks in sectors */
u_long pm_fatsize; /* size of fat in bytes */
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 */
char pm_ronly; /* read only if non-zero */
char pm_waitonfat; /* wait for writes of the fat to complete, when 0 use bdwrite, else use bwrite */
u_int pm_flags; /* see below */
struct netexport pm_export; /* export information */
};
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv)
#define VFSTOMSDOSFS(mp) ((struct msdosfsmount *)mp->mnt_data)
/* Number of bits in one pm_inusemap item: */
#define N_INUSEBITS (8 * sizeof(u_int))
/*
* How to compute pm_cnshift and pm_crbomask.
*
* pm_crbomask = (pm_SectPerClust * pm_BytesPerSect) - 1
* if (bytesperclust == * 0)
* return EBADBLKSZ;
* bit = 1;
* for (i = 0; i < 32; i++) {
* if (bit & bytesperclust) {
* if (bit ^ bytesperclust)
* return EBADBLKSZ;
* pm_cnshift = * i;
* break;
* }
* bit <<= 1;
* }
*/
/*
* Shorthand for fields in the bpb contained in the msdosfsmount structure.
*/
#define pm_BytesPerSec pm_bpb.bpbBytesPerSec
#define pm_SectPerClust pm_bpb.bpbSecPerClust
#define pm_ResSectors pm_bpb.bpbResSectors
#define pm_FATs pm_bpb.bpbFATs
#define pm_RootDirEnts pm_bpb.bpbRootDirEnts
#define pm_Sectors pm_bpb.bpbSectors
#define pm_Media pm_bpb.bpbMedia
#define pm_FATsecs pm_bpb.bpbFATsecs
#define pm_SecPerTrack pm_bpb.bpbSecPerTrack
#define pm_Heads pm_bpb.bpbHeads
#define pm_HiddenSects pm_bpb.bpbHiddenSecs
#define pm_HugeSectors pm_bpb.bpbHugeSectors
/*
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)(((bp)->b_data) \
+ ((dirofs) & (pmp)->pm_crbomask)))
/*
* Convert block number to cluster number
*/
#define de_bn2cn(pmp, bn) \
((bn) >> ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
* Convert cluster number to block number
*/
#define de_cn2bn(pmp, cn) \
((cn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
* Convert file offset to cluster number
*/
#define de_cluster(pmp, off) \
((off) >> (pmp)->pm_cnshift)
/*
* Clusters required to hold size bytes
*/
#define de_clcount(pmp, size) \
(((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
/*
* Convert file offset to block number
*/
#define de_blk(pmp, off) \
(de_cn2bn(pmp, de_cluster((pmp), (off))))
/*
* Convert cluster number to file offset
*/
#define de_cn2off(pmp, cn) \
((cn) << (pmp)->pm_cnshift)
/*
* Convert block number to file offset
*/
#define de_bn2off(pmp, bn) \
((bn) << (pmp)->pm_bnshift)
/*
* Map a cluster number into a filesystem relative block number.
*/
#define cntobn(pmp, cn) \
((((cn)-CLUST_FIRST) * (pmp)->pm_SectPerClust) + (pmp)->pm_firstcluster)
/*
* Map a filesystem relative block number back into a cluster number.
*/
#define bntocn(pmp, bn) \
((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
(de_cn2bn((pmp), (cn)-CLUST_FIRST) + (pmp)->pm_firstcluster)
/*
* Calculate block number for directory entry in root dir, offset dirofs
*/
#define roottobn(pmp, dirofs) \
(((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
+ (pmp)->pm_rootdirblk)
(de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk)
/*
* Calculate block number for directory entry at cluster dirclu, offset
@ -157,27 +186,8 @@ struct msdosfsmount {
? roottobn((pmp), (dirofs)) \
: cntobn((pmp), (dirclu)))
/*
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)((bp)->b_data) \
+ (dirofs) % (pmp)->pm_depclust)
/*
* Convert filesize to block number
*/
#define de_blk(pmp, off) \
((off) >> (pmp)->pm_cnshift)
/*
* Clusters required to hold size bytes
*/
#define de_clcount(pmp, size) \
(((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
int msdosfs_init __P((struct vfsconf *vfsp));
int msdosfs_mountroot __P((void));
#endif /* KERNEL */
@ -190,6 +200,27 @@ struct msdosfs_args {
uid_t uid; /* uid that owns msdosfs files */
gid_t gid; /* gid that owns msdosfs files */
mode_t mask; /* mask to be applied for msdosfs perms */
int flags; /* see below */
int magic; /* version number */
};
/*
* Msdosfs mount options:
*/
#define MSDOSFSMNT_SHORTNAME 1 /* Force old DOS short names only */
#define MSDOSFSMNT_LONGNAME 2 /* Force Win'95 long names */
#define MSDOSFSMNT_NOWIN95 4 /* Completely ignore Win95 entries */
#ifndef __FreeBSD__
#define MSDOSFSMNT_GEMDOSFS 8 /* This is a gemdos-flavour */
#endif
/* All flags above: */
#define MSDOSFSMNT_MNTOPT \
(MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \
/*|MSDOSFSMNT_GEMDOSFS*/)
#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */
#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */
#define MSDOSFS_ARGSMAGIC 0xe4eff300
#endif /* !_MSDOSFS_MSDOSFSMOUNT_H_ */