summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorimura <imura@FreeBSD.org>2005-07-17 07:10:05 +0000
committerimura <imura@FreeBSD.org>2005-07-17 07:10:05 +0000
commita519d1b3a07c559097431d2cc0ed72f0995301f5 (patch)
tree9de86e2c3ee87d8158340f34b2ed90bb0902dd13
parent9b75f72988c74c9ce57302046b905ba1551dd1bc (diff)
downloadFreeBSD-src-a519d1b3a07c559097431d2cc0ed72f0995301f5.zip
FreeBSD-src-a519d1b3a07c559097431d2cc0ed72f0995301f5.tar.gz
[1] unix2doschr()
If a character cannot be converted to DOS code page, unix2doschr() returned `0'. As a result, unix2dosfn() was forced to return `0', so we saw a file which was composed of these characters as `Invalid argument'. To correct this, if a character can be converted to Unicode, unix2doschr() now returns `1' which is a magic number to make unix2dosfn() know that the character must be converted to `_'. [2] unix2dosfn() The above-mentioned solution only works if a file has both of Unicode name and DOS code page name. Unicode name would not be recorded if file name can be settled within 11 bytes (DOS short name) and if no conversion from Unix charset to DOS code page has occurred. Thus, FreeBSD can create a file which has only short name, but there is no guarantee that the short name contains allways valid characters because we leave it to people by using mount_msdosfs(8) to select which conversion is used between DOS code page and unix charset. To avoid this, Unicode file name should be recorded unless a character is an ascii character. This is the way Windows XP do. PR: 77074 [1] MFC after: 1 week
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index 8010457..2da7723 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -560,7 +560,9 @@ unix2dosfn(un, dn, unlen, gen, pmp)
}
/*
- * Now convert it (this part is for extension)
+ * Now convert it (this part is for extension).
+ * As Windows XP do, if it's not ascii char,
+ * this function should return 2 or 3, so that checkng out Unicode name.
*/
if (dp) {
if (dp1)
@@ -573,6 +575,8 @@ unix2dosfn(un, dn, unlen, gen, pmp)
dn[j] = c >> 8;
if (++j < 11) {
dn[j] = c;
+ if (conv != 3)
+ conv = 2;
continue;
} else {
conv = 3;
@@ -582,7 +586,7 @@ unix2dosfn(un, dn, unlen, gen, pmp)
} else {
dn[j] = c;
}
- if (*(cp - 1) != dn[j] && conv != 3)
+ if (((dn[j] & 0x80) || *(cp - 1) != dn[j]) && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -610,6 +614,8 @@ unix2dosfn(un, dn, unlen, gen, pmp)
dn[j] = c >> 8;
if (++j < 8) {
dn[j] = c;
+ if (conv != 3)
+ conv = 2;
continue;
} else {
conv = 3;
@@ -619,7 +625,7 @@ unix2dosfn(un, dn, unlen, gen, pmp)
} else {
dn[j] = c;
}
- if (*(un - 1) != dn[j] && conv != 3)
+ if (((dn[j] & 0x80) || *(un - 1) != dn[j]) && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -1048,22 +1054,23 @@ unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp)
u_char c;
char *up, *outp, unicode[3], outbuf[3];
u_int16_t wc;
- size_t len, ulen, olen;
+ size_t len, ucslen, unixlen, olen;
if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
/*
* to hide an invisible character, using a unicode filter
*/
- ulen = 2;
+ ucslen = 2;
len = *ilen;
up = unicode;
msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr,
- ilen, &up, &ulen);
+ ilen, &up, &ucslen);
+ unixlen = len - *ilen;
/*
* cannot be converted
*/
- if (ulen == 2) {
+ if (unixlen == 0) {
(*ilen)--;
(*instr)++;
return (0);
@@ -1072,7 +1079,7 @@ unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp)
/*
* return magic number for ascii char
*/
- if ((len - *ilen) == 1) {
+ if (unixlen == 1) {
c = *(*instr -1);
if (! (c & 0x80)) {
c = unix2dos[c];
@@ -1084,14 +1091,24 @@ unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp)
/*
* now convert using libiconv
*/
- *instr -= len - *ilen;
- *ilen = (int)len;
+ *instr -= unixlen;
+ *ilen = len;
olen = len = 2;
outp = outbuf;
msdosfs_iconv->convchr_case(pmp->pm_u2d, (const char **)instr,
ilen, &outp, &olen, KICONV_FROM_UPPER);
len -= olen;
+
+ /*
+ * cannot be converted, but has unicode char, should return magic number
+ */
+ if (len == 0) {
+ (*ilen) -= unixlen;
+ (*instr) += unixlen;
+ return (1);
+ }
+
wc = 0;
while(len--)
wc |= (*(outp - len - 1) & 0xff) << (len << 3);
OpenPOWER on IntegriCloud