-/* $NetBSD: denode.h,v 1.16 1995/09/09 19:38:00 ws Exp $ */
+/* $NetBSD: denode.h,v 1.19 1995/11/29 15:08:32 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
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 */
pid_t de_lockholder; /* current lock holder */
pid_t de_lockwaiter; /* lock wanter */
- /* 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_CTime; /* creation time */
+ u_short de_CDate; /* creation date */
+ u_short de_ADate; /* access date */
+ u_short de_ATime; /* access time */
+ u_short de_MTime; /* modification time */
+ u_short de_MDate; /* modification date */
u_short de_StartCluster; /* starting cluster of file */
u_long de_FileSize; /* size of file in bytes */
struct fatcache de_fc[FC_SIZE]; /* fat cache */
#define DE_LOCKED 0x0001 /* Denode lock. */
#define DE_WANTED 0x0002 /* Denode is wanted by a process. */
#define DE_UPDATE 0x0004 /* Modification time update request. */
-#define DE_MODIFIED 0x0008 /* Denode has been modified. */
-#define DE_RENAME 0x0010 /* Denode is in the process of being renamed */
+#define DE_CREATE 0x0008 /* Creation time update */
+#define DE_ACCESS 0x0010 /* Access time update */
+#define DE_MODIFIED 0x0020 /* Denode has been modified. */
+#define DE_RENAME 0x0040 /* Denode is in the process of being renamed */
+
+/*
+ * Maximum filename length in Win95
+ * Note: Must be < sizeof(dirent.d_name)
+ */
+#define WIN_MAXLEN 255
/*
* Transfer directory entries between internal and external form.
#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_CTime = getushort((dp)->deCTime), \
+ (dep)->de_CDate = getushort((dp)->deCDate), \
+ (dep)->de_ATime = getushort((dp)->deATime), \
+ (dep)->de_ADate = getushort((dp)->deADate), \
+ (dep)->de_MTime = getushort((dp)->deMTime), \
+ (dep)->de_MDate = getushort((dp)->deMDate), \
(dep)->de_StartCluster = getushort((dp)->deStartCluster), \
(dep)->de_FileSize = getulong((dp)->deFileSize))
#define DE_EXTERNALIZE(dp, dep) \
(bcopy((dep)->de_Name, (dp)->deName, 11), \
(dp)->deAttributes = (dep)->de_Attributes, \
- putushort((dp)->deTime, (dep)->de_Time), \
- putushort((dp)->deDate, (dep)->de_Date), \
+ putushort((dp)->deCTime, (dep)->de_CTime), \
+ putushort((dp)->deCDate, (dep)->de_CDate), \
+ putushort((dp)->deATime, (dep)->de_ATime), \
+ putushort((dp)->deADate, (dep)->de_ADate), \
+ putushort((dp)->deMTime, (dep)->de_MTime), \
+ putushort((dp)->deMDate, (dep)->de_MDate), \
putushort((dp)->deStartCluster, (dep)->de_StartCluster), \
putulong((dp)->deFileSize, \
((dep)->de_Attributes & ATTR_DIRECTORY) ? 0 : (dep)->de_FileSize))
#define DETOV(de) ((de)->de_vnode)
#define DE_TIMES(dep) \
- if ((dep)->de_flag & DE_UPDATE) { \
- (dep)->de_flag &= ~DE_UPDATE; \
+ if ((dep)->de_flag & (DE_UPDATE | DE_CREATE | DE_ACCESS)) { \
if (((dep)->de_Attributes & ATTR_DIRECTORY) == 0) { \
- unix2dostime(NULL, &(dep)->de_Date, &(dep)->de_Time); \
- (dep)->de_Attributes |= ATTR_ARCHIVE; \
+ if ((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95 \
+ || (dep)->de_flag & DE_UPDATE) { \
+ unix2dostime(NULL, &(dep)->de_MDate, &(dep)->de_MTime); \
+ (dep)->de_Attributes |= ATTR_ARCHIVE; \
+ } \
+ if (!((dep)->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)) { \
+ if ((dep)->de_flag & DE_ACCESS) \
+ unix2dostime(NULL, &(dep)->de_ADate, &(dep)->de_ATime); \
+ if ((dep)->de_flag & DE_CREATE) \
+ unix2dostime(NULL, &(dep)->de_CDate, &(dep)->de_CTime); \
+ } \
(dep)->de_flag |= DE_MODIFIED; \
} \
+ (dep)->de_flag &= ~(DE_UPDATE | DE_CREATE | DE_ACCESS); \
}
/*
/*
* Internal service routine prototypes.
*/
-int createde __P((struct denode *, struct denode *, struct denode **));
+int createde __P((struct denode *, struct denode *, struct denode **, struct componentname *));
int deextend __P((struct denode *, u_long, struct ucred *));
-int deget __P((struct msdosfsmount *, u_long, u_long, struct direntry *, struct denode **));
+int deget __P((struct msdosfsmount *, u_long, u_long, struct denode **));
int detrunc __P((struct denode *, u_long, int, struct ucred *, struct proc *));
int deupdat __P((struct denode *, int));
int doscheckpath __P((struct denode *, struct denode *));
int readep __P((struct msdosfsmount *, u_long, u_long, struct buf **, struct direntry **));
void reinsert __P((struct denode *));
int removede __P((struct denode *, struct denode *));
+int uniqdosname __P((struct denode *, struct componentname *, u_char *));
#endif /* _KERNEL */
-/* $NetBSD: direntry.h,v 1.9 1995/03/29 22:08:52 briggs Exp $ */
+/* $NetBSD: direntry.h,v 1.11 1995/11/29 15:08:34 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#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[10]; /* reserved */
- u_int8_t deTime[2]; /* create/last update time */
- u_int8_t deDate[2]; /* create/last update date */
+ u_int8_t deReserved[2]; /* reserved */
+ u_int8_t deCTime[2]; /* create time */
+ u_int8_t deCDate[2]; /* create date */
+ u_int8_t deADate[2]; /* access date */
+ u_int8_t deATime[2]; /* access time */
+ u_int8_t 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 */
+
/*
* This is the format of the contents of the deTime field in the direntry
* structure.
#ifdef _KERNEL
void unix2dostime __P((struct timespec *tsp, u_int16_t *ddp, u_int16_t *dtp));
void dos2unixtime __P((u_int dd, u_int dt, struct timespec *tsp));
-int dos2unixfn __P((u_char dn[11], u_char *un));
-void unix2dosfn __P((u_char *un, u_char dn[11], int unlen));
+int dos2unixfn __P((u_char dn[11], u_char *un, int lower));
+int unix2dosfn __P((u_char *un, u_char dn[12], int unlen, u_int gen));
+int unix2winfn __P((u_char *un, int unlen, struct winentry *wep, int cnt, int chksum));
+int winChkName __P((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((u_char *un, int unlen));
#endif /* _KERNEL */
-/* $NetBSD: msdosfs_conv.c,v 1.10 1994/12/27 18:36:24 mycroft Exp $ */
+/* $NetBSD: msdosfs_conv.c,v 1.13 1995/11/29 15:08:36 ws Exp $ */
+/*-
+ * Copyright (C) 1995 Wolfgang Solfrank.
+ * Copyright (C) 1995 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)
*
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h> /* defines tz */
+#include <sys/dirent.h>
+#include <sys/vnode.h>
/*
* MSDOSFS include files.
*/
#include <msdosfs/direntry.h>
+#include <msdosfs/denode.h>
/*
* Days in each month in a regular year.
tsp->ts_nsec = 0;
}
-/*
- * 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, 0, /* 20-27 */
+ 0x28, 0x29, 0, 0, 0x2c, 0x2d, 0, 0, /* 28-2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
+ 0x38, 0x39, 0, 0x3b, 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, 0, 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.
* 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);
}
/*
- * 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)
+int
+unix2dosfn(un, dn, unlen, gen)
u_char *un;
- u_char dn[11];
+ u_char dn[12];
int unlen;
+ u_int gen;
{
- int i;
- u_char c;
-
+ int i, j, l;
+ int conv = 1;
+ u_char *cp, *dp, *dp1;
+ u_char gentext[6];
+
/*
* 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
* don't follow dos filename rules.
*/
if (un[0] == '.' && unlen == 1) {
dn[0] = '.';
- return;
+ return gen <= 1;
}
if (un[0] == '.' && un[1] == '.' && unlen == 2) {
dn[0] = '.';
dn[1] = '.';
- return;
+ return gen <= 1;
}
/*
- * Copy the unix filename into the dos filename string upto the end
- * of string, a '.', or 8 characters. Whichever happens first stops
- * us. This forms the name portion of the dos filename. Fold to
- * upper case.
+ * Filenames with only blanks and dots are not allowed!
*/
- for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ for (cp = un, i = unlen; --i >= 0; cp++)
+ if (*cp != ' ' && *cp != '.')
+ break;
+ if (i < 0)
+ return 0;
+
+ /*
+ * Now find the extension
+ * Note: dot as first char doesn't start extension
+ * and trailing dots and blanks are ignored
+ */
+ dp = dp1 = 0;
+ for (cp = un + 1, i = unlen - 1; --i >= 0;) {
+ switch (*cp++) {
+ case '.':
+ if (!dp1)
+ dp1 = cp;
+ break;
+ case ' ':
+ break;
+ default:
+ if (dp1)
+ dp = dp1;
+ dp1 = 0;
+ break;
+ }
+ }
+
+ /*
+ * 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++;
}
/*
- * If the first char of the filename is 0xe5, then translate it to
- * 0x05. This is because 0xe5 is the marker for a deleted
- * directory slot. I guess this means you can't have filenames
- * that start with 0x05. I suppose we should check for this and
- * doing something about it.
+ * Now convert the rest of the name
+ */
+ for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
+ if (*un != (dn[j] = unix2dos[*un])
+ && conv != 3)
+ conv = 2;
+ if (!dn[j]) {
+ conv = 3;
+ dn[j--] = ' ';
+ }
+ }
+ if (un < dp)
+ conv = 3;
+ /*
+ * If we didn't have any chars in filename,
+ * generate a default
+ */
+ if (!j)
+ dn[0] = '_';
+
+ /*
+ * The first character cannot be E5,
+ * because that means a deleted entry
*/
- if (dn[0] == SLOT_DELETED)
+ if (dn[0] == 0xe5)
dn[0] = SLOT_E5;
+
+ /*
+ * If there wasn't any char dropped,
+ * there is no place for generation numbers
+ */
+ if (conv != 3) {
+ if (gen > 1)
+ return 0;
+ return conv;
+ }
+
+ /*
+ * Now insert the generation number into the filename part
+ */
+ for (cp = gentext + sizeof(gentext); cp > gentext && gen; gen /= 10)
+ *--cp = gen % 10 + '0';
+ if (gen)
+ return 0;
+ for (i = 8; dn[--i] == ' ';);
+ if (gentext + sizeof(gentext) - cp + 1 > 8 - i)
+ i = 8 - (gentext + sizeof(gentext) - cp + 1);
+ dn[i++] = '~';
+ while (cp < gentext + sizeof(gentext))
+ dn[i] = *cp++;
+ 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)
+ u_char *un;
+ int unlen;
+ struct winentry *wep;
+ int cnt;
+ int chksum;
+{
+ u_int8_t *cp;
+ int i;
/*
- * Strip any further characters up to a '.' or the end of the
- * string.
+ * Drop trailing blanks and dots
*/
- while (unlen && (c = *un)) {
- un++;
- unlen--;
- /* Make sure we've skipped over the dot before stopping. */
- if (c == '.')
- break;
+ for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
+
+ un += (cnt - 1) * WIN_CHARS;
+ unlen -= (cnt - 1) * WIN_CHARS;
+
+ /*
+ * Initialize winentry to some useful default
+ */
+ for (cp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *cp++ = 0xff);
+ wep->weCnt = cnt;
+ wep->weAttributes = ATTR_WIN95;
+ wep->weReserved1 = 0;
+ wep->weChksum = chksum;
+ wep->weReserved2 = 0;
+
+ /*
+ * Now convert the filename parts
+ */
+ for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
+ if (--unlen < 0)
+ goto done;
+ *cp++ = *un++;
+ *cp++ = 0;
+ }
+ for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
+ if (--unlen < 0)
+ goto done;
+ *cp++ = *un++;
+ *cp++ = 0;
+ }
+ for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
+ if (--unlen < 0)
+ goto done;
+ *cp++ = *un++;
+ *cp++ = 0;
+ }
+ if (!unlen)
+ wep->weCnt |= WIN_LAST;
+ return unlen;
+
+done:
+ *cp++ = 0;
+ *cp++ = 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)
+ 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;
+ if ((unlen -= i) <= 0)
+ return -1;
+ un += i;
+
+ /*
+ * Compare the name parts
+ */
+ for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
+ if (--unlen < 0) {
+ if (!*cp++ && !*cp)
+ return chksum;
+ return -1;
+ }
+ if (u2l[*cp++] != u2l[*un++] || *cp++)
+ return -1;
+ }
+ for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
+ if (--unlen < 0) {
+ if (!*cp++ && !*cp)
+ return chksum;
+ return -1;
+ }
+ if (u2l[*cp++] != u2l[*un++] || *cp++)
+ return -1;
+ }
+ for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
+ if (--unlen < 0) {
+ if (!*cp++ && !*cp)
+ return chksum;
+ return -1;
+ }
+ if (u2l[*cp++] != u2l[*un++] || *cp++)
+ return -1;
}
+ return chksum;
+}
+
+/*
+ * Convert Win95 filename to dirbuf.
+ * Returns the checksum or -1 if impossible
+ */
+int
+win2unixfn(wep, dp, chksum)
+ struct winentry *wep;
+ struct dirent *dp;
+ int chksum;
+{
+ u_int8_t *cp;
+ u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
+ int i;
+ if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
+ || !(wep->weCnt&WIN_CNT))
+ return -1;
+
+ /*
+ * First compare checksums
+ */
+ if (wep->weCnt&WIN_LAST) {
+ chksum = wep->weChksum;
+ /*
+ * This works even though d_namlen is one byte!
+ */
+ dp->d_namlen = (wep->weCnt&WIN_CNT) * WIN_CHARS;
+ } else if (chksum != wep->weChksum)
+ chksum = -1;
+ if (chksum == -1)
+ return -1;
+
+ /*
+ * Offset of this entry
+ */
+ i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
+ np = (u_int8_t *)dp->d_name + i;
+
/*
- * 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.
+ * Convert the name parts
*/
- for (i = 8; i <= 10 && unlen && (c = *un); i++) {
- dn[i] = islower(c) ? toupper(c) : c;
- un++;
- unlen--;
+ 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)
+ 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);
}
-/* $NetBSD: msdosfs_denode.c,v 1.15 1995/09/09 19:38:03 ws Exp $ */
+/* $NetBSD: msdosfs_denode.c,v 1.18 1995/11/29 15:08:38 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/kernel.h> /* defines "time" */
+#include <sys/dirent.h>
#include <msdosfs/bpb.h>
#include <msdosfs/msdosfsmount.h>
* 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;
extern int (**msdosfs_vnodeop_p)();
+ struct direntry *direntptr;
struct denode *ldep;
struct vnode *nvp;
struct buf *bp;
#ifdef MSDOSFS_DEBUG
- printf("deget(pmp %08x, dirclust %d, diroffset %x, direntptr %x, depp %08x)\n",
- pmp, dirclust, diroffset, direntptr, depp);
+ printf("deget(pmp %08x, dirclust %d, diroffset %x, depp %08x)\n",
+ pmp, dirclust, diroffset, depp);
#endif
- /*
- * If dir entry is given and refers to a directory, convert to
- * canonical form
- */
- if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) {
- dirclust = getushort(direntptr->deStartCluster);
- if (dirclust == MSDOSFSROOT)
- diroffset = MSDOSFSROOT_OFS;
- else
- diroffset = 0;
- }
-
/*
* See if the denode is in the denode cache. Use the location of
* the directory entry to compute the hash value. For subdir use
* 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_CTime = 0x0000; /* 00:00:00 */
+ ldep->de_CDate = (0 << DD_YEAR_SHIFT) | (1 << DD_MONTH_SHIFT)
| (1 << DD_DAY_SHIFT);
/* Jan 1, 1980 */
+ ldep->de_ATime = ldep->de_CTime;
+ ldep->de_ADate = ldep->de_CDate;
+ ldep->de_MTime = ldep->de_CTime;
+ ldep->de_MDate = ldep->de_CDate;
/* leave the other fields as garbage */
} else {
- bp = NULL;
- if (!direntptr) {
- error = readep(pmp, dirclust, diroffset, &bp,
- &direntptr);
- if (error)
- return (error);
- }
+ if (error = readep(pmp, dirclust, diroffset, &bp, &direntptr))
+ return (error);
DE_INTERNALIZE(ldep, direntptr);
- if (bp)
- brelse(bp);
+ brelse(bp);
}
/*
else {
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);
}
}
- 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
NOCRED, &bp);
}
if (error) {
+ brelse(bp);
#ifdef MSDOSFS_DEBUG
printf("detrunc(): bread fails %d\n", error);
#endif
#endif
return (error);
}
- fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
+ fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
eofentry);
}
return (EINVAL);
/*
- * Directories can only be extended by the superuser.
- * Is this really important?
+ * Directories cannot be extended.
*/
- if (dep->de_Attributes & ATTR_DIRECTORY) {
- if (error = suser(cred, (u_short *)0))
- return (error);
- }
+ if (dep->de_Attributes & ATTR_DIRECTORY)
+ return (EISDIR);
if (length <= dep->de_FileSize)
panic("deextend: file too large");
printf("msdosfs_inactive(): dep %08x, refcnt %d, mntflag %x, MNT_RDONLY %x\n",
dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY);
#endif
- if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
+ if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
error = detrunc(dep, (u_long)0, 0, NOCRED, NULL);
+ dep->de_Name[0] = SLOT_DELETED;
+ }
deupdat(dep, 0);
VOP_UNLOCK(vp);
/*
-/* $NetBSD: msdosfs_fat.c,v 1.19 1995/09/09 19:38:04 ws Exp $ */
+/* $NetBSD: msdosfs_fat.c,v 1.21 1995/11/05 18:47:53 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#include <sys/mount.h> /* to define statfs structure */
#include <sys/vnode.h> /* to define vattr structure */
#include <sys/errno.h>
+#include <sys/dirent.h>
/*
* msdosfs include files.
*/
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;
+ *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;
if (sp)
*sp = min(pmp->pm_bpcluster,
- dep->de_FileSize - findcn * pmp->pm_bpcluster);
+ dep->de_FileSize - de_cn2off(pmp, findcn));
return (0);
} else { /* just an empty file */
if (cnp)
if (bp)
brelse(bp);
if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED,
- &bp))
+ &bp)) {
+ brelse(bp);
return (error);
+ }
bp_bn = bn;
}
prevcn = cn;
/* 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)
+ if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bpn);
else
bdwrite(bpn);
/*
* Write out the first fat last.
*/
- if (pmp->pm_waitonfat)
+ if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
bwrite(bp);
else
bdwrite(bp);
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
- if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp))
+ if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp)) {
+ brelse(bp);
return (error);
+ }
if (function & FAT_GET) {
readcn = getushort(&bp->b_data[bo]);
while (count > 0) {
byteoffset = FATOFS(pmp, start);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
- if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp))
+ if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp)) {
+ brelse(bp);
return (error);
+ }
while (count > 0) {
start++;
newc = --count > 0 ? start : fillwith;
if (lbn != bn) {
if (bp)
updatefats(pmp, bp, lbn);
- if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp))
+ if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp)) {
+ brelse(bp);
return (error);
+ }
lbn = bn;
}
usemap_free(pmp, cluster);
if (bp)
brelse(bp);
fatblock(pmp, byteoffset, &bn, &bsize, NULL);
- if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp))
+ if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp)) {
+ brelse(bp);
return (error);
+ }
}
readcn = getushort(&bp->b_data[bo]);
if (fat12) {
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, 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");
-/* $NetBSD: msdosfs_lookup.c,v 1.17 1995/09/09 19:38:06 ws Exp $ */
+/* $NetBSD: msdosfs_lookup.c,v 1.24 1995/11/30 19:00:57 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#include <sys/buf.h>
#include <sys/vnode.h>
#include <sys/mount.h>
+#include <sys/dirent.h>
#include <msdosfs/bpb.h>
#include <msdosfs/direntry.h>
* an inode). This can cause problems if we are searching while some other
* process is modifying a directory. To prevent one process from accessing
* incompletely modified directory information we depend upon being the
- * soul owner of a directory block. bread/brelse provide this service.
+ * sole owner of a directory block. bread/brelse provide this service.
* This being the case, when a process modifies a directory it must first
* acquire the disk block that contains the directory entry to be modified.
* Then update the disk block and the denode, and then write the disk block
int error;
int lockparent;
int wantparent;
- int slotstatus;
-
-#define NONE 0
-#define FOUND 1
+ int slotcount;
int slotoffset;
- int slotcluster;
int frcn;
u_long cluster;
- int rootreloff;
+ int blkoff;
int diroff;
int blsize;
int isadir; /* ~0 if found direntry is a directory */
u_char dosfilename[12];
int flags = cnp->cn_flags;
int nameiop = cnp->cn_nameiop;
-
+ int wincnt = 1;
+ int chksum = -1;
+ int olddos = 1;
+
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
#endif
printf("msdosfs_lookup(): looking for . or .. in root directory\n");
#endif
cluster = MSDOSFSROOT;
- diroff = MSDOSFSROOT_OFS;
+ blkoff = MSDOSFSROOT_OFS;
goto foundroot;
}
+ switch (unix2dosfn((u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0)) {
+ case 0:
+ return (EINVAL);
+ case 1:
+ break;
+ case 2:
+ wincnt = winSlotCnt((u_char *)cnp->cn_nameptr,cnp->cn_namelen) + 1;
+ break;
+ case 3:
+ olddos = 0;
+ wincnt = winSlotCnt((u_char *)cnp->cn_nameptr,cnp->cn_namelen) + 1;
+ break;
+ }
+ if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+ wincnt = 1;
+
/*
* 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;
+ slotcount = wincnt;
if ((nameiop == CREATE || nameiop == RENAME) &&
- (flags & ISLASTCN)) {
- slotstatus = NONE;
- slotoffset = -1;
- }
-
- unix2dosfn((u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen);
- dosfilename[11] = 0;
+ (flags & ISLASTCN))
+ slotcount = 0;
+
#ifdef MSDOSFS_DEBUG
printf("msdosfs_lookup(): dos version of filename %s, length %d\n",
dosfilename, cnp->cn_namelen);
* 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++) {
if (error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) {
if (error == E2BIG)
break;
return (error);
}
- if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp))
+ if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ brelse(bp);
return (error);
- for (diroff = 0; diroff < blsize;
- diroff += sizeof(struct direntry),
- rootreloff += sizeof(struct direntry)) {
- dep = (struct direntry *)(bp->b_data + diroff);
+ }
+ 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
*/
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);
goto notfound;
}
} 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((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)
+ if (dep->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
continue;
+ }
+
/*
- * Check for a name match.
+ * Check for a checksum or name match
*/
- if (bcmp(dosfilename, dep->deName, 11))
+ 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).
+ * this lookup.
*/
- if (cluster == MSDOSFSROOT)
- diroff = rootreloff;
dp->de_fndoffset = diroff;
- dp->de_fndclust = cluster;
+ dp->de_fndcnt = 0; /* unused anyway */
+
goto found;
}
- } /* for (diroff = 0; .... */
+ } /* for (blkoff = 0; .... */
/*
* Release the buffer holding the directory cluster just
* searched.
* 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 %d\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) {
return (error);
/*
* Return an indication of where the new directory
- * entry should be put. If we didn't find a slot,
- * then set dp->de_fndoffset to -1 indicating
- * that the new slot belongs at the end of the
- * directory. If we found a slot, then the new entry
- * can be put at dp->de_fndoffset.
+ * entry should be put.
*/
- 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_fndoffset = slotoffset;
+ dp->de_fndcnt = wincnt - 1;
/*
* We return with the directory locked, so that
isadir = dep->deAttributes & ATTR_DIRECTORY;
scn = getushort(dep->deStartCluster);
+ if (cluster == MSDOSFSROOT)
+ blkoff = diroff;
+ if (isadir) {
+ cluster = scn;
+ if (cluster == MSDOSFSROOT)
+ blkoff = MSDOSFSROOT_OFS;
+ else
+ blkoff = 0;
+ }
+
+ /*
+ * 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);
+
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.
*/
/*
/*
* Write access to directory required to delete files.
*/
- if (error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc)) {
- if (bp)
- brelse(bp);
+ if (error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc))
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);
}
- if (error = deget(pmp, cluster, diroff, dep, &tdp)) {
- if (bp)
- brelse(bp);
+ if (error = deget(pmp, cluster, blkoff, &tdp))
return (error);
- }
*vpp = DETOV(tdp);
if (!lockparent)
VOP_UNLOCK(vdp);
- if (bp)
- brelse(bp);
return (0);
}
*/
if (nameiop == RENAME && wantparent &&
(flags & ISLASTCN)) {
- if (error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc)) {
- if (bp)
- brelse(bp);
+ if (error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc))
return (error);
- }
+
/*
* Careful about locking second inode.
* This can only occur if the target is ".".
*/
- if (dp->de_StartCluster == scn && isadir) {
- if (bp)
- brelse(bp);
+ if (dp->de_StartCluster == scn && isadir)
return (EISDIR);
- }
- error = deget(pmp, cluster, diroff, dep, &tdp);
- if (error) {
- if (bp)
- brelse(bp);
+
+ if (error = deget(pmp, cluster, blkoff, &tdp))
return (error);
- }
*vpp = DETOV(tdp);
cnp->cn_flags |= SAVENAME;
if (!lockparent)
VOP_UNLOCK(vdp);
- if (bp)
- brelse(bp);
return (0);
}
pdp = vdp;
if (flags & ISDOTDOT) {
VOP_UNLOCK(pdp); /* race to get the inode */
- if (error = deget(pmp, cluster, diroff, dep, &tdp)) {
+ if (error = deget(pmp, cluster, blkoff, &tdp)) {
VOP_LOCK(pdp);
- if (bp)
- brelse(bp);
return (error);
}
if (lockparent && (flags & ISLASTCN) &&
(error = VOP_LOCK(pdp))) {
vput(DETOV(tdp));
- if (bp)
- brelse(bp);
return (error);
}
*vpp = DETOV(tdp);
VREF(vdp); /* we want ourself, ie "." */
*vpp = vdp;
} else {
- if (error = deget(pmp, cluster, diroff, dep, &tdp)) {
- if (bp)
- brelse(bp);
+ if (error = deget(pmp, cluster, blkoff, &tdp))
return (error);
- }
if (!lockparent || !(flags & ISLASTCN))
VOP_UNLOCK(pdp);
*vpp = DETOV(tdp);
}
- if (bp)
- brelse(bp);
/*
* Insert name into cache if appropriate.
* 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 %08x, ddep %08x, depp %08x, cnp %08x)\n",
+ dep, ddep, depp, cnp);
#endif
/*
* to extend the root directory. We just return an error in that
* case.
*/
- if (ddep->de_fndclust == (u_long)-1) {
- if (error = extendfile(ddep, 1, &bp, &dirclust, DE_CLEAR))
- 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;
+ if (ddep->de_fndoffset >= ddep->de_FileSize) {
+ diroffset = ddep->de_fndoffset + sizeof(struct direntry)
+ - ddep->de_FileSize;
+ dirclust = de_clcount(pmp, diroffset);
+ if (error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR))
+ return error;
/*
* 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;
- if (error = readep(pmp, dirclust, diroffset, &bp, &ndep))
- 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) {
- if (error = deget(pmp, dirclust, diroffset, ndep, depp))
- return (error);
- }
- if (error = bwrite(bp)) {
- vput(DETOV(*depp)); /* free the vnode we got on error */
- return (error);
+ if (error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
+ &bn, &dirclust, &blsize))
+ return error;
+ diroffset = ddep->de_fndoffset;
+ if (dirclust != MSDOSFSROOT)
+ diroffset &= pmp->pm_crbomask;
+ if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ brelse(bp);
+ return error;
}
- return (0);
-}
-
-/*
- * Read in a directory entry and mark it as being deleted.
- */
-int
-markdeleted(pmp, dirclust, diroffset)
- struct msdosfsmount *pmp;
- u_long dirclust;
- u_long diroffset;
-{
- int error;
- struct direntry *ep;
- struct buf *bp;
-
- if (error = readep(pmp, dirclust, diroffset, &bp, &ep))
- return (error);
- ep->deName[0] = SLOT_DELETED;
- return (bwrite(bp));
-}
+ ndep = bptoep(pmp, bp, ddep->de_fndoffset);
+
+ DE_EXTERNALIZE(ndep, dep);
+
+ /*
+ * Now write the Win95 long name
+ */
+ if (ddep->de_fndcnt > 0) {
+ u_int8_t chksum = winChksum(ndep->deName);
+ u_char *un = (u_char *)cnp->cn_nameptr;
+ int unlen = cnp->cn_namelen;
+ int cnt = 1;
+
+ while (--ddep->de_fndcnt >= 0) {
+ if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
+ if (error = bwrite(bp))
+ return error;
-/*
- * 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 */
-{
- int error;
+ ddep->de_fndoffset -= sizeof(struct direntry);
+ if (error = pcbmap(ddep,
+ de_cluster(pmp, ddep->de_fndoffset),
+ &bn, 0, &blsize))
+ 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
+ if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ 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))
+ 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.
*/
- if (error = markdeleted(pdep->de_pmp, pdep->de_fndclust, pdep->de_fndoffset))
- return (error);
- dep->de_refcnt--;
- return (0);
+ if (depp) {
+ if (dep->de_Attributes & ATTR_DIRECTORY) {
+ dirclust = dep->de_StartCluster;
+ if (dirclust == MSDOSFSROOT)
+ diroffset = MSDOSFSROOT_OFS;
+ else
+ diroffset = 0;
+ }
+ return deget(pmp, dirclust, diroffset, depp);
+ }
+
+ return 0;
}
/*
* we hit end of file.
*/
for (cn = 0;; cn++) {
- error = pcbmap(dep, cn, &bn, 0, &blsize);
- if (error == E2BIG)
- return (1); /* it's empty */
- if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp))
- return (error);
+ if (error = pcbmap(dep, cn, &bn, 0, &blsize)) {
+ if (error == E2BIG)
+ return (1); /* it's empty */
+ return (0);
+ }
+ if (error = 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++) {
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
- goto out;
+ break;
}
pmp = dep->de_pmp;
scn = dep->de_StartCluster;
if (error = bread(pmp->pm_devvp, cntobn(pmp, scn),
pmp->pm_bpcluster, NOCRED, &bp))
break;
+
ep = (struct direntry *) bp->b_data + 1;
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
bcmp(ep->deName, ".. ", 11) != 0) {
if (scn == MSDOSFSROOT)
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))
break;
}
out:;
boff = diroffset & ~pmp->pm_crbomask;
blsize = pmp->pm_bpcluster;
if (dirclust == MSDOSFSROOT
- && boff + blsize > (pmp->pm_rootdirsize << pmp->pm_bnshift))
- blsize = (pmp->pm_rootdirsize << pmp->pm_bnshift) - boff;
+ && 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)) {
+ brelse(*bpp);
*bpp = NULL;
return (error);
}
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 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 */
+{
+ 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 %08x, offset %08x\n",
+ dep->de_Name, dep, offset);
+#endif
+
+ dep->de_refcnt--;
+ do {
+ if (error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize))
+ return error;
+ if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ brelse(bp);
+ return error;
+ }
+ ep = bptoep(pmp, bp, offset);
+ 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.
+ */
+ ep--->deName[0] = SLOT_DELETED;
+ offset -= sizeof(struct direntry);
+ if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ || !((offset + sizeof(struct direntry)) & pmp->pm_crbomask)
+ || ep->deAttributes != ATTR_WIN95)
+ break;
+ }
+ if (error = bwrite(bp))
+ return error;
+ } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ && offset
+ && !(offset & pmp->pm_crbomask));
+ 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((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)) {
+ if (error == E2BIG) /* EOF reached and not found */
+ return 0;
+ return error;
+ }
+ if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
+ 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);
+ }
+}
-/* $NetBSD: msdosfs_vfsops.c,v 1.32 1995/09/09 19:38:08 ws Exp $ */
+/* $NetBSD: msdosfs_vfsops.c,v 1.36 1995/11/29 15:08:40 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#include <sys/disklabel.h>
#include <sys/ioctl.h>
#include <sys/malloc.h>
+#include <sys/dirent.h>
#include <msdosfs/bpb.h>
#include <msdosfs/bootsect.h>
if (mp->mnt_flag & MNT_UPDATE) {
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;
error = EOPNOTSUPP;
if (error)
return (error);
- if (pmp->pm_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
+ if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_WANTRDWR)) {
/*
* If upgrade to read-write by non-root, then verify
* that user has necessary permissions on the device.
}
VOP_UNLOCK(devvp);
}
- pmp->pm_ronly = 0;
+ 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.
*/
pmp->pm_gid = args.gid;
pmp->pm_uid = args.uid;
pmp->pm_mask = args.mask;
+ pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT;
+ 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 (error = msdosfs_root(mp, &rootvp)) {
+ msdosfs_unmount(mp, MNT_FORCE, p);
+ return (error);
+ }
+ pmp->pm_flags |= findwin95(VTODE(rootvp))
+ ? MSDOSFSMNT_LONGNAME
+ : MSDOSFSMNT_SHORTNAME;
+ vput(rootvp);
+ }
(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,
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
extern struct vnode *rootvp;
+ u_int8_t SecPerClust;
int ronly, error;
#ifdef atari
int bsize, dtype, tmp;
* 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_Media = b50->bpbMedia;
/* XXX - We should probably check more values here */
- if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust ||
+ if (!pmp->pm_BytesPerSec || !SecPerClust ||
pmp->pm_Heads > 255 || pmp->pm_SecPerTrack > 63) {
error = EINVAL;
goto error_exit;
*/
if ( pmp->pm_BytesPerSec < bsize
|| pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)
- || !pmp->pm_SectPerClust
- || pmp->pm_SectPerClust & (pmp->pm_SectPerClust - 1)
+ || !SecPerClust
+ || SecPerClust & (SecPerClust - 1)
|| !pmp->pm_HugeSectors
|| pmp->pm_HugeSectors * pmp->pm_BytesPerSec
> dpart.part->p_size * bsize) {
*/
tmp = pmp->pm_BytesPerSec / bsize;
pmp->pm_BytesPerSec = bsize;
- pmp->pm_SectPerClust *= tmp;
pmp->pm_HugeSectors *= tmp;
pmp->pm_HiddenSects *= tmp;
pmp->pm_ResSectors *= tmp;
pmp->pm_fatblk = pmp->pm_ResSectors;
pmp->pm_rootdirblk = pmp->pm_fatblk +
(pmp->pm_FATs * pmp->pm_FATsecs);
-#ifdef atari
- tmp = pmp->pm_RootDirEnts * sizeof(struct direntry);
- tmp += pmp->pm_BytesPerSec - 1;
- tmp /= pmp->pm_BytesPerSec;
- pmp->pm_rootdirsize = tmp; /* in sectors */
-#else /* !atari */
- pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
- /
- pmp->pm_BytesPerSec;/* in sectors */
-#endif /* !atari */
+ 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;
#ifdef atari
pmp->pm_fatblocksize = MAXBSIZE;
#endif /* !atari */
pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
+ pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
-#ifdef atari
/*
- * Be prepared for block size != 512
+ * Compute mask and shift value for isolating cluster relative byte
+ * offsets and cluster numbers from a file offset.
*/
- pmp->pm_brbomask = bsize - 1;
- for (tmp = 0; bsize >>= 1; ++tmp)
- ;
- pmp->pm_bnshift = tmp;
+ pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
+ pmp->pm_crbomask = pmp->pm_bpcluster - 1;
+ pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
+
+#ifdef atari
/*
- * Compute mask and shift value for isolating cluster relative
- * byte offsets and cluster numbers from a file offset. We
- * already know that the number of sectors per cluster is
+ * We already know that the number of sectors per cluster is
* > 0 and a power of 2.
*/
- bsize = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
- pmp->pm_crbomask = bsize - 1;
- pmp->pm_bpcluster = bsize;
- for (tmp = 0; bsize >>= 1; ++tmp)
- ;
- pmp->pm_cnshift = tmp;
-
#else /* !atari */
/*
- * Compute mask and shift value for isolating cluster relative byte
- * offsets and cluster numbers from a file offset.
+ * Check for valid cluster size
+ * must be a power of 2
*/
- pmp->pm_bpcluster = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
- pmp->pm_crbomask = pmp->pm_bpcluster - 1;
- pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
- if (pmp->pm_cnshift < 0
- || pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
+ if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
error = EINVAL;
goto error_exit;
}
-
- pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
- pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
#endif /* !atari */
/*
* 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;
printf("union %08x, tag %d, data[0] %08x, data[1] %08x\n",
vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]);
#endif
- error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD|FWRITE,
- NOCRED, p);
+ error = VOP_CLOSE(pmp->pm_devvp,
+ pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, p);
vrele(pmp->pm_devvp);
free(pmp->pm_inusemap, M_MSDOSFSFAT);
free(pmp, M_MSDOSFSMNT);
printf("msdosfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n",
mp, pmp, ndep, DETOV(ndep));
#endif
- if (error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep))
+ if (error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep))
return (error);
*vpp = DETOV(ndep);
return (0);
* this would be the place to update them from the first one.
*/
if (pmp->pm_fmod != 0)
- if (pmp->pm_ronly != 0)
+ if (pmp->pm_flags & MSDOSFSMNT_RONLY)
panic("msdosfs_sync: rofs mod");
else {
/* update fats here */
if (VOP_ISLOCKED(vp))
continue;
dep = VTODE(vp);
- if ((dep->de_flag & DE_UPDATE) == 0 &&
- vp->v_dirtyblkhd.lh_first == NULL)
+ if (dep->de_flag
+ & (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED) == 0
+ && vp->v_dirtyblkhd.lh_first == NULL)
continue;
if (vget(vp, 1))
goto loop;
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);
+ error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
if (error) {
*vpp = NULLVP;
return (error);
-/* $NetBSD: msdosfs_vnops.c,v 1.37 1995/09/09 19:38:10 ws Exp $ */
+/* $NetBSD: msdosfs_vnops.c,v 1.43 1995/12/01 07:26:58 mycroft Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */
#include <sys/malloc.h>
#include <sys/dir.h> /* defines dirent structure */
+#include <sys/lockf.h>
#include <msdosfs/bpb.h>
#include <msdosfs/direntry.h>
* 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) {
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
error = ENOSPC;
goto bad;
}
panic("msdosfs_create: no name");
#endif
bzero(&ndirent, sizeof(ndirent));
- unix2dostime(NULL, &ndirent.de_Date, &ndirent.de_Time);
- unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
+ if (error = uniqdosname(pdep, cnp, ndirent.de_Name))
+ 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))
+ ndirent.de_pmp = pdep->de_pmp;
+ ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
+ DE_TIMES(&ndirent);
+ if (error = createde(&ndirent, pdep, &dep, cnp))
goto bad;
if ((cnp->cn_flags & SAVESTART) == 0)
FREE(cnp->cn_pnbuf, M_NAMEI);
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;
-#ifndef MSDOSFS_NODIRMOD
- if (vap->va_mode & S_IFDIR)
- TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime);
-#endif
- vap->va_ctime = vap->va_atime;
+ dos2unixtime(dep->de_MDate, dep->de_MTime, &vap->va_mtime);
+ if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
+ dos2unixtime(dep->de_ADate, dep->de_ATime, &vap->va_atime);
+ dos2unixtime(dep->de_CDate, dep->de_CTime, &vap->va_ctime);
+ } 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;
#endif
return (EINVAL);
}
+ /*
+ * Directories must not ever get their attributes modified
+ */
if (ap->a_vp->v_type == VDIR)
return EISDIR;
if (error = detrunc(dep, (u_long)vap->va_size, 0, cred, ap->a_p))
return (error);
}
- if (vap->va_mtime.ts_sec != VNOVAL) {
+ if (vap->va_atime.ts_sec != VNOVAL || vap->va_mtime.ts_sec != VNOVAL) {
if (cred->cr_uid != dep->de_pmp->pm_uid &&
(error = suser(cred, &ap->a_p->p_acflag)) &&
((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
(error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
return (error);
- unix2dostime(&vap->va_mtime, &dep->de_Date, &dep->de_Time);
+ if (!(dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)
+ && vap->va_atime.ts_sec != VNOVAL)
+ unix2dostime(&vap->va_atime, &dep->de_ADate, &dep->de_ATime);
+ if (vap->va_mtime.ts_sec != VNOVAL)
+ unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime);
dep->de_Attributes |= ATTR_ARCHIVE;
dep->de_flag |= DE_MODIFIED;
}
dep->de_Attributes |= ATTR_ARCHIVE;
dep->de_flag |= DE_MODIFIED;
}
- return (0);
+ return (deupdat(dep, 1));
}
int
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;
} else {
rablock = lbn + 1;
if (vp->v_lastr + 1 == lbn &&
- rablock * pmp->pm_bpcluster < dep->de_FileSize) {
- error = breada(vp, lbn, pmp->pm_bpcluster,
- rablock, pmp->pm_bpcluster, NOCRED, &bp);
- } else {
- error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
- &bp);
- }
+ de_cn2off(pmp, rablock) < dep->de_FileSize)
+ error = breada(vp, de_cn2bn(pmp, lbn),
+ pmp->pm_bpcluster, de_cn2bn(pmp, rablock),
+ pmp->pm_bpcluster, 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);
return (error);
}
error = uiomove(bp->b_data + on, (int) n, uio);
+ if (!isadir)
+ dep->de_flag |= DE_ACCESS;
brelse(bp);
} while (error == 0 && uio->uio_resid > 0 && n != 0);
return (error);
dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
#endif
- if (vp->v_type == VREG) {
+ switch (vp->v_type) {
+ case VREG:
if (ioflag & IO_APPEND)
uio->uio_offset = dep->de_FileSize;
thisvp = vp;
- } else
+ break;
+ case VDIR:
+ return EISDIR;
+ default:
panic("msdosfs_write(): bad file type");
+ }
if (uio->uio_offset < 0)
return (EINVAL);
/*
* 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);
}
- /*
- * 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
lastcn = de_clcount(pmp, osize) - 1;
do {
- bn = de_blk(pmp, uio->uio_offset);
- if (bn > lastcn) {
+ if (de_cluster(pmp, uio->uio_offset) > lastcn) {
error = ENOSPC;
break;
}
+ 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)) {
* for the fat table. (see msdosfs_strategy)
*/
if (bp->b_blkno == bp->b_lblkno) {
- if (error = pcbmap(dep, bp->b_lblkno,
- &bp->b_blkno, 0, 0))
+ if (error = pcbmap(dep,
+ de_bn2cn(pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0))
bp->b_blkno = -1;
}
if (bp->b_blkno == -1) {
/*
* The block we need to write into exists, so read it in.
*/
- if (error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp))
+ if (error = bread(thisvp, bn, pmp->pm_bpcluster, NOCRED, &bp)) {
+ brelse(bp);
break;
+ }
}
croffset = uio->uio_offset & pmp->pm_crbomask;
if (uio->uio_resid != resid)
error = 0;
}
- } else
+ } else if (ioflag & IO_SYNC)
error = deupdat(dep, 1);
return (error);
}
register struct vnode *fdvp = ap->a_fdvp;
register struct componentname *tcnp = ap->a_tcnp;
register struct componentname *fcnp = ap->a_fcnp;
- register struct denode *ip, *xp, *dp;
+ register struct denode *ip, *xp, *dp, *zp;
u_char toname[11], oldname[11];
- u_long to_dirclust, to_diroffset;
+ u_long from_diroffset, to_diroffset;
+ u_char to_count;
int doingdirectory = 0, newparent = 0;
int error;
u_long cn;
* into the denode and directory entry for the destination
* file/directory.
*/
- unix2dosfn((u_char *)tcnp->cn_nameptr, toname, tcnp->cn_namelen);
+ if (error = uniqdosname(VTODE(tdvp), tcnp, toname))
+ goto abortit;
/* */
if (error = VOP_LOCK(fvp))
/*
* Remember direntry place to use for destination
*/
- to_dirclust = dp->de_fndclust;
to_diroffset = dp->de_fndoffset;
+ to_count = dp->de_fndcnt;
/*
* If ".." must be changed (ie the directory gets a new
goto bad;
if (xp != NULL)
vput(tvp);
- /* doscheckpath() vput()'s dp */
+ /*
+ * doscheckpath() vput()'s dp,
+ * so we have to do a relookup afterwards
+ */
if (error = doscheckpath(ip, dp))
goto out;
if ((tcnp->cn_flags & SAVESTART) == 0)
return 0;
}
xp = VTODE(fvp);
+ zp = VTODE(fdvp);
+ from_diroffset = zp->de_fndoffset;
/*
* Ensure that the directory entry still exists and has not
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.
+ * 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 (!newparent) {
- if (error = readep(dp->de_pmp,
- dp->de_fndclust,
- dp->de_fndoffset,
- &bp, &ep)) {
- VOP_UNLOCK(fvp);
- goto bad;
- }
- bcopy(toname, ep->deName, 11);
- if (error = bwrite(bp)) {
- VOP_UNLOCK(fvp);
- goto bad;
- }
- bcopy(toname, ip->de_Name, 11); /* update denode */
- } else {
- struct denode *zp;
-
- /*
- * If the source and destination are in different
- * directories, then 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.
- */
- bcopy(ip->de_Name, oldname, 11);
- bcopy(toname, ip->de_Name, 11); /* update denode */
- dp->de_fndclust = to_dirclust;
- dp->de_fndoffset = to_diroffset;
- if (error = createde(ip, dp, (struct denode **)0)) {
- bcopy(oldname, ip->de_Name, 11);
+ bcopy(ip->de_Name, oldname, 11);
+ bcopy(toname, ip->de_Name, 11); /* update denode */
+ dp->de_fndoffset = to_diroffset;
+ dp->de_fndcnt = to_count;
+ if (error = createde(ip, dp, (struct denode **)0, tcnp)) {
+ bcopy(oldname, ip->de_Name, 11);
+ if (newparent)
VOP_UNLOCK(fdvp);
- VOP_UNLOCK(fvp);
- goto bad;
- }
- zp = VTODE(fdvp);
- if (error = readep(zp->de_pmp, zp->de_fndclust, zp->de_fndoffset,
- &bp, &ep)) {
- /* XXX should really panic here, fs is corrupt */
+ VOP_UNLOCK(fvp);
+ goto bad;
+ }
+ ip->de_refcnt++;
+ zp->de_fndoffset = from_diroffset;
+ if (error = removede(zp, ip)) {
+ /* XXX should really panic here, fs is corrupt */
+ if (newparent)
VOP_UNLOCK(fdvp);
- VOP_UNLOCK(fvp);
- goto bad;
- }
- ep->deName[0] = SLOT_DELETED;
- if (error = bwrite(bp)) {
+ VOP_UNLOCK(fvp);
+ goto bad;
+ }
+ if (!doingdirectory) {
+ if (error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
+ &ip->de_dirclust, 0)) {
/* XXX should really panic here, fs is corrupt */
- VOP_UNLOCK(fdvp);
+ if (newparent)
+ VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
goto bad;
}
- if (!doingdirectory) {
- ip->de_dirclust = to_dirclust;
- ip->de_diroffset = to_diroffset;
- }
- reinsert(ip);
+ if (ip->de_dirclust != MSDOSFSROOT)
+ ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
+ }
+ reinsert(ip);
+ if (newparent)
VOP_UNLOCK(fdvp);
+ }
+
+ /*
+ * If we moved a directory to a new parent directory, then we must
+ * fixup the ".." entry in the moved directory.
+ */
+ if (doingdirectory && newparent) {
+ cn = ip->de_StartCluster;
+ if (cn == MSDOSFSROOT) {
+ /* this should never happen */
+ panic("msdosfs_rename: updating .. in root directory?\n");
+ } else
+ bn = cntobn(pmp, cn);
+ if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
+ &bp)) {
+ /* XXX should really panic here, fs is corrupt */
+ brelse(bp);
+ VOP_UNLOCK(fvp);
+ goto bad;
}
-
- /*
- * If we moved a directory to a new parent directory, then we must
- * fixup the ".." entry in the moved directory.
- */
- if (doingdirectory && newparent) {
- cn = ip->de_StartCluster;
- if (cn == MSDOSFSROOT) {
- /* this should never happen */
- panic("msdosfs_rename: updating .. in root directory?\n");
- } else
- bn = cntobn(pmp, cn);
- if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
- &bp)) {
- /* XXX should really panic here, fs is corrupt */
- VOP_UNLOCK(fvp);
- goto bad;
- }
- dotdotp = (struct direntry *)bp->b_data + 1;
- putushort(dotdotp->deStartCluster, dp->de_StartCluster);
- if (error = bwrite(bp)) {
- /* XXX should really panic here, fs is corrupt */
- VOP_UNLOCK(fvp);
- goto bad;
- }
+ dotdotp = (struct direntry *)bp->b_data + 1;
+ putushort(dotdotp->deStartCluster, dp->de_StartCluster);
+ if (error = bwrite(bp)) {
+ /* XXX should really panic here, fs is corrupt */
+ VOP_UNLOCK(fvp);
+ goto bad;
}
}
* 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) {
+ if (pdep->de_StartCluster == MSDOSFSROOT
+ && pdep->de_fndoffset >= pdep->de_FileSize) {
error = ENOSPC;
goto bad2;
}
goto bad2;
bzero(&ndirent, sizeof(ndirent));
- unix2dostime(NULL, &ndirent.de_Date, &ndirent.de_Time);
+ if (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)) {
+ unix2dostime(NULL, &ndirent.de_CDate, &ndirent.de_CTime);
+ unix2dostime(NULL, &ndirent.de_ADate, &ndirent.de_ATime);
+ }
+ unix2dostime(NULL, &ndirent.de_MDate, &ndirent.de_MTime);
/*
* Now fill the cluster with the "." and ".." entries. And write
bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
denp = (struct direntry *)bp->b_data;
putushort(denp[0].deStartCluster, newcluster);
- putushort(denp[0].deDate, ndirent.de_Date);
- putushort(denp[0].deTime, ndirent.de_Time);
+ putushort(denp[0].deCDate, ndirent.de_CDate);
+ putushort(denp[0].deCTime, ndirent.de_CTime);
+ putushort(denp[0].deADate, ndirent.de_ADate);
+ putushort(denp[0].deATime, ndirent.de_ATime);
+ putushort(denp[0].deMDate, ndirent.de_MDate);
+ putushort(denp[0].deMTime, ndirent.de_MTime);
putushort(denp[1].deStartCluster, pdep->de_StartCluster);
- putushort(denp[1].deDate, ndirent.de_Date);
- putushort(denp[1].deTime, ndirent.de_Time);
+ putushort(denp[1].deCDate, ndirent.de_CDate);
+ putushort(denp[1].deCTime, ndirent.de_CTime);
+ putushort(denp[1].deADate, ndirent.de_ADate);
+ putushort(denp[1].deATime, ndirent.de_ATime);
+ putushort(denp[1].deMDate, ndirent.de_MDate);
+ putushort(denp[1].deMTime, ndirent.de_MTime);
if (error = bwrite(bp))
goto bad;
if ((cnp->cn_flags & HASBUF) == 0)
panic("msdosfs_mkdir: no name");
#endif
- unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
+ if (error = uniqdosname(pdep, cnp, ndirent.de_Name))
+ 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;
- if (error = createde(&ndirent, pdep, &dep))
+ if (error = createde(&ndirent, pdep, &dep, cnp))
goto bad;
if ((cnp->cn_flags & SAVESTART) == 0)
FREE(cnp->cn_pnbuf, M_NAMEI);
u_long *cookies;
int ncookies;
off_t offset;
-
+ 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);
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
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
* entry or the file offset is not a multiple of the size of a
}
while (uio->uio_resid > 0) {
- lbn = (offset - bias) >> pmp->pm_cnshift;
+ 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);
*/
for (dentp = (struct direntry *)(bp->b_data + on);
(char *)dentp < bp->b_data + on + n;
- dentp++) {
+ dentp++, offset += sizeof(struct direntry)) {
/*
* printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
* dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
goto out;
}
/*
- * Skip deleted entries and volume labels.
+ * Skip deleted entries.
*/
- if (dentp->deName[0] == SLOT_DELETED ||
- (dentp->deAttributes & ATTR_VOLUME)) {
- offset += sizeof(struct direntry);
+ if (dentp->deName[0] == SLOT_DELETED) {
+ chksum = -1;
+ continue;
+ }
+
+ /*
+ * 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;
+ }
+
+ /*
+ * Skip volume labels
+ */
+ if (dentp->deAttributes & ATTR_VOLUME) {
+ chksum = -1;
continue;
}
/*
dirbuf.d_fileno = fileno;
dirbuf.d_type =
(dentp->deAttributes & ATTR_DIRECTORY) ? DT_DIR : DT_REG;
- dirbuf.d_namlen = dos2unixfn(dentp->deName,
- (u_char *)dirbuf.d_name);
+ 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 = DIRSIZ(&dirbuf);
if (uio->uio_resid < dirbuf.d_reclen) {
brelse(bp);
brelse(bp);
goto out;
}
- offset += sizeof(struct direntry);
if (cookies) {
- *cookies++ = offset;
+ *cookies++ = offset + sizeof(struct direntry);
if (--ncookies <= 0) {
brelse(bp);
goto out;
*/
*ap->a_runp = 0;
}
- return (pcbmap(dep, ap->a_bn << (pmp->pm_cnshift - pmp->pm_bnshift),
- ap->a_bnp, 0, 0));
+ return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
}
int
* don't allow files with holes, so we shouldn't ever see this.
*/
if (bp->b_blkno == bp->b_lblkno) {
- if (error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0))
+ if (error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
+ &bp->b_blkno, 0, 0))
bp->b_blkno = -1;
if (bp->b_blkno == -1)
clrbuf(bp);
int a_flags;
} */ *ap;
{
+ register struct denode *dep = VTODE(ap->a_vp);
- return (EINVAL); /* we don't do locking yet */
+ return (lf_advlock(&dep->de_lockf, dep->de_FileSize, ap->a_id, ap->a_op,
+ ap->a_fl, ap->a_flags));
}
int
register_t *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);
case _PC_NAME_MAX:
- *ap->a_retval = 12;
+ *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
return (0);
case _PC_PATH_MAX:
*ap->a_retval = PATH_MAX;
-/* $NetBSD: msdosfsmount.h,v 1.11 1995/09/09 19:38:12 ws Exp $ */
+/* $NetBSD: msdosfsmount.h,v 1.12 1995/10/15 15:34:34 ws Exp $ */
/*-
- * Copyright (C) 1994 Wolfgang Solfrank.
- * Copyright (C) 1994 TooLs GmbH.
+ * Copyright (C) 1994, 1995 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995 TooLs GmbH.
* All rights reserved.
* Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
*
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_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_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 complt, when 0 use bdwrite, else use bwrite */
+ u_int pm_flags; /* see below */
struct netexport pm_export; /* export information */
#ifdef atari
u_int pm_fatentrysize; /* size of fat entry (12/16) */
#endif /* atari */
};
+/*
+ * Mount point flags:
+ */
+/*#define MSDOSFSMNT_SHORTNAME 1 /* Defined in <sys/mount.h> */
+/*#define MSDOSFSMNT_LONGNAME 2 */
+/*#define MSDOSFSMNT_NOWIN95 4 */
+/* All flags above: */
+#define MSDOSFSMNT_MNTOPT \
+ (MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95)
+#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */
+#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
+
#define VFSTOMSDOSFS(mp) ((struct msdosfsmount *)mp->mnt_data)
/* Number of bits in one pm_inusemap item: */
* 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_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_bpcluster) * (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_crbomask)))
-
+#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)))
/*
* Prototypes for MSDOSFS virtual filesystem operations