kern/59765: msdosfs long file name matching should be case
insensitve
Ryuichiro Imura
imura at ryu16.org
Fri Nov 28 09:50:14 PST 2003
>Number: 59765
>Category: kern
>Synopsis: msdosfs long file name matching should be case insensitve
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Fri Nov 28 09:50:06 PST 2003
>Closed-Date:
>Last-Modified:
>Originator: Ryuichiro Imura
>Release: FreeBSD 5.2-BETA i186
>Organization:
>Environment:
System: FreeBSD bluewind.xt.ryu16.org 5.2-BETA FreeBSD 5.2-BETA #22: Wed Nov 26 02:09:08 JST 2003 root at bluewind.xt.ryu16.org:/usr/obj/usr/src/sys/BLUE i386
>Description:
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 at jp.freebsd.org
list.
>How-To-Repeat:
>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.
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 24 Nov 2003 06:34:07 -0000
@@ -339,7 +339,7 @@
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);
+ error = kiconv_add_xlat16_cspair(args->cs_win, args->cs_local, KICONV_FROM_LOWER);
if (error)
return (-1);
error = kiconv_add_xlat16_cspair(args->cs_local, args->cs_win, 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 28 Nov 2003 17:37:35 -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 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 {
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list