summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjkh <jkh@FreeBSD.org>1998-02-18 09:28:47 +0000
committerjkh <jkh@FreeBSD.org>1998-02-18 09:28:47 +0000
commit90f90fc3470f6725b317b359c1b3149995b822b7 (patch)
treea41d30021bc38cb8b60af8e616a1a634111adecc
parent4430df5b848751ab6f0d04b584f8c0921f47d494 (diff)
downloadFreeBSD-src-90f90fc3470f6725b317b359c1b3149995b822b7.zip
FreeBSD-src-90f90fc3470f6725b317b359c1b3149995b822b7.tar.gz
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
-rw-r--r--sys/fs/msdosfs/bootsect.h87
-rw-r--r--sys/fs/msdosfs/bpb.h217
-rw-r--r--sys/fs/msdosfs/denode.h114
-rw-r--r--sys/fs/msdosfs/direntry.h88
-rw-r--r--sys/fs/msdosfs/fat.h58
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c684
-rw-r--r--sys/fs/msdosfs/msdosfs_denode.c285
-rw-r--r--sys/fs/msdosfs/msdosfs_fat.c452
-rw-r--r--sys/fs/msdosfs/msdosfs_lookup.c878
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c842
-rw-r--r--sys/fs/msdosfs/msdosfs_vnops.c1411
-rw-r--r--sys/fs/msdosfs/msdosfsmount.h145
-rw-r--r--sys/msdosfs/bootsect.h87
-rw-r--r--sys/msdosfs/bpb.h217
-rw-r--r--sys/msdosfs/denode.h114
-rw-r--r--sys/msdosfs/direntry.h88
-rw-r--r--sys/msdosfs/fat.h58
-rw-r--r--sys/msdosfs/msdosfs_conv.c684
-rw-r--r--sys/msdosfs/msdosfs_denode.c285
-rw-r--r--sys/msdosfs/msdosfs_fat.c452
-rw-r--r--sys/msdosfs/msdosfs_lookup.c878
-rw-r--r--sys/msdosfs/msdosfs_vfsops.c842
-rw-r--r--sys/msdosfs/msdosfs_vnops.c1411
-rw-r--r--sys/msdosfs/msdosfsmount.h145
24 files changed, 6696 insertions, 3826 deletions
diff --git a/sys/fs/msdosfs/bootsect.h b/sys/fs/msdosfs/bootsect.h
index 86fc415..11b93371a 100644
--- a/sys/fs/msdosfs/bootsect.h
+++ b/sys/fs/msdosfs/bootsect.h
@@ -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 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) */
+struct extboot {
+ int8_t exDriveNumber; /* drive number (0x80) */
+ int8_t exReserved1; /* reserved */
+ int8_t exBootSignature; /* ext. 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
+ int8_t exVolumeID[4]; /* volume ID number */
+ int8_t exVolumeLabel[11]; /* volume label */
+ int8_t exFileSysType[8]; /* fs type (FAT12 or FAT16) */
+};
+
+struct bootsector50 {
+ u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
+ int8_t bsOemName[8]; /* OEM name and version */
+ int8_t bsBPB[25]; /* BIOS parameter block */
+ int8_t 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
diff --git a/sys/fs/msdosfs/bpb.h b/sys/fs/msdosfs/bpb.h
index 33e1eb6..bc00a75 100644
--- a/sys/fs/msdosfs/bpb.h
+++ b/sys/fs/msdosfs/bpb.h
@@ -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,21 +39,71 @@ 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
* because the compiler forces shorts and longs to align on word or
@@ -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];
};
diff --git a/sys/fs/msdosfs/denode.h b/sys/fs/msdosfs/denode.h
index 6ad3fcc..2b9d636 100644
--- a/sys/fs/msdosfs/denode.h
+++ b/sys/fs/msdosfs/denode.h
@@ -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 */
diff --git a/sys/fs/msdosfs/direntry.h b/sys/fs/msdosfs/direntry.h
index b97a105..0bfe164 100644
--- a/sys/fs/msdosfs/direntry.h
+++ b/sys/fs/msdosfs/direntry.h
@@ -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,27 +52,56 @@
* 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.
* We don't use bitfields because we don't know how compilers for
@@ -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 */
diff --git a/sys/fs/msdosfs/fat.h b/sys/fs/msdosfs/fat.h
index f8fdb6f..74b05e2 100644
--- a/sys/fs/msdosfs/fat.h
+++ b/sys/fs/msdosfs/fat.h
@@ -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 */
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index 59f4d2c..727cacd 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -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,90 +349,86 @@ 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.
+ * If first char of the filename is SLOT_E5 (0x05), then the real
+ * first char of the filename should be 0xe5. But, they couldn't
+ * just have a 0xe5 mean 0xe5 because that is used to mean a freed
+ * directory slot. Another dos quirk.
*/
- for (ei = 10; ei >= 8; ei--)
- if (dn[ei] != ' ')
- break;
+ if (*dn == SLOT_E5)
+ c = dos2unix[0xe5];
+ else
+ c = dos2unix[*dn];
+ *un++ = lower ? u2l[c] : c;
+ dn++;
/*
- * 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.
+ * Copy the name portion into the unix filename string.
*/
- for (i = 0; i <= ni; i++) {
- c = dn[i];
- *un++ = isupper(c) ? tolower(c) : c;
+ 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 (ei >= 8) {
+ if (*dn != ' ') {
*un++ = '.';
thislong++;
- for (i = 8; i <= ei; i++) {
- c = dn[i];
- *un++ = isupper(c) ? tolower(c) : c;
+ for (i = 0; i < 3 && *dn != ' '; i++) {
+ c = dos2unix[*dn++];
+ *un++ = lower ? u2l[c] : c;
thislong++;
}
}
*un++ = 0;
- /*
- * If first char of the filename is SLOT_E5 (0x05), then the real
- * first char of the filename should be 0xe5. But, they couldn't
- * 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;
-
- return thislong;
+ 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;
+ }
+
+ /*
+ * Filenames with only blanks and dots are not allowed!
+ */
+ for (cp = un, i = unlen; --i >= 0; cp++)
+ if (*cp != ' ' && *cp != '.')
+ break;
+ if (i < 0)
+ return 0;
+
+ /*
+ * Now find the extension
+ * Note: dot as first char doesn't start extension
+ * and trailing dots and blanks are ignored
+ */
+ dp = dp1 = 0;
+ for (cp = un + 1, i = unlen - 1; --i >= 0;) {
+ switch (*cp++) {
+ case '.':
+ if (!dp1)
+ dp1 = cp;
+ break;
+ case ' ':
+ break;
+ default:
+ if (dp1)
+ dp = dp1;
+ dp1 = 0;
+ break;
+ }
+ }
+
+ /*
+ * Now convert it
+ */
+ if (dp) {
+ if (dp1)
+ l = dp1 - dp;
+ else
+ l = unlen - (dp - un);
+ for (i = 0, j = 8; i < l && j < 11; i++, j++) {
+ if (dp[i] != (dn[j] = unix2dos[dp[i]])
+ && conv != 3)
+ conv = 2;
+ if (!dn[j]) {
+ conv = 3;
+ dn[j--] = ' ';
+ }
+ }
+ if (i < l)
+ conv = 3;
+ dp--;
+ } else {
+ for (dp = cp; *--dp == ' ' || *dp == '.';);
+ dp++;
}
/*
- * 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.
+ * Now convert the rest of the name
*/
- for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ 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] = '_';
/*
- * 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.
+ * The first character cannot be E5,
+ * because that means a deleted entry
*/
- if (dn[0] == SLOT_DELETED)
+ 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 (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;
+}
+
+/*
+ * Create a Win95 long name directory entry
+ * Note: assumes that the filename is valid,
+ * i.e. doesn't consist solely of blanks and dots
+ */
+int
+unix2winfn(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 (i = 8; i <= 10 && unlen && (c = *un); i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ 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;
}
/*
- * Get rid of these macros before someone discovers we are using such
- * hideous things.
+ * Convert Win95 filename to dirbuf.
+ * Returns the checksum or -1 if impossible
*/
-#undef isupper
-#undef islower
-#undef toupper
-#undef tolower
+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);
+}
diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c
index 81e0699..6feabbb 100644
--- a/sys/fs/msdosfs/msdosfs_denode.c
+++ b/sys/fs/msdosfs/msdosfs_denode.c
@@ -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);
-
-#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;
+ struct timespec ts;
- /*
- * 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 @@ out:
#endif
if (dep->de_Name[0] == SLOT_DELETED)
vrecycle(vp, (struct simplelock *)0, p);
- return error;
+ return (error);
}
diff --git a/sys/fs/msdosfs/msdosfs_fat.c b/sys/fs/msdosfs/msdosfs_fat.c
index bb25ec2..f556860 100644
--- a/sys/fs/msdosfs/msdosfs_fat.c
+++ b/sys/fs/msdosfs/msdosfs_fat.c
@@ -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,24 +175,33 @@ 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
* off the cache was from where we wanted to be.
@@ -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);
}
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index b757cf0..4991417 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_lookup.c,v 1.13 1997/09/02 20:06:17 bde Exp $ */
-/* $NetBSD: msdosfs_lookup.c,v 1.14 1994/08/21 18:44:07 ws Exp $ */
+/* $Id: msdosfs_lookup.c,v 1.14 1997/09/10 19:44:36 phk Exp $ */
+/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 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).
*
@@ -94,16 +94,13 @@ msdosfs_lookup(ap)
int error;
int lockparent;
int wantparent;
- int slotstatus;
-
-#define NONE 0
-#define FOUND 1
- int slotoffset = -1;
- int slotcluster = -1;
+ int slotcount;
+ int slotoffset = 0;
int frcn;
u_long cluster;
- int rootreloff;
+ int blkoff;
int diroff;
+ int blsize;
int isadir; /* ~0 if found direntry is a directory */
u_long scn; /* starting cluster number */
struct vnode *pdp;
@@ -118,6 +115,10 @@ msdosfs_lookup(ap)
int nameiop = cnp->cn_nameiop;
struct proc *p = cnp->cn_proc;
+ int wincnt = 1;
+ int chksum = -1;
+ int olddos = 1;
+
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
@@ -127,8 +128,8 @@ msdosfs_lookup(ap)
lockparent = flags & LOCKPARENT;
wantparent = flags & (LOCKPARENT | WANTPARENT);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
- vdp, dp, dp->de_Attributes);
+ printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
+ vdp, dp, dp->de_Attributes);
#endif
/*
@@ -145,25 +146,43 @@ msdosfs_lookup(ap)
printf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
cluster = MSDOSFSROOT;
- diroff = MSDOSFSROOT_OFS;
+ blkoff = MSDOSFSROOT_OFS;
goto foundroot;
}
+ switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
+ cnp->cn_namelen, 0)) {
+ case 0:
+ return (EINVAL);
+ case 1:
+ break;
+ case 2:
+ wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen) + 1;
+ break;
+ case 3:
+ olddos = 0;
+ wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen) + 1;
+ break;
+ }
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ wincnt = 1;
+
/*
- * Don't search for free slots unless we are creating a filename
- * and we are at the end of the pathname.
+ * Suppress search for slots unless creating
+ * file and at end of pathname, in which case
+ * we watch for a place to put the new file in
+ * case it doesn't already exist.
*/
- slotstatus = FOUND;
- if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) {
- slotstatus = NONE;
- slotoffset = -1;
- }
+ slotcount = wincnt;
+ if ((nameiop == CREATE || nameiop == RENAME) &&
+ (flags & ISLASTCN))
+ slotcount = 0;
- unix2dosfn((u_char *) cnp->cn_nameptr, dosfilename, cnp->cn_namelen);
- dosfilename[11] = 0;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): dos version of filename %s, length %d\n",
- dosfilename, cnp->cn_namelen);
+ printf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
+ dosfilename, cnp->cn_namelen);
#endif
/*
* Search the directory pointed at by vdp for the name pointed at
@@ -177,20 +196,23 @@ msdosfs_lookup(ap)
* part of the pool of allocatable clusters. So, we treat it a
* little differently. The root directory starts at "cluster" 0.
*/
- rootreloff = 0;
+ diroff = 0;
for (frcn = 0;; frcn++) {
- error = pcbmap(dp, frcn, &bn, &cluster);
+ error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
if (error) {
if (error == E2BIG)
break;
- return error;
+ return (error);
}
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,NOCRED,&bp);
- if (error)
- return error;
- for (diroff = 0; diroff < pmp->pm_depclust; diroff++) {
- dep = (struct direntry *) bp->b_data + diroff;
-
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return (error);
+ }
+ for (blkoff = 0; blkoff < blsize;
+ blkoff += sizeof(struct direntry),
+ diroff += sizeof(struct direntry)) {
+ dep = (struct direntry *)(bp->b_data + blkoff);
/*
* If the slot is empty and we are still looking
* for an empty then remember this one. If the
@@ -202,13 +224,14 @@ msdosfs_lookup(ap)
*/
if (dep->deName[0] == SLOT_EMPTY ||
dep->deName[0] == SLOT_DELETED) {
- if (slotstatus != FOUND) {
- slotstatus = FOUND;
- if (cluster == MSDOSFSROOT)
- slotoffset = rootreloff;
- else
- slotoffset = diroff;
- slotcluster = cluster;
+ /*
+ * Drop memory of previous long matches
+ */
+ chksum = -1;
+
+ if (slotcount < wincnt) {
+ slotcount++;
+ slotoffset = diroff;
}
if (dep->deName[0] == SLOT_EMPTY) {
brelse(bp);
@@ -216,204 +239,298 @@ msdosfs_lookup(ap)
}
} else {
/*
+ * If there wasn't enough space for our winentries,
+ * forget about the empty space
+ */
+ if (slotcount < wincnt)
+ slotcount = 0;
+
+ /*
+ * Check for Win95 long filename entry
+ */
+ if (dep->deAttributes == ATTR_WIN95) {
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ continue;
+
+ chksum = winChkName((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen,
+ (struct winentry *)dep,
+ chksum);
+ continue;
+ }
+
+ /*
* Ignore volume labels (anywhere, not just
* the root directory).
*/
- if ((dep->deAttributes & ATTR_VOLUME) == 0 &&
- bcmp(dosfilename, dep->deName, 11) == 0) {
+ if (dep->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
+ continue;
+ }
+
+ /*
+ * Check for a checksum or name match
+ */
+ if (chksum != winChksum(dep->deName)
+ && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
+ chksum = -1;
+ continue;
+ }
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): match diroff %d, rootreloff %d\n",
- diroff, rootreloff);
+ printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
+ blkoff, diroff);
#endif
- /*
- * Remember where this directory
- * entry came from for whoever did
- * this lookup. If this is the root
- * directory we are interested in
- * the offset relative to the
- * beginning of the directory (not
- * the beginning of the cluster).
- */
- if (cluster == MSDOSFSROOT)
- diroff = rootreloff;
- dp->de_fndoffset = diroff;
- dp->de_fndclust = cluster;
- goto found;
- }
+ /*
+ * Remember where this directory
+ * entry came from for whoever did
+ * this lookup.
+ */
+ dp->de_fndoffset = diroff;
+ dp->de_fndcnt = 0; /* unused anyway */
+
+ goto found;
}
- rootreloff++;
- } /* for (diroff = 0; .... */
+ } /* for (blkoff = 0; .... */
/*
* Release the buffer holding the directory cluster just
* searched.
*/
brelse(bp);
- } /* for (frcn = 0; ; frcn++) */
-notfound:;
+ } /* for (frcn = 0; ; frcn++) */
+
+notfound:
/*
* We hold no disk buffers at this point.
*/
/*
+ * Fixup the slot description to point to the place where
+ * we might put the new DOS direntry (putting the Win95
+ * long name entries before that)
+ */
+ if (!slotcount) {
+ slotcount = 1;
+ slotoffset = diroff;
+ }
+ if (wincnt > slotcount)
+ slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
+
+ /*
* If we get here we didn't find the entry we were looking for. But
* that's ok if we are creating or renaming and are at the end of
* the pathname and the directory hasn't been removed.
*/
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): op %d, refcnt %d, slotstatus %d\n",
- nameiop, dp->de_refcnt, slotstatus);
- printf(" slotoffset %d, slotcluster %d\n",
- slotoffset, slotcluster);
+ printf("msdosfs_lookup(): op %d, refcnt %ld\n",
+ nameiop, dp->de_refcnt);
+ printf(" slotcount %d, slotoffset %d\n",
+ slotcount, slotoffset);
#endif
if ((nameiop == CREATE || nameiop == RENAME) &&
(flags & ISLASTCN) && dp->de_refcnt != 0) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
+ /*
+ * Access for write is interpreted as allowing
+ * creation of files in the directory.
+ */
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
if (error)
- return error;
- if (slotstatus == NONE) {
- dp->de_fndoffset = (u_long)-1;
- dp->de_fndclust = (u_long)-1;
- } else {
-#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): saving empty slot location\n");
-#endif
- dp->de_fndoffset = slotoffset;
- dp->de_fndclust = slotcluster;
- }
- /* dp->de_flag |= DE_UPDATE; never update dos directories */
+ return (error);
+ /*
+ * Return an indication of where the new directory
+ * entry should be put.
+ */
+ dp->de_fndoffset = slotoffset;
+ dp->de_fndcnt = wincnt - 1;
+
+ /*
+ * We return with the directory locked, so that
+ * the parameters we set up above will still be
+ * valid if we actually decide to do a direnter().
+ * We return ni_vp == NULL to indicate that the entry
+ * does not currently exist; we leave a pointer to
+ * the (locked) directory inode in ndp->ni_dvp.
+ * The pathname buffer is saved so that the name
+ * can be obtained later.
+ *
+ * NB - if the directory is unlocked, then this
+ * information cannot be used.
+ */
cnp->cn_flags |= SAVENAME;
- if (!lockparent)/* leave searched dir locked? */
+ if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- return EJUSTRETURN;
+ return (EJUSTRETURN);
}
/*
- * Insert name in cache as non-existant if not trying to create it.
+ * Insert name into cache (as non-existent) if appropriate.
*/
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
cache_enter(vdp, *vpp, cnp);
- return ENOENT;
+ return (ENOENT);
-found: ;
+found:
/*
* NOTE: We still have the buffer with matched directory entry at
* this point.
*/
isadir = dep->deAttributes & ATTR_DIRECTORY;
scn = getushort(dep->deStartCluster);
+ if (FAT32(pmp)) {
+ scn |= getushort(dep->deHighClust) << 16;
+ if (scn == pmp->pm_rootdirblk) {
+ /*
+ * There should actually be 0 here.
+ * Just ignore the error.
+ */
+ scn = MSDOSFSROOT;
+ }
+ }
-foundroot:;
+ if (isadir) {
+ cluster = scn;
+ if (cluster == MSDOSFSROOT)
+ blkoff = MSDOSFSROOT_OFS;
+ else
+ blkoff = 0;
+ } else if (cluster == MSDOSFSROOT)
+ blkoff = diroff;
+
+ /*
+ * Now release buf to allow deget to read the entry again.
+ * Reserving it here and giving it to deget could result
+ * in a deadlock.
+ */
+ brelse(bp);
+ bp = 0;
+
+foundroot:
/*
* If we entered at foundroot, then we are looking for the . or ..
* entry of the filesystems root directory. isadir and scn were
- * setup before jumping here. And, bp is null. There is no buf
- * header.
+ * setup before jumping here. And, bp is already null.
*/
+ if (FAT32(pmp) && scn == MSDOSFSROOT)
+ scn = pmp->pm_rootdirblk;
/*
- * If deleting and at the end of the path, then if we matched on
- * "." then don't deget() we would probably panic(). Otherwise
- * deget() the directory entry.
+ * If deleting, and at end of pathname, return
+ * parameters which can be used to remove file.
+ * If the wantparent flag isn't set, we return only
+ * the directory (in ndp->ni_dvp), otherwise we go
+ * on and lock the inode, being careful with ".".
*/
if (nameiop == DELETE && (flags & ISLASTCN)) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ /*
+ * Don't allow deleting the root.
+ */
+ if (blkoff == MSDOSFSROOT_OFS)
+ return EROFS; /* really? XXX */
+
+ /*
+ * Write access to directory required to delete files.
+ */
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error)
+ return (error);
+
+ /*
+ * Return pointer to current entry in dp->i_offset.
+ * Save directory inode pointer in ndp->ni_dvp for dirremove().
+ */
if (dp->de_StartCluster == scn && isadir) { /* "." */
VREF(vdp);
*vpp = vdp;
- if (bp)
- brelse(bp);
- return 0;
- }
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
+ return (0);
}
+ error = deget(pmp, cluster, blkoff, &tdp);
+ if (error)
+ return (error);
*vpp = DETOV(tdp);
if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- if (bp)
- brelse(bp);
- return 0;
+ return (0);
}
/*
- * If renaming.
+ * If rewriting (RENAME), return the inode and the
+ * information required to rewrite the present directory
+ * Must get inode of directory entry to verify it's a
+ * regular file, or empty directory.
*/
- if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
- if (dp->de_StartCluster == scn && isadir) {
- if (bp)
- brelse(bp);
- return EISDIR;
- }
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ if (nameiop == RENAME && wantparent &&
+ (flags & ISLASTCN)) {
+ if (blkoff == MSDOSFSROOT_OFS)
+ return EROFS; /* really? XXX */
+
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error)
+ return (error);
+
+ /*
+ * Careful about locking second inode.
+ * This can only occur if the target is ".".
+ */
+ if (dp->de_StartCluster == scn && isadir)
+ return (EISDIR);
+
+ if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ return (error);
*vpp = DETOV(tdp);
cnp->cn_flags |= SAVENAME;
if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- if (bp)
- brelse(bp);
- return 0;
+ return (0);
}
/*
- * ?
+ * Step through the translation in the name. We do not `vput' the
+ * directory because we may need it again if a symbolic link
+ * is relative to the current directory. Instead we save it
+ * unlocked as "pdp". We must get the target inode before unlocking
+ * the directory to insure that the inode will not be removed
+ * before we get it. We prevent deadlock by always fetching
+ * inodes from the root, moving down the directory tree. Thus
+ * when following backward pointers ".." we must unlock the
+ * parent directory before getting the requested directory.
+ * There is a potential race condition here if both the current
+ * and parent directories are removed before the VFS_VGET for the
+ * inode associated with ".." returns. We hope that this occurs
+ * infrequently since we cannot avoid this race condition without
+ * implementing a sophisticated deadlock detection algorithm.
+ * Note also that this simple deadlock detection scheme will not
+ * work if the file system has any hard links other than ".."
+ * that point backwards in the directory structure.
*/
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp, 0, p);
- error = deget(pmp, cluster, diroff, dep, &tdp);
+ error = deget(pmp, cluster, blkoff, &tdp);
if (error) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
- if (bp)
- brelse(bp);
- return error;
+ vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
}
- if (lockparent && (flags & ISLASTCN)
- && (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
+ if (lockparent && (flags & ISLASTCN) &&
+ (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
vput(DETOV(tdp));
- return error;
+ return (error);
}
*vpp = DETOV(tdp);
- } else if (dp->de_StartCluster == scn && isadir) { /* "." */
- VREF(vdp);
+ } else if (dp->de_StartCluster == scn && isadir) {
+ VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
} else {
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ return (error);
if (!lockparent || !(flags & ISLASTCN))
VOP_UNLOCK(pdp, 0, p);
*vpp = DETOV(tdp);
}
- if (bp)
- brelse(bp);
/*
- * Insert name in cache if wanted.
+ * Insert name into cache if appropriate.
*/
if (cnp->cn_flags & MAKEENTRY)
cache_enter(vdp, *vpp, cnp);
- return 0;
+ return (0);
}
/*
@@ -421,21 +538,26 @@ foundroot:;
* ddep - directory to add to
* depp - return the address of the denode for the created directory entry
* if depp != 0
+ * cnp - componentname needed for Win95 long filenames
*/
int
-createde(dep, ddep, depp)
+createde(dep, ddep, depp, cnp)
struct denode *dep;
struct denode *ddep;
struct denode **depp;
+ struct componentname *cnp;
{
int error;
u_long dirclust, diroffset;
struct direntry *ndep;
struct msdosfsmount *pmp = ddep->de_pmp;
struct buf *bp;
+ daddr_t bn;
+ int blsize;
#ifdef MSDOSFS_DEBUG
- printf("createde(dep %08x, ddep %08x, depp %08x)\n", dep, ddep, depp);
+ printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
+ dep, ddep, depp, cnp);
#endif
/*
@@ -446,104 +568,100 @@ createde(dep, ddep, depp)
* to extend the root directory. We just return an error in that
* case.
*/
- if (ddep->de_fndclust == (u_long)-1) {
- error = extendfile(ddep, 1, &bp, &dirclust, DE_CLEAR);
- if (error)
+ if (ddep->de_fndoffset >= ddep->de_FileSize) {
+ diroffset = ddep->de_fndoffset + sizeof(struct direntry)
+ - ddep->de_FileSize;
+ dirclust = de_clcount(pmp, diroffset);
+ error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
+ if (error) {
+ (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
return error;
- ndep = (struct direntry *) bp->b_data;
- /*
- * Let caller know where we put the directory entry.
- */
- ddep->de_fndclust = dirclust;
- ddep->de_fndoffset = diroffset = 0;
+ }
+
/*
* Update the size of the directory
*/
- ddep->de_FileSize += pmp->pm_bpcluster;
- } else {
- /*
- * There is space in the existing directory. So, we just
- * read in the cluster with space. Copy the new directory
- * entry in. Then write it to disk. NOTE: DOS directories
- * do not get smaller as clusters are emptied.
- */
- dirclust = ddep->de_fndclust;
- diroffset = ddep->de_fndoffset;
-
- error = readep(pmp, dirclust, diroffset, &bp, &ndep);
- if (error)
- return error;
+ ddep->de_FileSize += de_cn2off(pmp, dirclust);
}
- DE_EXTERNALIZE(ndep, dep);
/*
- * If they want us to return with the denode gotten.
+ * We just read in the cluster with space. Copy the new directory
+ * entry in. Then write it to disk. NOTE: DOS directories
+ * do not get smaller as clusters are emptied.
*/
- if (depp) {
- error = deget(pmp, dirclust, diroffset, ndep, depp);
- if (error)
- return error;
- }
- error = bwrite(bp);
- if (error) {
- vput(DETOV(*depp)); /* free the vnode we got on error */
+ error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
+ &bn, &dirclust, &blsize);
+ if (error)
+ return error;
+ diroffset = ddep->de_fndoffset;
+ if (dirclust != MSDOSFSROOT)
+ diroffset &= pmp->pm_crbomask;
+ if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
+ brelse(bp);
return error;
}
- return 0;
-}
+ ndep = bptoep(pmp, bp, ddep->de_fndoffset);
-/*
- * Read in a directory entry and mark it as being deleted.
- */
-static int
-markdeleted(pmp, dirclust, diroffset)
- struct msdosfsmount *pmp;
- u_long dirclust;
- u_long diroffset;
-{
- int error;
- struct direntry *ep;
- struct buf *bp;
+ DE_EXTERNALIZE(ndep, dep);
- error = readep(pmp, dirclust, diroffset, &bp, &ep);
- if (error)
- return error;
- ep->deName[0] = SLOT_DELETED;
- return bwrite(bp);
-}
+ /*
+ * Now write the Win95 long name
+ */
+ if (ddep->de_fndcnt > 0) {
+ u_int8_t chksum = winChksum(ndep->deName);
+ const u_char *un = (const u_char *)cnp->cn_nameptr;
+ int unlen = cnp->cn_namelen;
+ int cnt = 1;
-/*
- * Remove a directory entry. At this point the file represented by the
- * directory entry to be removed is still full length until no one has it
- * open. When the file no longer being used msdosfs_inactive() is called
- * and will truncate the file to 0 length. When the vnode containing the
- * denode is needed for some other purpose by VFS it will call
- * msdosfs_reclaim() which will remove the denode from the denode cache.
- */
-int
-removede(pdep,dep)
- struct denode *pdep; /* directory where the entry is removed */
- struct denode *dep; /* file to be removed */
-{
- struct msdosfsmount *pmp = pdep->de_pmp;
- int error;
+ while (--ddep->de_fndcnt >= 0) {
+ if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
+ if ((error = bwrite(bp)) != 0)
+ return error;
-#ifdef MSDOSFS_DEBUG
- printf("removede(): filename %s\n", dep->de_Name);
- printf("removede(): dep %08x, ndpcluster %d, ndpoffset %d\n",
- dep, pdep->de_fndclust, pdep->de_fndoffset);
-#endif
+ ddep->de_fndoffset -= sizeof(struct direntry);
+ error = pcbmap(ddep,
+ de_cluster(pmp,
+ ddep->de_fndoffset),
+ &bn, 0, &blsize);
+ if (error)
+ return error;
+
+ error = bread(pmp->pm_devvp, bn, blsize,
+ NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ ndep = bptoep(pmp, bp, ddep->de_fndoffset);
+ } else {
+ ndep--;
+ ddep->de_fndoffset -= sizeof(struct direntry);
+ }
+ if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum))
+ break;
+ }
+ }
+
+ if ((error = bwrite(bp)) != 0)
+ return error;
/*
- * Read the directory block containing the directory entry we are
- * to make free. The nameidata structure holds the cluster number
- * and directory entry index number of the entry to free.
+ * If they want us to return with the denode gotten.
*/
- error = markdeleted(pmp, pdep->de_fndclust, pdep->de_fndoffset);
+ if (depp) {
+ if (dep->de_Attributes & ATTR_DIRECTORY) {
+ dirclust = dep->de_StartCluster;
+ if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
+ dirclust = MSDOSFSROOT;
+ if (dirclust == MSDOSFSROOT)
+ diroffset = MSDOSFSROOT_OFS;
+ else
+ diroffset = 0;
+ }
+ return deget(pmp, dirclust, diroffset, depp);
+ }
- if (error == 0)
- dep->de_refcnt--;
- return error;
+ return 0;
}
/*
@@ -554,7 +672,7 @@ int
dosdirempty(dep)
struct denode *dep;
{
- int dei;
+ int blsize;
int error;
u_long cn;
daddr_t bn;
@@ -568,16 +686,21 @@ dosdirempty(dep)
* we hit end of file.
*/
for (cn = 0;; cn++) {
- error = pcbmap(dep, cn, &bn, 0);
- if (error == E2BIG)
- return 1; /* it's empty */
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
- &bp);
- if (error)
- return error;
- dentp = (struct direntry *) bp->b_data;
- for (dei = 0; dei < pmp->pm_depclust; dei++) {
- if (dentp->deName[0] != SLOT_DELETED) {
+ if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
+ if (error == E2BIG)
+ return (1); /* it's empty */
+ return (0);
+ }
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return (0);
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] != SLOT_DELETED &&
+ (dentp->deAttributes & ATTR_VOLUME) == 0) {
/*
* In dos directories an entry whose name
* starts with SLOT_EMPTY (0) starts the
@@ -587,7 +710,7 @@ dosdirempty(dep)
*/
if (dentp->deName[0] == SLOT_EMPTY) {
brelse(bp);
- return 1;
+ return (1);
}
/*
* Any names other than "." and ".." in a
@@ -597,13 +720,12 @@ dosdirempty(dep)
bcmp(dentp->deName, ".. ", 11)) {
brelse(bp);
#ifdef MSDOSFS_DEBUG
- printf("dosdirempty(): entry %d found %02x, %02x\n",
- dei, dentp->deName[0], dentp->deName[1]);
+ printf("dosdirempty(): entry found %02x, %02x\n",
+ dentp->deName[0], dentp->deName[1]);
#endif
- return 0; /* not empty */
+ return (0); /* not empty */
}
}
- dentp++;
}
brelse(bp);
}
@@ -647,18 +769,25 @@ doscheckpath(source, target)
}
if (dep->de_StartCluster == MSDOSFSROOT)
goto out;
+ pmp = dep->de_pmp;
+#ifdef DIAGNOSTIC
+ if (pmp != source->de_pmp)
+ panic("doscheckpath: source and target on different filesystems");
+#endif
+ if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
+ goto out;
+
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
- goto out;
+ break;
}
- pmp = dep->de_pmp;
scn = dep->de_StartCluster;
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
- pmp->pm_bpcluster, NOCRED, &bp);
- if (error) {
+ pmp->pm_bpcluster, NOCRED, &bp);
+ if (error)
break;
- }
+
ep = (struct direntry *) bp->b_data + 1;
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
bcmp(ep->deName, ".. ", 11) != 0) {
@@ -666,28 +795,38 @@ doscheckpath(source, target)
break;
}
scn = getushort(ep->deStartCluster);
+ if (FAT32(pmp))
+ scn |= getushort(ep->deHighClust) << 16;
+
if (scn == source->de_StartCluster) {
error = EINVAL;
break;
}
if (scn == MSDOSFSROOT)
break;
+ if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
+ /*
+ * scn should be 0 in this case,
+ * but we silently ignore the error.
+ */
+ break;
+ }
+
vput(DETOV(dep));
- /* NOTE: deget() clears dep on error */
- error = deget(pmp, scn, 0, ep, &dep);
brelse(bp);
bp = NULL;
- if (error)
+ /* NOTE: deget() clears dep on error */
+ if ((error = deget(pmp, scn, 0, &dep)) != 0)
break;
}
-out: ;
+out:;
if (bp)
brelse(bp);
if (error == ENOTDIR)
printf("doscheckpath(): .. not a directory?\n");
if (dep != NULL)
vput(DETOV(dep));
- return error;
+ return (error);
}
/*
@@ -696,27 +835,33 @@ out: ;
* directory entry within the block.
*/
int
-readep(pmp, dirclu, dirofs, bpp, epp)
+readep(pmp, dirclust, diroffset, bpp, epp)
struct msdosfsmount *pmp;
- u_long dirclu, dirofs;
+ u_long dirclust, diroffset;
struct buf **bpp;
struct direntry **epp;
{
int error;
daddr_t bn;
+ int blsize;
+ u_long boff;
- bn = detobn(pmp, dirclu, dirofs);
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp);
- if (error) {
+ boff = diroffset & ~pmp->pm_crbomask;
+ blsize = pmp->pm_bpcluster;
+ if (dirclust == MSDOSFSROOT
+ && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
+ blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
+ bn = detobn(pmp, dirclust, diroffset);
+ if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
+ brelse(*bpp);
*bpp = NULL;
- return error;
+ return (error);
}
if (epp)
- *epp = bptoep(pmp, *bpp, dirofs);
- return 0;
+ *epp = bptoep(pmp, *bpp, diroffset);
+ return (0);
}
-
/*
* Read in the disk block containing the directory entry dep came from and
* return the address of the buf header, and the address of the directory
@@ -728,6 +873,195 @@ readde(dep, bpp, epp)
struct buf **bpp;
struct direntry **epp;
{
- return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
- bpp, epp);
+
+ return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
+ bpp, epp));
+}
+
+/*
+ * Remove a directory entry. At this point the file represented by the
+ * directory entry to be removed is still full length until noone has it
+ * open. When the file no longer being used msdosfs_inactive() is called
+ * and will truncate the file to 0 length. When the vnode containing the
+ * denode is needed for some other purpose by VFS it will call
+ * msdosfs_reclaim() which will remove the denode from the denode cache.
+ */
+int
+removede(pdep, dep)
+ struct denode *pdep; /* directory where the entry is removed */
+ struct denode *dep; /* file to be removed */
+{
+ int error;
+ struct direntry *ep;
+ struct buf *bp;
+ daddr_t bn;
+ int blsize;
+ struct msdosfsmount *pmp = pdep->de_pmp;
+ u_long offset = pdep->de_fndoffset;
+
+#ifdef MSDOSFS_DEBUG
+ printf("removede(): filename %s, dep %p, offset %08lx\n",
+ dep->de_Name, dep, offset);
+#endif
+
+ dep->de_refcnt--;
+ offset += sizeof(struct direntry);
+ do {
+ offset -= sizeof(struct direntry);
+ error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
+ if (error)
+ return error;
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ ep = bptoep(pmp, bp, offset);
+ /*
+ * Check whether, if we came here the second time, i.e.
+ * when underflowing into the previous block, the last
+ * entry in this block is a longfilename entry, too.
+ */
+ if (ep->deAttributes != ATTR_WIN95
+ && offset != pdep->de_fndoffset) {
+ brelse(bp);
+ break;
+ }
+ offset += sizeof(struct direntry);
+ while (1) {
+ /*
+ * We are a bit agressive here in that we delete any Win95
+ * entries preceding this entry, not just the ones we "own".
+ * Since these presumably aren't valid anyway,
+ * there should be no harm.
+ */
+ offset -= sizeof(struct direntry);
+ ep--->deName[0] = SLOT_DELETED;
+ if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ || !(offset & pmp->pm_crbomask)
+ || ep->deAttributes != ATTR_WIN95)
+ break;
+ }
+ if ((error = bwrite(bp)) != 0)
+ return error;
+ } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ && !(offset & pmp->pm_crbomask)
+ && offset);
+ return 0;
+}
+
+/*
+ * Create a unique DOS name in dvp
+ */
+int
+uniqdosname(dep, cnp, cp)
+ struct denode *dep;
+ struct componentname *cnp;
+ u_char *cp;
+{
+ struct msdosfsmount *pmp = dep->de_pmp;
+ struct direntry *dentp;
+ int gen;
+ int blsize;
+ u_long cn;
+ daddr_t bn;
+ struct buf *bp;
+ int error;
+
+ for (gen = 1;; gen++) {
+ /*
+ * Generate DOS name with generation number
+ */
+ if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
+ cnp->cn_namelen, gen))
+ return gen == 1 ? EINVAL : EEXIST;
+
+ /*
+ * Now look for a dir entry with this exact name
+ */
+ for (cn = error = 0; !error; cn++) {
+ if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
+ if (error == E2BIG) /* EOF reached and not found */
+ return 0;
+ return error;
+ }
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ /*
+ * Last used entry and not found
+ */
+ brelse(bp);
+ return 0;
+ }
+ /*
+ * Ignore volume labels and Win95 entries
+ */
+ if (dentp->deAttributes & ATTR_VOLUME)
+ continue;
+ if (!bcmp(dentp->deName, cp, 11)) {
+ error = EEXIST;
+ break;
+ }
+ }
+ brelse(bp);
+ }
+ }
+}
+
+/*
+ * Find any Win'95 long filename entry in directory dep
+ */
+int
+findwin95(dep)
+ struct denode *dep;
+{
+ struct msdosfsmount *pmp = dep->de_pmp;
+ struct direntry *dentp;
+ int blsize;
+ u_long cn;
+ daddr_t bn;
+ struct buf *bp;
+
+ /*
+ * Read through the directory looking for Win'95 entries
+ * Note: Error currently handled just as EOF XXX
+ */
+ for (cn = 0;; cn++) {
+ if (pcbmap(dep, cn, &bn, 0, &blsize))
+ return 0;
+ if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ brelse(bp);
+ return 0;
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ /*
+ * Last used entry and not found
+ */
+ brelse(bp);
+ return 0;
+ }
+ if (dentp->deName[0] == SLOT_DELETED) {
+ /*
+ * Ignore deleted files
+ * Note: might be an indication of Win'95 anyway XXX
+ */
+ continue;
+ }
+ if (dentp->deAttributes == ATTR_WIN95) {
+ brelse(bp);
+ return 1;
+ }
+ }
+ brelse(bp);
+ }
}
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 1fc73f6..f552266 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_vfsops.c,v 1.22 1997/10/12 20:25:01 phk Exp $ */
-/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */
+/* $Id: msdosfs_vfsops.c,v 1.23 1997/11/12 05:42:19 julian Exp $ */
+/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 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).
*
@@ -59,6 +59,7 @@
#include <sys/buf.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
+#include <sys/stat.h> /* defines ALLPERMS */
#include <msdosfs/bpb.h>
#include <msdosfs/bootsect.h>
@@ -70,8 +71,9 @@
MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
+static int update_mp __P((struct mount *mp, struct msdosfs_args *argp));
static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
- struct proc *p));
+ struct proc *p, struct msdosfs_args *argp));
static int msdosfs_fhtovp __P((struct mount *, struct fid *,
struct sockaddr *, struct vnode **, int *,
struct ucred **));
@@ -90,6 +92,111 @@ static int msdosfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
static int msdosfs_vptofh __P((struct vnode *, struct fid *));
+static int
+update_mp(mp, argp)
+ struct mount *mp;
+ struct msdosfs_args *argp;
+{
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
+ int error;
+
+ pmp->pm_gid = argp->gid;
+ pmp->pm_uid = argp->uid;
+ pmp->pm_mask = argp->mask & ALLPERMS;
+ pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
+
+#ifndef __FreeBSD__
+ /*
+ * GEMDOS knows nothing (yet) about win95
+ */
+ if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS)
+ pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
+#endif
+
+ if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
+ else if (!(pmp->pm_flags &
+ (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
+ struct vnode *rootvp;
+
+ /*
+ * Try to divine whether to support Win'95 long filenames
+ */
+ if (FAT32(pmp))
+ pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
+ else {
+ if ((error = msdosfs_root(mp, &rootvp)) != 0)
+ return error;
+ pmp->pm_flags |= findwin95(VTODE(rootvp))
+ ? MSDOSFSMNT_LONGNAME
+ : MSDOSFSMNT_SHORTNAME;
+ vput(rootvp);
+ }
+ }
+ return 0;
+}
+
+#ifndef __FreeBSD__
+int
+msdosfs_mountroot()
+{
+ register struct mount *mp;
+ struct proc *p = curproc; /* XXX */
+ size_t size;
+ int error;
+ struct msdosfs_args args;
+
+ if (root_device->dv_class != DV_DISK)
+ return (ENODEV);
+
+ /*
+ * Get vnodes for swapdev and rootdev.
+ */
+ if (bdevvp(rootdev, &rootvp))
+ panic("msdosfs_mountroot: can't setup rootvp");
+
+ mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
+ bzero((char *)mp, (u_long)sizeof(struct mount));
+ mp->mnt_op = &msdosfs_vfsops;
+ mp->mnt_flag = 0;
+ LIST_INIT(&mp->mnt_vnodelist);
+
+ args.flags = 0;
+ args.uid = 0;
+ args.gid = 0;
+ args.mask = 0777;
+
+ if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) {
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ if ((error = update_mp(mp, &args)) != 0) {
+ (void)msdosfs_unmount(mp, 0, p);
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ if ((error = vfs_lock(mp)) != 0) {
+ (void)msdosfs_unmount(mp, 0, p);
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
+ mp->mnt_vnodecovered = NULLVP;
+ (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+ (void)msdosfs_statfs(mp, &mp->mnt_stat, p);
+ vfs_unlock(mp);
+ return (0);
+}
+#endif
+
/*
* mp - path - addr in user space of mount point (ie /usr or whatever)
* data - addr in user space of mount params including the name of the block
@@ -105,29 +212,27 @@ msdosfs_mount(mp, path, data, ndp, p)
{
struct vnode *devvp; /* vnode for blk device to mount */
struct msdosfs_args args; /* will hold data from mount request */
- struct msdosfsmount *pmp; /* msdosfs specific mount control block */
+ /* msdosfs specific mount control block */
+ struct msdosfsmount *pmp = NULL;
+ size_t size;
int error, flags;
- u_int size;
- struct ucred *cred, *scred;
- struct vattr va;
+ mode_t accessmode;
- /*
- * Copy in the args for the mount request.
- */
- error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
+ error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args));
if (error)
- return error;
-
+ return (error);
+ if (args.magic != MSDOSFS_ARGSMAGIC) {
+ printf("Old mount_msdosfs, flags=%d\n", args.flags);
+ args.flags = 0;
+ }
/*
- * If they just want to update then be sure we can do what is
- * asked. Can't change a filesystem from read/write to read only.
- * Why? And if they've supplied a new device file name then we
- * continue, otherwise return.
+ * If updating, check whether changing from read-only to
+ * read/write; if there is no device name, that's all we do.
*/
if (mp->mnt_flag & MNT_UPDATE) {
- pmp = (struct msdosfsmount *) mp->mnt_data;
+ pmp = VFSTOMSDOSFS(mp);
error = 0;
- if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
+ if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) {
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
@@ -135,214 +240,226 @@ msdosfs_mount(mp, path, data, ndp, p)
}
if (!error && (mp->mnt_flag & MNT_RELOAD))
/* not yet implemented */
- error = EINVAL;
+ error = EOPNOTSUPP;
if (error)
- return error;
- if (pmp->pm_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR))
- pmp->pm_ronly = 0;
+ return (error);
+ if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
+ /*
+ * If upgrade to read-write by non-root, then verify
+ * that user has necessary permissions on the device.
+ */
+ if (p->p_ucred->cr_uid != 0) {
+ devvp = pmp->pm_devvp;
+ vn_lock(devvp, LK_EXCLUSIVE, p);
+ error = VOP_ACCESS(devvp, VREAD | VWRITE,
+ p->p_ucred, p);
+ if (error) {
+ VOP_UNLOCK(devvp, 0, p);
+ return (error);
+ }
+ VOP_UNLOCK(devvp, 0, p);
+ }
+ pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
+ }
if (args.fspec == 0) {
+#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
+ if (args.flags & MSDOSFSMNT_MNTOPT) {
+ pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT;
+ pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
+ if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
+ }
+#endif
/*
* Process export requests.
*/
- return vfs_export(mp, &pmp->pm_export, &args.export);
+ return (vfs_export(mp, &pmp->pm_export, &args.export));
}
- } else
- pmp = NULL;
-
- /*
- * check to see that the user in owns the target directory.
- * Note the very XXX trick to make sure we're checking as the
- * real user -- were mount() executable by anyone, this wouldn't
- * be a problem.
- *
- * XXX there should be one consistent error out.
- */
- cred = crdup(p->p_ucred); /* XXX */
- cred->cr_uid = p->p_cred->p_ruid; /* XXX */
- error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
- if (error) {
- crfree(cred); /* XXX */
- return error;
- }
- if (cred->cr_uid != 0) {
- if (va.va_uid != cred->cr_uid) {
- error = EACCES;
- crfree(cred); /* XXX */
- return error;
- }
-
- /* a user mounted it; we'll verify permissions when unmounting */
- mp->mnt_flag |= MNT_USER;
}
-
/*
- * Now, lookup the name of the block device this mount or name
- * update request is to apply to.
+ * Not an update, or updating the name: look up the name
+ * and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
- scred = p->p_ucred; /* XXX */
- p->p_ucred = cred; /* XXX */
error = namei(ndp);
- p->p_ucred = scred; /* XXX */
- crfree(cred); /* XXX */
- if (error != 0)
- return error;
-
- /*
- * Be sure they've given us a block device to treat as a
- * filesystem. And, that its major number is within the bdevsw
- * table.
- */
+ if (error)
+ return (error);
devvp = ndp->ni_vp;
+
if (devvp->v_type != VBLK) {
vrele(devvp);
- return ENOTBLK;
+ return (ENOTBLK);
}
if (major(devvp->v_rdev) >= nblkdev) {
vrele(devvp);
- return ENXIO;
+ return (ENXIO);
}
-
/*
- * If this is an update, then make sure the vnode for the block
- * special device is the same as the one our filesystem is in.
+ * If mount by non-root, then verify that user has necessary
+ * permissions on the device.
*/
- if (mp->mnt_flag & MNT_UPDATE) {
+ if (p->p_ucred->cr_uid != 0) {
+ accessmode = VREAD;
+ if ((mp->mnt_flag & MNT_RDONLY) == 0)
+ accessmode |= VWRITE;
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
+ error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
+ if (error) {
+ vput(devvp);
+ return (error);
+ }
+ VOP_UNLOCK(devvp, 0, p);
+ }
+ if ((mp->mnt_flag & MNT_UPDATE) == 0) {
+ error = mountmsdosfs(devvp, mp, p, &args);
+#ifdef MSDOSFS_DEBUG /* only needed for the printf below */
+ pmp = VFSTOMSDOSFS(mp);
+#endif
+ } else {
if (devvp != pmp->pm_devvp)
- error = EINVAL;
+ error = EINVAL; /* XXX needs translation */
else
vrele(devvp);
- } else {
-
- /*
- * Well, it's not an update, it's a real mount request.
- * Time to get dirty.
- */
- error = mountmsdosfs(devvp, mp, p);
}
if (error) {
vrele(devvp);
+ return (error);
+ }
+
+ error = update_mp(mp, &args);
+ if (error) {
+ msdosfs_unmount(mp, MNT_FORCE, p);
return error;
}
- /*
- * Copy in the name of the directory the filesystem is to be
- * mounted on. Then copy in the name of the block special file
- * representing the filesystem being mounted. And we clear the
- * remainder of the character strings to be tidy. Set up the
- * user id/group id/mask as specified by the user. Then, we try to
- * fill in the filesystem stats structure as best we can with
- * whatever applies from a dos file system.
- */
- pmp = (struct msdosfsmount *) mp->mnt_data;
- copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
- sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
- bzero(mp->mnt_stat.f_mntonname + size,
- sizeof(mp->mnt_stat.f_mntonname) - size);
- copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
- bzero(mp->mnt_stat.f_mntfromname + size,
- MNAMELEN - size);
- pmp->pm_mounter = p->p_cred->p_ruid;
- pmp->pm_gid = args.gid;
- pmp->pm_uid = args.uid;
- pmp->pm_mask = args.mask;
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void) msdosfs_statfs(mp, &mp->mnt_stat, p);
#ifdef MSDOSFS_DEBUG
printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
#endif
- return 0;
+ return (0);
}
static int
-mountmsdosfs(devvp, mp, p)
+mountmsdosfs(devvp, mp, p, argp)
struct vnode *devvp;
struct mount *mp;
struct proc *p;
+ struct msdosfs_args *argp;
{
- int i;
- int bpc;
- int bit;
- int error;
- int needclose;
- int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+ struct msdosfsmount *pmp;
+ struct buf *bp;
dev_t dev = devvp->v_rdev;
+#ifndef __FreeBSD__
+ struct partinfo dpart;
+#endif
union bootsector *bsp;
- struct msdosfsmount *pmp = NULL;
- struct buf *bp0 = NULL;
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
#ifdef PC98
u_int pc98_wrk;
u_int Phy_Sector_Size;
#endif
+ struct byte_bpb710 *b710;
+ u_int8_t SecPerClust;
+ int ronly, error;
+ int bsize = 0, dtype = 0, tmp;
/*
- * Multiple mounts of the same block special file aren't allowed.
- * Make sure no one else has the special file open. And flush any
- * old buffers from this filesystem. Presumably this prevents us
- * from running into buffers that are the wrong blocksize.
+ * Disallow multiple mounts of the same device.
+ * Disallow mounting of a device that is currently in use
+ * (except for root, which might share swap device for miniroot).
+ * Flush out any old buffers remaining from a previous use.
*/
error = vfs_mountedon(devvp);
if (error)
- return error;
- if (vcount(devvp) > 1)
- return EBUSY;
+ return (error);
+ if (vcount(devvp) > 1 && devvp != rootvp)
+ return (EBUSY);
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
+ VOP_UNLOCK(devvp, 0, p);
if (error)
- return error;
+ return (error);
- /*
- * Now open the block special file.
- */
- error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
+ ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+ error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
if (error)
- return error;
- needclose = 1;
-#ifdef HDSUPPORT
- /*
- * Put this in when we support reading dos filesystems from
- * partitioned harddisks.
- */
- if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
+ return (error);
+
+ bp = NULL; /* both used in error_exit */
+ pmp = NULL;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ /*
+ * We need the disklabel to calculate the size of a FAT entry
+ * later on. Also make sure the partition contains a filesystem
+ * of type FS_MSDOS. This doesn't work for floppies, so we have
+ * to check for them too.
+ *
+ * At least some parts of the msdos fs driver seem to assume
+ * that the size of a disk block will always be 512 bytes.
+ * Let's check it...
+ */
+ error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart,
+ FREAD, NOCRED, p);
+ if (error)
+ goto error_exit;
+ tmp = dpart.part->p_fstype;
+ dtype = dpart.disklab->d_type;
+ bsize = dpart.disklab->d_secsize;
+ if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) {
+ error = EINVAL;
+ goto error_exit;
+ }
}
#endif
/*
- * Read the boot sector of the filesystem, and then check the boot
- * signature. If not a dos boot sector then error out. We could
- * also add some checking on the bsOemName field. So far I've seen
- * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0"
+ * Read the boot sector of the filesystem, and then check the
+ * boot signature. If not a dos boot sector then error out.
*/
#ifdef PC98
devvp->v_flag &= 0xffff;
- error = bread(devvp, 0, 1024, NOCRED, &bp0);
+ error = bread(devvp, 0, 1024, NOCRED, &bp);
#else
- error = bread(devvp, 0, 512, NOCRED, &bp0);
+ error = bread(devvp, 0, 512, NOCRED, &bp);
#endif
if (error)
goto error_exit;
- bp0->b_flags |= B_AGE;
- bsp = (union bootsector *) bp0->b_data;
- b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
- b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
-#ifdef MSDOSFS_CHECKSIG
-#ifdef PC98
- if (bsp->bs50.bsBootSectSig != BOOTSIG &&
- bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */
- bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */
- bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */
+ bp->b_flags |= B_AGE;
+ bsp = (union bootsector *)bp->b_data;
+ b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
+ b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
+ b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;
+
+#ifndef __FreeBSD__
+ if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
+#endif
+#ifdef PC98
+ if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
+ || bsp->bs50.bsBootSectSig1 != BOOTSIG1
+ && bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */
+ || bsp->bs50.bsBootSectSig1 != 0
+ && bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */
+ || bsp->bs50.bsBootSectSig1 != 0x3d
+ && bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */
+ || bsp->bs50.bsBootSectSig1 != 0xfa) {
#else
- if (bsp->bs50.bsBootSectSig != BOOTSIG) {
+ if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
+ || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
#endif
- error = EINVAL;
- goto error_exit;
+ error = EINVAL;
+ goto error_exit;
+ }
+#ifndef __FreeBSD__
}
#endif
- if ( bsp->bs50.bsJump[0] != 0xe9 &&
- (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
- error = EINVAL;
- goto error_exit;
- }
pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
bzero((caddr_t)pmp, sizeof *pmp);
@@ -353,28 +470,34 @@ mountmsdosfs(devvp, mp, p)
* bootsector. Copy in the dos 5 variant of the bpb then fix up
* the fields that are different between dos 5 and dos 3.3.
*/
+ SecPerClust = b50->bpbSecPerClust;
pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
- pmp->pm_SectPerClust = b50->bpbSecPerClust;
pmp->pm_ResSectors = getushort(b50->bpbResSectors);
pmp->pm_FATs = b50->bpbFATs;
pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
pmp->pm_Sectors = getushort(b50->bpbSectors);
- pmp->pm_Media = b50->bpbMedia;
pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
pmp->pm_Heads = getushort(b50->bpbHeads);
+ pmp->pm_Media = b50->bpbMedia;
- /* XXX - We should probably check more values here */
- if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
- !pmp->pm_Heads || pmp->pm_Heads > 255 ||
+#ifndef __FreeBSD__
+ if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
+#endif
+ /* XXX - We should probably check more values here */
+ if (!pmp->pm_BytesPerSec || !SecPerClust
+ || !pmp->pm_Heads || pmp->pm_Heads > 255
#ifdef PC98
- !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
+ || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
#else
- !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
+ || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
#endif
- error = EINVAL;
- goto error_exit;
+ error = EINVAL;
+ goto error_exit;
+ }
+#ifndef __FreeBSD__
}
+#endif
if (pmp->pm_Sectors == 0) {
pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
@@ -411,86 +534,193 @@ mountmsdosfs(devvp, mp, p)
}
pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
pmp->pm_BytesPerSec = Phy_Sector_Size;
- pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
+ SecPerClust = SecPerClust * pc98_wrk;
pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
#endif /* */
+ if (pmp->pm_HugeSectors > 0xffffffff / pmp->pm_BytesPerSec + 1) {
+ /*
+ * We cannot deal currently with this size of disk
+ * due to fileid limitations (see msdosfs_getattr and
+ * msdosfs_readdir)
+ */
+ error = EINVAL;
+ goto error_exit;
+ }
+
+ if (pmp->pm_RootDirEnts == 0) {
+ if (bsp->bs710.bsBootSectSig2 != BOOTSIG2
+ || bsp->bs710.bsBootSectSig3 != BOOTSIG3
+ || pmp->pm_Sectors
+ || pmp->pm_FATsecs
+ || getushort(b710->bpbFSVers)) {
+ error = EINVAL;
+ goto error_exit;
+ }
+ pmp->pm_fatmask = FAT32_MASK;
+ pmp->pm_fatmult = 4;
+ pmp->pm_fatdiv = 1;
+ pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
+ if (getushort(b710->bpbExtFlags) & FATMIRROR)
+ pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
+ else
+ pmp->pm_flags |= MSDOSFS_FATMIRROR;
+ } else
+ pmp->pm_flags |= MSDOSFS_FATMIRROR;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ if (FAT32(pmp)) {
+ /*
+ * GEMDOS doesn't know fat32.
+ */
+ error = EINVAL;
+ goto error_exit;
+ }
+
+ /*
+ * Check a few values (could do some more):
+ * - logical sector size: power of 2, >= block size
+ * - sectors per cluster: power of 2, >= 1
+ * - number of sectors: >= 1, <= size of partition
+ */
+ if ( (SecPerClust == 0)
+ || (SecPerClust & (SecPerClust - 1))
+ || (pmp->pm_BytesPerSec < bsize)
+ || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
+ || (pmp->pm_HugeSectors == 0)
+ || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
+ > dpart.part->p_size)
+ ) {
+ error = EINVAL;
+ goto error_exit;
+ }
+ /*
+ * XXX - Many parts of the msdos fs driver seem to assume that
+ * the number of bytes per logical sector (BytesPerSec) will
+ * always be the same as the number of bytes per disk block
+ * Let's pretend it is.
+ */
+ tmp = pmp->pm_BytesPerSec / bsize;
+ pmp->pm_BytesPerSec = bsize;
+ pmp->pm_HugeSectors *= tmp;
+ pmp->pm_HiddenSects *= tmp;
+ pmp->pm_ResSectors *= tmp;
+ pmp->pm_Sectors *= tmp;
+ pmp->pm_FATsecs *= tmp;
+ SecPerClust *= tmp;
+ }
+#endif
pmp->pm_fatblk = pmp->pm_ResSectors;
- pmp->pm_rootdirblk = pmp->pm_fatblk +
- (pmp->pm_FATs * pmp->pm_FATsecs);
- pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
- /
- pmp->pm_BytesPerSec;/* in sectors */
- pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
+ if (FAT32(pmp)) {
+ pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
+ pmp->pm_firstcluster = pmp->pm_fatblk
+ + (pmp->pm_FATs * pmp->pm_FATsecs);
+ pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
+ } else {
+ pmp->pm_rootdirblk = pmp->pm_fatblk +
+ (pmp->pm_FATs * pmp->pm_FATsecs);
+ pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
+ + pmp->pm_BytesPerSec - 1)
+ / pmp->pm_BytesPerSec;/* in sectors */
+ pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
+ }
+
pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
- pmp->pm_SectPerClust;
+ SecPerClust;
pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ if ((pmp->pm_nmbrofclusters <= (0xff0 - 2))
+ && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE)
+ && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2))))
+ ) {
+ pmp->pm_fatmask = FAT12_MASK;
+ pmp->pm_fatmult = 3;
+ pmp->pm_fatdiv = 2;
+ } else {
+ pmp->pm_fatmask = FAT16_MASK;
+ pmp->pm_fatmult = 2;
+ pmp->pm_fatdiv = 1;
+ }
+ } else
+#endif
+ if (pmp->pm_fatmask == 0) {
+ if (pmp->pm_maxcluster
+ <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
+ /*
+ * This will usually be a floppy disk. This size makes
+ * sure that one fat entry will not be split across
+ * multiple blocks.
+ */
+ pmp->pm_fatmask = FAT12_MASK;
+ pmp->pm_fatmult = 3;
+ pmp->pm_fatdiv = 2;
+ } else {
+ pmp->pm_fatmask = FAT16_MASK;
+ pmp->pm_fatmult = 2;
+ pmp->pm_fatdiv = 1;
+ }
+ }
if (FAT12(pmp))
- /*
- * This will usually be a floppy disk. This size makes sure
- * that one fat entry will not be split across multiple
- * blocks.
- */
pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
else
- /*
- * This will usually be a hard disk. Reading or writing one
- * block should be quite fast.
- */
pmp->pm_fatblocksize = MAXBSIZE;
- pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
-
- if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
- printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
+ pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
+ pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
/*
* Compute mask and shift value for isolating cluster relative byte
* offsets and cluster numbers from a file offset.
*/
- bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
- pmp->pm_bpcluster = bpc;
- pmp->pm_depclust = bpc / sizeof(struct direntry);
- pmp->pm_crbomask = bpc - 1;
- if (bpc == 0) {
+ pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
+ pmp->pm_crbomask = pmp->pm_bpcluster - 1;
+ pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
+
+ /*
+ * Check for valid cluster size
+ * must be a power of 2
+ */
+ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
error = EINVAL;
goto error_exit;
}
- bit = 1;
- for (i = 0; i < 32; i++) {
- if (bit & bpc) {
- if (bit ^ bpc) {
- error = EINVAL;
- goto error_exit;
- }
- pmp->pm_cnshift = i;
- break;
- }
- bit <<= 1;
- }
-#ifdef PC98
- if (Phy_Sector_Size == 512) {
- pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
- pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
- } else {
- pmp->pm_brbomask = 0x03ff;
- pmp->pm_bnshift = 10;
+ /*
+ * Release the bootsector buffer.
+ */
+ brelse(bp);
+ bp = NULL;
+
+ /*
+ * Check FSInfo.
+ */
+ if (pmp->pm_fsinfo) {
+ struct fsinfo *fp;
+
+ if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0)
+ goto error_exit;
+ fp = (struct fsinfo *)bp->b_data;
+ if (!bcmp(fp->fsisig1, "RRaA", 4)
+ && !bcmp(fp->fsisig2, "rrAa", 4)
+ && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
+ && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
+ pmp->pm_nxtfree = getulong(fp->fsinxtfree);
+ else
+ pmp->pm_fsinfo = 0;
+ brelse(bp);
+ bp = NULL;
}
-#else
- pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
- pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
-#endif
/*
- * Release the bootsector buffer.
+ * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
*/
- brelse(bp0);
- bp0 = NULL;
/*
* Allocate memory for the bitmap of allocated clusters, and then
@@ -510,8 +740,7 @@ mountmsdosfs(devvp, mp, p)
/*
* Have the inuse map filled in.
*/
- error = fillinusemap(pmp);
- if (error)
+ if ((error = fillinusemap(pmp)) != 0)
goto error_exit;
/*
@@ -520,13 +749,15 @@ mountmsdosfs(devvp, mp, p)
* the fat being correct just about all the time. I suppose this
* would be a good thing to turn on if the kernel is still flakey.
*/
- pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
+ if (mp->mnt_flag & MNT_SYNCHRONOUS)
+ pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
/*
* Finish up.
*/
- pmp->pm_ronly = ronly;
- if (ronly == 0)
+ if (ronly)
+ pmp->pm_flags |= MSDOSFSMNT_RONLY;
+ else
pmp->pm_fmod = 1;
mp->mnt_data = (qaddr_t) pmp;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
@@ -536,19 +767,17 @@ mountmsdosfs(devvp, mp, p)
return 0;
-error_exit:;
- if (bp0)
- brelse(bp0);
- if (needclose)
- (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
- NOCRED, p);
+error_exit:
+ if (bp)
+ brelse(bp);
+ (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p);
if (pmp) {
if (pmp->pm_inusemap)
- free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
- free((caddr_t) pmp, M_MSDOSFSMNT);
- mp->mnt_data = (qaddr_t) 0;
+ free(pmp->pm_inusemap, M_MSDOSFSFAT);
+ free(pmp, M_MSDOSFSMNT);
+ mp->mnt_data = (qaddr_t)0;
}
- return error;
+ return (error);
}
static int
@@ -557,7 +786,8 @@ msdosfs_start(mp, flags, p)
int flags;
struct proc *p;
{
- return 0;
+
+ return (0);
}
/*
@@ -569,30 +799,47 @@ msdosfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- int flags = 0;
- int error;
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
-
- /* only the mounter, or superuser can unmount */
- if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
- (error = suser(p->p_ucred, &p->p_acflag)))
- return error;
+ struct msdosfsmount *pmp;
+ int error, flags;
- if (mntflags & MNT_FORCE) {
+ flags = 0;
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
error = vflush(mp, NULLVP, flags);
if (error)
return error;
+ pmp = VFSTOMSDOSFS(mp);
pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
- error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
+#ifdef MSDOSFS_DEBUG
+ {
+ struct vnode *vp = pmp->pm_devvp;
+
+ printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
+ printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n",
+ vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
+ printf("lastr %d, id %lu, mount %p, op %p\n",
+ vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op);
+ printf("freef %p, freeb %p, mount %p\n",
+ vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev,
+ vp->v_mount);
+ printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n",
+ vp->v_cleanblkhd.lh_first,
+ vp->v_dirtyblkhd.lh_first,
+ vp->v_numoutput, vp->v_type);
+ printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
+ vp->v_socket, vp->v_tag,
+ ((u_int *)vp->v_data)[0],
+ ((u_int *)vp->v_data)[1]);
+ }
+#endif
+ error = VOP_CLOSE(pmp->pm_devvp, (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE,
NOCRED, p);
vrele(pmp->pm_devvp);
- free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
- free((caddr_t) pmp, M_MSDOSFSMNT);
- mp->mnt_data = (qaddr_t) 0;
+ free(pmp->pm_inusemap, M_MSDOSFSFAT);
+ free(pmp, M_MSDOSFSMNT);
+ mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
- return error;
+ return (error);
}
static int
@@ -600,18 +847,18 @@ msdosfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
struct denode *ndep;
- struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
int error;
- error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
- mp, pmp, ndep, DETOV(ndep));
+ printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
#endif
- if (error == 0)
- *vpp = DETOV(ndep);
- return error;
+ error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep);
+ if (error)
+ return (error);
+ *vpp = DETOV(ndep);
+ return (0);
}
static int
@@ -631,11 +878,9 @@ msdosfs_statfs(mp, sbp, p)
struct statfs *sbp;
struct proc *p;
{
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp;
- /*
- * Fill in the stat block.
- */
+ pmp = VFSTOMSDOSFS(mp);
sbp->f_bsize = pmp->pm_bpcluster;
sbp->f_iosize = pmp->pm_bpcluster;
sbp->f_blocks = pmp->pm_nmbrofclusters;
@@ -643,23 +888,13 @@ msdosfs_statfs(mp, sbp, p)
sbp->f_bavail = pmp->pm_freeclustercount;
sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
sbp->f_ffree = 0; /* what to put in here? */
-
- /*
- * Copy the mounted on and mounted from names into the passed in
- * stat block, if it is not the one in the mount structure.
- */
if (sbp != &mp->mnt_stat) {
sbp->f_type = mp->mnt_vfc->vfc_typenum;
- bcopy((caddr_t) mp->mnt_stat.f_mntonname,
- (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
- bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
- (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
-#if 0
- strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
- sbp->f_fstypename[MFSNAMELEN] = '\0';
-#endif
- return 0;
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return (0);
}
static int
@@ -669,39 +904,42 @@ msdosfs_sync(mp, waitfor, cred, p)
struct ucred *cred;
struct proc *p;
{
- struct vnode *vp;
+ struct vnode *vp, *nvp;
struct denode *dep;
- struct msdosfsmount *pmp;
- int error;
- int allerror = 0;
-
- pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
+ int error, allerror = 0;
/*
* If we ever switch to not updating all of the fats all the time,
* this would be the place to update them from the first one.
*/
- if (pmp->pm_fmod)
- if (pmp->pm_ronly)
+ if (pmp->pm_fmod != 0)
+ if (pmp->pm_flags & MSDOSFSMNT_RONLY)
panic("msdosfs_sync: rofs mod");
else {
/* update fats here */
}
-
/*
- * Go thru in memory denodes and write them out along with
- * unwritten file blocks.
+ * Write back each (modified) denode.
*/
simple_lock(&mntvnode_slock);
loop:
- for (vp = mp->mnt_vnodelist.lh_first; vp;
- vp = vp->v_mntvnodes.le_next) {
- if (vp->v_mount != mp) /* not ours anymore */
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = nvp) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * assoicated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
goto loop;
+
simple_lock(&vp->v_interlock);
+ nvp = vp->v_mntvnodes.le_next;
dep = VTODE(vp);
- if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
- vp->v_dirtyblkhd.lh_first == NULL) {
+ if (vp->v_type == VNON || ((dep->de_flag &
+ (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0)
+ && vp->v_dirtyblkhd.lh_first == NULL) {
simple_unlock(&vp->v_interlock);
continue;
}
@@ -728,7 +966,7 @@ loop:
error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
if (error)
allerror = error;
- return allerror;
+ return (allerror);
}
static int
@@ -740,7 +978,7 @@ msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
int *exflagsp;
struct ucred **credanonp;
{
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
struct defid *defhp = (struct defid *) fhp;
struct denode *dep;
struct netcred *np;
@@ -748,33 +986,33 @@ msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
np = vfs_export_lookup(mp, &pmp->pm_export, nam);
if (np == NULL)
- return EACCES;
- error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
- NULL, &dep);
+ return (EACCES);
+ error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
if (error) {
*vpp = NULLVP;
- return error;
+ return (error);
}
*vpp = DETOV(dep);
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
- return 0;
+ return (0);
}
-
static int
msdosfs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
- struct denode *dep = VTODE(vp);
- struct defid *defhp = (struct defid *) fhp;
+ struct denode *dep;
+ struct defid *defhp;
+ dep = VTODE(vp);
+ defhp = (struct defid *)fhp;
defhp->defid_len = sizeof(struct defid);
defhp->defid_dirclust = dep->de_dirclust;
defhp->defid_dirofs = dep->de_diroffset;
- /* defhp->defid_gen = ip->i_gen; */
- return 0;
+ /* defhp->defid_gen = dep->de_gen; */
+ return (0);
}
static int
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 3d7b3f7..a78a467 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_vnops.c,v 1.54 1998/02/04 22:33:01 eivind Exp $ */
-/* $NetBSD: msdosfs_vnops.c,v 1.20 1994/08/21 18:44:13 ws Exp $ */
+/* $Id: msdosfs_vnops.c,v 1.55 1998/02/06 12:13:46 eivind Exp $ */
+/* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 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).
*
@@ -140,38 +140,58 @@ msdosfs_create(ap)
int error;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
+ printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
#endif
/*
+ * If this is the root directory and there is no space left we
+ * can't do anything. This is because the root directory can not
+ * change size.
+ */
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
+ error = ENOSPC;
+ goto bad;
+ }
+
+ /*
* Create a directory entry for the file, then call createde() to
* have it installed. NOTE: DOS files are always executable. We
* use the absence of the owner write bit to make the file
* readonly.
*/
#ifdef DIAGNOSTIC
- if ((cnp->cn_flags & SAVENAME) == 0)
+ if ((cnp->cn_flags & HASBUF) == 0)
panic("msdosfs_create: no name");
#endif
bzero(&ndirent, sizeof(ndirent));
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &ndirent.de_Date, &ndirent.de_Time);
- unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
- ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE)
- ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
+ error = uniqdosname(pdep, cnp, ndirent.de_Name);
+ if (error)
+ goto bad;
+
+ ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
+ ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
ndirent.de_StartCluster = 0;
ndirent.de_FileSize = 0;
ndirent.de_dev = pdep->de_dev;
ndirent.de_devvp = pdep->de_devvp;
- if ((error = createde(&ndirent, pdep, &dep)) == 0) {
- *ap->a_vpp = DETOV(dep);
- if ((cnp->cn_flags & SAVESTART) == 0)
- zfree(namei_zone, cnp->cn_pnbuf);
- } else {
+ ndirent.de_pmp = pdep->de_pmp;
+ ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(&ndirent, &ts, &ts, &ts);
+ error = createde(&ndirent, pdep, &dep, cnp);
+ if (error)
+ goto bad;
+ if ((cnp->cn_flags & SAVESTART) == 0)
zfree(namei_zone, cnp->cn_pnbuf);
- }
- vput(ap->a_dvp); /* release parent dir */
- return error;
+ vput(ap->a_dvp);
+ *ap->a_vpp = DETOV(dep);
+ return (0);
+
+bad:
+ zfree(namei_zone, cnp->cn_pnbuf);
+ vput(ap->a_dvp);
+ return (error);
}
static int
@@ -183,24 +203,22 @@ msdosfs_mknod(ap)
struct vattr *a_vap;
} */ *ap;
{
- int error;
switch (ap->a_vap->va_type) {
case VDIR:
- error = msdosfs_mkdir((struct vop_mkdir_args *)ap);
+ return (msdosfs_mkdir((struct vop_mkdir_args *)ap));
break;
case VREG:
- error = msdosfs_create((struct vop_create_args *)ap);
+ return (msdosfs_create((struct vop_create_args *)ap));
break;
default:
- error = EINVAL;
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
vput(ap->a_dvp);
- break;
+ return (EINVAL);
}
- return error;
+ /* NOTREACHED */
}
static int
@@ -214,10 +232,13 @@ msdosfs_close(ap)
{
struct vnode *vp = ap->a_vp;
struct denode *dep = VTODE(vp);
+ struct timespec ts;
simple_lock(&vp->v_interlock);
- if (vp->v_usecount > 1)
- DE_TIMES(dep, &time);
+ if (vp->v_usecount > 1) {
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(dep, &ts, &ts, &ts);
+ }
simple_unlock(&vp->v_interlock);
return 0;
}
@@ -309,9 +330,15 @@ msdosfs_getattr(ap)
{
u_int cn;
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
struct vattr *vap = ap->a_vap;
+ mode_t mode;
+ struct timespec ts;
+ u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
+ u_long fileid;
- DE_TIMES(dep, &time);
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(dep, &ts, &ts, &ts);
vap->va_fsid = dep->de_dev;
/*
* The following computation of the fileid must be the same as that
@@ -319,41 +346,44 @@ msdosfs_getattr(ap)
* doesn't work.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
- if ((cn = dep->de_StartCluster) == MSDOSFSROOT)
- cn = 1;
+ fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
+ if (dep->de_StartCluster == MSDOSFSROOT)
+ fileid = 1;
} else {
- if ((cn = dep->de_dirclust) == MSDOSFSROOT)
- cn = 1;
- cn = (cn << 16) | (dep->de_diroffset & 0xffff);
+ fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
+ if (dep->de_dirclust == MSDOSFSROOT)
+ fileid = roottobn(pmp, 0) * dirsperblk;
+ fileid += dep->de_diroffset / sizeof(struct direntry);
}
- vap->va_fileid = cn;
- vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
- ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
- vap->va_mode &= dep->de_pmp->pm_mask;
- if (dep->de_Attributes & ATTR_DIRECTORY)
- vap->va_mode |= S_IFDIR;
+ vap->va_fileid = fileid;
+ if ((dep->de_Attributes & ATTR_READONLY) == 0)
+ mode = S_IRWXU|S_IRWXG|S_IRWXO;
+ else
+ mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+ vap->va_mode = mode & pmp->pm_mask;
+ vap->va_uid = pmp->pm_uid;
+ vap->va_gid = pmp->pm_gid;
vap->va_nlink = 1;
- vap->va_gid = dep->de_pmp->pm_gid;
- vap->va_uid = dep->de_pmp->pm_uid;
vap->va_rdev = 0;
vap->va_size = dep->de_FileSize;
- dos2unixtime(dep->de_Date, dep->de_Time, &vap->va_atime);
- vap->va_mtime = vap->va_atime;
-#if 0
-#ifndef MSDOSFS_NODIRMOD
- if (vap->va_mode & S_IFDIR)
- TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime);
-#endif
-#endif
- vap->va_ctime = vap->va_atime;
- vap->va_flags = (dep->de_Attributes & ATTR_ARCHIVE) ? 0 : SF_ARCHIVED;
+ dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
+ if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
+ dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
+ dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
+ } else {
+ vap->va_atime = vap->va_mtime;
+ vap->va_ctime = vap->va_mtime;
+ }
+ vap->va_flags = 0;
+ if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
+ vap->va_flags |= SF_ARCHIVED;
vap->va_gen = 0;
- vap->va_blocksize = dep->de_pmp->pm_bpcluster;
- vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
- ~(dep->de_pmp->pm_crbomask);
+ vap->va_blocksize = pmp->pm_bpcluster;
+ vap->va_bytes =
+ (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
vap->va_type = ap->a_vp->v_type;
vap->va_filerev = dep->de_modrev;
- return 0;
+ return (0);
}
static int
@@ -367,10 +397,16 @@ msdosfs_setattr(ap)
{
struct vnode *vp = ap->a_vp;
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
struct vattr *vap = ap->a_vap;
struct ucred *cred = ap->a_cred;
int error = 0;
+#ifdef MSDOSFS_DEBUG
+ printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n",
+ ap->a_vp, vap, cred, ap->a_p);
+#endif
+
/*
* Check for unsettable attributes.
*/
@@ -378,12 +414,21 @@ msdosfs_setattr(ap)
(vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
(vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
(vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+#ifdef MSDOSFS_DEBUG
+ printf("msdosfs_setattr(): returning EINVAL\n");
+ printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %lx\n",
+ vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
+ printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",
+ vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
+ printf(" va_uid %x, va_gid %x\n",
+ vap->va_uid, vap->va_gid);
+#endif
return (EINVAL);
}
if (vap->va_flags != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)))
return (error);
/*
@@ -411,19 +456,26 @@ msdosfs_setattr(ap)
dep->de_flag |= DE_MODIFIED;
}
- if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) {
+ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+ uid_t uid;
+ gid_t gid;
+
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if ((cred->cr_uid != dep->de_pmp->pm_uid ||
- vap->va_uid != dep->de_pmp->pm_uid ||
- (vap->va_gid != dep->de_pmp->pm_gid &&
- !groupmember(vap->va_gid, cred))) &&
+ uid = vap->va_uid;
+ if (uid == (uid_t)VNOVAL)
+ uid = pmp->pm_uid;
+ gid = vap->va_gid;
+ if (gid == (gid_t)VNOVAL)
+ gid = pmp->pm_gid;
+ if ((cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
+ (gid != pmp->pm_gid && !groupmember(gid, cred))) &&
(error = suser(cred, &ap->a_p->p_acflag)))
return error;
- if (vap->va_uid != dep->de_pmp->pm_uid ||
- vap->va_gid != dep->de_pmp->pm_gid)
+ if (uid != pmp->pm_uid || gid != pmp->pm_gid)
return EINVAL;
}
+
if (vap->va_size != VNOVAL) {
/*
* Disallow write attempts on read-only file systems;
@@ -443,41 +495,45 @@ msdosfs_setattr(ap)
if (error)
return error;
}
- if (vap->va_mtime.tv_sec != VNOVAL) {
+ if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)) &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
- (error = VOP_ACCESS(vp, VWRITE, cred, ap->a_p))))
- return error;
- dep->de_flag |= DE_UPDATE;
- error = deupdat(dep, &vap->va_mtime, 1);
- if (error)
- return error;
+ (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
+ return (error);
+ if (vp->v_type != VDIR) {
+ if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
+ vap->va_atime.tv_sec != VNOVAL)
+ unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
+ if (vap->va_mtime.tv_sec != VNOVAL)
+ unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
+ dep->de_Attributes |= ATTR_ARCHIVE;
+ dep->de_flag |= DE_MODIFIED;
+ }
}
-
/*
* DOS files only have the ability to have their writability
* attribute set, so we use the owner write bit to set the readonly
* attribute.
*/
- error = 0;
- if (vap->va_mode != (u_short) VNOVAL) {
+ if (vap->va_mode != (mode_t)VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)))
- return error;
-
- /* We ignore the read and execute bits */
- if (vap->va_mode & VWRITE)
- dep->de_Attributes &= ~ATTR_READONLY;
- else
- dep->de_Attributes |= ATTR_READONLY;
- dep->de_flag |= DE_MODIFIED;
+ return (error);
+ if (vp->v_type != VDIR) {
+ /* We ignore the read and execute bits. */
+ if (vap->va_mode & VWRITE)
+ dep->de_Attributes &= ~ATTR_READONLY;
+ else
+ dep->de_Attributes |= ATTR_READONLY;
+ dep->de_flag |= DE_MODIFIED;
+ }
}
- return error;
+ return (deupdat(dep, 1));
}
static int
@@ -491,11 +547,12 @@ msdosfs_read(ap)
{
int error = 0;
int diff;
+ int blsize;
int isadir;
long n;
long on;
daddr_t lbn;
- daddr_t rablock;
+ daddr_t rablock, rablock1;
int rasize;
struct buf *bp;
struct vnode *vp = ap->a_vp;
@@ -507,34 +564,33 @@ msdosfs_read(ap)
* If they didn't ask for any data, then we are done.
*/
if (uio->uio_resid == 0)
- return 0;
+ return (0);
if (uio->uio_offset < 0)
- return EINVAL;
+ return (EINVAL);
isadir = dep->de_Attributes & ATTR_DIRECTORY;
do {
- lbn = uio->uio_offset >> pmp->pm_cnshift;
+ lbn = de_cluster(pmp, uio->uio_offset);
on = uio->uio_offset & pmp->pm_crbomask;
n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
diff = dep->de_FileSize - uio->uio_offset;
if (diff <= 0)
- return 0;
+ return (0);
+ if (diff < n)
+ n = diff;
/* convert cluster # to block # if a directory */
if (isadir) {
- error = pcbmap(dep, lbn, &lbn, 0);
+ error = pcbmap(dep, lbn, &lbn, 0, &blsize);
if (error)
- return error;
+ return (error);
}
- if (diff < n)
- n = diff;
/*
* If we are operating on a directory file then be sure to
* do i/o with the vnode for the filesystem instead of the
* vnode for the directory.
*/
if (isadir) {
- error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
- NOCRED, &bp);
+ error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
} else {
rablock = lbn + 1;
#ifdef PC98
@@ -545,36 +601,28 @@ msdosfs_read(ap)
vp->v_flag |= 0x10000;
#endif
if (vp->v_lastr + 1 == lbn &&
- rablock * pmp->pm_bpcluster < dep->de_FileSize) {
+ de_cn2off(pmp, rablock) < dep->de_FileSize) {
+ rablock1 = de_cn2bn(pmp, rablock);
rasize = pmp->pm_bpcluster;
- error = breadn(vp, lbn, pmp->pm_bpcluster,
- &rablock, &rasize, 1,
- NOCRED, &bp);
- } else {
- error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
- &bp);
- }
+ error = breadn(vp, de_cn2bn(pmp, lbn),
+ pmp->pm_bpcluster, &rablock1, &rasize, 1,
+ NOCRED, &bp);
+ } else
+ error = bread(vp, de_cn2bn(pmp, lbn),
+ pmp->pm_bpcluster, NOCRED, &bp);
vp->v_lastr = lbn;
}
n = min(n, pmp->pm_bpcluster - bp->b_resid);
if (error) {
brelse(bp);
- return error;
+ return (error);
}
error = uiomove(bp->b_data + on, (int) n, uio);
- /*
- * If we have read everything from this block or have read
- * to end of file then we are done with this block. Mark
- * it to say the buffer can be reused if need be.
- */
-#if 0
- if (n + on == pmp->pm_bpcluster ||
- uio->uio_offset == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif
+ if (!isadir)
+ dep->de_flag |= DE_ACCESS;
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
- return error;
+ return (error);
}
/*
@@ -590,10 +638,9 @@ msdosfs_write(ap)
} */ *ap;
{
int n;
- int isadir;
int croffset;
int resid;
- int osize;
+ u_long osize;
int error = 0;
u_long count;
daddr_t bn, lastcn;
@@ -606,61 +653,43 @@ msdosfs_write(ap)
struct denode *dep = VTODE(vp);
struct msdosfsmount *pmp = dep->de_pmp;
struct ucred *cred = ap->a_cred;
- struct timespec ts;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
- vp, uio, ioflag, cred);
- printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
- dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
+ printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
+ vp, uio, ioflag, cred);
+ printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
+ dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
#endif
switch (vp->v_type) {
case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = dep->de_FileSize;
- isadir = 0;
thisvp = vp;
break;
-
case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("msdosfs_write(): non-sync directory update");
- isadir = 1;
- thisvp = pmp->pm_devvp;
- break;
-
+ return EISDIR;
default:
panic("msdosfs_write(): bad file type");
- break;
}
if (uio->uio_offset < 0)
- return EINVAL;
+ return (EINVAL);
if (uio->uio_resid == 0)
- return 0;
+ return (0);
/*
* If they've exceeded their filesize limit, tell them about it.
*/
- if (vp->v_type == VREG && p &&
+ if (p &&
((uio->uio_offset + uio->uio_resid) >
- p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
+ p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
psignal(p, SIGXFSZ);
- return EFBIG;
+ return (EFBIG);
}
/*
- * If attempting to write beyond the end of the root directory we
- * stop that here because the root directory can not grow.
- */
- if ((dep->de_Attributes & ATTR_DIRECTORY) &&
- dep->de_StartCluster == MSDOSFSROOT &&
- (uio->uio_offset + uio->uio_resid) > dep->de_FileSize)
- return ENOSPC;
-
- /*
* If the offset we are starting the write at is beyond the end of
* the file, then they've done a seek. Unix filesystems allow
* files with holes in them, DOS doesn't so we must fill the hole
@@ -669,7 +698,7 @@ msdosfs_write(ap)
if (uio->uio_offset > dep->de_FileSize) {
error = deextend(dep, uio->uio_offset, cred);
if (error)
- return error;
+ return (error);
}
/*
@@ -678,7 +707,6 @@ msdosfs_write(ap)
resid = uio->uio_resid;
osize = dep->de_FileSize;
-
#ifdef PC98
/*
* 1024byte/sector support
@@ -691,21 +719,17 @@ msdosfs_write(ap)
* size ahead of the time to hopefully get a contiguous area.
*/
if (uio->uio_offset + resid > osize) {
- count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize);
- if ((error = extendfile(dep, count, NULL, NULL, 0))
- && (error != ENOSPC || (ioflag & IO_UNIT)))
+ count = de_clcount(pmp, uio->uio_offset + resid) -
+ de_clcount(pmp, osize);
+ error = extendfile(dep, count, NULL, NULL, 0);
+ if (error && (error != ENOSPC || (ioflag & IO_UNIT)))
goto errexit;
lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
} else
lastcn = de_clcount(pmp, osize) - 1;
do {
- bn = de_blk(pmp, uio->uio_offset);
- if (isadir) {
- error = pcbmap(dep, bn, &bn, 0);
- if (error)
- break;
- } else if (bn > lastcn) {
+ if (de_cluster(pmp, uio->uio_offset) > lastcn) {
error = ENOSPC;
break;
}
@@ -718,6 +742,7 @@ msdosfs_write(ap)
vnode_pager_setsize(vp, dep->de_FileSize);
}
+ bn = de_blk(pmp, uio->uio_offset);
if ((uio->uio_offset & pmp->pm_crbomask) == 0
&& (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
|| uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
@@ -732,27 +757,28 @@ msdosfs_write(ap)
* Do the bmap now, since pcbmap needs buffers
* for the fat table. (see msdosfs_strategy)
*/
- if (!isadir) {
- if (bp->b_blkno == bp->b_lblkno) {
- error = pcbmap(dep, bp->b_lblkno,
- &bp->b_blkno, 0);
- if (error)
- bp->b_blkno = -1;
- }
- if (bp->b_blkno == -1) {
- brelse(bp);
- if (!error)
- error = EIO; /* XXX */
- break;
- }
+ if (bp->b_blkno == bp->b_lblkno) {
+ error = pcbmap(dep,
+ de_bn2cn(pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0);
+ if (error)
+ bp->b_blkno = -1;
+ }
+ if (bp->b_blkno == -1) {
+ brelse(bp);
+ if (!error)
+ error = EIO; /* XXX */
+ break;
}
} else {
/*
* The block we need to write into exists, so read it in.
*/
error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
- if (error)
+ if (error) {
+ brelse(bp);
break;
+ }
}
/*
@@ -774,9 +800,9 @@ msdosfs_write(ap)
*/
if (ioflag & IO_SYNC)
(void) bwrite(bp);
- else if (n + croffset == pmp->pm_bpcluster) {
+ else if (n + croffset == pmp->pm_bpcluster)
bawrite(bp);
- } else
+ else
bdwrite(bp);
dep->de_flag |= DE_UPDATE;
} while (error == 0 && uio->uio_resid > 0);
@@ -796,11 +822,9 @@ errexit:
if (uio->uio_resid != resid)
error = 0;
}
- } else if (ioflag & IO_SYNC) {
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- error = deupdat(dep, &ts, 1);
- }
- return error;
+ } else if (ioflag & IO_SYNC)
+ error = deupdat(dep, 1);
+ return (error);
}
/*
@@ -818,12 +842,9 @@ msdosfs_fsync(ap)
struct proc *a_p;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct buf *bp;
- int wait = ap->a_waitfor == MNT_WAIT;
- struct timespec ts;
- struct buf *nbp;
+ struct vnode *vp = ap->a_vp;
int s;
+ struct buf *bp, *nbp;
/*
* Flush all dirty buffers associated with a vnode.
@@ -853,8 +874,7 @@ loop:
}
#endif
splx(s);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- return deupdat(VTODE(vp), &ts, wait);
+ return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
}
static int
@@ -869,9 +889,12 @@ msdosfs_remove(ap)
struct denode *dep = VTODE(ap->a_vp);
struct denode *ddep = VTODE(ap->a_dvp);
- error = removede(ddep,dep);
+ if (ap->a_vp->v_type == VDIR)
+ error = EPERM;
+ else
+ error = removede(ddep, dep);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
+ printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
#endif
if (ddep == dep)
vrele(ap->a_vp);
@@ -879,7 +902,7 @@ msdosfs_remove(ap)
vput(ap->a_vp); /* causes msdosfs_inactive() to be called
* via vrele() */
vput(ap->a_dvp);
- return error;
+ return (error);
}
/*
@@ -962,22 +985,27 @@ msdosfs_rename(ap)
struct componentname *a_tcnp;
} */ *ap;
{
- u_char toname[11];
- int error;
- int newparent = 0;
- int sourceisadirectory = 0;
- u_long cn;
- daddr_t bn;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *fdvp = ap->a_fdvp;
struct vnode *tvp = ap->a_tvp;
+ struct componentname *tcnp = ap->a_tcnp;
struct componentname *fcnp = ap->a_fcnp;
struct proc *p = fcnp->cn_proc;
+ struct denode *ip, *xp, *dp, *zp;
+ u_char toname[11], oldname[11];
+ u_long from_diroffset, to_diroffset;
+ u_char to_count;
+ int doingdirectory = 0, newparent = 0;
+ int error;
+ u_long cn;
+ daddr_t bn;
struct denode *fddep; /* from file's parent directory */
struct denode *fdep; /* from file or directory */
struct denode *tddep; /* to file's parent directory */
struct denode *tdep; /* to file or directory */
struct msdosfsmount *pmp;
struct direntry *dotdotp;
- struct direntry *ep;
struct buf *bp;
fddep = VTODE(ap->a_fdvp);
@@ -986,28 +1014,46 @@ msdosfs_rename(ap)
tdep = tvp ? VTODE(tvp) : NULL;
pmp = fddep->de_pmp;
- /* Check for cross-device rename */
- if ((ap->a_fvp->v_mount != ap->a_tdvp->v_mount) ||
- (tvp && (ap->a_fvp->v_mount != tvp->v_mount))) {
- error = EXDEV;
- goto bad;
- }
+ pmp = VFSTOMSDOSFS(fdvp->v_mount);
+#ifdef DIAGNOSTIC
+ if ((tcnp->cn_flags & HASBUF) == 0 ||
+ (fcnp->cn_flags & HASBUF) == 0)
+ panic("msdosfs_rename: no name");
+#endif
/*
- * Convert the filename in tcnp into a dos filename. We copy this
- * into the denode and directory entry for the destination
- * file/directory.
+ * Check for cross-device rename.
*/
- unix2dosfn((u_char *) ap->a_tcnp->cn_nameptr,
- toname, ap->a_tcnp->cn_namelen);
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+abortit:
+ VOP_ABORTOP(tdvp, tcnp);
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ VOP_ABORTOP(fdvp, fcnp);
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+ }
/*
- * At this point this is the lock state of the denodes:
- * fddep referenced
- * fdep referenced
- * tddep locked
- * tdep locked if it exists
+ * If source and dest are the same, do nothing.
*/
+ if (tvp == fvp) {
+ error = 0;
+ goto abortit;
+ }
+
+ error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (error)
+ goto abortit;
+ dp = VTODE(fdvp);
+ ip = VTODE(fvp);
/*
* Be sure we are not renaming ".", "..", or an alias of ".". This
@@ -1015,218 +1061,270 @@ msdosfs_rename(ap)
* "ls" or "pwd" with the "." directory entry missing, and "cd .."
* doesn't work if the ".." entry is missing.
*/
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- if ((ap->a_fcnp->cn_namelen == 1
- && ap->a_fcnp->cn_nameptr[0] == '.')
- || fddep == fdep
- || (ap->a_fcnp->cn_flags | ap->a_tcnp->cn_flags)
- & ISDOTDOT) {
- VOP_ABORTOP(ap->a_tdvp, ap->a_tcnp);
- vput(ap->a_tdvp);
- if (tvp)
- vput(tvp);
- VOP_ABORTOP(ap->a_fdvp, ap->a_fcnp);
- vrele(ap->a_fdvp);
- vrele(ap->a_fvp);
- return EINVAL;
+ if (ip->de_Attributes & ATTR_DIRECTORY) {
+ /*
+ * Avoid ".", "..", and aliases of "." for obvious reasons.
+ */
+ if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
+ dp == ip ||
+ (fcnp->cn_flags & ISDOTDOT) ||
+ (tcnp->cn_flags & ISDOTDOT) ||
+ (ip->de_flag & DE_RENAME)) {
+ VOP_UNLOCK(fvp, 0, p);
+ error = EINVAL;
+ goto abortit;
}
- sourceisadirectory = 1;
+ ip->de_flag |= DE_RENAME;
+ doingdirectory++;
}
/*
- * If we are renaming a directory, and the directory is being moved
- * to another directory, then we must be sure the destination
- * directory is not in the subtree of the source directory. This
- * could orphan everything under the source directory.
- * doscheckpath() unlocks the destination's parent directory so we
- * must look it up again to relock it.
+ * When the target exists, both the directory
+ * and target vnodes are returned locked.
*/
- if (fddep->de_StartCluster != tddep->de_StartCluster)
+ dp = VTODE(tdvp);
+ xp = tvp ? VTODE(tvp) : NULL;
+ /*
+ * Remember direntry place to use for destination
+ */
+ to_diroffset = dp->de_fndoffset;
+ to_count = dp->de_fndcnt;
+
+ /*
+ * If ".." must be changed (ie the directory gets a new
+ * parent) then the source directory must not be in the
+ * directory heirarchy above the target, as this would
+ * orphan everything below the source directory. Also
+ * the user must have write permission in the source so
+ * as to be able to change "..". We must repeat the call
+ * to namei, as the parent directory is unlocked by the
+ * call to doscheckpath().
+ */
+ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
+ VOP_UNLOCK(fvp, 0, p);
+ if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
newparent = 1;
- if (sourceisadirectory && newparent) {
- if (tdep) {
- vput(ap->a_tvp);
- tdep = NULL;
- }
- /* doscheckpath() vput()'s tddep */
- error = doscheckpath(fdep, tddep);
- tddep = NULL;
- if (error)
+ vrele(fdvp);
+ if (doingdirectory && newparent) {
+ if (error) /* write access check above */
goto bad;
- if ((ap->a_tcnp->cn_flags & SAVESTART) == 0)
- panic("msdosfs_rename(): lost to startdir");
- error = relookup(ap->a_tdvp, &tvp, ap->a_tcnp);
+ if (xp != NULL)
+ vput(tvp);
+ /*
+ * doscheckpath() vput()'s dp,
+ * so we have to do a relookup afterwards
+ */
+ error = doscheckpath(ip, dp);
if (error)
- goto bad;
- tddep = VTODE(ap->a_tdvp);
- tdep = tvp ? VTODE(tvp) : NULL;
+ goto out;
+ if ((tcnp->cn_flags & SAVESTART) == 0)
+ panic("msdosfs_rename: lost to startdir");
+ error = relookup(tdvp, &tvp, tcnp);
+ if (error)
+ goto out;
+ dp = VTODE(tdvp);
+ xp = tvp ? VTODE(tvp) : NULL;
}
- /*
- * If the destination exists, then be sure its type (file or dir)
- * matches that of the source. And, if it is a directory make sure
- * it is empty. Then delete the destination.
- */
- if (tdep) {
- if (tdep->de_Attributes & ATTR_DIRECTORY) {
- if (!sourceisadirectory) {
- error = ENOTDIR;
- goto bad;
- }
- if (!dosdirempty(tdep)) {
+ if (xp != NULL) {
+ /*
+ * Target must be empty if a directory and have no links
+ * to it. Also, ensure source and target are compatible
+ * (both directories, or both not directories).
+ */
+ if (xp->de_Attributes & ATTR_DIRECTORY) {
+ if (!dosdirempty(xp)) {
error = ENOTEMPTY;
goto bad;
}
- cache_purge(DETOV(tddep));
- } else { /* destination is file */
- if (sourceisadirectory) {
- error = EISDIR;
+ if (!doingdirectory) {
+ error = ENOTDIR;
goto bad;
}
+ cache_purge(tdvp);
+ } else if (doingdirectory) {
+ error = EISDIR;
+ goto bad;
}
- error = removede(tddep,tdep);
+ error = removede(dp, xp);
if (error)
goto bad;
- vput(ap->a_tvp);
- tdep = NULL;
+ vput(tvp);
+ xp = NULL;
}
/*
- * If the source and destination are in the same directory then
- * just read in the directory entry, change the name in the
- * directory entry and write it back to disk.
+ * Convert the filename in tcnp into a dos filename. We copy this
+ * into the denode and directory entry for the destination
+ * file/directory.
*/
- if (newparent == 0) {
- /* tddep and fddep point to the same denode here */
- vn_lock(ap->a_fvp, LK_EXCLUSIVE, p); /* ap->a_fdvp is already locked */
- error = readep(fddep->de_pmp, fdep->de_dirclust,
- fdep->de_diroffset, &bp, &ep);
- if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- bcopy(toname, ep->deName, 11);
- error = bwrite(bp);
- if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- bcopy(toname, fdep->de_Name, 11); /* update denode */
+ error = uniqdosname(VTODE(tdvp), tcnp, toname);
+ if (error)
+ goto abortit;
+
+ /*
+ * Since from wasn't locked at various places above,
+ * have to do a relookup here.
+ */
+ fcnp->cn_flags &= ~MODMASK;
+ fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
+ if ((fcnp->cn_flags & SAVESTART) == 0)
+ panic("msdosfs_rename: lost from startdir");
+ if (!newparent)
+ VOP_UNLOCK(tdvp, 0, p);
+ (void) relookup(fdvp, &fvp, fcnp);
+ if (fvp == NULL) {
/*
- * fdep locked fddep and tddep point to the same denode
- * which is locked tdep is NULL
+ * From name has disappeared.
*/
+ if (doingdirectory)
+ panic("rename: lost dir entry");
+ vrele(ap->a_fvp);
+ if (newparent)
+ VOP_UNLOCK(tdvp, 0, p);
+ vrele(tdvp);
+ return 0;
+ }
+ xp = VTODE(fvp);
+ zp = VTODE(fdvp);
+ from_diroffset = zp->de_fndoffset;
+
+ /*
+ * Ensure that the directory entry still exists and has not
+ * changed till now. If the source is a file the entry may
+ * have been unlinked or renamed. In either case there is
+ * no further work to be done. If the source is a directory
+ * then it cannot have been rmdir'ed or renamed; this is
+ * prohibited by the DE_RENAME flag.
+ */
+ if (xp != ip) {
+ if (doingdirectory)
+ panic("rename: lost dir entry");
+ vrele(ap->a_fvp);
+ VOP_UNLOCK(fvp, 0, p);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ xp = NULL;
} else {
- u_long dirsize = 0L;
+ vrele(fvp);
+ xp = NULL;
/*
- * If the source and destination are in different
- * directories, then mark the entry in the source directory
- * as deleted and write a new entry in the destination
- * directory. Then move the denode to the correct hash
+ * First write a new entry in the destination
+ * directory and mark the entry in the source directory
+ * as deleted. Then move the denode to the correct hash
* chain for its new location in the filesystem. And, if
* we moved a directory, then update its .. entry to point
- * to the new parent directory. If we moved a directory
- * will also insure that the directory entry on disk has a
- * filesize of zero.
+ * to the new parent directory.
*/
- vn_lock(ap->a_fvp, LK_EXCLUSIVE, p);
- bcopy(toname, fdep->de_Name, 11); /* update denode */
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- dirsize = fdep->de_FileSize;
- fdep->de_FileSize = 0;
- }
- error = createde(fdep, tddep, (struct denode **) 0);
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- fdep->de_FileSize = dirsize;
- }
- if (error) {
- /* should put back filename */
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- vn_lock(ap->a_fdvp, LK_EXCLUSIVE, p);
- error = readep(fddep->de_pmp, fddep->de_fndclust,
- fddep->de_fndoffset, &bp, &ep);
+ bcopy(ip->de_Name, oldname, 11);
+ bcopy(toname, ip->de_Name, 11); /* update denode */
+ dp->de_fndoffset = to_diroffset;
+ dp->de_fndcnt = to_count;
+ error = createde(ip, dp, (struct denode **)0, tcnp);
if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ bcopy(oldname, ip->de_Name, 11);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- ep->deName[0] = SLOT_DELETED;
- error = bwrite(bp);
+ ip->de_refcnt++;
+ zp->de_fndoffset = from_diroffset;
+ error = removede(zp, ip);
if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ /* XXX should really panic here, fs is corrupt */
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- if (!sourceisadirectory) {
- fdep->de_dirclust = tddep->de_fndclust;
- fdep->de_diroffset = tddep->de_fndoffset;
- reinsert(fdep);
+ if (!doingdirectory) {
+ error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
+ &ip->de_dirclust, 0);
+ if (error) {
+ /* XXX should really panic here, fs is corrupt */
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
+ goto bad;
+ }
+ if (ip->de_dirclust != MSDOSFSROOT)
+ ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
}
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ reinsert(ip);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
}
- /* fdep is still locked here */
/*
* If we moved a directory to a new parent directory, then we must
* fixup the ".." entry in the moved directory.
*/
- if (sourceisadirectory && newparent) {
- cn = fdep->de_StartCluster;
+ if (doingdirectory && newparent) {
+ cn = ip->de_StartCluster;
if (cn == MSDOSFSROOT) {
/* this should never happen */
panic("msdosfs_rename(): updating .. in root directory?");
- } else {
+ } else
bn = cntobn(pmp, cn);
- }
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
NOCRED, &bp);
if (error) {
- /* should really panic here, fs is corrupt */
- VOP_UNLOCK(ap->a_fvp, 0, p);
+ /* XXX should really panic here, fs is corrupt */
+ brelse(bp);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- dotdotp = (struct direntry *) bp->b_data + 1;
- putushort(dotdotp->deStartCluster, tddep->de_StartCluster);
+ dotdotp = (struct direntry *)bp->b_data + 1;
+ putushort(dotdotp->deStartCluster, dp->de_StartCluster);
+ if (FAT32(pmp))
+ putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
error = bwrite(bp);
- VOP_UNLOCK(ap->a_fvp, 0, p);
if (error) {
- /* should really panic here, fs is corrupt */
+ /* XXX should really panic here, fs is corrupt */
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- } else
- VOP_UNLOCK(ap->a_fvp, 0, p);
-bad: ;
- vrele(DETOV(fdep));
- vrele(DETOV(fddep));
- if (tdep)
- vput(DETOV(tdep));
- if (tddep)
- vput(DETOV(tddep));
- return error;
+ }
+
+ VOP_UNLOCK(fvp, 0, p);
+bad:
+ if (xp)
+ vput(tvp);
+ vput(tdvp);
+out:
+ ip->de_flag &= ~DE_RENAME;
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+
}
static struct {
struct direntry dot;
struct direntry dotdot;
-} dosdirtemplate = {
- {
- ". ", " ", /* the . entry */
- ATTR_DIRECTORY, /* file attribute */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
- {210, 4}, {210, 4}, /* time and date */
- {0, 0}, /* startcluster */
- {0, 0, 0, 0}, /* filesize */
- },{
- ".. ", " ", /* the .. entry */
- ATTR_DIRECTORY, /* file attribute */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
- {210, 4}, {210, 4}, /* time and date */
- {0, 0}, /* startcluster */
- {0, 0, 0, 0}, /* filesize */
- }
+} dosdirtemplate = {
+ { ". ", " ", /* the . entry */
+ ATTR_DIRECTORY, /* file attribute */
+ 0, /* reserved */
+ 0, { 0, 0 }, { 0, 0 }, /* create time & date */
+ { 0, 0 }, /* access date */
+ { 0, 0 }, /* high bits of start cluster */
+ { 210, 4 }, { 210, 4 }, /* modify time & date */
+ { 0, 0 }, /* startcluster */
+ { 0, 0, 0, 0 } /* filesize */
+ },
+ { ".. ", " ", /* the .. entry */
+ ATTR_DIRECTORY, /* file attribute */
+ 0, /* reserved */
+ 0, { 0, 0 }, { 0, 0 }, /* create time & date */
+ { 0, 0 }, /* access date */
+ { 0, 0 }, /* high bits of start cluster */
+ { 210, 4 }, { 210, 4 }, /* modify time & date */
+ { 0, 0 }, /* startcluster */
+ { 0, 0, 0, 0 } /* filesize */
+ }
};
static int
@@ -1238,42 +1336,41 @@ msdosfs_mkdir(ap)
struct vattr *a_vap;
} */ *ap;
{
- int bn;
+ struct componentname *cnp = ap->a_cnp;
+ struct denode ndirent;
+ struct denode *dep;
+ struct denode *pdep = VTODE(ap->a_dvp);
int error;
- u_long newcluster;
- struct denode *pdep;
- struct denode *ndep;
+ int bn;
+ u_long newcluster, pcl;
struct direntry *denp;
- struct denode ndirent;
- struct msdosfsmount *pmp;
+ struct msdosfsmount *pmp = pdep->de_pmp;
struct buf *bp;
struct timespec ts;
- u_short dDate, dTime;
-
- pdep = VTODE(ap->a_dvp);
/*
* If this is the root directory and there is no space left we
* can't do anything. This is because the root directory can not
* change size.
*/
- if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndclust == (u_long)-1) {
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return ENOSPC;
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
+ error = ENOSPC;
+ goto bad2;
}
- pmp = pdep->de_pmp;
-
/*
* Allocate a cluster to hold the about to be created directory.
*/
error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
- if (error) {
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return error;
- }
+ if (error)
+ goto bad2;
+
+ bzero(&ndirent, sizeof(ndirent));
+ ndirent.de_pmp = pmp;
+ ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(&ndirent, &ts, &ts, &ts);
/*
* Now fill the cluster with the "." and ".." entries. And write
@@ -1285,50 +1382,66 @@ msdosfs_mkdir(ap)
bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
bzero(bp->b_data, pmp->pm_bpcluster);
bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
- denp = (struct direntry *) bp->b_data;
- putushort(denp->deStartCluster, newcluster);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &dDate, &dTime);
- putushort(denp->deDate, dDate);
- putushort(denp->deTime, dTime);
- denp++;
- putushort(denp->deStartCluster, pdep->de_StartCluster);
- putushort(denp->deDate, dDate);
- putushort(denp->deTime, dTime);
- error = bwrite(bp);
- if (error) {
- clusterfree(pmp, newcluster, NULL);
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return error;
+ denp = (struct direntry *)bp->b_data;
+ putushort(denp[0].deStartCluster, newcluster);
+ putushort(denp[0].deCDate, ndirent.de_CDate);
+ putushort(denp[0].deCTime, ndirent.de_CTime);
+ denp[0].deCHundredth = ndirent.de_CHun;
+ putushort(denp[0].deADate, ndirent.de_ADate);
+ putushort(denp[0].deMDate, ndirent.de_MDate);
+ putushort(denp[0].deMTime, ndirent.de_MTime);
+ pcl = pdep->de_StartCluster;
+ if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
+ pcl = 0;
+ putushort(denp[1].deStartCluster, pcl);
+ putushort(denp[1].deCDate, ndirent.de_CDate);
+ putushort(denp[1].deCTime, ndirent.de_CTime);
+ denp[1].deCHundredth = ndirent.de_CHun;
+ putushort(denp[1].deADate, ndirent.de_ADate);
+ putushort(denp[1].deMDate, ndirent.de_MDate);
+ putushort(denp[1].deMTime, ndirent.de_MTime);
+ if (FAT32(pmp)) {
+ putushort(denp[0].deHighClust, newcluster >> 16);
+ putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
}
+ error = bwrite(bp);
+ if (error)
+ goto bad;
+
/*
* Now build up a directory entry pointing to the newly allocated
* cluster. This will be written to an empty slot in the parent
* directory.
*/
- ndep = &ndirent;
- bzero(ndep, sizeof(*ndep));
- unix2dosfn((u_char *)ap->a_cnp->cn_nameptr,
- ndep->de_Name, ap->a_cnp->cn_namelen);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &ndep->de_Date, &ndep->de_Time);
- ndep->de_StartCluster = newcluster;
- ndep->de_Attributes = ATTR_DIRECTORY;
-
- error = createde(ndep, pdep, &ndep);
- if (error) {
- clusterfree(pmp, newcluster, NULL);
- } else {
- *ap->a_vpp = DETOV(ndep);
- }
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
-#ifdef MSDOSFS_DEBUG
- printf("msdosfs_mkdir(): vput(%08x)\n", ap->a_dvp);
+#ifdef DIAGNOSTIC
+ if ((cnp->cn_flags & HASBUF) == 0)
+ panic("msdosfs_mkdir: no name");
#endif
+ error = uniqdosname(pdep, cnp, ndirent.de_Name);
+ if (error)
+ goto bad;
+
+ ndirent.de_Attributes = ATTR_DIRECTORY;
+ ndirent.de_StartCluster = newcluster;
+ ndirent.de_FileSize = 0;
+ ndirent.de_dev = pdep->de_dev;
+ ndirent.de_devvp = pdep->de_devvp;
+ error = createde(&ndirent, pdep, &dep, cnp);
+ if (error)
+ goto bad;
+ if ((cnp->cn_flags & SAVESTART) == 0)
+ zfree(namei_zone, cnp->cn_pnbuf);
vput(ap->a_dvp);
- return error;
+ *ap->a_vpp = DETOV(dep);
+ return (0);
+
+bad:
+ clusterfree(pmp, newcluster, NULL);
+bad2:
+ zfree(namei_zone, cnp->cn_pnbuf);
+ vput(ap->a_dvp);
+ return (error);
}
static int
@@ -1339,21 +1452,27 @@ msdosfs_rmdir(ap)
struct componentname *a_cnp;
} */ *ap;
{
- struct denode *ddep;
- struct denode *dep;
- int error = 0;
-
- ddep = VTODE(ap->a_dvp); /* parent dir of dir to delete */
- dep = VTODE(ap->a_vp);/* directory to delete */
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ register struct denode *ip, *dp;
+ int error;
+
+ ip = VTODE(vp);
+ dp = VTODE(dvp);
/*
- * Be sure the directory being deleted is empty.
+ * Verify the directory is empty (and valid).
+ * (Rmdir ".." won't be valid since
+ * ".." will contain a reference to
+ * the current directory and thus be
+ * non-empty.)
*/
- if (dosdirempty(dep) == 0) {
+ error = 0;
+ if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
error = ENOTEMPTY;
goto out;
}
-
/*
* Delete the entry from the directory. For dos filesystems this
* gets rid of the directory entry on disk, the in memory copy
@@ -1362,30 +1481,27 @@ msdosfs_rmdir(ap)
* up access and eventually msdosfs_reclaim() will be called which
* will remove it from the denode cache.
*/
- error = removede(ddep,dep);
+ error = removede(dp, ip);
if (error)
goto out;
-
/*
* This is where we decrement the link count in the parent
* directory. Since dos filesystems don't do this we just purge
* the name cache and let go of the parent directory denode.
*/
- cache_purge(DETOV(ddep));
- vput(ap->a_dvp);
- ap->a_dvp = NULL;
-
+ cache_purge(dvp);
+ vput(dvp);
+ dvp = NULL;
/*
* Truncate the directory that is being deleted.
*/
- error = detrunc(dep, (u_long) 0, IO_SYNC, NOCRED, NULL);
- cache_purge(DETOV(dep));
-
-out: ;
- if (ap->a_dvp)
- vput(ap->a_dvp);
- vput(ap->a_vp);
- return error;
+ error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
+ cache_purge(vp);
+out:
+ if (dvp)
+ vput(dvp);
+ vput(vp);
+ return (error);
}
/*
@@ -1402,39 +1518,11 @@ msdosfs_symlink(ap)
} */ *ap;
{
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
vput(ap->a_dvp);
- return EINVAL;
+ return (EOPNOTSUPP);
}
-/*
- * Dummy dirents to simulate the "." and ".." entries of the root directory
- * in a dos filesystem. Dos doesn't provide these. Note that each entry
- * must be the same size as a dos directory entry (32 bytes).
- */
-static struct dos_dirent {
- u_long d_fileno;
- u_short d_reclen;
- u_char d_type;
- u_char d_namlen;
- u_char d_name[24];
-} rootdots[2] = {
-
- {
- 1, /* d_fileno */
- sizeof(struct direntry), /* d_reclen */
- DT_DIR, /* d_type */
- 1, /* d_namlen */
- "." /* d_name */
- },
- {
- 1, /* d_fileno */
- sizeof(struct direntry), /* d_reclen */
- DT_DIR, /* d_type */
- 2, /* d_namlen */
- ".." /* d_name */
- }
-};
-
static int
msdosfs_readdir(ap)
struct vop_readdir_args /* {
@@ -1448,30 +1536,30 @@ msdosfs_readdir(ap)
{
int error = 0;
int diff;
- char pushout;
long n;
+ int blsize;
long on;
long lost;
long count;
u_long cn;
u_long fileno;
+ u_long dirsperblk;
long bias = 0;
- daddr_t bn;
- daddr_t lbn;
+ daddr_t bn, lbn;
struct buf *bp;
struct denode *dep = VTODE(ap->a_vp);
struct msdosfsmount *pmp = dep->de_pmp;
struct direntry *dentp;
- struct dirent *prev;
- struct dirent *crnt;
- u_char dirbuf[512]; /* holds converted dos directories */
+ struct dirent dirbuf;
struct uio *uio = ap->a_uio;
- off_t off;
+ u_long *cookies = NULL;
int ncookies = 0;
+ off_t offset, off;
+ int chksum = -1;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
- ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
+ printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
+ ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
#endif
/*
@@ -1481,7 +1569,12 @@ msdosfs_readdir(ap)
* So, fail attempts to readdir() on a plain file.
*/
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
- return ENOTDIR;
+ return (ENOTDIR);
+
+ /*
+ * To be safe, initialize dirbuf
+ */
+ bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
/*
* If the user buffer is smaller than the size of one dos directory
@@ -1489,13 +1582,22 @@ msdosfs_readdir(ap)
* directory entry, then we fail the read.
*/
count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
- lost = uio->uio_resid - count;
+ offset = uio->uio_offset;
if (count < sizeof(struct direntry) ||
- (uio->uio_offset & (sizeof(struct direntry) - 1)))
- return EINVAL;
+ (offset & (sizeof(struct direntry) - 1)))
+ return (EINVAL);
+ lost = uio->uio_resid - count;
uio->uio_resid = count;
- uio->uio_iov->iov_len = count;
- off = uio->uio_offset;
+
+ if (ap->a_ncookies) {
+ ncookies = uio->uio_resid / 16;
+ MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
+ M_WAITOK);
+ *ap->a_cookies = cookies;
+ *ap->a_ncookies = ncookies;
+ }
+
+ dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
/*
* If they are reading from the root directory then, we simulate
@@ -1504,194 +1606,184 @@ msdosfs_readdir(ap)
* simulate these entries. By this I mean that at file offset 64 we
* read the first entry in the root directory that lives on disk.
*/
- if (dep->de_StartCluster == MSDOSFSROOT) {
- /*
- * printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
- * uio->uio_offset);
- */
+ if (dep->de_StartCluster == MSDOSFSROOT
+ || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
+#if 0
+ printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
+ offset);
+#endif
bias = 2 * sizeof(struct direntry);
- if (uio->uio_offset < 2 * sizeof(struct direntry)) {
- if (uio->uio_offset
- && uio->uio_offset != sizeof(struct direntry)) {
- error = EINVAL;
- goto out;
- }
- n = 1;
- if (!uio->uio_offset) {
- n = 2;
- ncookies++;
+ if (offset < bias) {
+ for (n = (int)offset / sizeof(struct direntry);
+ n < 2; n++) {
+ if (FAT32(pmp))
+ dirbuf.d_fileno = cntobn(pmp,
+ pmp->pm_rootdirblk)
+ * dirsperblk;
+ else
+ dirbuf.d_fileno = 1;
+ dirbuf.d_type = DT_DIR;
+ switch (n) {
+ case 0:
+ dirbuf.d_namlen = 1;
+ strcpy(dirbuf.d_name, ".");
+ break;
+ case 1:
+ dirbuf.d_namlen = 2;
+ strcpy(dirbuf.d_name, "..");
+ break;
+ }
+ dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
+ if (uio->uio_resid < dirbuf.d_reclen)
+ goto out;
+ error = uiomove((caddr_t) &dirbuf,
+ dirbuf.d_reclen, uio);
+ if (error)
+ goto out;
+ if (cookies) {
+ *cookies++ = offset;
+ if (--ncookies <= 0)
+ goto out;
+ }
+ offset += sizeof(struct direntry);
}
- ncookies++;
- error = uiomove((char *) rootdots + uio->uio_offset,
- n * sizeof(struct direntry), uio);
}
}
- while (!error && uio->uio_resid > 0) {
- lbn = (uio->uio_offset - bias) >> pmp->pm_cnshift;
- on = (uio->uio_offset - bias) & pmp->pm_crbomask;
- n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
- diff = dep->de_FileSize - (uio->uio_offset - bias);
+
+ off = offset;
+ while (uio->uio_resid > 0) {
+ lbn = de_cluster(pmp, offset - bias);
+ on = (offset - bias) & pmp->pm_crbomask;
+ n = min(pmp->pm_bpcluster - on, uio->uio_resid);
+ diff = dep->de_FileSize - (offset - bias);
if (diff <= 0)
break;
- if (diff < n)
- n = diff;
- error = pcbmap(dep, lbn, &bn, &cn);
+ n = min(n, diff);
+ error = pcbmap(dep, lbn, &bn, &cn, &blsize);
if (error)
break;
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
- n = min(n, pmp->pm_bpcluster - bp->b_resid);
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
if (error) {
brelse(bp);
- return error;
+ return (error);
}
+ n = min(n, blsize - bp->b_resid);
/*
- * code to convert from dos directory entries to ufs
- * directory entries
+ * Convert from dos directory entries to fs-independent
+ * directory entries.
*/
- pushout = 0;
- dentp = (struct direntry *)(bp->b_data + on);
- prev = 0;
- crnt = (struct dirent *) dirbuf;
- while ((char *) dentp < bp->b_data + on + n) {
+ for (dentp = (struct direntry *)(bp->b_data + on);
+ (char *)dentp < bp->b_data + on + n;
+ dentp++, offset += sizeof(struct direntry)) {
+#if 0
+ printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
+ dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
+#endif
/*
- * printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
- * dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
+ * If this is an unused entry, we can stop.
*/
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ brelse(bp);
+ goto out;
+ }
/*
- * If we have an empty entry or a slot from a
- * deleted file, or a volume label entry just
- * concatenate its space onto the end of the
- * previous entry or, manufacture an empty entry if
- * there is no previous entry.
+ * Skip deleted entries.
*/
- if (dentp->deName[0] == SLOT_EMPTY ||
- dentp->deName[0] == SLOT_DELETED ||
- (dentp->deAttributes & ATTR_VOLUME)) {
- if (prev) {
- prev->d_reclen += sizeof(struct direntry);
- } else {
- prev = crnt;
- prev->d_fileno = 0;
- prev->d_reclen = sizeof(struct direntry);
- prev->d_type = DT_UNKNOWN;
- prev->d_namlen = 0;
- prev->d_name[0] = 0;
- ncookies++;
- }
- } else {
- /*
- * this computation of d_fileno must match
- * the computation of va_fileid in
- * msdosfs_getattr
- */
- if (dentp->deAttributes & ATTR_DIRECTORY) {
- /* if this is the root directory */
- fileno = getushort(dentp->deStartCluster);
- if (fileno == MSDOSFSROOT)
- fileno = 1;
- } else {
- /*
- * if the file's dirent lives in
- * root dir
- */
- if ((fileno = cn) == MSDOSFSROOT)
- fileno = 1;
- fileno = (fileno << 16) |
- ((dentp - (struct direntry *) bp->b_data) & 0xffff);
- }
- crnt->d_fileno = fileno;
- crnt->d_reclen = sizeof(struct direntry);
- crnt->d_type = (dentp->deAttributes & ATTR_DIRECTORY)
- ? DT_DIR : DT_REG;
- crnt->d_namlen = dos2unixfn(dentp->deName,
- (u_char *)crnt->d_name);
- /*
- * printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
- * crnt->d_name, crnt->d_fileno, dentp->deAttributes,
- * dentp->deStartCluster);
- */
- prev = crnt;
- ncookies++;
+ if (dentp->deName[0] == SLOT_DELETED) {
+ chksum = -1;
+ continue;
}
- dentp++;
- crnt = (struct dirent *) ((char *) crnt + sizeof(struct direntry));
- pushout = 1;
+ /*
+ * Handle Win95 long directory entries
+ */
+ if (dentp->deAttributes == ATTR_WIN95) {
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ continue;
+ chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
+ continue;
+ }
/*
- * If our intermediate buffer is full then copy its
- * contents to user space. I would just use the
- * buffer the buf header points to but, I'm afraid
- * that when we brelse() it someone else might find
- * it in the cache and think its contents are
- * valid. Maybe there is a way to invalidate the
- * buffer before brelse()'ing it.
+ * Skip volume labels
*/
- if ((u_char *) crnt >= &dirbuf[sizeof dirbuf]) {
- pushout = 0;
- error = uiomove(dirbuf, sizeof(dirbuf), uio);
- if (error)
- break;
- prev = 0;
- crnt = (struct dirent *) dirbuf;
+ if (dentp->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
+ continue;
+ }
+ /*
+ * This computation of d_fileno must match
+ * the computation of va_fileid in
+ * msdosfs_getattr.
+ */
+ if (dentp->deAttributes & ATTR_DIRECTORY) {
+ fileno = getushort(dentp->deStartCluster);
+ if (FAT32(pmp))
+ fileno |= getushort(dentp->deHighClust) << 16;
+ /* if this is the root directory */
+ if (fileno == MSDOSFSROOT)
+ if (FAT32(pmp))
+ fileno = cntobn(pmp,
+ pmp->pm_rootdirblk)
+ * dirsperblk;
+ else
+ fileno = 1;
+ else
+ fileno = cntobn(pmp, fileno) * dirsperblk;
+ dirbuf.d_fileno = fileno;
+ dirbuf.d_type = DT_DIR;
+ } else {
+ dirbuf.d_fileno = offset / sizeof(struct direntry);
+ dirbuf.d_type = DT_REG;
+ }
+ if (chksum != winChksum(dentp->deName))
+ dirbuf.d_namlen = dos2unixfn(dentp->deName,
+ (u_char *)dirbuf.d_name,
+ pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
+ else
+ dirbuf.d_name[dirbuf.d_namlen] = 0;
+ chksum = -1;
+ dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
+ if (uio->uio_resid < dirbuf.d_reclen) {
+ brelse(bp);
+ goto out;
+ }
+ error = uiomove((caddr_t) &dirbuf,
+ dirbuf.d_reclen, uio);
+ if (error) {
+ brelse(bp);
+ goto out;
+ }
+ if (cookies) {
+ *cookies++ = off;
+ off = offset + sizeof(struct direntry);
+ if (--ncookies <= 0) {
+ brelse(bp);
+ goto out;
+ }
}
}
- if (pushout) {
- pushout = 0;
- error = uiomove(dirbuf, (char *) crnt - (char *) dirbuf,
- uio);
- }
-
-#if 0
- /*
- * If we have read everything from this block or have read
- * to end of file then we are done with this block. Mark
- * it to say the buffer can be reused if need be.
- */
- if (n + on == pmp->pm_bpcluster ||
- (uio->uio_offset - bias) == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif /* if 0 */
brelse(bp);
- if (n == 0)
- break;
}
-out: ;
+out:
+ /* Subtract unused cookies */
+ if (ap->a_ncookies)
+ *ap->a_ncookies -= ncookies;
+
+ uio->uio_offset = offset;
uio->uio_resid += lost;
- if (!error && ap->a_ncookies != NULL) {
- struct dirent* dpStart;
- struct dirent* dpEnd;
- struct dirent* dp;
- u_long *cookies;
- u_long *cookiep;
-
- if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
- panic("msdosfs_readdir: unexpected uio from NFS server");
- dpStart = (struct dirent *)
- (uio->uio_iov->iov_base - (uio->uio_offset - off));
- dpEnd = (struct dirent *) uio->uio_iov->iov_base;
- cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
- for (dp = dpStart, cookiep = cookies;
- dp < dpEnd;
- dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
- off += dp->d_reclen;
- *cookiep++ = (u_long) off;
- }
- *ap->a_ncookies = ncookies;
- *ap->a_cookies = cookies;
- }
/*
* Set the eofflag (NFS uses it)
*/
if (ap->a_eofflag)
- if (dep->de_FileSize - (uio->uio_offset - bias) <= 0)
+ if (dep->de_FileSize - (offset - bias) <= 0)
*ap->a_eofflag = 1;
else
*ap->a_eofflag = 0;
- return error;
+ return (error);
}
static int
@@ -1703,7 +1795,7 @@ msdosfs_abortop(ap)
{
if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- return 0;
+ return (0);
}
/*
@@ -1725,11 +1817,12 @@ msdosfs_bmap(ap)
} */ *ap;
{
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
if (ap->a_vpp != NULL)
*ap->a_vpp = dep->de_devvp;
if (ap->a_bnp == NULL)
- return 0;
+ return (0);
if (ap->a_runp) {
/*
* Sequential clusters should be counted here.
@@ -1739,7 +1832,7 @@ msdosfs_bmap(ap)
if (ap->a_runb) {
*ap->a_runb = 0;
}
- return pcbmap(dep, ap->a_bn, ap->a_bnp, 0);
+ return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
}
static int
@@ -1762,18 +1855,21 @@ msdosfs_strategy(ap)
* don't allow files with holes, so we shouldn't ever see this.
*/
if (bp->b_blkno == bp->b_lblkno) {
- error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0);
- if (error)
- bp->b_blkno = -1;
- if (bp->b_blkno == -1)
- clrbuf(bp);
+ error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0);
+ if (error) {
+ bp->b_error = error;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ return (error);
+ }
+ if ((long)bp->b_blkno == -1)
+ vfs_bio_clrbuf(bp);
}
if (bp->b_blkno == -1) {
biodone(bp);
- return error;
+ return (0);
}
-#ifdef DIAGNOSTIC
-#endif
/*
* Read/write the block from/to the disk that contains the desired
* file block.
@@ -1781,7 +1877,7 @@ msdosfs_strategy(ap)
vp = dep->de_devvp;
bp->b_dev = vp->v_rdev;
VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
- return 0;
+ return (0);
}
static int
@@ -1798,7 +1894,7 @@ msdosfs_print(ap)
printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
lockmgr_printinfo(&dep->de_lock);
printf("\n");
- return 0;
+ return (0);
}
static int
@@ -1809,25 +1905,28 @@ msdosfs_pathconf(ap)
int *a_retval;
} */ *ap;
{
+ struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
+
switch (ap->a_name) {
case _PC_LINK_MAX:
*ap->a_retval = 1;
- return 0;
+ return (0);
case _PC_NAME_MAX:
- *ap->a_retval = 12;
- return 0;
+ *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
+ return (0);
case _PC_PATH_MAX:
- *ap->a_retval = PATH_MAX; /* 255? */
- return 0;
+ *ap->a_retval = PATH_MAX;
+ return (0);
case _PC_CHOWN_RESTRICTED:
*ap->a_retval = 1;
- return 0;
+ return (0);
case _PC_NO_TRUNC:
*ap->a_retval = 0;
- return 0;
+ return (0);
default:
- return EINVAL;
+ return (EINVAL);
}
+ /* NOTREACHED */
}
/* Global vfs data structures for msdosfs */
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index 49a9327..3a0ee6e 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -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,121 +63,131 @@ 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
/*
- * Map a cluster number into a filesystem relative block number.
+ * Convert pointer to buffer -> pointer to direntry
*/
-#define cntobn(pmp, cn) \
- ((((cn)-CLUST_FIRST) * (pmp)->pm_SectPerClust) + (pmp)->pm_firstcluster)
+#define bptoep(pmp, bp, dirofs) \
+ ((struct direntry *)(((bp)->b_data) \
+ + ((dirofs) & (pmp)->pm_crbomask)))
/*
- * Map a filesystem relative block number back into a cluster number.
+ * Convert block number to cluster number
*/
-#define bntocn(pmp, bn) \
- ((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
+#define de_bn2cn(pmp, bn) \
+ ((bn) >> ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
- * Calculate block number for directory entry in root dir, offset dirofs
+ * Convert cluster number to block number
*/
-#define roottobn(pmp, dirofs) \
- (((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
- + (pmp)->pm_rootdirblk)
+#define de_cn2bn(pmp, cn) \
+ ((cn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
- * Calculate block number for directory entry at cluster dirclu, offset
- * dirofs
+ * Convert file offset to cluster number
*/
-#define detobn(pmp, dirclu, dirofs) \
- ((dirclu) == MSDOSFSROOT \
- ? roottobn((pmp), (dirofs)) \
- : cntobn((pmp), (dirclu)))
+#define de_cluster(pmp, off) \
+ ((off) >> (pmp)->pm_cnshift)
/*
- * Convert pointer to buffer -> pointer to direntry
+ * Clusters required to hold size bytes
*/
-#define bptoep(pmp, bp, dirofs) \
- ((struct direntry *)((bp)->b_data) \
- + (dirofs) % (pmp)->pm_depclust)
-
+#define de_clcount(pmp, size) \
+ (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
/*
- * Convert filesize to block number
+ * Convert file offset to block number
*/
#define de_blk(pmp, off) \
- ((off) >> (pmp)->pm_cnshift)
+ (de_cn2bn(pmp, de_cluster((pmp), (off))))
/*
- * Clusters required to hold size bytes
+ * Convert cluster number to file offset
*/
-#define de_clcount(pmp, size) \
- (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
+#define de_cn2off(pmp, cn) \
+ ((cn) << (pmp)->pm_cnshift)
+
+/*
+ * Convert block number to file offset
+ */
+#define de_bn2off(pmp, bn) \
+ ((bn) << (pmp)->pm_bnshift)
+/*
+ * Map a cluster number into a filesystem relative block number.
+ */
+#define cntobn(pmp, cn) \
+ (de_cn2bn((pmp), (cn)-CLUST_FIRST) + (pmp)->pm_firstcluster)
+
+/*
+ * Calculate block number for directory entry in root dir, offset dirofs
+ */
+#define roottobn(pmp, dirofs) \
+ (de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk)
+
+/*
+ * Calculate block number for directory entry at cluster dirclu, offset
+ * dirofs
+ */
+#define detobn(pmp, dirclu, dirofs) \
+ ((dirclu) == MSDOSFSROOT \
+ ? roottobn((pmp), (dirofs)) \
+ : cntobn((pmp), (dirclu)))
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_ */
diff --git a/sys/msdosfs/bootsect.h b/sys/msdosfs/bootsect.h
index 86fc415..11b93371a 100644
--- a/sys/msdosfs/bootsect.h
+++ b/sys/msdosfs/bootsect.h
@@ -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 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) */
+struct extboot {
+ int8_t exDriveNumber; /* drive number (0x80) */
+ int8_t exReserved1; /* reserved */
+ int8_t exBootSignature; /* ext. 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
+ int8_t exVolumeID[4]; /* volume ID number */
+ int8_t exVolumeLabel[11]; /* volume label */
+ int8_t exFileSysType[8]; /* fs type (FAT12 or FAT16) */
+};
+
+struct bootsector50 {
+ u_int8_t bsJump[3]; /* jump inst E9xxxx or EBxx90 */
+ int8_t bsOemName[8]; /* OEM name and version */
+ int8_t bsBPB[25]; /* BIOS parameter block */
+ int8_t 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
diff --git a/sys/msdosfs/bpb.h b/sys/msdosfs/bpb.h
index 33e1eb6..bc00a75 100644
--- a/sys/msdosfs/bpb.h
+++ b/sys/msdosfs/bpb.h
@@ -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,21 +39,71 @@ 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
* because the compiler forces shorts and longs to align on word or
@@ -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];
};
diff --git a/sys/msdosfs/denode.h b/sys/msdosfs/denode.h
index 6ad3fcc..2b9d636 100644
--- a/sys/msdosfs/denode.h
+++ b/sys/msdosfs/denode.h
@@ -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 */
diff --git a/sys/msdosfs/direntry.h b/sys/msdosfs/direntry.h
index b97a105..0bfe164 100644
--- a/sys/msdosfs/direntry.h
+++ b/sys/msdosfs/direntry.h
@@ -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,27 +52,56 @@
* 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.
* We don't use bitfields because we don't know how compilers for
@@ -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 */
diff --git a/sys/msdosfs/fat.h b/sys/msdosfs/fat.h
index f8fdb6f..74b05e2 100644
--- a/sys/msdosfs/fat.h
+++ b/sys/msdosfs/fat.h
@@ -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 */
diff --git a/sys/msdosfs/msdosfs_conv.c b/sys/msdosfs/msdosfs_conv.c
index 59f4d2c..727cacd 100644
--- a/sys/msdosfs/msdosfs_conv.c
+++ b/sys/msdosfs/msdosfs_conv.c
@@ -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,90 +349,86 @@ 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.
+ * If first char of the filename is SLOT_E5 (0x05), then the real
+ * first char of the filename should be 0xe5. But, they couldn't
+ * just have a 0xe5 mean 0xe5 because that is used to mean a freed
+ * directory slot. Another dos quirk.
*/
- for (ei = 10; ei >= 8; ei--)
- if (dn[ei] != ' ')
- break;
+ if (*dn == SLOT_E5)
+ c = dos2unix[0xe5];
+ else
+ c = dos2unix[*dn];
+ *un++ = lower ? u2l[c] : c;
+ dn++;
/*
- * 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.
+ * Copy the name portion into the unix filename string.
*/
- for (i = 0; i <= ni; i++) {
- c = dn[i];
- *un++ = isupper(c) ? tolower(c) : c;
+ 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 (ei >= 8) {
+ if (*dn != ' ') {
*un++ = '.';
thislong++;
- for (i = 8; i <= ei; i++) {
- c = dn[i];
- *un++ = isupper(c) ? tolower(c) : c;
+ for (i = 0; i < 3 && *dn != ' '; i++) {
+ c = dos2unix[*dn++];
+ *un++ = lower ? u2l[c] : c;
thislong++;
}
}
*un++ = 0;
- /*
- * If first char of the filename is SLOT_E5 (0x05), then the real
- * first char of the filename should be 0xe5. But, they couldn't
- * 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;
-
- return thislong;
+ 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;
+ }
+
+ /*
+ * Filenames with only blanks and dots are not allowed!
+ */
+ for (cp = un, i = unlen; --i >= 0; cp++)
+ if (*cp != ' ' && *cp != '.')
+ break;
+ if (i < 0)
+ return 0;
+
+ /*
+ * Now find the extension
+ * Note: dot as first char doesn't start extension
+ * and trailing dots and blanks are ignored
+ */
+ dp = dp1 = 0;
+ for (cp = un + 1, i = unlen - 1; --i >= 0;) {
+ switch (*cp++) {
+ case '.':
+ if (!dp1)
+ dp1 = cp;
+ break;
+ case ' ':
+ break;
+ default:
+ if (dp1)
+ dp = dp1;
+ dp1 = 0;
+ break;
+ }
+ }
+
+ /*
+ * Now convert it
+ */
+ if (dp) {
+ if (dp1)
+ l = dp1 - dp;
+ else
+ l = unlen - (dp - un);
+ for (i = 0, j = 8; i < l && j < 11; i++, j++) {
+ if (dp[i] != (dn[j] = unix2dos[dp[i]])
+ && conv != 3)
+ conv = 2;
+ if (!dn[j]) {
+ conv = 3;
+ dn[j--] = ' ';
+ }
+ }
+ if (i < l)
+ conv = 3;
+ dp--;
+ } else {
+ for (dp = cp; *--dp == ' ' || *dp == '.';);
+ dp++;
}
/*
- * 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.
+ * Now convert the rest of the name
*/
- for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ 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] = '_';
/*
- * 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.
+ * The first character cannot be E5,
+ * because that means a deleted entry
*/
- if (dn[0] == SLOT_DELETED)
+ 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 (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;
+}
+
+/*
+ * Create a Win95 long name directory entry
+ * Note: assumes that the filename is valid,
+ * i.e. doesn't consist solely of blanks and dots
+ */
+int
+unix2winfn(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 (i = 8; i <= 10 && unlen && (c = *un); i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ 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;
}
/*
- * Get rid of these macros before someone discovers we are using such
- * hideous things.
+ * Convert Win95 filename to dirbuf.
+ * Returns the checksum or -1 if impossible
*/
-#undef isupper
-#undef islower
-#undef toupper
-#undef tolower
+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);
+}
diff --git a/sys/msdosfs/msdosfs_denode.c b/sys/msdosfs/msdosfs_denode.c
index 81e0699..6feabbb 100644
--- a/sys/msdosfs/msdosfs_denode.c
+++ b/sys/msdosfs/msdosfs_denode.c
@@ -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);
-
-#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;
+ struct timespec ts;
- /*
- * 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 @@ out:
#endif
if (dep->de_Name[0] == SLOT_DELETED)
vrecycle(vp, (struct simplelock *)0, p);
- return error;
+ return (error);
}
diff --git a/sys/msdosfs/msdosfs_fat.c b/sys/msdosfs/msdosfs_fat.c
index bb25ec2..f556860 100644
--- a/sys/msdosfs/msdosfs_fat.c
+++ b/sys/msdosfs/msdosfs_fat.c
@@ -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,24 +175,33 @@ 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
* off the cache was from where we wanted to be.
@@ -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);
}
diff --git a/sys/msdosfs/msdosfs_lookup.c b/sys/msdosfs/msdosfs_lookup.c
index b757cf0..4991417 100644
--- a/sys/msdosfs/msdosfs_lookup.c
+++ b/sys/msdosfs/msdosfs_lookup.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_lookup.c,v 1.13 1997/09/02 20:06:17 bde Exp $ */
-/* $NetBSD: msdosfs_lookup.c,v 1.14 1994/08/21 18:44:07 ws Exp $ */
+/* $Id: msdosfs_lookup.c,v 1.14 1997/09/10 19:44:36 phk Exp $ */
+/* $NetBSD: msdosfs_lookup.c,v 1.37 1997/11/17 15:36:54 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).
*
@@ -94,16 +94,13 @@ msdosfs_lookup(ap)
int error;
int lockparent;
int wantparent;
- int slotstatus;
-
-#define NONE 0
-#define FOUND 1
- int slotoffset = -1;
- int slotcluster = -1;
+ int slotcount;
+ int slotoffset = 0;
int frcn;
u_long cluster;
- int rootreloff;
+ int blkoff;
int diroff;
+ int blsize;
int isadir; /* ~0 if found direntry is a directory */
u_long scn; /* starting cluster number */
struct vnode *pdp;
@@ -118,6 +115,10 @@ msdosfs_lookup(ap)
int nameiop = cnp->cn_nameiop;
struct proc *p = cnp->cn_proc;
+ int wincnt = 1;
+ int chksum = -1;
+ int olddos = 1;
+
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
@@ -127,8 +128,8 @@ msdosfs_lookup(ap)
lockparent = flags & LOCKPARENT;
wantparent = flags & (LOCKPARENT | WANTPARENT);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
- vdp, dp, dp->de_Attributes);
+ printf("msdosfs_lookup(): vdp %p, dp %p, Attr %02x\n",
+ vdp, dp, dp->de_Attributes);
#endif
/*
@@ -145,25 +146,43 @@ msdosfs_lookup(ap)
printf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
cluster = MSDOSFSROOT;
- diroff = MSDOSFSROOT_OFS;
+ blkoff = MSDOSFSROOT_OFS;
goto foundroot;
}
+ switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
+ cnp->cn_namelen, 0)) {
+ case 0:
+ return (EINVAL);
+ case 1:
+ break;
+ case 2:
+ wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen) + 1;
+ break;
+ case 3:
+ olddos = 0;
+ wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen) + 1;
+ break;
+ }
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ wincnt = 1;
+
/*
- * Don't search for free slots unless we are creating a filename
- * and we are at the end of the pathname.
+ * Suppress search for slots unless creating
+ * file and at end of pathname, in which case
+ * we watch for a place to put the new file in
+ * case it doesn't already exist.
*/
- slotstatus = FOUND;
- if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) {
- slotstatus = NONE;
- slotoffset = -1;
- }
+ slotcount = wincnt;
+ if ((nameiop == CREATE || nameiop == RENAME) &&
+ (flags & ISLASTCN))
+ slotcount = 0;
- unix2dosfn((u_char *) cnp->cn_nameptr, dosfilename, cnp->cn_namelen);
- dosfilename[11] = 0;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): dos version of filename %s, length %d\n",
- dosfilename, cnp->cn_namelen);
+ printf("msdosfs_lookup(): dos version of filename %s, length %ld\n",
+ dosfilename, cnp->cn_namelen);
#endif
/*
* Search the directory pointed at by vdp for the name pointed at
@@ -177,20 +196,23 @@ msdosfs_lookup(ap)
* part of the pool of allocatable clusters. So, we treat it a
* little differently. The root directory starts at "cluster" 0.
*/
- rootreloff = 0;
+ diroff = 0;
for (frcn = 0;; frcn++) {
- error = pcbmap(dp, frcn, &bn, &cluster);
+ error = pcbmap(dp, frcn, &bn, &cluster, &blsize);
if (error) {
if (error == E2BIG)
break;
- return error;
+ return (error);
}
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,NOCRED,&bp);
- if (error)
- return error;
- for (diroff = 0; diroff < pmp->pm_depclust; diroff++) {
- dep = (struct direntry *) bp->b_data + diroff;
-
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return (error);
+ }
+ for (blkoff = 0; blkoff < blsize;
+ blkoff += sizeof(struct direntry),
+ diroff += sizeof(struct direntry)) {
+ dep = (struct direntry *)(bp->b_data + blkoff);
/*
* If the slot is empty and we are still looking
* for an empty then remember this one. If the
@@ -202,13 +224,14 @@ msdosfs_lookup(ap)
*/
if (dep->deName[0] == SLOT_EMPTY ||
dep->deName[0] == SLOT_DELETED) {
- if (slotstatus != FOUND) {
- slotstatus = FOUND;
- if (cluster == MSDOSFSROOT)
- slotoffset = rootreloff;
- else
- slotoffset = diroff;
- slotcluster = cluster;
+ /*
+ * Drop memory of previous long matches
+ */
+ chksum = -1;
+
+ if (slotcount < wincnt) {
+ slotcount++;
+ slotoffset = diroff;
}
if (dep->deName[0] == SLOT_EMPTY) {
brelse(bp);
@@ -216,204 +239,298 @@ msdosfs_lookup(ap)
}
} else {
/*
+ * If there wasn't enough space for our winentries,
+ * forget about the empty space
+ */
+ if (slotcount < wincnt)
+ slotcount = 0;
+
+ /*
+ * Check for Win95 long filename entry
+ */
+ if (dep->deAttributes == ATTR_WIN95) {
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ continue;
+
+ chksum = winChkName((const u_char *)cnp->cn_nameptr,
+ cnp->cn_namelen,
+ (struct winentry *)dep,
+ chksum);
+ continue;
+ }
+
+ /*
* Ignore volume labels (anywhere, not just
* the root directory).
*/
- if ((dep->deAttributes & ATTR_VOLUME) == 0 &&
- bcmp(dosfilename, dep->deName, 11) == 0) {
+ if (dep->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
+ continue;
+ }
+
+ /*
+ * Check for a checksum or name match
+ */
+ if (chksum != winChksum(dep->deName)
+ && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
+ chksum = -1;
+ continue;
+ }
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): match diroff %d, rootreloff %d\n",
- diroff, rootreloff);
+ printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
+ blkoff, diroff);
#endif
- /*
- * Remember where this directory
- * entry came from for whoever did
- * this lookup. If this is the root
- * directory we are interested in
- * the offset relative to the
- * beginning of the directory (not
- * the beginning of the cluster).
- */
- if (cluster == MSDOSFSROOT)
- diroff = rootreloff;
- dp->de_fndoffset = diroff;
- dp->de_fndclust = cluster;
- goto found;
- }
+ /*
+ * Remember where this directory
+ * entry came from for whoever did
+ * this lookup.
+ */
+ dp->de_fndoffset = diroff;
+ dp->de_fndcnt = 0; /* unused anyway */
+
+ goto found;
}
- rootreloff++;
- } /* for (diroff = 0; .... */
+ } /* for (blkoff = 0; .... */
/*
* Release the buffer holding the directory cluster just
* searched.
*/
brelse(bp);
- } /* for (frcn = 0; ; frcn++) */
-notfound:;
+ } /* for (frcn = 0; ; frcn++) */
+
+notfound:
/*
* We hold no disk buffers at this point.
*/
/*
+ * Fixup the slot description to point to the place where
+ * we might put the new DOS direntry (putting the Win95
+ * long name entries before that)
+ */
+ if (!slotcount) {
+ slotcount = 1;
+ slotoffset = diroff;
+ }
+ if (wincnt > slotcount)
+ slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
+
+ /*
* If we get here we didn't find the entry we were looking for. But
* that's ok if we are creating or renaming and are at the end of
* the pathname and the directory hasn't been removed.
*/
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): op %d, refcnt %d, slotstatus %d\n",
- nameiop, dp->de_refcnt, slotstatus);
- printf(" slotoffset %d, slotcluster %d\n",
- slotoffset, slotcluster);
+ printf("msdosfs_lookup(): op %d, refcnt %ld\n",
+ nameiop, dp->de_refcnt);
+ printf(" slotcount %d, slotoffset %d\n",
+ slotcount, slotoffset);
#endif
if ((nameiop == CREATE || nameiop == RENAME) &&
(flags & ISLASTCN) && dp->de_refcnt != 0) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
+ /*
+ * Access for write is interpreted as allowing
+ * creation of files in the directory.
+ */
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
if (error)
- return error;
- if (slotstatus == NONE) {
- dp->de_fndoffset = (u_long)-1;
- dp->de_fndclust = (u_long)-1;
- } else {
-#ifdef MSDOSFS_DEBUG
- printf("msdosfs_lookup(): saving empty slot location\n");
-#endif
- dp->de_fndoffset = slotoffset;
- dp->de_fndclust = slotcluster;
- }
- /* dp->de_flag |= DE_UPDATE; never update dos directories */
+ return (error);
+ /*
+ * Return an indication of where the new directory
+ * entry should be put.
+ */
+ dp->de_fndoffset = slotoffset;
+ dp->de_fndcnt = wincnt - 1;
+
+ /*
+ * We return with the directory locked, so that
+ * the parameters we set up above will still be
+ * valid if we actually decide to do a direnter().
+ * We return ni_vp == NULL to indicate that the entry
+ * does not currently exist; we leave a pointer to
+ * the (locked) directory inode in ndp->ni_dvp.
+ * The pathname buffer is saved so that the name
+ * can be obtained later.
+ *
+ * NB - if the directory is unlocked, then this
+ * information cannot be used.
+ */
cnp->cn_flags |= SAVENAME;
- if (!lockparent)/* leave searched dir locked? */
+ if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- return EJUSTRETURN;
+ return (EJUSTRETURN);
}
/*
- * Insert name in cache as non-existant if not trying to create it.
+ * Insert name into cache (as non-existent) if appropriate.
*/
if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
cache_enter(vdp, *vpp, cnp);
- return ENOENT;
+ return (ENOENT);
-found: ;
+found:
/*
* NOTE: We still have the buffer with matched directory entry at
* this point.
*/
isadir = dep->deAttributes & ATTR_DIRECTORY;
scn = getushort(dep->deStartCluster);
+ if (FAT32(pmp)) {
+ scn |= getushort(dep->deHighClust) << 16;
+ if (scn == pmp->pm_rootdirblk) {
+ /*
+ * There should actually be 0 here.
+ * Just ignore the error.
+ */
+ scn = MSDOSFSROOT;
+ }
+ }
-foundroot:;
+ if (isadir) {
+ cluster = scn;
+ if (cluster == MSDOSFSROOT)
+ blkoff = MSDOSFSROOT_OFS;
+ else
+ blkoff = 0;
+ } else if (cluster == MSDOSFSROOT)
+ blkoff = diroff;
+
+ /*
+ * Now release buf to allow deget to read the entry again.
+ * Reserving it here and giving it to deget could result
+ * in a deadlock.
+ */
+ brelse(bp);
+ bp = 0;
+
+foundroot:
/*
* If we entered at foundroot, then we are looking for the . or ..
* entry of the filesystems root directory. isadir and scn were
- * setup before jumping here. And, bp is null. There is no buf
- * header.
+ * setup before jumping here. And, bp is already null.
*/
+ if (FAT32(pmp) && scn == MSDOSFSROOT)
+ scn = pmp->pm_rootdirblk;
/*
- * If deleting and at the end of the path, then if we matched on
- * "." then don't deget() we would probably panic(). Otherwise
- * deget() the directory entry.
+ * If deleting, and at end of pathname, return
+ * parameters which can be used to remove file.
+ * If the wantparent flag isn't set, we return only
+ * the directory (in ndp->ni_dvp), otherwise we go
+ * on and lock the inode, being careful with ".".
*/
if (nameiop == DELETE && (flags & ISLASTCN)) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ /*
+ * Don't allow deleting the root.
+ */
+ if (blkoff == MSDOSFSROOT_OFS)
+ return EROFS; /* really? XXX */
+
+ /*
+ * Write access to directory required to delete files.
+ */
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error)
+ return (error);
+
+ /*
+ * Return pointer to current entry in dp->i_offset.
+ * Save directory inode pointer in ndp->ni_dvp for dirremove().
+ */
if (dp->de_StartCluster == scn && isadir) { /* "." */
VREF(vdp);
*vpp = vdp;
- if (bp)
- brelse(bp);
- return 0;
- }
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
+ return (0);
}
+ error = deget(pmp, cluster, blkoff, &tdp);
+ if (error)
+ return (error);
*vpp = DETOV(tdp);
if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- if (bp)
- brelse(bp);
- return 0;
+ return (0);
}
/*
- * If renaming.
+ * If rewriting (RENAME), return the inode and the
+ * information required to rewrite the present directory
+ * Must get inode of directory entry to verify it's a
+ * regular file, or empty directory.
*/
- if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
- error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
- if (dp->de_StartCluster == scn && isadir) {
- if (bp)
- brelse(bp);
- return EISDIR;
- }
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ if (nameiop == RENAME && wantparent &&
+ (flags & ISLASTCN)) {
+ if (blkoff == MSDOSFSROOT_OFS)
+ return EROFS; /* really? XXX */
+
+ error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
+ if (error)
+ return (error);
+
+ /*
+ * Careful about locking second inode.
+ * This can only occur if the target is ".".
+ */
+ if (dp->de_StartCluster == scn && isadir)
+ return (EISDIR);
+
+ if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ return (error);
*vpp = DETOV(tdp);
cnp->cn_flags |= SAVENAME;
if (!lockparent)
VOP_UNLOCK(vdp, 0, p);
- if (bp)
- brelse(bp);
- return 0;
+ return (0);
}
/*
- * ?
+ * Step through the translation in the name. We do not `vput' the
+ * directory because we may need it again if a symbolic link
+ * is relative to the current directory. Instead we save it
+ * unlocked as "pdp". We must get the target inode before unlocking
+ * the directory to insure that the inode will not be removed
+ * before we get it. We prevent deadlock by always fetching
+ * inodes from the root, moving down the directory tree. Thus
+ * when following backward pointers ".." we must unlock the
+ * parent directory before getting the requested directory.
+ * There is a potential race condition here if both the current
+ * and parent directories are removed before the VFS_VGET for the
+ * inode associated with ".." returns. We hope that this occurs
+ * infrequently since we cannot avoid this race condition without
+ * implementing a sophisticated deadlock detection algorithm.
+ * Note also that this simple deadlock detection scheme will not
+ * work if the file system has any hard links other than ".."
+ * that point backwards in the directory structure.
*/
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp, 0, p);
- error = deget(pmp, cluster, diroff, dep, &tdp);
+ error = deget(pmp, cluster, blkoff, &tdp);
if (error) {
- vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
- if (bp)
- brelse(bp);
- return error;
+ vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p);
+ return (error);
}
- if (lockparent && (flags & ISLASTCN)
- && (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
+ if (lockparent && (flags & ISLASTCN) &&
+ (error = vn_lock(pdp, LK_EXCLUSIVE, p))) {
vput(DETOV(tdp));
- return error;
+ return (error);
}
*vpp = DETOV(tdp);
- } else if (dp->de_StartCluster == scn && isadir) { /* "." */
- VREF(vdp);
+ } else if (dp->de_StartCluster == scn && isadir) {
+ VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
} else {
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
- return error;
- }
+ if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
+ return (error);
if (!lockparent || !(flags & ISLASTCN))
VOP_UNLOCK(pdp, 0, p);
*vpp = DETOV(tdp);
}
- if (bp)
- brelse(bp);
/*
- * Insert name in cache if wanted.
+ * Insert name into cache if appropriate.
*/
if (cnp->cn_flags & MAKEENTRY)
cache_enter(vdp, *vpp, cnp);
- return 0;
+ return (0);
}
/*
@@ -421,21 +538,26 @@ foundroot:;
* ddep - directory to add to
* depp - return the address of the denode for the created directory entry
* if depp != 0
+ * cnp - componentname needed for Win95 long filenames
*/
int
-createde(dep, ddep, depp)
+createde(dep, ddep, depp, cnp)
struct denode *dep;
struct denode *ddep;
struct denode **depp;
+ struct componentname *cnp;
{
int error;
u_long dirclust, diroffset;
struct direntry *ndep;
struct msdosfsmount *pmp = ddep->de_pmp;
struct buf *bp;
+ daddr_t bn;
+ int blsize;
#ifdef MSDOSFS_DEBUG
- printf("createde(dep %08x, ddep %08x, depp %08x)\n", dep, ddep, depp);
+ printf("createde(dep %p, ddep %p, depp %p, cnp %p)\n",
+ dep, ddep, depp, cnp);
#endif
/*
@@ -446,104 +568,100 @@ createde(dep, ddep, depp)
* to extend the root directory. We just return an error in that
* case.
*/
- if (ddep->de_fndclust == (u_long)-1) {
- error = extendfile(ddep, 1, &bp, &dirclust, DE_CLEAR);
- if (error)
+ if (ddep->de_fndoffset >= ddep->de_FileSize) {
+ diroffset = ddep->de_fndoffset + sizeof(struct direntry)
+ - ddep->de_FileSize;
+ dirclust = de_clcount(pmp, diroffset);
+ error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR);
+ if (error) {
+ (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
return error;
- ndep = (struct direntry *) bp->b_data;
- /*
- * Let caller know where we put the directory entry.
- */
- ddep->de_fndclust = dirclust;
- ddep->de_fndoffset = diroffset = 0;
+ }
+
/*
* Update the size of the directory
*/
- ddep->de_FileSize += pmp->pm_bpcluster;
- } else {
- /*
- * There is space in the existing directory. So, we just
- * read in the cluster with space. Copy the new directory
- * entry in. Then write it to disk. NOTE: DOS directories
- * do not get smaller as clusters are emptied.
- */
- dirclust = ddep->de_fndclust;
- diroffset = ddep->de_fndoffset;
-
- error = readep(pmp, dirclust, diroffset, &bp, &ndep);
- if (error)
- return error;
+ ddep->de_FileSize += de_cn2off(pmp, dirclust);
}
- DE_EXTERNALIZE(ndep, dep);
/*
- * If they want us to return with the denode gotten.
+ * We just read in the cluster with space. Copy the new directory
+ * entry in. Then write it to disk. NOTE: DOS directories
+ * do not get smaller as clusters are emptied.
*/
- if (depp) {
- error = deget(pmp, dirclust, diroffset, ndep, depp);
- if (error)
- return error;
- }
- error = bwrite(bp);
- if (error) {
- vput(DETOV(*depp)); /* free the vnode we got on error */
+ error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
+ &bn, &dirclust, &blsize);
+ if (error)
+ return error;
+ diroffset = ddep->de_fndoffset;
+ if (dirclust != MSDOSFSROOT)
+ diroffset &= pmp->pm_crbomask;
+ if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
+ brelse(bp);
return error;
}
- return 0;
-}
+ ndep = bptoep(pmp, bp, ddep->de_fndoffset);
-/*
- * Read in a directory entry and mark it as being deleted.
- */
-static int
-markdeleted(pmp, dirclust, diroffset)
- struct msdosfsmount *pmp;
- u_long dirclust;
- u_long diroffset;
-{
- int error;
- struct direntry *ep;
- struct buf *bp;
+ DE_EXTERNALIZE(ndep, dep);
- error = readep(pmp, dirclust, diroffset, &bp, &ep);
- if (error)
- return error;
- ep->deName[0] = SLOT_DELETED;
- return bwrite(bp);
-}
+ /*
+ * Now write the Win95 long name
+ */
+ if (ddep->de_fndcnt > 0) {
+ u_int8_t chksum = winChksum(ndep->deName);
+ const u_char *un = (const u_char *)cnp->cn_nameptr;
+ int unlen = cnp->cn_namelen;
+ int cnt = 1;
-/*
- * Remove a directory entry. At this point the file represented by the
- * directory entry to be removed is still full length until no one has it
- * open. When the file no longer being used msdosfs_inactive() is called
- * and will truncate the file to 0 length. When the vnode containing the
- * denode is needed for some other purpose by VFS it will call
- * msdosfs_reclaim() which will remove the denode from the denode cache.
- */
-int
-removede(pdep,dep)
- struct denode *pdep; /* directory where the entry is removed */
- struct denode *dep; /* file to be removed */
-{
- struct msdosfsmount *pmp = pdep->de_pmp;
- int error;
+ while (--ddep->de_fndcnt >= 0) {
+ if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
+ if ((error = bwrite(bp)) != 0)
+ return error;
-#ifdef MSDOSFS_DEBUG
- printf("removede(): filename %s\n", dep->de_Name);
- printf("removede(): dep %08x, ndpcluster %d, ndpoffset %d\n",
- dep, pdep->de_fndclust, pdep->de_fndoffset);
-#endif
+ ddep->de_fndoffset -= sizeof(struct direntry);
+ error = pcbmap(ddep,
+ de_cluster(pmp,
+ ddep->de_fndoffset),
+ &bn, 0, &blsize);
+ if (error)
+ return error;
+
+ error = bread(pmp->pm_devvp, bn, blsize,
+ NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ ndep = bptoep(pmp, bp, ddep->de_fndoffset);
+ } else {
+ ndep--;
+ ddep->de_fndoffset -= sizeof(struct direntry);
+ }
+ if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum))
+ break;
+ }
+ }
+
+ if ((error = bwrite(bp)) != 0)
+ return error;
/*
- * Read the directory block containing the directory entry we are
- * to make free. The nameidata structure holds the cluster number
- * and directory entry index number of the entry to free.
+ * If they want us to return with the denode gotten.
*/
- error = markdeleted(pmp, pdep->de_fndclust, pdep->de_fndoffset);
+ if (depp) {
+ if (dep->de_Attributes & ATTR_DIRECTORY) {
+ dirclust = dep->de_StartCluster;
+ if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
+ dirclust = MSDOSFSROOT;
+ if (dirclust == MSDOSFSROOT)
+ diroffset = MSDOSFSROOT_OFS;
+ else
+ diroffset = 0;
+ }
+ return deget(pmp, dirclust, diroffset, depp);
+ }
- if (error == 0)
- dep->de_refcnt--;
- return error;
+ return 0;
}
/*
@@ -554,7 +672,7 @@ int
dosdirempty(dep)
struct denode *dep;
{
- int dei;
+ int blsize;
int error;
u_long cn;
daddr_t bn;
@@ -568,16 +686,21 @@ dosdirempty(dep)
* we hit end of file.
*/
for (cn = 0;; cn++) {
- error = pcbmap(dep, cn, &bn, 0);
- if (error == E2BIG)
- return 1; /* it's empty */
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
- &bp);
- if (error)
- return error;
- dentp = (struct direntry *) bp->b_data;
- for (dei = 0; dei < pmp->pm_depclust; dei++) {
- if (dentp->deName[0] != SLOT_DELETED) {
+ if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
+ if (error == E2BIG)
+ return (1); /* it's empty */
+ return (0);
+ }
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return (0);
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] != SLOT_DELETED &&
+ (dentp->deAttributes & ATTR_VOLUME) == 0) {
/*
* In dos directories an entry whose name
* starts with SLOT_EMPTY (0) starts the
@@ -587,7 +710,7 @@ dosdirempty(dep)
*/
if (dentp->deName[0] == SLOT_EMPTY) {
brelse(bp);
- return 1;
+ return (1);
}
/*
* Any names other than "." and ".." in a
@@ -597,13 +720,12 @@ dosdirempty(dep)
bcmp(dentp->deName, ".. ", 11)) {
brelse(bp);
#ifdef MSDOSFS_DEBUG
- printf("dosdirempty(): entry %d found %02x, %02x\n",
- dei, dentp->deName[0], dentp->deName[1]);
+ printf("dosdirempty(): entry found %02x, %02x\n",
+ dentp->deName[0], dentp->deName[1]);
#endif
- return 0; /* not empty */
+ return (0); /* not empty */
}
}
- dentp++;
}
brelse(bp);
}
@@ -647,18 +769,25 @@ doscheckpath(source, target)
}
if (dep->de_StartCluster == MSDOSFSROOT)
goto out;
+ pmp = dep->de_pmp;
+#ifdef DIAGNOSTIC
+ if (pmp != source->de_pmp)
+ panic("doscheckpath: source and target on different filesystems");
+#endif
+ if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
+ goto out;
+
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
- goto out;
+ break;
}
- pmp = dep->de_pmp;
scn = dep->de_StartCluster;
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
- pmp->pm_bpcluster, NOCRED, &bp);
- if (error) {
+ pmp->pm_bpcluster, NOCRED, &bp);
+ if (error)
break;
- }
+
ep = (struct direntry *) bp->b_data + 1;
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
bcmp(ep->deName, ".. ", 11) != 0) {
@@ -666,28 +795,38 @@ doscheckpath(source, target)
break;
}
scn = getushort(ep->deStartCluster);
+ if (FAT32(pmp))
+ scn |= getushort(ep->deHighClust) << 16;
+
if (scn == source->de_StartCluster) {
error = EINVAL;
break;
}
if (scn == MSDOSFSROOT)
break;
+ if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
+ /*
+ * scn should be 0 in this case,
+ * but we silently ignore the error.
+ */
+ break;
+ }
+
vput(DETOV(dep));
- /* NOTE: deget() clears dep on error */
- error = deget(pmp, scn, 0, ep, &dep);
brelse(bp);
bp = NULL;
- if (error)
+ /* NOTE: deget() clears dep on error */
+ if ((error = deget(pmp, scn, 0, &dep)) != 0)
break;
}
-out: ;
+out:;
if (bp)
brelse(bp);
if (error == ENOTDIR)
printf("doscheckpath(): .. not a directory?\n");
if (dep != NULL)
vput(DETOV(dep));
- return error;
+ return (error);
}
/*
@@ -696,27 +835,33 @@ out: ;
* directory entry within the block.
*/
int
-readep(pmp, dirclu, dirofs, bpp, epp)
+readep(pmp, dirclust, diroffset, bpp, epp)
struct msdosfsmount *pmp;
- u_long dirclu, dirofs;
+ u_long dirclust, diroffset;
struct buf **bpp;
struct direntry **epp;
{
int error;
daddr_t bn;
+ int blsize;
+ u_long boff;
- bn = detobn(pmp, dirclu, dirofs);
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp);
- if (error) {
+ boff = diroffset & ~pmp->pm_crbomask;
+ blsize = pmp->pm_bpcluster;
+ if (dirclust == MSDOSFSROOT
+ && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
+ blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
+ bn = detobn(pmp, dirclust, diroffset);
+ if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
+ brelse(*bpp);
*bpp = NULL;
- return error;
+ return (error);
}
if (epp)
- *epp = bptoep(pmp, *bpp, dirofs);
- return 0;
+ *epp = bptoep(pmp, *bpp, diroffset);
+ return (0);
}
-
/*
* Read in the disk block containing the directory entry dep came from and
* return the address of the buf header, and the address of the directory
@@ -728,6 +873,195 @@ readde(dep, bpp, epp)
struct buf **bpp;
struct direntry **epp;
{
- return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
- bpp, epp);
+
+ return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
+ bpp, epp));
+}
+
+/*
+ * Remove a directory entry. At this point the file represented by the
+ * directory entry to be removed is still full length until noone has it
+ * open. When the file no longer being used msdosfs_inactive() is called
+ * and will truncate the file to 0 length. When the vnode containing the
+ * denode is needed for some other purpose by VFS it will call
+ * msdosfs_reclaim() which will remove the denode from the denode cache.
+ */
+int
+removede(pdep, dep)
+ struct denode *pdep; /* directory where the entry is removed */
+ struct denode *dep; /* file to be removed */
+{
+ int error;
+ struct direntry *ep;
+ struct buf *bp;
+ daddr_t bn;
+ int blsize;
+ struct msdosfsmount *pmp = pdep->de_pmp;
+ u_long offset = pdep->de_fndoffset;
+
+#ifdef MSDOSFS_DEBUG
+ printf("removede(): filename %s, dep %p, offset %08lx\n",
+ dep->de_Name, dep, offset);
+#endif
+
+ dep->de_refcnt--;
+ offset += sizeof(struct direntry);
+ do {
+ offset -= sizeof(struct direntry);
+ error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
+ if (error)
+ return error;
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ ep = bptoep(pmp, bp, offset);
+ /*
+ * Check whether, if we came here the second time, i.e.
+ * when underflowing into the previous block, the last
+ * entry in this block is a longfilename entry, too.
+ */
+ if (ep->deAttributes != ATTR_WIN95
+ && offset != pdep->de_fndoffset) {
+ brelse(bp);
+ break;
+ }
+ offset += sizeof(struct direntry);
+ while (1) {
+ /*
+ * We are a bit agressive here in that we delete any Win95
+ * entries preceding this entry, not just the ones we "own".
+ * Since these presumably aren't valid anyway,
+ * there should be no harm.
+ */
+ offset -= sizeof(struct direntry);
+ ep--->deName[0] = SLOT_DELETED;
+ if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ || !(offset & pmp->pm_crbomask)
+ || ep->deAttributes != ATTR_WIN95)
+ break;
+ }
+ if ((error = bwrite(bp)) != 0)
+ return error;
+ } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ && !(offset & pmp->pm_crbomask)
+ && offset);
+ return 0;
+}
+
+/*
+ * Create a unique DOS name in dvp
+ */
+int
+uniqdosname(dep, cnp, cp)
+ struct denode *dep;
+ struct componentname *cnp;
+ u_char *cp;
+{
+ struct msdosfsmount *pmp = dep->de_pmp;
+ struct direntry *dentp;
+ int gen;
+ int blsize;
+ u_long cn;
+ daddr_t bn;
+ struct buf *bp;
+ int error;
+
+ for (gen = 1;; gen++) {
+ /*
+ * Generate DOS name with generation number
+ */
+ if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
+ cnp->cn_namelen, gen))
+ return gen == 1 ? EINVAL : EEXIST;
+
+ /*
+ * Now look for a dir entry with this exact name
+ */
+ for (cn = error = 0; !error; cn++) {
+ if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
+ if (error == E2BIG) /* EOF reached and not found */
+ return 0;
+ return error;
+ }
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
+ if (error) {
+ brelse(bp);
+ return error;
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ /*
+ * Last used entry and not found
+ */
+ brelse(bp);
+ return 0;
+ }
+ /*
+ * Ignore volume labels and Win95 entries
+ */
+ if (dentp->deAttributes & ATTR_VOLUME)
+ continue;
+ if (!bcmp(dentp->deName, cp, 11)) {
+ error = EEXIST;
+ break;
+ }
+ }
+ brelse(bp);
+ }
+ }
+}
+
+/*
+ * Find any Win'95 long filename entry in directory dep
+ */
+int
+findwin95(dep)
+ struct denode *dep;
+{
+ struct msdosfsmount *pmp = dep->de_pmp;
+ struct direntry *dentp;
+ int blsize;
+ u_long cn;
+ daddr_t bn;
+ struct buf *bp;
+
+ /*
+ * Read through the directory looking for Win'95 entries
+ * Note: Error currently handled just as EOF XXX
+ */
+ for (cn = 0;; cn++) {
+ if (pcbmap(dep, cn, &bn, 0, &blsize))
+ return 0;
+ if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ brelse(bp);
+ return 0;
+ }
+ for (dentp = (struct direntry *)bp->b_data;
+ (char *)dentp < bp->b_data + blsize;
+ dentp++) {
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ /*
+ * Last used entry and not found
+ */
+ brelse(bp);
+ return 0;
+ }
+ if (dentp->deName[0] == SLOT_DELETED) {
+ /*
+ * Ignore deleted files
+ * Note: might be an indication of Win'95 anyway XXX
+ */
+ continue;
+ }
+ if (dentp->deAttributes == ATTR_WIN95) {
+ brelse(bp);
+ return 1;
+ }
+ }
+ brelse(bp);
+ }
}
diff --git a/sys/msdosfs/msdosfs_vfsops.c b/sys/msdosfs/msdosfs_vfsops.c
index 1fc73f6..f552266 100644
--- a/sys/msdosfs/msdosfs_vfsops.c
+++ b/sys/msdosfs/msdosfs_vfsops.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_vfsops.c,v 1.22 1997/10/12 20:25:01 phk Exp $ */
-/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */
+/* $Id: msdosfs_vfsops.c,v 1.23 1997/11/12 05:42:19 julian Exp $ */
+/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 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).
*
@@ -59,6 +59,7 @@
#include <sys/buf.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
+#include <sys/stat.h> /* defines ALLPERMS */
#include <msdosfs/bpb.h>
#include <msdosfs/bootsect.h>
@@ -70,8 +71,9 @@
MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
+static int update_mp __P((struct mount *mp, struct msdosfs_args *argp));
static int mountmsdosfs __P((struct vnode *devvp, struct mount *mp,
- struct proc *p));
+ struct proc *p, struct msdosfs_args *argp));
static int msdosfs_fhtovp __P((struct mount *, struct fid *,
struct sockaddr *, struct vnode **, int *,
struct ucred **));
@@ -90,6 +92,111 @@ static int msdosfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
static int msdosfs_vptofh __P((struct vnode *, struct fid *));
+static int
+update_mp(mp, argp)
+ struct mount *mp;
+ struct msdosfs_args *argp;
+{
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
+ int error;
+
+ pmp->pm_gid = argp->gid;
+ pmp->pm_uid = argp->uid;
+ pmp->pm_mask = argp->mask & ALLPERMS;
+ pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
+
+#ifndef __FreeBSD__
+ /*
+ * GEMDOS knows nothing (yet) about win95
+ */
+ if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS)
+ pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
+#endif
+
+ if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
+ else if (!(pmp->pm_flags &
+ (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
+ struct vnode *rootvp;
+
+ /*
+ * Try to divine whether to support Win'95 long filenames
+ */
+ if (FAT32(pmp))
+ pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
+ else {
+ if ((error = msdosfs_root(mp, &rootvp)) != 0)
+ return error;
+ pmp->pm_flags |= findwin95(VTODE(rootvp))
+ ? MSDOSFSMNT_LONGNAME
+ : MSDOSFSMNT_SHORTNAME;
+ vput(rootvp);
+ }
+ }
+ return 0;
+}
+
+#ifndef __FreeBSD__
+int
+msdosfs_mountroot()
+{
+ register struct mount *mp;
+ struct proc *p = curproc; /* XXX */
+ size_t size;
+ int error;
+ struct msdosfs_args args;
+
+ if (root_device->dv_class != DV_DISK)
+ return (ENODEV);
+
+ /*
+ * Get vnodes for swapdev and rootdev.
+ */
+ if (bdevvp(rootdev, &rootvp))
+ panic("msdosfs_mountroot: can't setup rootvp");
+
+ mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK);
+ bzero((char *)mp, (u_long)sizeof(struct mount));
+ mp->mnt_op = &msdosfs_vfsops;
+ mp->mnt_flag = 0;
+ LIST_INIT(&mp->mnt_vnodelist);
+
+ args.flags = 0;
+ args.uid = 0;
+ args.gid = 0;
+ args.mask = 0777;
+
+ if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) {
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ if ((error = update_mp(mp, &args)) != 0) {
+ (void)msdosfs_unmount(mp, 0, p);
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ if ((error = vfs_lock(mp)) != 0) {
+ (void)msdosfs_unmount(mp, 0, p);
+ free(mp, M_MOUNT);
+ return (error);
+ }
+
+ CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
+ mp->mnt_vnodecovered = NULLVP;
+ (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
+ (void)msdosfs_statfs(mp, &mp->mnt_stat, p);
+ vfs_unlock(mp);
+ return (0);
+}
+#endif
+
/*
* mp - path - addr in user space of mount point (ie /usr or whatever)
* data - addr in user space of mount params including the name of the block
@@ -105,29 +212,27 @@ msdosfs_mount(mp, path, data, ndp, p)
{
struct vnode *devvp; /* vnode for blk device to mount */
struct msdosfs_args args; /* will hold data from mount request */
- struct msdosfsmount *pmp; /* msdosfs specific mount control block */
+ /* msdosfs specific mount control block */
+ struct msdosfsmount *pmp = NULL;
+ size_t size;
int error, flags;
- u_int size;
- struct ucred *cred, *scred;
- struct vattr va;
+ mode_t accessmode;
- /*
- * Copy in the args for the mount request.
- */
- error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args));
+ error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args));
if (error)
- return error;
-
+ return (error);
+ if (args.magic != MSDOSFS_ARGSMAGIC) {
+ printf("Old mount_msdosfs, flags=%d\n", args.flags);
+ args.flags = 0;
+ }
/*
- * If they just want to update then be sure we can do what is
- * asked. Can't change a filesystem from read/write to read only.
- * Why? And if they've supplied a new device file name then we
- * continue, otherwise return.
+ * If updating, check whether changing from read-only to
+ * read/write; if there is no device name, that's all we do.
*/
if (mp->mnt_flag & MNT_UPDATE) {
- pmp = (struct msdosfsmount *) mp->mnt_data;
+ pmp = VFSTOMSDOSFS(mp);
error = 0;
- if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
+ if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) {
flags = WRITECLOSE;
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
@@ -135,214 +240,226 @@ msdosfs_mount(mp, path, data, ndp, p)
}
if (!error && (mp->mnt_flag & MNT_RELOAD))
/* not yet implemented */
- error = EINVAL;
+ error = EOPNOTSUPP;
if (error)
- return error;
- if (pmp->pm_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR))
- pmp->pm_ronly = 0;
+ return (error);
+ if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
+ /*
+ * If upgrade to read-write by non-root, then verify
+ * that user has necessary permissions on the device.
+ */
+ if (p->p_ucred->cr_uid != 0) {
+ devvp = pmp->pm_devvp;
+ vn_lock(devvp, LK_EXCLUSIVE, p);
+ error = VOP_ACCESS(devvp, VREAD | VWRITE,
+ p->p_ucred, p);
+ if (error) {
+ VOP_UNLOCK(devvp, 0, p);
+ return (error);
+ }
+ VOP_UNLOCK(devvp, 0, p);
+ }
+ pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
+ }
if (args.fspec == 0) {
+#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */
+ if (args.flags & MSDOSFSMNT_MNTOPT) {
+ pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT;
+ pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
+ if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
+ }
+#endif
/*
* Process export requests.
*/
- return vfs_export(mp, &pmp->pm_export, &args.export);
+ return (vfs_export(mp, &pmp->pm_export, &args.export));
}
- } else
- pmp = NULL;
-
- /*
- * check to see that the user in owns the target directory.
- * Note the very XXX trick to make sure we're checking as the
- * real user -- were mount() executable by anyone, this wouldn't
- * be a problem.
- *
- * XXX there should be one consistent error out.
- */
- cred = crdup(p->p_ucred); /* XXX */
- cred->cr_uid = p->p_cred->p_ruid; /* XXX */
- error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p);
- if (error) {
- crfree(cred); /* XXX */
- return error;
- }
- if (cred->cr_uid != 0) {
- if (va.va_uid != cred->cr_uid) {
- error = EACCES;
- crfree(cred); /* XXX */
- return error;
- }
-
- /* a user mounted it; we'll verify permissions when unmounting */
- mp->mnt_flag |= MNT_USER;
}
-
/*
- * Now, lookup the name of the block device this mount or name
- * update request is to apply to.
+ * Not an update, or updating the name: look up the name
+ * and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
- scred = p->p_ucred; /* XXX */
- p->p_ucred = cred; /* XXX */
error = namei(ndp);
- p->p_ucred = scred; /* XXX */
- crfree(cred); /* XXX */
- if (error != 0)
- return error;
-
- /*
- * Be sure they've given us a block device to treat as a
- * filesystem. And, that its major number is within the bdevsw
- * table.
- */
+ if (error)
+ return (error);
devvp = ndp->ni_vp;
+
if (devvp->v_type != VBLK) {
vrele(devvp);
- return ENOTBLK;
+ return (ENOTBLK);
}
if (major(devvp->v_rdev) >= nblkdev) {
vrele(devvp);
- return ENXIO;
+ return (ENXIO);
}
-
/*
- * If this is an update, then make sure the vnode for the block
- * special device is the same as the one our filesystem is in.
+ * If mount by non-root, then verify that user has necessary
+ * permissions on the device.
*/
- if (mp->mnt_flag & MNT_UPDATE) {
+ if (p->p_ucred->cr_uid != 0) {
+ accessmode = VREAD;
+ if ((mp->mnt_flag & MNT_RDONLY) == 0)
+ accessmode |= VWRITE;
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
+ error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p);
+ if (error) {
+ vput(devvp);
+ return (error);
+ }
+ VOP_UNLOCK(devvp, 0, p);
+ }
+ if ((mp->mnt_flag & MNT_UPDATE) == 0) {
+ error = mountmsdosfs(devvp, mp, p, &args);
+#ifdef MSDOSFS_DEBUG /* only needed for the printf below */
+ pmp = VFSTOMSDOSFS(mp);
+#endif
+ } else {
if (devvp != pmp->pm_devvp)
- error = EINVAL;
+ error = EINVAL; /* XXX needs translation */
else
vrele(devvp);
- } else {
-
- /*
- * Well, it's not an update, it's a real mount request.
- * Time to get dirty.
- */
- error = mountmsdosfs(devvp, mp, p);
}
if (error) {
vrele(devvp);
+ return (error);
+ }
+
+ error = update_mp(mp, &args);
+ if (error) {
+ msdosfs_unmount(mp, MNT_FORCE, p);
return error;
}
- /*
- * Copy in the name of the directory the filesystem is to be
- * mounted on. Then copy in the name of the block special file
- * representing the filesystem being mounted. And we clear the
- * remainder of the character strings to be tidy. Set up the
- * user id/group id/mask as specified by the user. Then, we try to
- * fill in the filesystem stats structure as best we can with
- * whatever applies from a dos file system.
- */
- pmp = (struct msdosfsmount *) mp->mnt_data;
- copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname,
- sizeof(mp->mnt_stat.f_mntonname) - 1, &size);
- bzero(mp->mnt_stat.f_mntonname + size,
- sizeof(mp->mnt_stat.f_mntonname) - size);
- copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size);
- bzero(mp->mnt_stat.f_mntfromname + size,
- MNAMELEN - size);
- pmp->pm_mounter = p->p_cred->p_ruid;
- pmp->pm_gid = args.gid;
- pmp->pm_uid = args.uid;
- pmp->pm_mask = args.mask;
+ (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
+ bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
+ (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
+ &size);
+ bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
(void) msdosfs_statfs(mp, &mp->mnt_stat, p);
#ifdef MSDOSFS_DEBUG
printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
#endif
- return 0;
+ return (0);
}
static int
-mountmsdosfs(devvp, mp, p)
+mountmsdosfs(devvp, mp, p, argp)
struct vnode *devvp;
struct mount *mp;
struct proc *p;
+ struct msdosfs_args *argp;
{
- int i;
- int bpc;
- int bit;
- int error;
- int needclose;
- int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+ struct msdosfsmount *pmp;
+ struct buf *bp;
dev_t dev = devvp->v_rdev;
+#ifndef __FreeBSD__
+ struct partinfo dpart;
+#endif
union bootsector *bsp;
- struct msdosfsmount *pmp = NULL;
- struct buf *bp0 = NULL;
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
#ifdef PC98
u_int pc98_wrk;
u_int Phy_Sector_Size;
#endif
+ struct byte_bpb710 *b710;
+ u_int8_t SecPerClust;
+ int ronly, error;
+ int bsize = 0, dtype = 0, tmp;
/*
- * Multiple mounts of the same block special file aren't allowed.
- * Make sure no one else has the special file open. And flush any
- * old buffers from this filesystem. Presumably this prevents us
- * from running into buffers that are the wrong blocksize.
+ * Disallow multiple mounts of the same device.
+ * Disallow mounting of a device that is currently in use
+ * (except for root, which might share swap device for miniroot).
+ * Flush out any old buffers remaining from a previous use.
*/
error = vfs_mountedon(devvp);
if (error)
- return error;
- if (vcount(devvp) > 1)
- return EBUSY;
+ return (error);
+ if (vcount(devvp) > 1 && devvp != rootvp)
+ return (EBUSY);
+ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
+ VOP_UNLOCK(devvp, 0, p);
if (error)
- return error;
+ return (error);
- /*
- * Now open the block special file.
- */
- error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p);
+ ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
+ error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
if (error)
- return error;
- needclose = 1;
-#ifdef HDSUPPORT
- /*
- * Put this in when we support reading dos filesystems from
- * partitioned harddisks.
- */
- if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) {
+ return (error);
+
+ bp = NULL; /* both used in error_exit */
+ pmp = NULL;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ /*
+ * We need the disklabel to calculate the size of a FAT entry
+ * later on. Also make sure the partition contains a filesystem
+ * of type FS_MSDOS. This doesn't work for floppies, so we have
+ * to check for them too.
+ *
+ * At least some parts of the msdos fs driver seem to assume
+ * that the size of a disk block will always be 512 bytes.
+ * Let's check it...
+ */
+ error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart,
+ FREAD, NOCRED, p);
+ if (error)
+ goto error_exit;
+ tmp = dpart.part->p_fstype;
+ dtype = dpart.disklab->d_type;
+ bsize = dpart.disklab->d_secsize;
+ if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) {
+ error = EINVAL;
+ goto error_exit;
+ }
}
#endif
/*
- * Read the boot sector of the filesystem, and then check the boot
- * signature. If not a dos boot sector then error out. We could
- * also add some checking on the bsOemName field. So far I've seen
- * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0"
+ * Read the boot sector of the filesystem, and then check the
+ * boot signature. If not a dos boot sector then error out.
*/
#ifdef PC98
devvp->v_flag &= 0xffff;
- error = bread(devvp, 0, 1024, NOCRED, &bp0);
+ error = bread(devvp, 0, 1024, NOCRED, &bp);
#else
- error = bread(devvp, 0, 512, NOCRED, &bp0);
+ error = bread(devvp, 0, 512, NOCRED, &bp);
#endif
if (error)
goto error_exit;
- bp0->b_flags |= B_AGE;
- bsp = (union bootsector *) bp0->b_data;
- b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB;
- b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB;
-#ifdef MSDOSFS_CHECKSIG
-#ifdef PC98
- if (bsp->bs50.bsBootSectSig != BOOTSIG &&
- bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */
- bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */
- bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */
+ bp->b_flags |= B_AGE;
+ bsp = (union bootsector *)bp->b_data;
+ b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
+ b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
+ b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP;
+
+#ifndef __FreeBSD__
+ if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
+#endif
+#ifdef PC98
+ if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
+ || bsp->bs50.bsBootSectSig1 != BOOTSIG1
+ && bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */
+ || bsp->bs50.bsBootSectSig1 != 0
+ && bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */
+ || bsp->bs50.bsBootSectSig1 != 0x3d
+ && bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */
+ || bsp->bs50.bsBootSectSig1 != 0xfa) {
#else
- if (bsp->bs50.bsBootSectSig != BOOTSIG) {
+ if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
+ || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
#endif
- error = EINVAL;
- goto error_exit;
+ error = EINVAL;
+ goto error_exit;
+ }
+#ifndef __FreeBSD__
}
#endif
- if ( bsp->bs50.bsJump[0] != 0xe9 &&
- (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) {
- error = EINVAL;
- goto error_exit;
- }
pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
bzero((caddr_t)pmp, sizeof *pmp);
@@ -353,28 +470,34 @@ mountmsdosfs(devvp, mp, p)
* bootsector. Copy in the dos 5 variant of the bpb then fix up
* the fields that are different between dos 5 and dos 3.3.
*/
+ SecPerClust = b50->bpbSecPerClust;
pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
- pmp->pm_SectPerClust = b50->bpbSecPerClust;
pmp->pm_ResSectors = getushort(b50->bpbResSectors);
pmp->pm_FATs = b50->bpbFATs;
pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
pmp->pm_Sectors = getushort(b50->bpbSectors);
- pmp->pm_Media = b50->bpbMedia;
pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
pmp->pm_Heads = getushort(b50->bpbHeads);
+ pmp->pm_Media = b50->bpbMedia;
- /* XXX - We should probably check more values here */
- if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
- !pmp->pm_Heads || pmp->pm_Heads > 255 ||
+#ifndef __FreeBSD__
+ if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
+#endif
+ /* XXX - We should probably check more values here */
+ if (!pmp->pm_BytesPerSec || !SecPerClust
+ || !pmp->pm_Heads || pmp->pm_Heads > 255
#ifdef PC98
- !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
+ || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) {
#else
- !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
+ || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) {
#endif
- error = EINVAL;
- goto error_exit;
+ error = EINVAL;
+ goto error_exit;
+ }
+#ifndef __FreeBSD__
}
+#endif
if (pmp->pm_Sectors == 0) {
pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
@@ -411,86 +534,193 @@ mountmsdosfs(devvp, mp, p)
}
pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size;
pmp->pm_BytesPerSec = Phy_Sector_Size;
- pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk;
+ SecPerClust = SecPerClust * pc98_wrk;
pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk;
pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk;
pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk;
pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk;
pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk;
#endif /* */
+ if (pmp->pm_HugeSectors > 0xffffffff / pmp->pm_BytesPerSec + 1) {
+ /*
+ * We cannot deal currently with this size of disk
+ * due to fileid limitations (see msdosfs_getattr and
+ * msdosfs_readdir)
+ */
+ error = EINVAL;
+ goto error_exit;
+ }
+
+ if (pmp->pm_RootDirEnts == 0) {
+ if (bsp->bs710.bsBootSectSig2 != BOOTSIG2
+ || bsp->bs710.bsBootSectSig3 != BOOTSIG3
+ || pmp->pm_Sectors
+ || pmp->pm_FATsecs
+ || getushort(b710->bpbFSVers)) {
+ error = EINVAL;
+ goto error_exit;
+ }
+ pmp->pm_fatmask = FAT32_MASK;
+ pmp->pm_fatmult = 4;
+ pmp->pm_fatdiv = 1;
+ pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
+ if (getushort(b710->bpbExtFlags) & FATMIRROR)
+ pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
+ else
+ pmp->pm_flags |= MSDOSFS_FATMIRROR;
+ } else
+ pmp->pm_flags |= MSDOSFS_FATMIRROR;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ if (FAT32(pmp)) {
+ /*
+ * GEMDOS doesn't know fat32.
+ */
+ error = EINVAL;
+ goto error_exit;
+ }
+
+ /*
+ * Check a few values (could do some more):
+ * - logical sector size: power of 2, >= block size
+ * - sectors per cluster: power of 2, >= 1
+ * - number of sectors: >= 1, <= size of partition
+ */
+ if ( (SecPerClust == 0)
+ || (SecPerClust & (SecPerClust - 1))
+ || (pmp->pm_BytesPerSec < bsize)
+ || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
+ || (pmp->pm_HugeSectors == 0)
+ || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
+ > dpart.part->p_size)
+ ) {
+ error = EINVAL;
+ goto error_exit;
+ }
+ /*
+ * XXX - Many parts of the msdos fs driver seem to assume that
+ * the number of bytes per logical sector (BytesPerSec) will
+ * always be the same as the number of bytes per disk block
+ * Let's pretend it is.
+ */
+ tmp = pmp->pm_BytesPerSec / bsize;
+ pmp->pm_BytesPerSec = bsize;
+ pmp->pm_HugeSectors *= tmp;
+ pmp->pm_HiddenSects *= tmp;
+ pmp->pm_ResSectors *= tmp;
+ pmp->pm_Sectors *= tmp;
+ pmp->pm_FATsecs *= tmp;
+ SecPerClust *= tmp;
+ }
+#endif
pmp->pm_fatblk = pmp->pm_ResSectors;
- pmp->pm_rootdirblk = pmp->pm_fatblk +
- (pmp->pm_FATs * pmp->pm_FATsecs);
- pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
- /
- pmp->pm_BytesPerSec;/* in sectors */
- pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
+ if (FAT32(pmp)) {
+ pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
+ pmp->pm_firstcluster = pmp->pm_fatblk
+ + (pmp->pm_FATs * pmp->pm_FATsecs);
+ pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
+ } else {
+ pmp->pm_rootdirblk = pmp->pm_fatblk +
+ (pmp->pm_FATs * pmp->pm_FATsecs);
+ pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
+ + pmp->pm_BytesPerSec - 1)
+ / pmp->pm_BytesPerSec;/* in sectors */
+ pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
+ }
+
pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
- pmp->pm_SectPerClust;
+ SecPerClust;
pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
+
+#ifndef __FreeBSD__
+ if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
+ if ((pmp->pm_nmbrofclusters <= (0xff0 - 2))
+ && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE)
+ && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2))))
+ ) {
+ pmp->pm_fatmask = FAT12_MASK;
+ pmp->pm_fatmult = 3;
+ pmp->pm_fatdiv = 2;
+ } else {
+ pmp->pm_fatmask = FAT16_MASK;
+ pmp->pm_fatmult = 2;
+ pmp->pm_fatdiv = 1;
+ }
+ } else
+#endif
+ if (pmp->pm_fatmask == 0) {
+ if (pmp->pm_maxcluster
+ <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
+ /*
+ * This will usually be a floppy disk. This size makes
+ * sure that one fat entry will not be split across
+ * multiple blocks.
+ */
+ pmp->pm_fatmask = FAT12_MASK;
+ pmp->pm_fatmult = 3;
+ pmp->pm_fatdiv = 2;
+ } else {
+ pmp->pm_fatmask = FAT16_MASK;
+ pmp->pm_fatmult = 2;
+ pmp->pm_fatdiv = 1;
+ }
+ }
if (FAT12(pmp))
- /*
- * This will usually be a floppy disk. This size makes sure
- * that one fat entry will not be split across multiple
- * blocks.
- */
pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
else
- /*
- * This will usually be a hard disk. Reading or writing one
- * block should be quite fast.
- */
pmp->pm_fatblocksize = MAXBSIZE;
- pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
-
- if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
- printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n");
+ pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
+ pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
/*
* Compute mask and shift value for isolating cluster relative byte
* offsets and cluster numbers from a file offset.
*/
- bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
- pmp->pm_bpcluster = bpc;
- pmp->pm_depclust = bpc / sizeof(struct direntry);
- pmp->pm_crbomask = bpc - 1;
- if (bpc == 0) {
+ pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
+ pmp->pm_crbomask = pmp->pm_bpcluster - 1;
+ pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
+
+ /*
+ * Check for valid cluster size
+ * must be a power of 2
+ */
+ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
error = EINVAL;
goto error_exit;
}
- bit = 1;
- for (i = 0; i < 32; i++) {
- if (bit & bpc) {
- if (bit ^ bpc) {
- error = EINVAL;
- goto error_exit;
- }
- pmp->pm_cnshift = i;
- break;
- }
- bit <<= 1;
- }
-#ifdef PC98
- if (Phy_Sector_Size == 512) {
- pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
- pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
- } else {
- pmp->pm_brbomask = 0x03ff;
- pmp->pm_bnshift = 10;
+ /*
+ * Release the bootsector buffer.
+ */
+ brelse(bp);
+ bp = NULL;
+
+ /*
+ * Check FSInfo.
+ */
+ if (pmp->pm_fsinfo) {
+ struct fsinfo *fp;
+
+ if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0)
+ goto error_exit;
+ fp = (struct fsinfo *)bp->b_data;
+ if (!bcmp(fp->fsisig1, "RRaA", 4)
+ && !bcmp(fp->fsisig2, "rrAa", 4)
+ && !bcmp(fp->fsisig3, "\0\0\125\252", 4)
+ && !bcmp(fp->fsisig4, "\0\0\125\252", 4))
+ pmp->pm_nxtfree = getulong(fp->fsinxtfree);
+ else
+ pmp->pm_fsinfo = 0;
+ brelse(bp);
+ bp = NULL;
}
-#else
- pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
- pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
-#endif
/*
- * Release the bootsector buffer.
+ * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX
*/
- brelse(bp0);
- bp0 = NULL;
/*
* Allocate memory for the bitmap of allocated clusters, and then
@@ -510,8 +740,7 @@ mountmsdosfs(devvp, mp, p)
/*
* Have the inuse map filled in.
*/
- error = fillinusemap(pmp);
- if (error)
+ if ((error = fillinusemap(pmp)) != 0)
goto error_exit;
/*
@@ -520,13 +749,15 @@ mountmsdosfs(devvp, mp, p)
* the fat being correct just about all the time. I suppose this
* would be a good thing to turn on if the kernel is still flakey.
*/
- pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
+ if (mp->mnt_flag & MNT_SYNCHRONOUS)
+ pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
/*
* Finish up.
*/
- pmp->pm_ronly = ronly;
- if (ronly == 0)
+ if (ronly)
+ pmp->pm_flags |= MSDOSFSMNT_RONLY;
+ else
pmp->pm_fmod = 1;
mp->mnt_data = (qaddr_t) pmp;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
@@ -536,19 +767,17 @@ mountmsdosfs(devvp, mp, p)
return 0;
-error_exit:;
- if (bp0)
- brelse(bp0);
- if (needclose)
- (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE,
- NOCRED, p);
+error_exit:
+ if (bp)
+ brelse(bp);
+ (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p);
if (pmp) {
if (pmp->pm_inusemap)
- free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
- free((caddr_t) pmp, M_MSDOSFSMNT);
- mp->mnt_data = (qaddr_t) 0;
+ free(pmp->pm_inusemap, M_MSDOSFSFAT);
+ free(pmp, M_MSDOSFSMNT);
+ mp->mnt_data = (qaddr_t)0;
}
- return error;
+ return (error);
}
static int
@@ -557,7 +786,8 @@ msdosfs_start(mp, flags, p)
int flags;
struct proc *p;
{
- return 0;
+
+ return (0);
}
/*
@@ -569,30 +799,47 @@ msdosfs_unmount(mp, mntflags, p)
int mntflags;
struct proc *p;
{
- int flags = 0;
- int error;
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
-
- /* only the mounter, or superuser can unmount */
- if ((p->p_cred->p_ruid != pmp->pm_mounter) &&
- (error = suser(p->p_ucred, &p->p_acflag)))
- return error;
+ struct msdosfsmount *pmp;
+ int error, flags;
- if (mntflags & MNT_FORCE) {
+ flags = 0;
+ if (mntflags & MNT_FORCE)
flags |= FORCECLOSE;
- }
error = vflush(mp, NULLVP, flags);
if (error)
return error;
+ pmp = VFSTOMSDOSFS(mp);
pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
- error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE,
+#ifdef MSDOSFS_DEBUG
+ {
+ struct vnode *vp = pmp->pm_devvp;
+
+ printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
+ printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n",
+ vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
+ printf("lastr %d, id %lu, mount %p, op %p\n",
+ vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op);
+ printf("freef %p, freeb %p, mount %p\n",
+ vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev,
+ vp->v_mount);
+ printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n",
+ vp->v_cleanblkhd.lh_first,
+ vp->v_dirtyblkhd.lh_first,
+ vp->v_numoutput, vp->v_type);
+ printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
+ vp->v_socket, vp->v_tag,
+ ((u_int *)vp->v_data)[0],
+ ((u_int *)vp->v_data)[1]);
+ }
+#endif
+ error = VOP_CLOSE(pmp->pm_devvp, (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE,
NOCRED, p);
vrele(pmp->pm_devvp);
- free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT);
- free((caddr_t) pmp, M_MSDOSFSMNT);
- mp->mnt_data = (qaddr_t) 0;
+ free(pmp->pm_inusemap, M_MSDOSFSFAT);
+ free(pmp, M_MSDOSFSMNT);
+ mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
- return error;
+ return (error);
}
static int
@@ -600,18 +847,18 @@ msdosfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
struct denode *ndep;
- struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data);
int error;
- error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n",
- mp, pmp, ndep, DETOV(ndep));
+ printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
#endif
- if (error == 0)
- *vpp = DETOV(ndep);
- return error;
+ error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep);
+ if (error)
+ return (error);
+ *vpp = DETOV(ndep);
+ return (0);
}
static int
@@ -631,11 +878,9 @@ msdosfs_statfs(mp, sbp, p)
struct statfs *sbp;
struct proc *p;
{
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp;
- /*
- * Fill in the stat block.
- */
+ pmp = VFSTOMSDOSFS(mp);
sbp->f_bsize = pmp->pm_bpcluster;
sbp->f_iosize = pmp->pm_bpcluster;
sbp->f_blocks = pmp->pm_nmbrofclusters;
@@ -643,23 +888,13 @@ msdosfs_statfs(mp, sbp, p)
sbp->f_bavail = pmp->pm_freeclustercount;
sbp->f_files = pmp->pm_RootDirEnts; /* XXX */
sbp->f_ffree = 0; /* what to put in here? */
-
- /*
- * Copy the mounted on and mounted from names into the passed in
- * stat block, if it is not the one in the mount structure.
- */
if (sbp != &mp->mnt_stat) {
sbp->f_type = mp->mnt_vfc->vfc_typenum;
- bcopy((caddr_t) mp->mnt_stat.f_mntonname,
- (caddr_t) & sbp->f_mntonname[0], MNAMELEN);
- bcopy((caddr_t) mp->mnt_stat.f_mntfromname,
- (caddr_t) & sbp->f_mntfromname[0], MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
+ bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
}
-#if 0
- strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN);
- sbp->f_fstypename[MFSNAMELEN] = '\0';
-#endif
- return 0;
+ strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
+ return (0);
}
static int
@@ -669,39 +904,42 @@ msdosfs_sync(mp, waitfor, cred, p)
struct ucred *cred;
struct proc *p;
{
- struct vnode *vp;
+ struct vnode *vp, *nvp;
struct denode *dep;
- struct msdosfsmount *pmp;
- int error;
- int allerror = 0;
-
- pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
+ int error, allerror = 0;
/*
* If we ever switch to not updating all of the fats all the time,
* this would be the place to update them from the first one.
*/
- if (pmp->pm_fmod)
- if (pmp->pm_ronly)
+ if (pmp->pm_fmod != 0)
+ if (pmp->pm_flags & MSDOSFSMNT_RONLY)
panic("msdosfs_sync: rofs mod");
else {
/* update fats here */
}
-
/*
- * Go thru in memory denodes and write them out along with
- * unwritten file blocks.
+ * Write back each (modified) denode.
*/
simple_lock(&mntvnode_slock);
loop:
- for (vp = mp->mnt_vnodelist.lh_first; vp;
- vp = vp->v_mntvnodes.le_next) {
- if (vp->v_mount != mp) /* not ours anymore */
+ for (vp = mp->mnt_vnodelist.lh_first;
+ vp != NULL;
+ vp = nvp) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * assoicated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
goto loop;
+
simple_lock(&vp->v_interlock);
+ nvp = vp->v_mntvnodes.le_next;
dep = VTODE(vp);
- if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 &&
- vp->v_dirtyblkhd.lh_first == NULL) {
+ if (vp->v_type == VNON || ((dep->de_flag &
+ (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0)
+ && vp->v_dirtyblkhd.lh_first == NULL) {
simple_unlock(&vp->v_interlock);
continue;
}
@@ -728,7 +966,7 @@ loop:
error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p);
if (error)
allerror = error;
- return allerror;
+ return (allerror);
}
static int
@@ -740,7 +978,7 @@ msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
int *exflagsp;
struct ucred **credanonp;
{
- struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data;
+ struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
struct defid *defhp = (struct defid *) fhp;
struct denode *dep;
struct netcred *np;
@@ -748,33 +986,33 @@ msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
np = vfs_export_lookup(mp, &pmp->pm_export, nam);
if (np == NULL)
- return EACCES;
- error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs,
- NULL, &dep);
+ return (EACCES);
+ error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
if (error) {
*vpp = NULLVP;
- return error;
+ return (error);
}
*vpp = DETOV(dep);
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
- return 0;
+ return (0);
}
-
static int
msdosfs_vptofh(vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
- struct denode *dep = VTODE(vp);
- struct defid *defhp = (struct defid *) fhp;
+ struct denode *dep;
+ struct defid *defhp;
+ dep = VTODE(vp);
+ defhp = (struct defid *)fhp;
defhp->defid_len = sizeof(struct defid);
defhp->defid_dirclust = dep->de_dirclust;
defhp->defid_dirofs = dep->de_diroffset;
- /* defhp->defid_gen = ip->i_gen; */
- return 0;
+ /* defhp->defid_gen = dep->de_gen; */
+ return (0);
}
static int
diff --git a/sys/msdosfs/msdosfs_vnops.c b/sys/msdosfs/msdosfs_vnops.c
index 3d7b3f7..a78a467 100644
--- a/sys/msdosfs/msdosfs_vnops.c
+++ b/sys/msdosfs/msdosfs_vnops.c
@@ -1,9 +1,9 @@
-/* $Id: msdosfs_vnops.c,v 1.54 1998/02/04 22:33:01 eivind Exp $ */
-/* $NetBSD: msdosfs_vnops.c,v 1.20 1994/08/21 18:44:13 ws Exp $ */
+/* $Id: msdosfs_vnops.c,v 1.55 1998/02/06 12:13:46 eivind Exp $ */
+/* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 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).
*
@@ -140,38 +140,58 @@ msdosfs_create(ap)
int error;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
+ printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
#endif
/*
+ * If this is the root directory and there is no space left we
+ * can't do anything. This is because the root directory can not
+ * change size.
+ */
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
+ error = ENOSPC;
+ goto bad;
+ }
+
+ /*
* Create a directory entry for the file, then call createde() to
* have it installed. NOTE: DOS files are always executable. We
* use the absence of the owner write bit to make the file
* readonly.
*/
#ifdef DIAGNOSTIC
- if ((cnp->cn_flags & SAVENAME) == 0)
+ if ((cnp->cn_flags & HASBUF) == 0)
panic("msdosfs_create: no name");
#endif
bzero(&ndirent, sizeof(ndirent));
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &ndirent.de_Date, &ndirent.de_Time);
- unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
- ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE)
- ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
+ error = uniqdosname(pdep, cnp, ndirent.de_Name);
+ if (error)
+ goto bad;
+
+ ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
+ ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
ndirent.de_StartCluster = 0;
ndirent.de_FileSize = 0;
ndirent.de_dev = pdep->de_dev;
ndirent.de_devvp = pdep->de_devvp;
- if ((error = createde(&ndirent, pdep, &dep)) == 0) {
- *ap->a_vpp = DETOV(dep);
- if ((cnp->cn_flags & SAVESTART) == 0)
- zfree(namei_zone, cnp->cn_pnbuf);
- } else {
+ ndirent.de_pmp = pdep->de_pmp;
+ ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(&ndirent, &ts, &ts, &ts);
+ error = createde(&ndirent, pdep, &dep, cnp);
+ if (error)
+ goto bad;
+ if ((cnp->cn_flags & SAVESTART) == 0)
zfree(namei_zone, cnp->cn_pnbuf);
- }
- vput(ap->a_dvp); /* release parent dir */
- return error;
+ vput(ap->a_dvp);
+ *ap->a_vpp = DETOV(dep);
+ return (0);
+
+bad:
+ zfree(namei_zone, cnp->cn_pnbuf);
+ vput(ap->a_dvp);
+ return (error);
}
static int
@@ -183,24 +203,22 @@ msdosfs_mknod(ap)
struct vattr *a_vap;
} */ *ap;
{
- int error;
switch (ap->a_vap->va_type) {
case VDIR:
- error = msdosfs_mkdir((struct vop_mkdir_args *)ap);
+ return (msdosfs_mkdir((struct vop_mkdir_args *)ap));
break;
case VREG:
- error = msdosfs_create((struct vop_create_args *)ap);
+ return (msdosfs_create((struct vop_create_args *)ap));
break;
default:
- error = EINVAL;
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
vput(ap->a_dvp);
- break;
+ return (EINVAL);
}
- return error;
+ /* NOTREACHED */
}
static int
@@ -214,10 +232,13 @@ msdosfs_close(ap)
{
struct vnode *vp = ap->a_vp;
struct denode *dep = VTODE(vp);
+ struct timespec ts;
simple_lock(&vp->v_interlock);
- if (vp->v_usecount > 1)
- DE_TIMES(dep, &time);
+ if (vp->v_usecount > 1) {
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(dep, &ts, &ts, &ts);
+ }
simple_unlock(&vp->v_interlock);
return 0;
}
@@ -309,9 +330,15 @@ msdosfs_getattr(ap)
{
u_int cn;
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
struct vattr *vap = ap->a_vap;
+ mode_t mode;
+ struct timespec ts;
+ u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
+ u_long fileid;
- DE_TIMES(dep, &time);
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(dep, &ts, &ts, &ts);
vap->va_fsid = dep->de_dev;
/*
* The following computation of the fileid must be the same as that
@@ -319,41 +346,44 @@ msdosfs_getattr(ap)
* doesn't work.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
- if ((cn = dep->de_StartCluster) == MSDOSFSROOT)
- cn = 1;
+ fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
+ if (dep->de_StartCluster == MSDOSFSROOT)
+ fileid = 1;
} else {
- if ((cn = dep->de_dirclust) == MSDOSFSROOT)
- cn = 1;
- cn = (cn << 16) | (dep->de_diroffset & 0xffff);
+ fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
+ if (dep->de_dirclust == MSDOSFSROOT)
+ fileid = roottobn(pmp, 0) * dirsperblk;
+ fileid += dep->de_diroffset / sizeof(struct direntry);
}
- vap->va_fileid = cn;
- vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
- ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
- vap->va_mode &= dep->de_pmp->pm_mask;
- if (dep->de_Attributes & ATTR_DIRECTORY)
- vap->va_mode |= S_IFDIR;
+ vap->va_fileid = fileid;
+ if ((dep->de_Attributes & ATTR_READONLY) == 0)
+ mode = S_IRWXU|S_IRWXG|S_IRWXO;
+ else
+ mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
+ vap->va_mode = mode & pmp->pm_mask;
+ vap->va_uid = pmp->pm_uid;
+ vap->va_gid = pmp->pm_gid;
vap->va_nlink = 1;
- vap->va_gid = dep->de_pmp->pm_gid;
- vap->va_uid = dep->de_pmp->pm_uid;
vap->va_rdev = 0;
vap->va_size = dep->de_FileSize;
- dos2unixtime(dep->de_Date, dep->de_Time, &vap->va_atime);
- vap->va_mtime = vap->va_atime;
-#if 0
-#ifndef MSDOSFS_NODIRMOD
- if (vap->va_mode & S_IFDIR)
- TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime);
-#endif
-#endif
- vap->va_ctime = vap->va_atime;
- vap->va_flags = (dep->de_Attributes & ATTR_ARCHIVE) ? 0 : SF_ARCHIVED;
+ dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
+ if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
+ dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
+ dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
+ } else {
+ vap->va_atime = vap->va_mtime;
+ vap->va_ctime = vap->va_mtime;
+ }
+ vap->va_flags = 0;
+ if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
+ vap->va_flags |= SF_ARCHIVED;
vap->va_gen = 0;
- vap->va_blocksize = dep->de_pmp->pm_bpcluster;
- vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
- ~(dep->de_pmp->pm_crbomask);
+ vap->va_blocksize = pmp->pm_bpcluster;
+ vap->va_bytes =
+ (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
vap->va_type = ap->a_vp->v_type;
vap->va_filerev = dep->de_modrev;
- return 0;
+ return (0);
}
static int
@@ -367,10 +397,16 @@ msdosfs_setattr(ap)
{
struct vnode *vp = ap->a_vp;
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
struct vattr *vap = ap->a_vap;
struct ucred *cred = ap->a_cred;
int error = 0;
+#ifdef MSDOSFS_DEBUG
+ printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n",
+ ap->a_vp, vap, cred, ap->a_p);
+#endif
+
/*
* Check for unsettable attributes.
*/
@@ -378,12 +414,21 @@ msdosfs_setattr(ap)
(vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
(vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
(vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
+#ifdef MSDOSFS_DEBUG
+ printf("msdosfs_setattr(): returning EINVAL\n");
+ printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %lx\n",
+ vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
+ printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",
+ vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
+ printf(" va_uid %x, va_gid %x\n",
+ vap->va_uid, vap->va_gid);
+#endif
return (EINVAL);
}
if (vap->va_flags != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)))
return (error);
/*
@@ -411,19 +456,26 @@ msdosfs_setattr(ap)
dep->de_flag |= DE_MODIFIED;
}
- if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) {
+ if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+ uid_t uid;
+ gid_t gid;
+
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if ((cred->cr_uid != dep->de_pmp->pm_uid ||
- vap->va_uid != dep->de_pmp->pm_uid ||
- (vap->va_gid != dep->de_pmp->pm_gid &&
- !groupmember(vap->va_gid, cred))) &&
+ uid = vap->va_uid;
+ if (uid == (uid_t)VNOVAL)
+ uid = pmp->pm_uid;
+ gid = vap->va_gid;
+ if (gid == (gid_t)VNOVAL)
+ gid = pmp->pm_gid;
+ if ((cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
+ (gid != pmp->pm_gid && !groupmember(gid, cred))) &&
(error = suser(cred, &ap->a_p->p_acflag)))
return error;
- if (vap->va_uid != dep->de_pmp->pm_uid ||
- vap->va_gid != dep->de_pmp->pm_gid)
+ if (uid != pmp->pm_uid || gid != pmp->pm_gid)
return EINVAL;
}
+
if (vap->va_size != VNOVAL) {
/*
* Disallow write attempts on read-only file systems;
@@ -443,41 +495,45 @@ msdosfs_setattr(ap)
if (error)
return error;
}
- if (vap->va_mtime.tv_sec != VNOVAL) {
+ if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)) &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
- (error = VOP_ACCESS(vp, VWRITE, cred, ap->a_p))))
- return error;
- dep->de_flag |= DE_UPDATE;
- error = deupdat(dep, &vap->va_mtime, 1);
- if (error)
- return error;
+ (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
+ return (error);
+ if (vp->v_type != VDIR) {
+ if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
+ vap->va_atime.tv_sec != VNOVAL)
+ unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
+ if (vap->va_mtime.tv_sec != VNOVAL)
+ unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
+ dep->de_Attributes |= ATTR_ARCHIVE;
+ dep->de_flag |= DE_MODIFIED;
+ }
}
-
/*
* DOS files only have the ability to have their writability
* attribute set, so we use the owner write bit to set the readonly
* attribute.
*/
- error = 0;
- if (vap->va_mode != (u_short) VNOVAL) {
+ if (vap->va_mode != (mode_t)VNOVAL) {
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (EROFS);
- if (cred->cr_uid != dep->de_pmp->pm_uid &&
+ if (cred->cr_uid != pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)))
- return error;
-
- /* We ignore the read and execute bits */
- if (vap->va_mode & VWRITE)
- dep->de_Attributes &= ~ATTR_READONLY;
- else
- dep->de_Attributes |= ATTR_READONLY;
- dep->de_flag |= DE_MODIFIED;
+ return (error);
+ if (vp->v_type != VDIR) {
+ /* We ignore the read and execute bits. */
+ if (vap->va_mode & VWRITE)
+ dep->de_Attributes &= ~ATTR_READONLY;
+ else
+ dep->de_Attributes |= ATTR_READONLY;
+ dep->de_flag |= DE_MODIFIED;
+ }
}
- return error;
+ return (deupdat(dep, 1));
}
static int
@@ -491,11 +547,12 @@ msdosfs_read(ap)
{
int error = 0;
int diff;
+ int blsize;
int isadir;
long n;
long on;
daddr_t lbn;
- daddr_t rablock;
+ daddr_t rablock, rablock1;
int rasize;
struct buf *bp;
struct vnode *vp = ap->a_vp;
@@ -507,34 +564,33 @@ msdosfs_read(ap)
* If they didn't ask for any data, then we are done.
*/
if (uio->uio_resid == 0)
- return 0;
+ return (0);
if (uio->uio_offset < 0)
- return EINVAL;
+ return (EINVAL);
isadir = dep->de_Attributes & ATTR_DIRECTORY;
do {
- lbn = uio->uio_offset >> pmp->pm_cnshift;
+ lbn = de_cluster(pmp, uio->uio_offset);
on = uio->uio_offset & pmp->pm_crbomask;
n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
diff = dep->de_FileSize - uio->uio_offset;
if (diff <= 0)
- return 0;
+ return (0);
+ if (diff < n)
+ n = diff;
/* convert cluster # to block # if a directory */
if (isadir) {
- error = pcbmap(dep, lbn, &lbn, 0);
+ error = pcbmap(dep, lbn, &lbn, 0, &blsize);
if (error)
- return error;
+ return (error);
}
- if (diff < n)
- n = diff;
/*
* If we are operating on a directory file then be sure to
* do i/o with the vnode for the filesystem instead of the
* vnode for the directory.
*/
if (isadir) {
- error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
- NOCRED, &bp);
+ error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
} else {
rablock = lbn + 1;
#ifdef PC98
@@ -545,36 +601,28 @@ msdosfs_read(ap)
vp->v_flag |= 0x10000;
#endif
if (vp->v_lastr + 1 == lbn &&
- rablock * pmp->pm_bpcluster < dep->de_FileSize) {
+ de_cn2off(pmp, rablock) < dep->de_FileSize) {
+ rablock1 = de_cn2bn(pmp, rablock);
rasize = pmp->pm_bpcluster;
- error = breadn(vp, lbn, pmp->pm_bpcluster,
- &rablock, &rasize, 1,
- NOCRED, &bp);
- } else {
- error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
- &bp);
- }
+ error = breadn(vp, de_cn2bn(pmp, lbn),
+ pmp->pm_bpcluster, &rablock1, &rasize, 1,
+ NOCRED, &bp);
+ } else
+ error = bread(vp, de_cn2bn(pmp, lbn),
+ pmp->pm_bpcluster, NOCRED, &bp);
vp->v_lastr = lbn;
}
n = min(n, pmp->pm_bpcluster - bp->b_resid);
if (error) {
brelse(bp);
- return error;
+ return (error);
}
error = uiomove(bp->b_data + on, (int) n, uio);
- /*
- * If we have read everything from this block or have read
- * to end of file then we are done with this block. Mark
- * it to say the buffer can be reused if need be.
- */
-#if 0
- if (n + on == pmp->pm_bpcluster ||
- uio->uio_offset == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif
+ if (!isadir)
+ dep->de_flag |= DE_ACCESS;
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
- return error;
+ return (error);
}
/*
@@ -590,10 +638,9 @@ msdosfs_write(ap)
} */ *ap;
{
int n;
- int isadir;
int croffset;
int resid;
- int osize;
+ u_long osize;
int error = 0;
u_long count;
daddr_t bn, lastcn;
@@ -606,61 +653,43 @@ msdosfs_write(ap)
struct denode *dep = VTODE(vp);
struct msdosfsmount *pmp = dep->de_pmp;
struct ucred *cred = ap->a_cred;
- struct timespec ts;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
- vp, uio, ioflag, cred);
- printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
- dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
+ printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
+ vp, uio, ioflag, cred);
+ printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
+ dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
#endif
switch (vp->v_type) {
case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = dep->de_FileSize;
- isadir = 0;
thisvp = vp;
break;
-
case VDIR:
- if ((ioflag & IO_SYNC) == 0)
- panic("msdosfs_write(): non-sync directory update");
- isadir = 1;
- thisvp = pmp->pm_devvp;
- break;
-
+ return EISDIR;
default:
panic("msdosfs_write(): bad file type");
- break;
}
if (uio->uio_offset < 0)
- return EINVAL;
+ return (EINVAL);
if (uio->uio_resid == 0)
- return 0;
+ return (0);
/*
* If they've exceeded their filesize limit, tell them about it.
*/
- if (vp->v_type == VREG && p &&
+ if (p &&
((uio->uio_offset + uio->uio_resid) >
- p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
+ p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
psignal(p, SIGXFSZ);
- return EFBIG;
+ return (EFBIG);
}
/*
- * If attempting to write beyond the end of the root directory we
- * stop that here because the root directory can not grow.
- */
- if ((dep->de_Attributes & ATTR_DIRECTORY) &&
- dep->de_StartCluster == MSDOSFSROOT &&
- (uio->uio_offset + uio->uio_resid) > dep->de_FileSize)
- return ENOSPC;
-
- /*
* If the offset we are starting the write at is beyond the end of
* the file, then they've done a seek. Unix filesystems allow
* files with holes in them, DOS doesn't so we must fill the hole
@@ -669,7 +698,7 @@ msdosfs_write(ap)
if (uio->uio_offset > dep->de_FileSize) {
error = deextend(dep, uio->uio_offset, cred);
if (error)
- return error;
+ return (error);
}
/*
@@ -678,7 +707,6 @@ msdosfs_write(ap)
resid = uio->uio_resid;
osize = dep->de_FileSize;
-
#ifdef PC98
/*
* 1024byte/sector support
@@ -691,21 +719,17 @@ msdosfs_write(ap)
* size ahead of the time to hopefully get a contiguous area.
*/
if (uio->uio_offset + resid > osize) {
- count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize);
- if ((error = extendfile(dep, count, NULL, NULL, 0))
- && (error != ENOSPC || (ioflag & IO_UNIT)))
+ count = de_clcount(pmp, uio->uio_offset + resid) -
+ de_clcount(pmp, osize);
+ error = extendfile(dep, count, NULL, NULL, 0);
+ if (error && (error != ENOSPC || (ioflag & IO_UNIT)))
goto errexit;
lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
} else
lastcn = de_clcount(pmp, osize) - 1;
do {
- bn = de_blk(pmp, uio->uio_offset);
- if (isadir) {
- error = pcbmap(dep, bn, &bn, 0);
- if (error)
- break;
- } else if (bn > lastcn) {
+ if (de_cluster(pmp, uio->uio_offset) > lastcn) {
error = ENOSPC;
break;
}
@@ -718,6 +742,7 @@ msdosfs_write(ap)
vnode_pager_setsize(vp, dep->de_FileSize);
}
+ bn = de_blk(pmp, uio->uio_offset);
if ((uio->uio_offset & pmp->pm_crbomask) == 0
&& (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
|| uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
@@ -732,27 +757,28 @@ msdosfs_write(ap)
* Do the bmap now, since pcbmap needs buffers
* for the fat table. (see msdosfs_strategy)
*/
- if (!isadir) {
- if (bp->b_blkno == bp->b_lblkno) {
- error = pcbmap(dep, bp->b_lblkno,
- &bp->b_blkno, 0);
- if (error)
- bp->b_blkno = -1;
- }
- if (bp->b_blkno == -1) {
- brelse(bp);
- if (!error)
- error = EIO; /* XXX */
- break;
- }
+ if (bp->b_blkno == bp->b_lblkno) {
+ error = pcbmap(dep,
+ de_bn2cn(pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0);
+ if (error)
+ bp->b_blkno = -1;
+ }
+ if (bp->b_blkno == -1) {
+ brelse(bp);
+ if (!error)
+ error = EIO; /* XXX */
+ break;
}
} else {
/*
* The block we need to write into exists, so read it in.
*/
error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
- if (error)
+ if (error) {
+ brelse(bp);
break;
+ }
}
/*
@@ -774,9 +800,9 @@ msdosfs_write(ap)
*/
if (ioflag & IO_SYNC)
(void) bwrite(bp);
- else if (n + croffset == pmp->pm_bpcluster) {
+ else if (n + croffset == pmp->pm_bpcluster)
bawrite(bp);
- } else
+ else
bdwrite(bp);
dep->de_flag |= DE_UPDATE;
} while (error == 0 && uio->uio_resid > 0);
@@ -796,11 +822,9 @@ errexit:
if (uio->uio_resid != resid)
error = 0;
}
- } else if (ioflag & IO_SYNC) {
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- error = deupdat(dep, &ts, 1);
- }
- return error;
+ } else if (ioflag & IO_SYNC)
+ error = deupdat(dep, 1);
+ return (error);
}
/*
@@ -818,12 +842,9 @@ msdosfs_fsync(ap)
struct proc *a_p;
} */ *ap;
{
- register struct vnode *vp = ap->a_vp;
- register struct buf *bp;
- int wait = ap->a_waitfor == MNT_WAIT;
- struct timespec ts;
- struct buf *nbp;
+ struct vnode *vp = ap->a_vp;
int s;
+ struct buf *bp, *nbp;
/*
* Flush all dirty buffers associated with a vnode.
@@ -853,8 +874,7 @@ loop:
}
#endif
splx(s);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- return deupdat(VTODE(vp), &ts, wait);
+ return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
}
static int
@@ -869,9 +889,12 @@ msdosfs_remove(ap)
struct denode *dep = VTODE(ap->a_vp);
struct denode *ddep = VTODE(ap->a_dvp);
- error = removede(ddep,dep);
+ if (ap->a_vp->v_type == VDIR)
+ error = EPERM;
+ else
+ error = removede(ddep, dep);
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
+ printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
#endif
if (ddep == dep)
vrele(ap->a_vp);
@@ -879,7 +902,7 @@ msdosfs_remove(ap)
vput(ap->a_vp); /* causes msdosfs_inactive() to be called
* via vrele() */
vput(ap->a_dvp);
- return error;
+ return (error);
}
/*
@@ -962,22 +985,27 @@ msdosfs_rename(ap)
struct componentname *a_tcnp;
} */ *ap;
{
- u_char toname[11];
- int error;
- int newparent = 0;
- int sourceisadirectory = 0;
- u_long cn;
- daddr_t bn;
+ struct vnode *tdvp = ap->a_tdvp;
+ struct vnode *fvp = ap->a_fvp;
+ struct vnode *fdvp = ap->a_fdvp;
struct vnode *tvp = ap->a_tvp;
+ struct componentname *tcnp = ap->a_tcnp;
struct componentname *fcnp = ap->a_fcnp;
struct proc *p = fcnp->cn_proc;
+ struct denode *ip, *xp, *dp, *zp;
+ u_char toname[11], oldname[11];
+ u_long from_diroffset, to_diroffset;
+ u_char to_count;
+ int doingdirectory = 0, newparent = 0;
+ int error;
+ u_long cn;
+ daddr_t bn;
struct denode *fddep; /* from file's parent directory */
struct denode *fdep; /* from file or directory */
struct denode *tddep; /* to file's parent directory */
struct denode *tdep; /* to file or directory */
struct msdosfsmount *pmp;
struct direntry *dotdotp;
- struct direntry *ep;
struct buf *bp;
fddep = VTODE(ap->a_fdvp);
@@ -986,28 +1014,46 @@ msdosfs_rename(ap)
tdep = tvp ? VTODE(tvp) : NULL;
pmp = fddep->de_pmp;
- /* Check for cross-device rename */
- if ((ap->a_fvp->v_mount != ap->a_tdvp->v_mount) ||
- (tvp && (ap->a_fvp->v_mount != tvp->v_mount))) {
- error = EXDEV;
- goto bad;
- }
+ pmp = VFSTOMSDOSFS(fdvp->v_mount);
+#ifdef DIAGNOSTIC
+ if ((tcnp->cn_flags & HASBUF) == 0 ||
+ (fcnp->cn_flags & HASBUF) == 0)
+ panic("msdosfs_rename: no name");
+#endif
/*
- * Convert the filename in tcnp into a dos filename. We copy this
- * into the denode and directory entry for the destination
- * file/directory.
+ * Check for cross-device rename.
*/
- unix2dosfn((u_char *) ap->a_tcnp->cn_nameptr,
- toname, ap->a_tcnp->cn_namelen);
+ if ((fvp->v_mount != tdvp->v_mount) ||
+ (tvp && (fvp->v_mount != tvp->v_mount))) {
+ error = EXDEV;
+abortit:
+ VOP_ABORTOP(tdvp, tcnp);
+ if (tdvp == tvp)
+ vrele(tdvp);
+ else
+ vput(tdvp);
+ if (tvp)
+ vput(tvp);
+ VOP_ABORTOP(fdvp, fcnp);
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+ }
/*
- * At this point this is the lock state of the denodes:
- * fddep referenced
- * fdep referenced
- * tddep locked
- * tdep locked if it exists
+ * If source and dest are the same, do nothing.
*/
+ if (tvp == fvp) {
+ error = 0;
+ goto abortit;
+ }
+
+ error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
+ if (error)
+ goto abortit;
+ dp = VTODE(fdvp);
+ ip = VTODE(fvp);
/*
* Be sure we are not renaming ".", "..", or an alias of ".". This
@@ -1015,218 +1061,270 @@ msdosfs_rename(ap)
* "ls" or "pwd" with the "." directory entry missing, and "cd .."
* doesn't work if the ".." entry is missing.
*/
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- if ((ap->a_fcnp->cn_namelen == 1
- && ap->a_fcnp->cn_nameptr[0] == '.')
- || fddep == fdep
- || (ap->a_fcnp->cn_flags | ap->a_tcnp->cn_flags)
- & ISDOTDOT) {
- VOP_ABORTOP(ap->a_tdvp, ap->a_tcnp);
- vput(ap->a_tdvp);
- if (tvp)
- vput(tvp);
- VOP_ABORTOP(ap->a_fdvp, ap->a_fcnp);
- vrele(ap->a_fdvp);
- vrele(ap->a_fvp);
- return EINVAL;
+ if (ip->de_Attributes & ATTR_DIRECTORY) {
+ /*
+ * Avoid ".", "..", and aliases of "." for obvious reasons.
+ */
+ if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
+ dp == ip ||
+ (fcnp->cn_flags & ISDOTDOT) ||
+ (tcnp->cn_flags & ISDOTDOT) ||
+ (ip->de_flag & DE_RENAME)) {
+ VOP_UNLOCK(fvp, 0, p);
+ error = EINVAL;
+ goto abortit;
}
- sourceisadirectory = 1;
+ ip->de_flag |= DE_RENAME;
+ doingdirectory++;
}
/*
- * If we are renaming a directory, and the directory is being moved
- * to another directory, then we must be sure the destination
- * directory is not in the subtree of the source directory. This
- * could orphan everything under the source directory.
- * doscheckpath() unlocks the destination's parent directory so we
- * must look it up again to relock it.
+ * When the target exists, both the directory
+ * and target vnodes are returned locked.
*/
- if (fddep->de_StartCluster != tddep->de_StartCluster)
+ dp = VTODE(tdvp);
+ xp = tvp ? VTODE(tvp) : NULL;
+ /*
+ * Remember direntry place to use for destination
+ */
+ to_diroffset = dp->de_fndoffset;
+ to_count = dp->de_fndcnt;
+
+ /*
+ * If ".." must be changed (ie the directory gets a new
+ * parent) then the source directory must not be in the
+ * directory heirarchy above the target, as this would
+ * orphan everything below the source directory. Also
+ * the user must have write permission in the source so
+ * as to be able to change "..". We must repeat the call
+ * to namei, as the parent directory is unlocked by the
+ * call to doscheckpath().
+ */
+ error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
+ VOP_UNLOCK(fvp, 0, p);
+ if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
newparent = 1;
- if (sourceisadirectory && newparent) {
- if (tdep) {
- vput(ap->a_tvp);
- tdep = NULL;
- }
- /* doscheckpath() vput()'s tddep */
- error = doscheckpath(fdep, tddep);
- tddep = NULL;
- if (error)
+ vrele(fdvp);
+ if (doingdirectory && newparent) {
+ if (error) /* write access check above */
goto bad;
- if ((ap->a_tcnp->cn_flags & SAVESTART) == 0)
- panic("msdosfs_rename(): lost to startdir");
- error = relookup(ap->a_tdvp, &tvp, ap->a_tcnp);
+ if (xp != NULL)
+ vput(tvp);
+ /*
+ * doscheckpath() vput()'s dp,
+ * so we have to do a relookup afterwards
+ */
+ error = doscheckpath(ip, dp);
if (error)
- goto bad;
- tddep = VTODE(ap->a_tdvp);
- tdep = tvp ? VTODE(tvp) : NULL;
+ goto out;
+ if ((tcnp->cn_flags & SAVESTART) == 0)
+ panic("msdosfs_rename: lost to startdir");
+ error = relookup(tdvp, &tvp, tcnp);
+ if (error)
+ goto out;
+ dp = VTODE(tdvp);
+ xp = tvp ? VTODE(tvp) : NULL;
}
- /*
- * If the destination exists, then be sure its type (file or dir)
- * matches that of the source. And, if it is a directory make sure
- * it is empty. Then delete the destination.
- */
- if (tdep) {
- if (tdep->de_Attributes & ATTR_DIRECTORY) {
- if (!sourceisadirectory) {
- error = ENOTDIR;
- goto bad;
- }
- if (!dosdirempty(tdep)) {
+ if (xp != NULL) {
+ /*
+ * Target must be empty if a directory and have no links
+ * to it. Also, ensure source and target are compatible
+ * (both directories, or both not directories).
+ */
+ if (xp->de_Attributes & ATTR_DIRECTORY) {
+ if (!dosdirempty(xp)) {
error = ENOTEMPTY;
goto bad;
}
- cache_purge(DETOV(tddep));
- } else { /* destination is file */
- if (sourceisadirectory) {
- error = EISDIR;
+ if (!doingdirectory) {
+ error = ENOTDIR;
goto bad;
}
+ cache_purge(tdvp);
+ } else if (doingdirectory) {
+ error = EISDIR;
+ goto bad;
}
- error = removede(tddep,tdep);
+ error = removede(dp, xp);
if (error)
goto bad;
- vput(ap->a_tvp);
- tdep = NULL;
+ vput(tvp);
+ xp = NULL;
}
/*
- * If the source and destination are in the same directory then
- * just read in the directory entry, change the name in the
- * directory entry and write it back to disk.
+ * Convert the filename in tcnp into a dos filename. We copy this
+ * into the denode and directory entry for the destination
+ * file/directory.
*/
- if (newparent == 0) {
- /* tddep and fddep point to the same denode here */
- vn_lock(ap->a_fvp, LK_EXCLUSIVE, p); /* ap->a_fdvp is already locked */
- error = readep(fddep->de_pmp, fdep->de_dirclust,
- fdep->de_diroffset, &bp, &ep);
- if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- bcopy(toname, ep->deName, 11);
- error = bwrite(bp);
- if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- bcopy(toname, fdep->de_Name, 11); /* update denode */
+ error = uniqdosname(VTODE(tdvp), tcnp, toname);
+ if (error)
+ goto abortit;
+
+ /*
+ * Since from wasn't locked at various places above,
+ * have to do a relookup here.
+ */
+ fcnp->cn_flags &= ~MODMASK;
+ fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
+ if ((fcnp->cn_flags & SAVESTART) == 0)
+ panic("msdosfs_rename: lost from startdir");
+ if (!newparent)
+ VOP_UNLOCK(tdvp, 0, p);
+ (void) relookup(fdvp, &fvp, fcnp);
+ if (fvp == NULL) {
/*
- * fdep locked fddep and tddep point to the same denode
- * which is locked tdep is NULL
+ * From name has disappeared.
*/
+ if (doingdirectory)
+ panic("rename: lost dir entry");
+ vrele(ap->a_fvp);
+ if (newparent)
+ VOP_UNLOCK(tdvp, 0, p);
+ vrele(tdvp);
+ return 0;
+ }
+ xp = VTODE(fvp);
+ zp = VTODE(fdvp);
+ from_diroffset = zp->de_fndoffset;
+
+ /*
+ * Ensure that the directory entry still exists and has not
+ * changed till now. If the source is a file the entry may
+ * have been unlinked or renamed. In either case there is
+ * no further work to be done. If the source is a directory
+ * then it cannot have been rmdir'ed or renamed; this is
+ * prohibited by the DE_RENAME flag.
+ */
+ if (xp != ip) {
+ if (doingdirectory)
+ panic("rename: lost dir entry");
+ vrele(ap->a_fvp);
+ VOP_UNLOCK(fvp, 0, p);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ xp = NULL;
} else {
- u_long dirsize = 0L;
+ vrele(fvp);
+ xp = NULL;
/*
- * If the source and destination are in different
- * directories, then mark the entry in the source directory
- * as deleted and write a new entry in the destination
- * directory. Then move the denode to the correct hash
+ * First write a new entry in the destination
+ * directory and mark the entry in the source directory
+ * as deleted. Then move the denode to the correct hash
* chain for its new location in the filesystem. And, if
* we moved a directory, then update its .. entry to point
- * to the new parent directory. If we moved a directory
- * will also insure that the directory entry on disk has a
- * filesize of zero.
+ * to the new parent directory.
*/
- vn_lock(ap->a_fvp, LK_EXCLUSIVE, p);
- bcopy(toname, fdep->de_Name, 11); /* update denode */
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- dirsize = fdep->de_FileSize;
- fdep->de_FileSize = 0;
- }
- error = createde(fdep, tddep, (struct denode **) 0);
- if (fdep->de_Attributes & ATTR_DIRECTORY) {
- fdep->de_FileSize = dirsize;
- }
- if (error) {
- /* should put back filename */
- VOP_UNLOCK(ap->a_fvp, 0, p);
- goto bad;
- }
- vn_lock(ap->a_fdvp, LK_EXCLUSIVE, p);
- error = readep(fddep->de_pmp, fddep->de_fndclust,
- fddep->de_fndoffset, &bp, &ep);
+ bcopy(ip->de_Name, oldname, 11);
+ bcopy(toname, ip->de_Name, 11); /* update denode */
+ dp->de_fndoffset = to_diroffset;
+ dp->de_fndcnt = to_count;
+ error = createde(ip, dp, (struct denode **)0, tcnp);
if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ bcopy(oldname, ip->de_Name, 11);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- ep->deName[0] = SLOT_DELETED;
- error = bwrite(bp);
+ ip->de_refcnt++;
+ zp->de_fndoffset = from_diroffset;
+ error = removede(zp, ip);
if (error) {
- VOP_UNLOCK(ap->a_fvp, 0, p);
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ /* XXX should really panic here, fs is corrupt */
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- if (!sourceisadirectory) {
- fdep->de_dirclust = tddep->de_fndclust;
- fdep->de_diroffset = tddep->de_fndoffset;
- reinsert(fdep);
+ if (!doingdirectory) {
+ error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
+ &ip->de_dirclust, 0);
+ if (error) {
+ /* XXX should really panic here, fs is corrupt */
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
+ VOP_UNLOCK(fvp, 0, p);
+ goto bad;
+ }
+ if (ip->de_dirclust != MSDOSFSROOT)
+ ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
}
- VOP_UNLOCK(ap->a_fdvp, 0, p);
+ reinsert(ip);
+ if (newparent)
+ VOP_UNLOCK(fdvp, 0, p);
}
- /* fdep is still locked here */
/*
* If we moved a directory to a new parent directory, then we must
* fixup the ".." entry in the moved directory.
*/
- if (sourceisadirectory && newparent) {
- cn = fdep->de_StartCluster;
+ if (doingdirectory && newparent) {
+ cn = ip->de_StartCluster;
if (cn == MSDOSFSROOT) {
/* this should never happen */
panic("msdosfs_rename(): updating .. in root directory?");
- } else {
+ } else
bn = cntobn(pmp, cn);
- }
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
NOCRED, &bp);
if (error) {
- /* should really panic here, fs is corrupt */
- VOP_UNLOCK(ap->a_fvp, 0, p);
+ /* XXX should really panic here, fs is corrupt */
+ brelse(bp);
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- dotdotp = (struct direntry *) bp->b_data + 1;
- putushort(dotdotp->deStartCluster, tddep->de_StartCluster);
+ dotdotp = (struct direntry *)bp->b_data + 1;
+ putushort(dotdotp->deStartCluster, dp->de_StartCluster);
+ if (FAT32(pmp))
+ putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
error = bwrite(bp);
- VOP_UNLOCK(ap->a_fvp, 0, p);
if (error) {
- /* should really panic here, fs is corrupt */
+ /* XXX should really panic here, fs is corrupt */
+ VOP_UNLOCK(fvp, 0, p);
goto bad;
}
- } else
- VOP_UNLOCK(ap->a_fvp, 0, p);
-bad: ;
- vrele(DETOV(fdep));
- vrele(DETOV(fddep));
- if (tdep)
- vput(DETOV(tdep));
- if (tddep)
- vput(DETOV(tddep));
- return error;
+ }
+
+ VOP_UNLOCK(fvp, 0, p);
+bad:
+ if (xp)
+ vput(tvp);
+ vput(tdvp);
+out:
+ ip->de_flag &= ~DE_RENAME;
+ vrele(fdvp);
+ vrele(fvp);
+ return (error);
+
}
static struct {
struct direntry dot;
struct direntry dotdot;
-} dosdirtemplate = {
- {
- ". ", " ", /* the . entry */
- ATTR_DIRECTORY, /* file attribute */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
- {210, 4}, {210, 4}, /* time and date */
- {0, 0}, /* startcluster */
- {0, 0, 0, 0}, /* filesize */
- },{
- ".. ", " ", /* the .. entry */
- ATTR_DIRECTORY, /* file attribute */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
- {210, 4}, {210, 4}, /* time and date */
- {0, 0}, /* startcluster */
- {0, 0, 0, 0}, /* filesize */
- }
+} dosdirtemplate = {
+ { ". ", " ", /* the . entry */
+ ATTR_DIRECTORY, /* file attribute */
+ 0, /* reserved */
+ 0, { 0, 0 }, { 0, 0 }, /* create time & date */
+ { 0, 0 }, /* access date */
+ { 0, 0 }, /* high bits of start cluster */
+ { 210, 4 }, { 210, 4 }, /* modify time & date */
+ { 0, 0 }, /* startcluster */
+ { 0, 0, 0, 0 } /* filesize */
+ },
+ { ".. ", " ", /* the .. entry */
+ ATTR_DIRECTORY, /* file attribute */
+ 0, /* reserved */
+ 0, { 0, 0 }, { 0, 0 }, /* create time & date */
+ { 0, 0 }, /* access date */
+ { 0, 0 }, /* high bits of start cluster */
+ { 210, 4 }, { 210, 4 }, /* modify time & date */
+ { 0, 0 }, /* startcluster */
+ { 0, 0, 0, 0 } /* filesize */
+ }
};
static int
@@ -1238,42 +1336,41 @@ msdosfs_mkdir(ap)
struct vattr *a_vap;
} */ *ap;
{
- int bn;
+ struct componentname *cnp = ap->a_cnp;
+ struct denode ndirent;
+ struct denode *dep;
+ struct denode *pdep = VTODE(ap->a_dvp);
int error;
- u_long newcluster;
- struct denode *pdep;
- struct denode *ndep;
+ int bn;
+ u_long newcluster, pcl;
struct direntry *denp;
- struct denode ndirent;
- struct msdosfsmount *pmp;
+ struct msdosfsmount *pmp = pdep->de_pmp;
struct buf *bp;
struct timespec ts;
- u_short dDate, dTime;
-
- pdep = VTODE(ap->a_dvp);
/*
* If this is the root directory and there is no space left we
* can't do anything. This is because the root directory can not
* change size.
*/
- if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndclust == (u_long)-1) {
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return ENOSPC;
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
+ error = ENOSPC;
+ goto bad2;
}
- pmp = pdep->de_pmp;
-
/*
* Allocate a cluster to hold the about to be created directory.
*/
error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
- if (error) {
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return error;
- }
+ if (error)
+ goto bad2;
+
+ bzero(&ndirent, sizeof(ndirent));
+ ndirent.de_pmp = pmp;
+ ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+ TIMEVAL_TO_TIMESPEC(&time, &ts);
+ DETIMES(&ndirent, &ts, &ts, &ts);
/*
* Now fill the cluster with the "." and ".." entries. And write
@@ -1285,50 +1382,66 @@ msdosfs_mkdir(ap)
bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
bzero(bp->b_data, pmp->pm_bpcluster);
bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
- denp = (struct direntry *) bp->b_data;
- putushort(denp->deStartCluster, newcluster);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &dDate, &dTime);
- putushort(denp->deDate, dDate);
- putushort(denp->deTime, dTime);
- denp++;
- putushort(denp->deStartCluster, pdep->de_StartCluster);
- putushort(denp->deDate, dDate);
- putushort(denp->deTime, dTime);
- error = bwrite(bp);
- if (error) {
- clusterfree(pmp, newcluster, NULL);
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- vput(ap->a_dvp);
- return error;
+ denp = (struct direntry *)bp->b_data;
+ putushort(denp[0].deStartCluster, newcluster);
+ putushort(denp[0].deCDate, ndirent.de_CDate);
+ putushort(denp[0].deCTime, ndirent.de_CTime);
+ denp[0].deCHundredth = ndirent.de_CHun;
+ putushort(denp[0].deADate, ndirent.de_ADate);
+ putushort(denp[0].deMDate, ndirent.de_MDate);
+ putushort(denp[0].deMTime, ndirent.de_MTime);
+ pcl = pdep->de_StartCluster;
+ if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
+ pcl = 0;
+ putushort(denp[1].deStartCluster, pcl);
+ putushort(denp[1].deCDate, ndirent.de_CDate);
+ putushort(denp[1].deCTime, ndirent.de_CTime);
+ denp[1].deCHundredth = ndirent.de_CHun;
+ putushort(denp[1].deADate, ndirent.de_ADate);
+ putushort(denp[1].deMDate, ndirent.de_MDate);
+ putushort(denp[1].deMTime, ndirent.de_MTime);
+ if (FAT32(pmp)) {
+ putushort(denp[0].deHighClust, newcluster >> 16);
+ putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
}
+ error = bwrite(bp);
+ if (error)
+ goto bad;
+
/*
* Now build up a directory entry pointing to the newly allocated
* cluster. This will be written to an empty slot in the parent
* directory.
*/
- ndep = &ndirent;
- bzero(ndep, sizeof(*ndep));
- unix2dosfn((u_char *)ap->a_cnp->cn_nameptr,
- ndep->de_Name, ap->a_cnp->cn_namelen);
- TIMEVAL_TO_TIMESPEC(&time, &ts);
- unix2dostime(&ts, &ndep->de_Date, &ndep->de_Time);
- ndep->de_StartCluster = newcluster;
- ndep->de_Attributes = ATTR_DIRECTORY;
-
- error = createde(ndep, pdep, &ndep);
- if (error) {
- clusterfree(pmp, newcluster, NULL);
- } else {
- *ap->a_vpp = DETOV(ndep);
- }
- zfree(namei_zone, ap->a_cnp->cn_pnbuf);
-#ifdef MSDOSFS_DEBUG
- printf("msdosfs_mkdir(): vput(%08x)\n", ap->a_dvp);
+#ifdef DIAGNOSTIC
+ if ((cnp->cn_flags & HASBUF) == 0)
+ panic("msdosfs_mkdir: no name");
#endif
+ error = uniqdosname(pdep, cnp, ndirent.de_Name);
+ if (error)
+ goto bad;
+
+ ndirent.de_Attributes = ATTR_DIRECTORY;
+ ndirent.de_StartCluster = newcluster;
+ ndirent.de_FileSize = 0;
+ ndirent.de_dev = pdep->de_dev;
+ ndirent.de_devvp = pdep->de_devvp;
+ error = createde(&ndirent, pdep, &dep, cnp);
+ if (error)
+ goto bad;
+ if ((cnp->cn_flags & SAVESTART) == 0)
+ zfree(namei_zone, cnp->cn_pnbuf);
vput(ap->a_dvp);
- return error;
+ *ap->a_vpp = DETOV(dep);
+ return (0);
+
+bad:
+ clusterfree(pmp, newcluster, NULL);
+bad2:
+ zfree(namei_zone, cnp->cn_pnbuf);
+ vput(ap->a_dvp);
+ return (error);
}
static int
@@ -1339,21 +1452,27 @@ msdosfs_rmdir(ap)
struct componentname *a_cnp;
} */ *ap;
{
- struct denode *ddep;
- struct denode *dep;
- int error = 0;
-
- ddep = VTODE(ap->a_dvp); /* parent dir of dir to delete */
- dep = VTODE(ap->a_vp);/* directory to delete */
+ register struct vnode *vp = ap->a_vp;
+ register struct vnode *dvp = ap->a_dvp;
+ register struct componentname *cnp = ap->a_cnp;
+ register struct denode *ip, *dp;
+ int error;
+
+ ip = VTODE(vp);
+ dp = VTODE(dvp);
/*
- * Be sure the directory being deleted is empty.
+ * Verify the directory is empty (and valid).
+ * (Rmdir ".." won't be valid since
+ * ".." will contain a reference to
+ * the current directory and thus be
+ * non-empty.)
*/
- if (dosdirempty(dep) == 0) {
+ error = 0;
+ if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
error = ENOTEMPTY;
goto out;
}
-
/*
* Delete the entry from the directory. For dos filesystems this
* gets rid of the directory entry on disk, the in memory copy
@@ -1362,30 +1481,27 @@ msdosfs_rmdir(ap)
* up access and eventually msdosfs_reclaim() will be called which
* will remove it from the denode cache.
*/
- error = removede(ddep,dep);
+ error = removede(dp, ip);
if (error)
goto out;
-
/*
* This is where we decrement the link count in the parent
* directory. Since dos filesystems don't do this we just purge
* the name cache and let go of the parent directory denode.
*/
- cache_purge(DETOV(ddep));
- vput(ap->a_dvp);
- ap->a_dvp = NULL;
-
+ cache_purge(dvp);
+ vput(dvp);
+ dvp = NULL;
/*
* Truncate the directory that is being deleted.
*/
- error = detrunc(dep, (u_long) 0, IO_SYNC, NOCRED, NULL);
- cache_purge(DETOV(dep));
-
-out: ;
- if (ap->a_dvp)
- vput(ap->a_dvp);
- vput(ap->a_vp);
- return error;
+ error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
+ cache_purge(vp);
+out:
+ if (dvp)
+ vput(dvp);
+ vput(vp);
+ return (error);
}
/*
@@ -1402,39 +1518,11 @@ msdosfs_symlink(ap)
} */ *ap;
{
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
+ /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
vput(ap->a_dvp);
- return EINVAL;
+ return (EOPNOTSUPP);
}
-/*
- * Dummy dirents to simulate the "." and ".." entries of the root directory
- * in a dos filesystem. Dos doesn't provide these. Note that each entry
- * must be the same size as a dos directory entry (32 bytes).
- */
-static struct dos_dirent {
- u_long d_fileno;
- u_short d_reclen;
- u_char d_type;
- u_char d_namlen;
- u_char d_name[24];
-} rootdots[2] = {
-
- {
- 1, /* d_fileno */
- sizeof(struct direntry), /* d_reclen */
- DT_DIR, /* d_type */
- 1, /* d_namlen */
- "." /* d_name */
- },
- {
- 1, /* d_fileno */
- sizeof(struct direntry), /* d_reclen */
- DT_DIR, /* d_type */
- 2, /* d_namlen */
- ".." /* d_name */
- }
-};
-
static int
msdosfs_readdir(ap)
struct vop_readdir_args /* {
@@ -1448,30 +1536,30 @@ msdosfs_readdir(ap)
{
int error = 0;
int diff;
- char pushout;
long n;
+ int blsize;
long on;
long lost;
long count;
u_long cn;
u_long fileno;
+ u_long dirsperblk;
long bias = 0;
- daddr_t bn;
- daddr_t lbn;
+ daddr_t bn, lbn;
struct buf *bp;
struct denode *dep = VTODE(ap->a_vp);
struct msdosfsmount *pmp = dep->de_pmp;
struct direntry *dentp;
- struct dirent *prev;
- struct dirent *crnt;
- u_char dirbuf[512]; /* holds converted dos directories */
+ struct dirent dirbuf;
struct uio *uio = ap->a_uio;
- off_t off;
+ u_long *cookies = NULL;
int ncookies = 0;
+ off_t offset, off;
+ int chksum = -1;
#ifdef MSDOSFS_DEBUG
- printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
- ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
+ printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
+ ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
#endif
/*
@@ -1481,7 +1569,12 @@ msdosfs_readdir(ap)
* So, fail attempts to readdir() on a plain file.
*/
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
- return ENOTDIR;
+ return (ENOTDIR);
+
+ /*
+ * To be safe, initialize dirbuf
+ */
+ bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
/*
* If the user buffer is smaller than the size of one dos directory
@@ -1489,13 +1582,22 @@ msdosfs_readdir(ap)
* directory entry, then we fail the read.
*/
count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
- lost = uio->uio_resid - count;
+ offset = uio->uio_offset;
if (count < sizeof(struct direntry) ||
- (uio->uio_offset & (sizeof(struct direntry) - 1)))
- return EINVAL;
+ (offset & (sizeof(struct direntry) - 1)))
+ return (EINVAL);
+ lost = uio->uio_resid - count;
uio->uio_resid = count;
- uio->uio_iov->iov_len = count;
- off = uio->uio_offset;
+
+ if (ap->a_ncookies) {
+ ncookies = uio->uio_resid / 16;
+ MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
+ M_WAITOK);
+ *ap->a_cookies = cookies;
+ *ap->a_ncookies = ncookies;
+ }
+
+ dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
/*
* If they are reading from the root directory then, we simulate
@@ -1504,194 +1606,184 @@ msdosfs_readdir(ap)
* simulate these entries. By this I mean that at file offset 64 we
* read the first entry in the root directory that lives on disk.
*/
- if (dep->de_StartCluster == MSDOSFSROOT) {
- /*
- * printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
- * uio->uio_offset);
- */
+ if (dep->de_StartCluster == MSDOSFSROOT
+ || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
+#if 0
+ printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
+ offset);
+#endif
bias = 2 * sizeof(struct direntry);
- if (uio->uio_offset < 2 * sizeof(struct direntry)) {
- if (uio->uio_offset
- && uio->uio_offset != sizeof(struct direntry)) {
- error = EINVAL;
- goto out;
- }
- n = 1;
- if (!uio->uio_offset) {
- n = 2;
- ncookies++;
+ if (offset < bias) {
+ for (n = (int)offset / sizeof(struct direntry);
+ n < 2; n++) {
+ if (FAT32(pmp))
+ dirbuf.d_fileno = cntobn(pmp,
+ pmp->pm_rootdirblk)
+ * dirsperblk;
+ else
+ dirbuf.d_fileno = 1;
+ dirbuf.d_type = DT_DIR;
+ switch (n) {
+ case 0:
+ dirbuf.d_namlen = 1;
+ strcpy(dirbuf.d_name, ".");
+ break;
+ case 1:
+ dirbuf.d_namlen = 2;
+ strcpy(dirbuf.d_name, "..");
+ break;
+ }
+ dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
+ if (uio->uio_resid < dirbuf.d_reclen)
+ goto out;
+ error = uiomove((caddr_t) &dirbuf,
+ dirbuf.d_reclen, uio);
+ if (error)
+ goto out;
+ if (cookies) {
+ *cookies++ = offset;
+ if (--ncookies <= 0)
+ goto out;
+ }
+ offset += sizeof(struct direntry);
}
- ncookies++;
- error = uiomove((char *) rootdots + uio->uio_offset,
- n * sizeof(struct direntry), uio);
}
}
- while (!error && uio->uio_resid > 0) {
- lbn = (uio->uio_offset - bias) >> pmp->pm_cnshift;
- on = (uio->uio_offset - bias) & pmp->pm_crbomask;
- n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
- diff = dep->de_FileSize - (uio->uio_offset - bias);
+
+ off = offset;
+ while (uio->uio_resid > 0) {
+ lbn = de_cluster(pmp, offset - bias);
+ on = (offset - bias) & pmp->pm_crbomask;
+ n = min(pmp->pm_bpcluster - on, uio->uio_resid);
+ diff = dep->de_FileSize - (offset - bias);
if (diff <= 0)
break;
- if (diff < n)
- n = diff;
- error = pcbmap(dep, lbn, &bn, &cn);
+ n = min(n, diff);
+ error = pcbmap(dep, lbn, &bn, &cn, &blsize);
if (error)
break;
- error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
- n = min(n, pmp->pm_bpcluster - bp->b_resid);
+ error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
if (error) {
brelse(bp);
- return error;
+ return (error);
}
+ n = min(n, blsize - bp->b_resid);
/*
- * code to convert from dos directory entries to ufs
- * directory entries
+ * Convert from dos directory entries to fs-independent
+ * directory entries.
*/
- pushout = 0;
- dentp = (struct direntry *)(bp->b_data + on);
- prev = 0;
- crnt = (struct dirent *) dirbuf;
- while ((char *) dentp < bp->b_data + on + n) {
+ for (dentp = (struct direntry *)(bp->b_data + on);
+ (char *)dentp < bp->b_data + on + n;
+ dentp++, offset += sizeof(struct direntry)) {
+#if 0
+ printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
+ dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
+#endif
/*
- * printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
- * dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
+ * If this is an unused entry, we can stop.
*/
+ if (dentp->deName[0] == SLOT_EMPTY) {
+ brelse(bp);
+ goto out;
+ }
/*
- * If we have an empty entry or a slot from a
- * deleted file, or a volume label entry just
- * concatenate its space onto the end of the
- * previous entry or, manufacture an empty entry if
- * there is no previous entry.
+ * Skip deleted entries.
*/
- if (dentp->deName[0] == SLOT_EMPTY ||
- dentp->deName[0] == SLOT_DELETED ||
- (dentp->deAttributes & ATTR_VOLUME)) {
- if (prev) {
- prev->d_reclen += sizeof(struct direntry);
- } else {
- prev = crnt;
- prev->d_fileno = 0;
- prev->d_reclen = sizeof(struct direntry);
- prev->d_type = DT_UNKNOWN;
- prev->d_namlen = 0;
- prev->d_name[0] = 0;
- ncookies++;
- }
- } else {
- /*
- * this computation of d_fileno must match
- * the computation of va_fileid in
- * msdosfs_getattr
- */
- if (dentp->deAttributes & ATTR_DIRECTORY) {
- /* if this is the root directory */
- fileno = getushort(dentp->deStartCluster);
- if (fileno == MSDOSFSROOT)
- fileno = 1;
- } else {
- /*
- * if the file's dirent lives in
- * root dir
- */
- if ((fileno = cn) == MSDOSFSROOT)
- fileno = 1;
- fileno = (fileno << 16) |
- ((dentp - (struct direntry *) bp->b_data) & 0xffff);
- }
- crnt->d_fileno = fileno;
- crnt->d_reclen = sizeof(struct direntry);
- crnt->d_type = (dentp->deAttributes & ATTR_DIRECTORY)
- ? DT_DIR : DT_REG;
- crnt->d_namlen = dos2unixfn(dentp->deName,
- (u_char *)crnt->d_name);
- /*
- * printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
- * crnt->d_name, crnt->d_fileno, dentp->deAttributes,
- * dentp->deStartCluster);
- */
- prev = crnt;
- ncookies++;
+ if (dentp->deName[0] == SLOT_DELETED) {
+ chksum = -1;
+ continue;
}
- dentp++;
- crnt = (struct dirent *) ((char *) crnt + sizeof(struct direntry));
- pushout = 1;
+ /*
+ * Handle Win95 long directory entries
+ */
+ if (dentp->deAttributes == ATTR_WIN95) {
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ continue;
+ chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
+ continue;
+ }
/*
- * If our intermediate buffer is full then copy its
- * contents to user space. I would just use the
- * buffer the buf header points to but, I'm afraid
- * that when we brelse() it someone else might find
- * it in the cache and think its contents are
- * valid. Maybe there is a way to invalidate the
- * buffer before brelse()'ing it.
+ * Skip volume labels
*/
- if ((u_char *) crnt >= &dirbuf[sizeof dirbuf]) {
- pushout = 0;
- error = uiomove(dirbuf, sizeof(dirbuf), uio);
- if (error)
- break;
- prev = 0;
- crnt = (struct dirent *) dirbuf;
+ if (dentp->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
+ continue;
+ }
+ /*
+ * This computation of d_fileno must match
+ * the computation of va_fileid in
+ * msdosfs_getattr.
+ */
+ if (dentp->deAttributes & ATTR_DIRECTORY) {
+ fileno = getushort(dentp->deStartCluster);
+ if (FAT32(pmp))
+ fileno |= getushort(dentp->deHighClust) << 16;
+ /* if this is the root directory */
+ if (fileno == MSDOSFSROOT)
+ if (FAT32(pmp))
+ fileno = cntobn(pmp,
+ pmp->pm_rootdirblk)
+ * dirsperblk;
+ else
+ fileno = 1;
+ else
+ fileno = cntobn(pmp, fileno) * dirsperblk;
+ dirbuf.d_fileno = fileno;
+ dirbuf.d_type = DT_DIR;
+ } else {
+ dirbuf.d_fileno = offset / sizeof(struct direntry);
+ dirbuf.d_type = DT_REG;
+ }
+ if (chksum != winChksum(dentp->deName))
+ dirbuf.d_namlen = dos2unixfn(dentp->deName,
+ (u_char *)dirbuf.d_name,
+ pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
+ else
+ dirbuf.d_name[dirbuf.d_namlen] = 0;
+ chksum = -1;
+ dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
+ if (uio->uio_resid < dirbuf.d_reclen) {
+ brelse(bp);
+ goto out;
+ }
+ error = uiomove((caddr_t) &dirbuf,
+ dirbuf.d_reclen, uio);
+ if (error) {
+ brelse(bp);
+ goto out;
+ }
+ if (cookies) {
+ *cookies++ = off;
+ off = offset + sizeof(struct direntry);
+ if (--ncookies <= 0) {
+ brelse(bp);
+ goto out;
+ }
}
}
- if (pushout) {
- pushout = 0;
- error = uiomove(dirbuf, (char *) crnt - (char *) dirbuf,
- uio);
- }
-
-#if 0
- /*
- * If we have read everything from this block or have read
- * to end of file then we are done with this block. Mark
- * it to say the buffer can be reused if need be.
- */
- if (n + on == pmp->pm_bpcluster ||
- (uio->uio_offset - bias) == dep->de_FileSize)
- bp->b_flags |= B_AGE;
-#endif /* if 0 */
brelse(bp);
- if (n == 0)
- break;
}
-out: ;
+out:
+ /* Subtract unused cookies */
+ if (ap->a_ncookies)
+ *ap->a_ncookies -= ncookies;
+
+ uio->uio_offset = offset;
uio->uio_resid += lost;
- if (!error && ap->a_ncookies != NULL) {
- struct dirent* dpStart;
- struct dirent* dpEnd;
- struct dirent* dp;
- u_long *cookies;
- u_long *cookiep;
-
- if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
- panic("msdosfs_readdir: unexpected uio from NFS server");
- dpStart = (struct dirent *)
- (uio->uio_iov->iov_base - (uio->uio_offset - off));
- dpEnd = (struct dirent *) uio->uio_iov->iov_base;
- cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
- for (dp = dpStart, cookiep = cookies;
- dp < dpEnd;
- dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
- off += dp->d_reclen;
- *cookiep++ = (u_long) off;
- }
- *ap->a_ncookies = ncookies;
- *ap->a_cookies = cookies;
- }
/*
* Set the eofflag (NFS uses it)
*/
if (ap->a_eofflag)
- if (dep->de_FileSize - (uio->uio_offset - bias) <= 0)
+ if (dep->de_FileSize - (offset - bias) <= 0)
*ap->a_eofflag = 1;
else
*ap->a_eofflag = 0;
- return error;
+ return (error);
}
static int
@@ -1703,7 +1795,7 @@ msdosfs_abortop(ap)
{
if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
zfree(namei_zone, ap->a_cnp->cn_pnbuf);
- return 0;
+ return (0);
}
/*
@@ -1725,11 +1817,12 @@ msdosfs_bmap(ap)
} */ *ap;
{
struct denode *dep = VTODE(ap->a_vp);
+ struct msdosfsmount *pmp = dep->de_pmp;
if (ap->a_vpp != NULL)
*ap->a_vpp = dep->de_devvp;
if (ap->a_bnp == NULL)
- return 0;
+ return (0);
if (ap->a_runp) {
/*
* Sequential clusters should be counted here.
@@ -1739,7 +1832,7 @@ msdosfs_bmap(ap)
if (ap->a_runb) {
*ap->a_runb = 0;
}
- return pcbmap(dep, ap->a_bn, ap->a_bnp, 0);
+ return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
}
static int
@@ -1762,18 +1855,21 @@ msdosfs_strategy(ap)
* don't allow files with holes, so we shouldn't ever see this.
*/
if (bp->b_blkno == bp->b_lblkno) {
- error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0);
- if (error)
- bp->b_blkno = -1;
- if (bp->b_blkno == -1)
- clrbuf(bp);
+ error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0);
+ if (error) {
+ bp->b_error = error;
+ bp->b_flags |= B_ERROR;
+ biodone(bp);
+ return (error);
+ }
+ if ((long)bp->b_blkno == -1)
+ vfs_bio_clrbuf(bp);
}
if (bp->b_blkno == -1) {
biodone(bp);
- return error;
+ return (0);
}
-#ifdef DIAGNOSTIC
-#endif
/*
* Read/write the block from/to the disk that contains the desired
* file block.
@@ -1781,7 +1877,7 @@ msdosfs_strategy(ap)
vp = dep->de_devvp;
bp->b_dev = vp->v_rdev;
VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
- return 0;
+ return (0);
}
static int
@@ -1798,7 +1894,7 @@ msdosfs_print(ap)
printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
lockmgr_printinfo(&dep->de_lock);
printf("\n");
- return 0;
+ return (0);
}
static int
@@ -1809,25 +1905,28 @@ msdosfs_pathconf(ap)
int *a_retval;
} */ *ap;
{
+ struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
+
switch (ap->a_name) {
case _PC_LINK_MAX:
*ap->a_retval = 1;
- return 0;
+ return (0);
case _PC_NAME_MAX:
- *ap->a_retval = 12;
- return 0;
+ *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
+ return (0);
case _PC_PATH_MAX:
- *ap->a_retval = PATH_MAX; /* 255? */
- return 0;
+ *ap->a_retval = PATH_MAX;
+ return (0);
case _PC_CHOWN_RESTRICTED:
*ap->a_retval = 1;
- return 0;
+ return (0);
case _PC_NO_TRUNC:
*ap->a_retval = 0;
- return 0;
+ return (0);
default:
- return EINVAL;
+ return (EINVAL);
}
+ /* NOTREACHED */
}
/* Global vfs data structures for msdosfs */
diff --git a/sys/msdosfs/msdosfsmount.h b/sys/msdosfs/msdosfsmount.h
index 49a9327..3a0ee6e 100644
--- a/sys/msdosfs/msdosfsmount.h
+++ b/sys/msdosfs/msdosfsmount.h
@@ -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,121 +63,131 @@ 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
/*
- * Map a cluster number into a filesystem relative block number.
+ * Convert pointer to buffer -> pointer to direntry
*/
-#define cntobn(pmp, cn) \
- ((((cn)-CLUST_FIRST) * (pmp)->pm_SectPerClust) + (pmp)->pm_firstcluster)
+#define bptoep(pmp, bp, dirofs) \
+ ((struct direntry *)(((bp)->b_data) \
+ + ((dirofs) & (pmp)->pm_crbomask)))
/*
- * Map a filesystem relative block number back into a cluster number.
+ * Convert block number to cluster number
*/
-#define bntocn(pmp, bn) \
- ((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
+#define de_bn2cn(pmp, bn) \
+ ((bn) >> ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
- * Calculate block number for directory entry in root dir, offset dirofs
+ * Convert cluster number to block number
*/
-#define roottobn(pmp, dirofs) \
- (((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
- + (pmp)->pm_rootdirblk)
+#define de_cn2bn(pmp, cn) \
+ ((cn) << ((pmp)->pm_cnshift - (pmp)->pm_bnshift))
/*
- * Calculate block number for directory entry at cluster dirclu, offset
- * dirofs
+ * Convert file offset to cluster number
*/
-#define detobn(pmp, dirclu, dirofs) \
- ((dirclu) == MSDOSFSROOT \
- ? roottobn((pmp), (dirofs)) \
- : cntobn((pmp), (dirclu)))
+#define de_cluster(pmp, off) \
+ ((off) >> (pmp)->pm_cnshift)
/*
- * Convert pointer to buffer -> pointer to direntry
+ * Clusters required to hold size bytes
*/
-#define bptoep(pmp, bp, dirofs) \
- ((struct direntry *)((bp)->b_data) \
- + (dirofs) % (pmp)->pm_depclust)
-
+#define de_clcount(pmp, size) \
+ (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
/*
- * Convert filesize to block number
+ * Convert file offset to block number
*/
#define de_blk(pmp, off) \
- ((off) >> (pmp)->pm_cnshift)
+ (de_cn2bn(pmp, de_cluster((pmp), (off))))
/*
- * Clusters required to hold size bytes
+ * Convert cluster number to file offset
*/
-#define de_clcount(pmp, size) \
- (((size) + (pmp)->pm_bpcluster - 1) >> (pmp)->pm_cnshift)
+#define de_cn2off(pmp, cn) \
+ ((cn) << (pmp)->pm_cnshift)
+
+/*
+ * Convert block number to file offset
+ */
+#define de_bn2off(pmp, bn) \
+ ((bn) << (pmp)->pm_bnshift)
+/*
+ * Map a cluster number into a filesystem relative block number.
+ */
+#define cntobn(pmp, cn) \
+ (de_cn2bn((pmp), (cn)-CLUST_FIRST) + (pmp)->pm_firstcluster)
+
+/*
+ * Calculate block number for directory entry in root dir, offset dirofs
+ */
+#define roottobn(pmp, dirofs) \
+ (de_blk((pmp), (dirofs)) + (pmp)->pm_rootdirblk)
+
+/*
+ * Calculate block number for directory entry at cluster dirclu, offset
+ * dirofs
+ */
+#define detobn(pmp, dirclu, dirofs) \
+ ((dirclu) == MSDOSFSROOT \
+ ? roottobn((pmp), (dirofs)) \
+ : cntobn((pmp), (dirclu)))
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_ */
OpenPOWER on IntegriCloud