from netbsd (mostly by ws):
authorderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 04:19:50 +0000 (04:19 +0000)
committerderaadt <deraadt@openbsd.org>
Thu, 14 Dec 1995 04:19:50 +0000 (04:19 +0000)
Win95 ignores case on lookup
Really don't generate long names when mounted with -s
Fix cookie handling
Don't forward credentials to bread, it makes nfs panic
(Of course, nfs shouldn't rely on the credentials not being referenced)
Don't give directory entry to deget, it could result in a deadlock
Use device blocks, not clusters for logical block numbers
Add support for Win'95 separate creation/modification/access timestamps
Re-introduce lowercase filenames for non-Win'95-filesystems
Fix thinko with block boundaries in directories
Don't overwrite dirclust, it's needed later on
Enable flock(2).

sys/msdosfs/denode.h
sys/msdosfs/direntry.h
sys/msdosfs/msdosfs_conv.c
sys/msdosfs/msdosfs_denode.c
sys/msdosfs/msdosfs_fat.c
sys/msdosfs/msdosfs_lookup.c
sys/msdosfs/msdosfs_vfsops.c
sys/msdosfs/msdosfs_vnops.c
sys/msdosfs/msdosfsmount.h

index 1b5c425..75c331c 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -141,20 +141,22 @@ 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 */
        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 */
@@ -166,8 +168,16 @@ struct denode {
 #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.
@@ -177,16 +187,24 @@ struct denode {
 #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))
@@ -200,13 +218,22 @@ struct denode {
 #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); \
        }
 
 /*
@@ -269,9 +296,9 @@ int msdosfs_reallocblks __P((struct vop_reallocblks_args *));
 /*
  * 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 *));
@@ -280,4 +307,5 @@ int readde __P((struct denode *, struct buf **, struct direntry **));
 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 */
index 8ed9ce1..57d0e48 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -64,13 +64,35 @@ struct direntry {
 #define        ATTR_VOLUME     0x08            /* entry is a volume label */
 #define        ATTR_DIRECTORY  0x10            /* entry is a directory name */
 #define        ATTR_ARCHIVE    0x20            /* file is new or modified */
-       u_int8_t        deReserved[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.
@@ -98,6 +120,11 @@ struct direntry {
 #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 */
index fcf4a69..4b47581 100644 (file)
@@ -1,5 +1,36 @@
-/*     $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.
@@ -187,14 +221,113 @@ dos2unixtime(dd, dt, tsp)
        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.
@@ -209,147 +342,476 @@ 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);
 }
 
 /*
- * 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);
 }
index 4183501..df9e833 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -55,6 +55,7 @@
 #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>
@@ -143,41 +144,27 @@ 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;
        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
@@ -243,22 +230,20 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
                 * 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);
        }
 
        /*
@@ -283,7 +268,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
                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);
@@ -424,7 +409,7 @@ detrunc(dep, length, flags, cred, p)
                }
        }
 
-       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
@@ -442,6 +427,7 @@ detrunc(dep, length, flags, cred, p)
                            NOCRED, &bp);
                }
                if (error) {
+                       brelse(bp);
 #ifdef MSDOSFS_DEBUG
                        printf("detrunc(): bread fails %d\n", error);
 #endif
@@ -485,7 +471,7 @@ detrunc(dep, length, flags, cred, p)
 #endif
                        return (error);
                }
-               fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
+               fc_setcache(dep, FC_LASTFC, de_cluster(pmp, length - 1),
                            eofentry);
        }
 
@@ -519,13 +505,10 @@ deextend(dep, length, cred)
                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");
@@ -656,8 +639,10 @@ msdosfs_inactive(ap)
        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);
        /*
index a7ec896..3b2bdbc 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -58,6 +58,7 @@
 #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.
@@ -163,18 +164,18 @@ pcbmap(dep, findcn, bnp, cnp, sp)
         */
        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)
@@ -213,8 +214,10 @@ pcbmap(dep, findcn, bnp, cnp, sp)
                        if (bp)
                                brelse(bp);
                        if (error = bread(pmp->pm_devvp, bn, bsize, NOCRED,
-                                         &bp))
+                                         &bp)) {
+                               brelse(bp);
                                return (error);
+                       }
                        bp_bn = bn;
                }
                prevcn = cn;
@@ -338,7 +341,7 @@ updatefats(pmp, bp, fatbn)
                /* 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);
@@ -346,7 +349,7 @@ updatefats(pmp, bp, fatbn)
        /*
         * Write out the first fat last.
         */
-       if (pmp->pm_waitonfat)
+       if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
                bwrite(bp);
        else
                bdwrite(bp);
@@ -477,8 +480,10 @@ fatentry(function, pmp, cn, oldcontents, newcontents)
 
        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]);
@@ -546,8 +551,10 @@ fatchain(pmp, start, count, fillwith)
        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;
@@ -772,8 +779,10 @@ freeclusterchain(pmp, cluster)
                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);
@@ -837,8 +846,10 @@ fillinusemap(pmp)
                        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) {
@@ -960,11 +971,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, 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");
index 712a7f4..cb6d760 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -52,6 +52,7 @@
 #include <sys/buf.h>
 #include <sys/vnode.h>
 #include <sys/mount.h>
+#include <sys/dirent.h>
 
 #include <msdosfs/bpb.h>
 #include <msdosfs/direntry.h>
@@ -67,7 +68,7 @@
  * 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
@@ -89,15 +90,11 @@ msdosfs_lookup(ap)
        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   */
@@ -111,7 +108,10 @@ msdosfs_lookup(ap)
        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
@@ -204,25 +204,37 @@ 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((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);
@@ -239,19 +251,21 @@ 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++) {
                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
@@ -263,50 +277,73 @@ 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);
                                        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.
@@ -319,16 +356,28 @@ 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 %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) {
@@ -340,22 +389,10 @@ notfound:;
                        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
@@ -390,12 +427,28 @@ found:;
        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.
         */
 
        /*
@@ -409,11 +462,9 @@ foundroot:;
                /*
                 * 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().
@@ -421,20 +472,13 @@ foundroot:;
                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);
        }
 
@@ -446,32 +490,22 @@ foundroot:;
         */
        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);
        }
 
@@ -497,17 +531,13 @@ foundroot:;
        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);
@@ -515,17 +545,12 @@ foundroot:;
                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.
@@ -540,21 +565,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 %08x, ddep %08x, depp %08x, cnp %08x)\n",
+              dep, ddep, depp, cnp);
 #endif
 
        /*
@@ -565,96 +595,89 @@ createde(dep, ddep, depp)
         * 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;
 }
 
 /*
@@ -679,11 +702,15 @@ dosdirempty(dep)
         * 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++) {
@@ -760,13 +787,14 @@ doscheckpath(source, target)
        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) {
@@ -781,11 +809,10 @@ doscheckpath(source, target)
                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:;
@@ -818,10 +845,11 @@ readep(pmp, dirclust, diroffset, bpp, epp)
        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);
        }
@@ -845,3 +873,174 @@ readde(dep, 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 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);
+       }
+}
index 176b99f..27d3800 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -60,6 +60,7 @@
 #include <sys/disklabel.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
+#include <sys/dirent.h>
 
 #include <msdosfs/bpb.h>
 #include <msdosfs/bootsect.h>
@@ -97,7 +98,7 @@ msdosfs_mount(mp, path, data, ndp, p)
        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;
@@ -111,7 +112,7 @@ msdosfs_mount(mp, path, data, ndp, p)
                        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.
@@ -126,9 +127,17 @@ msdosfs_mount(mp, path, data, ndp, p)
                                }
                                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.
                         */
@@ -183,6 +192,24 @@ msdosfs_mount(mp, path, data, ndp, p)
        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,
@@ -208,6 +235,7 @@ msdosfs_mountfs(devvp, mp, p)
        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;
@@ -280,8 +308,8 @@ msdosfs_mountfs(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);
@@ -301,7 +329,7 @@ msdosfs_mountfs(devvp, mp, p)
        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;
@@ -324,8 +352,8 @@ msdosfs_mountfs(devvp, mp, p)
         */
        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) {
@@ -340,7 +368,6 @@ msdosfs_mountfs(devvp, mp, p)
         */
        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;
@@ -350,19 +377,12 @@ msdosfs_mountfs(devvp, mp, p)
        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
@@ -389,44 +409,30 @@ msdosfs_mountfs(devvp, mp, p)
                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 */
 
        /*
@@ -462,13 +468,15 @@ msdosfs_mountfs(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;
@@ -544,8 +552,8 @@ msdosfs_unmount(mp, mntflags, p)
        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);
@@ -567,7 +575,7 @@ msdosfs_root(mp, vpp)
        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);
@@ -635,7 +643,7 @@ msdosfs_sync(mp, waitfor, cred, p)
         * 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 */
@@ -656,8 +664,9 @@ loop:
                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;
@@ -693,8 +702,7 @@ 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);
+       error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep);
        if (error) {
                *vpp = NULLVP;
                return (error);
index a432477..98f3a1e 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -61,6 +61,7 @@
 #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>
@@ -116,7 +117,8 @@ msdosfs_create(ap)
         * 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;
        }
@@ -132,15 +134,19 @@ msdosfs_create(ap)
                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);
@@ -274,13 +280,14 @@ msdosfs_getattr(ap)
        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;
@@ -326,6 +333,9 @@ msdosfs_setattr(ap)
 #endif
                return (EINVAL);
        }
+       /*
+        * Directories must not ever get their attributes modified
+        */
        if (ap->a_vp->v_type == VDIR)
                return EISDIR;
 
@@ -333,13 +343,17 @@ msdosfs_setattr(ap)
                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;
        }
@@ -372,7 +386,7 @@ msdosfs_setattr(ap)
                        dep->de_Attributes |= ATTR_ARCHIVE;
                dep->de_flag |= DE_MODIFIED;
        }
-       return (0);
+       return (deupdat(dep, 1));
 }
 
 int
@@ -408,7 +422,7 @@ msdosfs_read(ap)
 
        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;
@@ -432,13 +446,13 @@ msdosfs_read(ap)
                } 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);
@@ -447,6 +461,8 @@ msdosfs_read(ap)
                        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);
@@ -488,12 +504,17 @@ msdosfs_write(ap)
               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);
@@ -504,22 +525,13 @@ msdosfs_write(ap)
        /*
         * 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
@@ -552,12 +564,12 @@ msdosfs_write(ap)
                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)) {
@@ -573,8 +585,9 @@ msdosfs_write(ap)
                         * 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) {
@@ -587,8 +600,10 @@ msdosfs_write(ap)
                        /*
                         * 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;
@@ -639,7 +654,7 @@ errexit:
                        if (uio->uio_resid != resid)
                                error = 0;
                }
-       } else
+       } else if (ioflag & IO_SYNC)
                error = deupdat(dep, 1);
        return (error);
 }
@@ -838,9 +853,10 @@ msdosfs_rename(ap)
        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;
@@ -882,7 +898,8 @@ abortit:
         * 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))
@@ -920,8 +937,8 @@ abortit:
        /*
         * 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
@@ -943,7 +960,10 @@ abortit:
                        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)
@@ -1004,6 +1024,8 @@ abortit:
                return 0;
        }
        xp = VTODE(fvp);
+       zp = VTODE(fdvp);
+       from_diroffset = zp->de_fndoffset;
 
        /*
         * Ensure that the directory entry still exists and has not
@@ -1026,93 +1048,74 @@ abortit:
                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;
                }
        }
 
@@ -1172,7 +1175,8 @@ msdosfs_mkdir(ap)
         * 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;
        }
@@ -1184,7 +1188,11 @@ msdosfs_mkdir(ap)
                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
@@ -1198,11 +1206,19 @@ msdosfs_mkdir(ap)
        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;
 
@@ -1215,13 +1231,15 @@ msdosfs_mkdir(ap)
        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);
@@ -1356,7 +1374,8 @@ msdosfs_readdir(ap)
        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);
@@ -1371,6 +1390,11 @@ msdosfs_readdir(ap)
        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
@@ -1431,7 +1455,7 @@ msdosfs_readdir(ap)
        }
 
        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);
@@ -1452,7 +1476,7 @@ msdosfs_readdir(ap)
                 */
                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);
@@ -1465,11 +1489,28 @@ msdosfs_readdir(ap)
                                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;
                        }
                        /*
@@ -1495,8 +1536,13 @@ msdosfs_readdir(ap)
                        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);
@@ -1506,9 +1552,8 @@ msdosfs_readdir(ap)
                                brelse(bp);
                                goto out;
                        }
-                       offset += sizeof(struct direntry);
                        if (cookies) {
-                               *cookies++ = offset;
+                               *cookies++ = offset + sizeof(struct direntry);
                                if (--ncookies <= 0) {
                                        brelse(bp);
                                        goto out;
@@ -1672,8 +1717,7 @@ msdosfs_bmap(ap)
                 */
                *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
@@ -1708,7 +1752,8 @@ msdosfs_strategy(ap)
         * 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);
@@ -1762,8 +1807,10 @@ msdosfs_advlock(ap)
                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
@@ -1774,13 +1821,14 @@ msdosfs_pathconf(ap)
                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;
index 2267f68..4498f19 100644 (file)
@@ -1,8 +1,8 @@
-/*     $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).
  *
@@ -65,24 +65,34 @@ struct msdosfsmount {
        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: */
@@ -92,7 +102,6 @@ struct msdosfsmount {
  * 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
@@ -105,52 +114,73 @@ struct msdosfsmount {
 #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