Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 1 Sep 2007 21:53:08 +0800
From:      "Tz-Huan Huang" <tzhuan@csie.org>
To:        "Bruce Evans" <brde@optusnet.com.au>
Cc:        bugs@freebsd.org, fs@freebsd.org
Subject:   Re: msdosfs not MPSAFE
Message-ID:  <6a7033710709010653i2e43f517y953885b67160c1cd@mail.gmail.com>
In-Reply-To: <20070831092907.K8647@besplex.bde.org>
References:  <20070712084115.GA2200@deviant.kiev.zoral.com.ua> <20070721233613.Q3366@besplex.bde.org> <20070804075730.GP2738@deviant.kiev.zoral.com.ua> <20070808004001.O926@besplex.bde.org> <20070807170259.GJ2738@deviant.kiev.zoral.com.ua> <20070810133946.H769@besplex.bde.org> <20070810124153.GW2738@deviant.kiev.zoral.com.ua> <20070814154812.J24186@besplex.bde.org> <6a7033710708300835n5ac95063o6331ede5fcc80662@mail.gmail.com> <20070831092907.K8647@besplex.bde.org>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
2007/8/31, Bruce Evans <brde@optusnet.com.au>:
> This is too late.  I just got approval to commit my version mailed
> here on 10 Aug, and will commit it today.  That version also removes
> the globals, but doesn't change the algorithm so much.  Your version
> seems to be simpler but has too many style bugs for me.  If you want
> to do more work on this, please adjust your patch to apply to the
> version that I will commit and clean it up.

(sorry that I forgot to replay to all in the previous mail)

Ok, the attachment is the new version.
I think it's worth committing because it doesn't only solve the global
variables problem but also solve the kiconv problem. In original
interface the win2unixchr() return a 2-byte int thus it's impossible to
convert from UTF-16BE to UTF-8 because the size of a character in
UTF-8 may be from 1 byte to 6 bytes.

Tz-Huan Huang

[-- Attachment #2 --]
diff -urN msdosfs.orig/direntry.h msdosfs/direntry.h
--- msdosfs.orig/direntry.h	2007-09-01 06:29:55.000000000 +0800
+++ msdosfs/direntry.h	2007-09-01 21:17:25.000000000 +0800
@@ -133,27 +133,18 @@
 #define DD_YEAR_SHIFT		9
 
 #ifdef _KERNEL
-struct mbnambuf {
-	size_t	nb_len;
-	int	nb_last_id;
-	char	nb_buf[WIN_MAXLEN + 1];
-};
-
 struct dirent;
 struct msdosfsmount;
 
-char	*mbnambuf_flush(struct mbnambuf *nbp, struct dirent *dp);
-void	mbnambuf_init(struct mbnambuf *nbp);
-void	mbnambuf_write(struct mbnambuf *nbp, char *name, int id);
 int	dos2unixfn(u_char dn[11], u_char *un, int lower,
 	    struct msdosfsmount *pmp);
 int	unix2dosfn(const u_char *un, u_char dn[12], size_t unlen, u_int gen,
 	    struct msdosfsmount *pmp);
-int	unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, int cnt,
-	    int chksum, struct msdosfsmount *pmp);
-int	winChkName(struct mbnambuf *nbp, const u_char *un, size_t unlen,
+int	unix2winfn(const u_char *un, size_t unlen, struct winentry *wep, 
+	    int cnt, int chksum, struct msdosfsmount *pmp);
+int	winChkName(const u_char *un, size_t unlen, struct dirent *dirbufptr,
 	    int chksum, struct msdosfsmount *pmp);
-int	win2unixfn(struct mbnambuf *nbp, struct winentry *wep, int chksum,
+int	win2unixfn(struct winentry *wep, struct dirent *dirbufptr, int chksum, 
 	    struct msdosfsmount *pmp);
 u_int8_t winChksum(struct direntry *dep);
 int	winSlotCnt(const u_char *un, size_t unlen, struct msdosfsmount *pmp);
diff -urN msdosfs.orig/msdosfs_conv.c msdosfs/msdosfs_conv.c
--- msdosfs.orig/msdosfs_conv.c	2007-09-01 06:29:55.000000000 +0800
+++ msdosfs/msdosfs_conv.c	2007-09-01 21:34:11.000000000 +0800
@@ -52,6 +52,7 @@
 #include <sys/systm.h>
 #include <sys/dirent.h>
 #include <sys/iconv.h>
+#include <sys/malloc.h>
 #include <sys/mount.h>
 
 #include <fs/msdosfs/bpb.h>
@@ -61,10 +62,14 @@
 extern struct iconv_functions *msdosfs_iconv;
 
 static int mbsadjpos(const char **, size_t, size_t, int, int, void *handle);
-static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *);
+static u_int16_t dos2unixchr(const u_char **, size_t *, int, 
+	    struct msdosfsmount *);
 static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *);
-static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *);
-static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *);
+static size_t win2unixchr(u_int16_t wc, struct dirent *dirbufptr, 
+	    struct msdosfsmount *pmp);
+static u_int16_t unix2winchr(const u_char **, size_t *, int,
+	    struct msdosfsmount *);
+static void strreverse(char *, size_t);
 
 /*
  * 0 - character disallowed in long file name.
@@ -596,38 +601,33 @@
  * Returns the checksum or -1 if no match
  */
 int
-winChkName(nbp, un, unlen, chksum, pmp)
-	struct mbnambuf *nbp;
+winChkName(un, unlen, dirbufptr, chksum, pmp)
 	const u_char *un;
 	size_t unlen;
+	struct dirent *dirbufptr;
 	int chksum;
 	struct msdosfsmount *pmp;
 {
 	size_t len;
 	u_int16_t c1, c2;
 	u_char *np;
-	struct dirent dirbuf;
 
-	/*
-	 * We already have winentry in *nbp.
-	 */
-	if (!mbnambuf_flush(nbp, &dirbuf) || dirbuf.d_namlen == 0)
-		return -1;
+	if (dirbufptr->d_namlen == 0)
+		return (-1);
 
 #ifdef MSDOSFS_DEBUG
-	printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen,
-							dirbuf.d_name,
-							dirbuf.d_namlen);
+	printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen, 
+	    dirbufptr->d_name, dirbufptr->d_namlen);
 #endif
 
 	/*
 	 * Compare the name parts
 	 */
-	len = dirbuf.d_namlen;
+	len = dirbufptr->d_namlen;
 	if (unlen != len)
-		return -2;
+		return (-2);
 
-	for (np = dirbuf.d_name; unlen > 0 && len > 0;) {
+	for (np = dirbufptr->d_name; unlen > 0 && len > 0;) {
 		/*
 		 * Comparison must be case insensitive, because FAT disallows
 		 * to look up or create files in case sensitive even when
@@ -636,24 +636,24 @@
 		c1 = unix2winchr((const u_char **)&np, &len, LCASE_BASE, pmp);
 		c2 = unix2winchr(&un, &unlen, LCASE_BASE, pmp);
 		if (c1 != c2)
-			return -2;
+			return (-2);
 	}
-	return chksum;
+	return (chksum);
 }
 
 /*
- * Convert Win95 filename to dirbuf.
+ * Convert Win95 filename to dirbufptr->d_name.
  * Returns the checksum or -1 if impossible
  */
 int
-win2unixfn(nbp, wep, chksum, pmp)
-	struct mbnambuf *nbp;
+win2unixfn(wep, dirbufptr, chksum, pmp)
 	struct winentry *wep;
+	struct dirent *dirbufptr;
 	int chksum;
 	struct msdosfsmount *pmp;
 {
+	const size_t d_namlen = dirbufptr->d_namlen; /* save for reverse */
 	u_int8_t *cp;
-	u_int8_t *np, name[WIN_CHARS * 2 + 1];
 	u_int16_t code;
 	int i;
 
@@ -674,22 +674,19 @@
 	/*
 	 * Convert the name parts
 	 */
-	np = name;
 	for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
 		code = (cp[1] << 8) | cp[0];
 		switch (code) {
 		case 0:
-			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
-			return chksum;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (chksum);
 		case '/':
-			*np = '\0';
-			return -1;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (-1);
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			code = win2unixchr(code, dirbufptr, pmp);
+			if (code != 0)
+				return (-1);
 			break;
 		}
 		cp += 2;
@@ -698,17 +695,15 @@
 		code = (cp[1] << 8) | cp[0];
 		switch (code) {
 		case 0:
-			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
-			return chksum;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (chksum);
 		case '/':
-			*np = '\0';
-			return -1;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (-1);
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			code = win2unixchr(code, dirbufptr, pmp);
+			if (code != 0)
+				return (-1);
 			break;
 		}
 		cp += 2;
@@ -717,24 +712,28 @@
 		code = (cp[1] << 8) | cp[0];
 		switch (code) {
 		case 0:
-			*np = '\0';
-			mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
-			return chksum;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (chksum);
 		case '/':
-			*np = '\0';
-			return -1;
+			dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+			return (-1);
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			code = win2unixchr(code, dirbufptr, pmp);
+			if (code != 0)
+				return (-1);
 			break;
 		}
 		cp += 2;
 	}
-	*np = '\0';
-	mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
-	return chksum;
+	dirbufptr->d_name[dirbufptr->d_namlen] = '\0';
+
+	/* swap the dirbufptr->d_name */
+	strreverse(dirbufptr->d_name, dirbufptr->d_namlen);
+	strreverse(dirbufptr->d_name, dirbufptr->d_namlen - d_namlen);
+	strreverse(dirbufptr->d_name + dirbufptr->d_namlen - d_namlen,
+	    d_namlen);
+
+	return (chksum);
 }
 
 /*
@@ -949,10 +948,10 @@
 /*
  * Convert Windows char to Local char
  */
-static u_int16_t
-win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
+static size_t
+win2unixchr(u_int16_t wc, struct dirent *dirbufptr, struct msdosfsmount *pmp)
 {
-	u_char *inp, *outp, inbuf[3], outbuf[3];
+	u_char *inp, *outp, inbuf[3];
 	size_t ilen, olen, len;
 
 	if (wc == 0)
@@ -963,31 +962,44 @@
 		inbuf[1] = (u_char)wc;
 		inbuf[2] = '\0';
 
-		ilen = olen = len = 2;
+		ilen = 2;
+		olen = len = sizeof(dirbufptr->d_name) - dirbufptr->d_namlen - 1;
 		inp = inbuf;
-		outp = outbuf;
+		outp = dirbufptr->d_name + dirbufptr->d_namlen;
+
 		msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
-				     (char **)&outp, &olen);
-		len -= olen;
+		    (char **)&outp, &olen);
 
-		/*
-		 * return '?' if failed to convert
-		 */
-		if (len == 0) {
-			wc = '?';
-			return (wc);
-		}
+		dirbufptr->d_namlen += len - olen;
 
-		wc = 0;
-		while(len--)
-			wc |= (*(outp - len - 1) & 0xff) << (len << 3);
-		return (wc);
+		if (ilen != 0) {
+			if (olen == 0)
+				goto too_long;	/* longer than MAXNAMLEN */
+			else
+				goto failed;	/* convert failed */
+		} 
+
+		goto ok;
 	}
 
-	if (wc & 0xff00)
-		wc = '?';
+	if (sizeof(dirbufptr->d_name) <= dirbufptr->d_namlen + 2)
+		goto too_long;	/* longer then MAXNAMLEN */
+	else if (wc & 0xff00)
+		goto failed;	/* illegal character? */
 
-	return (wc);
+	dirbufptr->d_name[dirbufptr->d_namlen++] = (u_char)(wc>>8);
+	dirbufptr->d_name[dirbufptr->d_namlen++] = (u_char)wc;
+	goto ok;
+
+ok:
+	return (0);
+
+too_long:
+	return (1);
+
+failed:
+	dirbufptr->d_name[dirbufptr->d_namlen++] = '?';
+	return (2);
 }
 
 /*
@@ -1034,73 +1046,17 @@
 }
 
 /*
- * Initialize the temporary concatenation buffer.
- */
-void
-mbnambuf_init(struct mbnambuf *nbp)
-{
-
-	nbp->nb_len = 0;
-	nbp->nb_last_id = -1;
-	nbp->nb_buf[sizeof(nbp->nb_buf) - 1] = '\0';
-}
-
-/*
- * Fill out our concatenation buffer with the given substring, at the offset
- * specified by its id.  Since this function must be called with ids in
- * descending order, we take advantage of the fact that ASCII substrings are
- * exactly WIN_CHARS in length.  For non-ASCII substrings, we shift all
- * previous (i.e. higher id) substrings upwards to make room for this one.
- * This only penalizes portions of substrings that contain more than
- * WIN_CHARS bytes when they are first encountered.
+ * Reverse c-string in length n, for example, "12345" -> "54321".
  */
-void
-mbnambuf_write(struct mbnambuf *nbp, char *name, int id)
+static void
+strreverse(char *str, size_t n)
 {
-	char *slot;
-	size_t count, newlen;
-
-	KASSERT(nbp->nb_len == 0 || id == nbp->nb_last_id - 1,
-	    ("non-decreasing id: id %d, last id %d", id, nbp->nb_last_id));
-
-	/* Will store this substring in a WIN_CHARS-aligned slot. */
-	slot = &nbp->nb_buf[id * WIN_CHARS];
-	count = strlen(name);
-	newlen = nbp->nb_len + count;
-	if (newlen > WIN_MAXLEN || newlen > MAXNAMLEN) {
-		printf("msdosfs: file name length %zu too large\n", newlen);
-		return;
-	}
-
-	/* Shift suffix upwards by the amount length exceeds WIN_CHARS. */
-	if (count > WIN_CHARS && nbp->nb_len != 0)
-		bcopy(slot + WIN_CHARS, slot + count, nbp->nb_len);
-
-	/* Copy in the substring to its slot and update length so far. */
-	bcopy(name, slot, count);
-	nbp->nb_len = newlen;
-	nbp->nb_last_id = id;
-}
-
-/*
- * Take the completed string and use it to setup the struct dirent.
- * Be sure to always nul-terminate the d_name and then copy the string
- * from our buffer.  Note that this function assumes the full string has
- * been reassembled in the buffer.  If it's called before all substrings
- * have been written via mbnambuf_write(), the result will be incorrect.
- */
-char *
-mbnambuf_flush(struct mbnambuf *nbp, struct dirent *dp)
-{
-
-	if (nbp->nb_len > sizeof(dp->d_name) - 1) {
-		mbnambuf_init(nbp);
-		return (NULL);
-	}
-	bcopy(&nbp->nb_buf[0], dp->d_name, nbp->nb_len);
-	dp->d_name[nbp->nb_len] = '\0';
-	dp->d_namlen = nbp->nb_len;
+	size_t i;
+	char c;
 
-	mbnambuf_init(nbp);
-	return (dp->d_name);
+	for (i = 0; i < n/2; ++i) {
+		c = str[i];
+		str[i] = str[n - i - 1];
+		str[n - i - 1] = c;
+	}
 }
diff -urN msdosfs.orig/msdosfs_lookup.c msdosfs/msdosfs_lookup.c
--- msdosfs.orig/msdosfs_lookup.c	2007-09-01 06:29:55.000000000 +0800
+++ msdosfs/msdosfs_lookup.c	2007-09-01 21:35:00.000000000 +0800
@@ -54,6 +54,7 @@
 #include <sys/mount.h>
 #include <sys/namei.h>
 #include <sys/vnode.h>
+#include <sys/dirent.h>
 
 #include <fs/msdosfs/bpb.h>
 #include <fs/msdosfs/direntry.h>
@@ -84,7 +85,6 @@
 		struct componentname *a_cnp;
 	} */ *ap;
 {
-	struct mbnambuf nb;
 	struct vnode *vdp = ap->a_dvp;
 	struct vnode **vpp = ap->a_vpp;
 	struct componentname *cnp = ap->a_cnp;
@@ -104,6 +104,7 @@
 	struct denode *tdp;
 	struct msdosfsmount *pmp;
 	struct buf *bp = 0;
+	struct dirent namebuf;
 	struct direntry *dep = NULL;
 	u_char dosfilename[12];
 	int flags = cnp->cn_flags;
@@ -186,7 +187,7 @@
 	 * by cnp->cn_nameptr.
 	 */
 	tdp = NULL;
-	mbnambuf_init(&nb);
+	namebuf.d_namlen = 0;
 	/*
 	 * The outer loop ranges over the clusters that make up the
 	 * directory.  Note that the root directory is different from all
@@ -226,7 +227,7 @@
 				 * Drop memory of previous long matches
 				 */
 				chksum = -1;
-				mbnambuf_init(&nb);
+				namebuf.d_namlen = 0;
 
 				if (slotcount < wincnt) {
 					slotcount++;
@@ -251,16 +252,17 @@
 					if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 						continue;
 
-					chksum = win2unixfn(&nb,
-					    (struct winentry *)dep, chksum,
-					    pmp);
+					chksum = win2unixfn(
+					    (struct winentry *)dep, &namebuf,
+					    chksum, pmp);
 					continue;
 				}
 
-				chksum = winChkName(&nb,
+				chksum = winChkName(
 				    (const u_char *)cnp->cn_nameptr, unlen,
-				    chksum, pmp);
+				    &namebuf, chksum, pmp);
 				if (chksum == -2) {
+					namebuf.d_namlen = 0;
 					chksum = -1;
 					continue;
 				}
diff -urN msdosfs.orig/msdosfs_vnops.c msdosfs/msdosfs_vnops.c
--- msdosfs.orig/msdosfs_vnops.c	2007-09-01 06:29:55.000000000 +0800
+++ msdosfs/msdosfs_vnops.c	2007-09-01 21:30:40.000000000 +0800
@@ -1510,7 +1510,6 @@
 		u_long **a_cookies;
 	} */ *ap;
 {
-	struct mbnambuf nb;
 	int error = 0;
 	int diff;
 	long n;
@@ -1549,6 +1548,7 @@
 	/*
 	 * To be safe, initialize dirbuf
 	 */
+	dirbuf.d_namlen = 0;
 	bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
 
 	/*
@@ -1630,7 +1630,7 @@
 		}
 	}
 
-	mbnambuf_init(&nb);
+	dirbuf.d_namlen = 0;
 	off = offset;
 	while (uio->uio_resid > 0) {
 		lbn = de_cluster(pmp, offset - bias);
@@ -1677,7 +1677,7 @@
 			 */
 			if (dentp->deName[0] == SLOT_DELETED) {
 				chksum = -1;
-				mbnambuf_init(&nb);
+				dirbuf.d_namlen = 0;
 				continue;
 			}
 
@@ -1687,8 +1687,8 @@
 			if (dentp->deAttributes == ATTR_WIN95) {
 				if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 					continue;
-				chksum = win2unixfn(&nb,
-				    (struct winentry *)dentp, chksum, pmp);
+				chksum = win2unixfn((struct winentry *)dentp,
+				    &dirbuf, chksum, pmp);
 				continue;
 			}
 
@@ -1697,7 +1697,7 @@
 			 */
 			if (dentp->deAttributes & ATTR_VOLUME) {
 				chksum = -1;
-				mbnambuf_init(&nb);
+				dirbuf.d_namlen = 0;
 				continue;
 			}
 			/*
@@ -1739,9 +1739,8 @@
 					((pmp->pm_flags & MSDOSFSMNT_SHORTNAME) ?
 					(LCASE_BASE | LCASE_EXT) : 0),
 				    pmp);
-				mbnambuf_init(&nb);
-			} else
-				mbnambuf_flush(&nb, &dirbuf);
+			} 
+
 			chksum = -1;
 			dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
 			if (uio->uio_resid < dirbuf.d_reclen) {
@@ -1761,6 +1760,7 @@
 				}
 			}
 			off = offset + sizeof(struct direntry);
+			dirbuf.d_namlen = 0;
 		}
 		brelse(bp);
 	}

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a7033710709010653i2e43f517y953885b67160c1cd>