Bug 59765 - msdosfs long file name matching should be case insensitve
Summary: msdosfs long file name matching should be case insensitve
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: Max Khon
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-11-28 17:50 UTC by imura
Modified: 2003-12-08 08:34 UTC (History)
1 user (show)

See Also:


Attachments
file.diff (3.64 KB, patch)
2003-11-28 17:50 UTC, imura
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description imura 2003-11-28 17:50:06 UTC
Although msdosfs's long file name matching should be case insensitive,
current code has been changed to do in case sensitive after kiconv(3) changes.
Sorry for that.
Just FYI, the first problem was reported at FreeBSD-users-jp@jp.freebsd.org 
list.

Fix: Fixing this problem should be very easy if nobody using kiconv feature, but
sad to say that iconv_xlat16.c has a bug when using KICONV_FROM_XX with UCS-2,
This patch fixes this problem and iconv_xlat16.c's bug.
Comment 1 imura 2003-12-01 14:43:13 UTC
On Sat, Nov 29, 2003 at 02:42:15AM +0900, Ryuichiro Imura wrote:
> Although msdosfs's long file name matching should be case insensitive,
> current code has been changed to do in case sensitive after kiconv(3) changes.
> Sorry for that.

I noticed the previous patch is insufficient.
Since convertion tables are shared by other file systems, if you mount
msdosfs after mount cd9660, there aren't any upper/lower tables.
We need to create upper/lower table for every file systems and need to
reserve it for msdosfs.  Now I'd like to add a new function which wraps
upper/lower operations, and replace existent kiconv functions with it.

- R. Imura

Index: lib/libkiconv/Makefile
===================================================================
RCS file: /home/ncvs/src/lib/libkiconv/Makefile,v
retrieving revision 1.1
diff -u -r1.1 Makefile
--- lib/libkiconv/Makefile	26 Sep 2003 20:26:20 -0000	1.1
+++ lib/libkiconv/Makefile	1 Dec 2003 14:41:21 -0000
@@ -10,6 +10,7 @@
 MAN=		kiconv.3
 
 MLINKS+=	kiconv.3 kiconv_add_xlat16_cspair.3 \
+		kiconv.3 kiconv_add_xlat16_cspairs.3 \
 		kiconv.3 kiconv_add_xlat16_table.3
 
 CFLAGS+=	-I${.CURDIR}/../../sys
Index: lib/libkiconv/kiconv.3
===================================================================
RCS file: /home/ncvs/src/lib/libkiconv/kiconv.3,v
retrieving revision 1.2
diff -u -r1.2 kiconv.3
--- lib/libkiconv/kiconv.3	5 Oct 2003 13:39:28 -0000	1.2
+++ lib/libkiconv/kiconv.3	30 Nov 2003 23:28:05 -0000
@@ -30,6 +30,7 @@
 .Os
 .Sh NAME
 .Nm kiconv_add_xlat16_cspair ,
+.Nm kiconv_add_xlat16_cspairs ,
 .Nm kiconv_add_xlat16_table
 .Nd Kernel side iconv library
 .Sh LIBRARY
@@ -43,6 +44,11 @@
 .Fa "int flag"
 .Fc
 .Ft int
+.Fo kiconv_add_xlat16_cspairs
+.Fa "const char *foreigncode"
+.Fa "const char *localcode"
+.Fc
+.Ft int
 .Fo kiconv_add_xlat16_table
 .Fa "const char *tocode"
 .Fa "const char *fromcode"
@@ -92,6 +98,17 @@
 .Pp
 A tolower/toupper conversion is limited to single-byte characters.
 .Pp 
+.Fn kiconv_add_xlat16_cspairs
+defines two conversion tables which are from
+.Ar localcode
+to
+.Ar foreigncode
+and from
+.Ar foreigncode
+to
+.Ar localcode .
+This conversion tables also contain both of tolower and toupper tables.
+.Pp
 .Fn kiconv_add_xlat16_table
 defines a conversion table directly pointed by
 .Ar data
Index: lib/libkiconv/xlat16_iconv.c
===================================================================
RCS file: /home/ncvs/src/lib/libkiconv/xlat16_iconv.c,v
retrieving revision 1.1
diff -u -r1.1 xlat16_iconv.c
--- lib/libkiconv/xlat16_iconv.c	26 Sep 2003 20:26:20 -0000	1.1
+++ lib/libkiconv/xlat16_iconv.c	30 Nov 2003 23:37:10 -0000
@@ -113,6 +113,23 @@
 	return (-1);
 }
 
+int
+kiconv_add_xlat16_cspairs(const char *foreigncode, const char *localcode)
+{
+	int error;
+
+	error = kiconv_add_xlat16_cspair(foreigncode, localcode,
+	    KICONV_FROM_LOWER | KICONV_FROM_UPPER);
+	if (error)
+		return (error);
+	error = kiconv_add_xlat16_cspair(localcode, foreigncode,
+	    KICONV_LOWER | KICONV_UPPER);
+	if (error)
+		return (error);
+	
+	return (0);
+}
+
 static struct xlat16_table
 kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase)
 {
Index: sbin/mount_cd9660/mount_cd9660.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount_cd9660/mount_cd9660.c,v
retrieving revision 1.25
diff -u -r1.25 mount_cd9660.c
--- sbin/mount_cd9660/mount_cd9660.c	4 Nov 2003 21:04:14 -0000	1.25
+++ sbin/mount_cd9660/mount_cd9660.c	30 Nov 2003 23:28:06 -0000
@@ -255,10 +255,7 @@
 	strncpy(args->cs_disk, ENCODING_UNICODE, ICONV_CSNMAXLEN);
 	strncpy(args->cs_local, kiconv_quirkcs(localcs, KICONV_VENDOR_MICSFT),
 	    ICONV_CSNMAXLEN);
-	error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_disk, 0);
-	if (error)
-		return (-1);
-	error = kiconv_add_xlat16_cspair(args->cs_disk, args->cs_local, 0);
+	error = kiconv_add_xlat16_cspairs(args->cs_disk, args->cs_local);
 	if (error)
 		return (-1);
 
Index: sbin/mount_msdosfs/mount_msdosfs.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount_msdosfs/mount_msdosfs.c,v
retrieving revision 1.31
diff -u -r1.31 mount_msdosfs.c
--- sbin/mount_msdosfs/mount_msdosfs.c	23 Oct 2003 16:09:20 -0000	1.31
+++ sbin/mount_msdosfs/mount_msdosfs.c	30 Nov 2003 23:28:06 -0000
@@ -339,17 +339,11 @@
 	if ((args->cs_win = malloc(ICONV_CSNMAXLEN)) == NULL)
 		return (-1);
 	strncpy(args->cs_win, ENCODING_UNICODE, ICONV_CSNMAXLEN);
-	error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, 0);
-	if (error)
-		return (-1);
-	error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 0);
+	error = kiconv_add_xlat16_cspairs(args->cs_win, args->cs_local);
 	if (error)
 		return (-1);
 	if (args->cs_dos) {
-		error = kiconv_add_xlat16_cspair(args->cs_dos, args->cs_local, KICONV_FROM_UPPER);
-		if (error)
-			return (-1);
-		error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_dos, KICONV_LOWER);
+		error = kiconv_add_xlat16_cspairs(args->cs_dos, args->cs_local);
 		if (error)
 			return (-1);
 	} else {
Index: sbin/mount_ntfs/mount_ntfs.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount_ntfs/mount_ntfs.c,v
retrieving revision 1.9
diff -u -r1.9 mount_ntfs.c
--- sbin/mount_ntfs/mount_ntfs.c	26 Sep 2003 20:26:21 -0000	1.9
+++ sbin/mount_ntfs/mount_ntfs.c	30 Nov 2003 23:28:06 -0000
@@ -275,10 +275,7 @@
 	if ((pargs->cs_ntfs = malloc(ICONV_CSNMAXLEN)) == NULL)
 		return (-1);
 	strncpy(pargs->cs_ntfs, ENCODING_UNICODE, ICONV_CSNMAXLEN);
-	error = kiconv_add_xlat16_cspair(pargs->cs_local, pargs->cs_ntfs, 0);
-	if (error)
-		return (-1);
-	error = kiconv_add_xlat16_cspair(pargs->cs_ntfs, pargs->cs_local, 0);
+	error = kiconv_add_xlat16_cspairs(pargs->cs_ntfs, pargs->cs_local);
 	if (error)
 		return (-1);
 
Index: sbin/mount_udf/mount_udf.c
===================================================================
RCS file: /home/ncvs/src/sbin/mount_udf/mount_udf.c,v
retrieving revision 1.8
diff -u -r1.8 mount_udf.c
--- sbin/mount_udf/mount_udf.c	24 Nov 2003 16:14:32 -0000	1.8
+++ sbin/mount_udf/mount_udf.c	30 Nov 2003 23:28:07 -0000
@@ -172,14 +172,9 @@
 		return (-1);
 	strncpy(*cs_disk, ENCODING_UNICODE, ICONV_CSNMAXLEN);
 	strncpy(*cs_local, localcs, ICONV_CSNMAXLEN);
-	error = kiconv_add_xlat16_cspair(*cs_local, *cs_disk, 0);
+	error = kiconv_add_xlat16_cspairs(*cs_disk, *cs_local);
 	if (error)
 		return (-1);
-#if 0
-	error = kiconv_add_xlat16_cspair(*cs_disk, *cs_local, 0);
-	if (error)
-		return (-1);
-#endif
 
 	return (0);
 }
Index: sys/fs/msdosfs/msdosfs_conv.c
===================================================================
RCS file: /home/ncvs/src/sys/fs/msdosfs/msdosfs_conv.c,v
retrieving revision 1.34
diff -u -r1.34 msdosfs_conv.c
--- sys/fs/msdosfs/msdosfs_conv.c	26 Sep 2003 20:26:22 -0000	1.34
+++ sys/fs/msdosfs/msdosfs_conv.c	30 Nov 2003 23:28:06 -0000
@@ -800,10 +800,12 @@
 
 	for (np = dirbuf.d_name; unlen > 0 && len > 0;) {
 		/*
-		 * Should comparison be case insensitive?
+		 * Comparison must be case insensitive, because FAT disallows
+		 * to look up or create files in case sensitive even when
+		 * it's a long file name.
 		 */
-		c1 = unix2winchr((const u_char **)&np, (size_t *)&len, 0, pmp);
-		c2 = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+		c1 = unix2winchr((const u_char **)&np, (size_t *)&len, LCASE_BASE, pmp);
+		c2 = unix2winchr(&un, (size_t *)&unlen, LCASE_BASE, pmp);
 		if (c1 != c2)
 			return -2;
 	}
Index: sys/libkern/iconv_xlat16.c
===================================================================
RCS file: /home/ncvs/src/sys/libkern/iconv_xlat16.c,v
retrieving revision 1.1
diff -u -r1.1 iconv_xlat16.c
--- sys/libkern/iconv_xlat16.c	26 Sep 2003 20:26:24 -0000	1.1
+++ sys/libkern/iconv_xlat16.c	24 Nov 2003 17:32:09 -0000
@@ -96,11 +96,11 @@
 	struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
 	const char *src;
 	char *dst;
-	int ret = 0;
+	int nullin, ret = 0;
 	size_t in, on, ir, or, inlen;
 	uint32_t code;
 	u_char u, l;
-	u_int16_t c1, c2;
+	uint16_t c1, c2;
 
 	if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
 		return (0);
@@ -146,7 +146,8 @@
 			}
 		}
 
-		if ((inlen == 1) && (code & XLAT16_ACCEPT_NULL_IN)) {
+		nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0;
+		if (inlen == 1 && nullin) {
 			/*
 			 * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte
 			 */
@@ -157,6 +158,14 @@
 		/*
 		 * now start translation
 		 */
+		if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) ||
+		    (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE)) {
+			c2 = (u_char)(code >> 16);
+			c1 = c2 & 0x80 ? 0x100 : 0;
+			c2 = c2 & 0x80 ? c2 & 0x7f : c2;
+			code = dp->d_table[c1][c2];
+		}
+
 		u = (u_char)(code >> 8);
 		l = (u_char)code;
 
@@ -184,9 +193,6 @@
 			if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) ||
 			    (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE))
 				*dst++ = (u_char)(code >> 16);
-			else if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) ||
-				 (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE))
-				*dst++ = dp->d_table[0][(u_char)(code >> 16)];
 			else
 				*dst++ = l;
 			or--;
@@ -197,8 +203,7 @@
 			 * there is a case that inbuf char is a single
 			 * byte char while inlen == 2
 			 */
-			if ((u_char)*(src+1) == 0 &&
-			    (code & XLAT16_ACCEPT_NULL_IN) == 0 ) {
+			if ((u_char)*(src+1) == 0 && !nullin ) {
 				src++;
 				ir--;
 			} else {
Index: sys/sys/iconv.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/iconv.h,v
retrieving revision 1.7
diff -u -r1.7 iconv.h
--- sys/sys/iconv.h	5 Nov 2003 06:27:40 -0000	1.7
+++ sys/sys/iconv.h	30 Nov 2003 23:35:36 -0000
@@ -92,6 +103,7 @@
 
 int   kiconv_add_xlat_table(const char *, const char *, const u_char *);
 int   kiconv_add_xlat16_cspair(const char *, const char *, int);
+int   kiconv_add_xlat16_cspairs(const char *, const char *);
 int   kiconv_add_xlat16_table(const char *, const char *, const void *, int);
 const char *kiconv_quirkcs(const char *, int);
Comment 2 Max Khon freebsd_committer freebsd_triage 2003-12-03 01:54:44 UTC
Responsible Changed
From-To: freebsd-bugs->fjoe

I'll take this.
Comment 3 Max Khon freebsd_committer freebsd_triage 2003-12-08 08:34:01 UTC
State Changed
From-To: open->closed

Committed, thanks!