summaryrefslogtreecommitdiffstats
path: root/sys/fs/msdosfs/msdosfs_conv.c
diff options
context:
space:
mode:
authorfjoe <fjoe@FreeBSD.org>2003-09-26 20:26:25 +0000
committerfjoe <fjoe@FreeBSD.org>2003-09-26 20:26:25 +0000
commit571ef024e3f3a472116a55a8489d77eb4f5f933e (patch)
tree5e4dbdee80eebe5477ad9c5637bb6b0ee47993d5 /sys/fs/msdosfs/msdosfs_conv.c
parent0c8bfb6d004a87cd501c13516a69b3ef59ed6c7c (diff)
downloadFreeBSD-src-571ef024e3f3a472116a55a8489d77eb4f5f933e.zip
FreeBSD-src-571ef024e3f3a472116a55a8489d77eb4f5f933e.tar.gz
- Support for multibyte charsets in LIBICONV.
- CD9660_ICONV, NTFS_ICONV and MSDOSFS_ICONV kernel options (with corresponding modules). - kiconv(3) for loadable charset conversion tables support. Submitted by: Ryuichiro Imura <imura@ryu16.org>
Diffstat (limited to 'sys/fs/msdosfs/msdosfs_conv.c')
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c771
1 files changed, 482 insertions, 289 deletions
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index d135bfa..5c663c8 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -57,10 +57,17 @@
#include <sys/systm.h>
#include <machine/clock.h>
#include <sys/dirent.h>
+#include <sys/iconv.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+
+extern struct iconv_functions *msdosfs_iconv;
/*
* MSDOSFS include files.
*/
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
/*
@@ -88,7 +95,17 @@ static u_long lastday;
static u_short lastddate;
static u_short lastdtime;
-static __inline u_int8_t find_lcode(u_int16_t code, u_int16_t *u2w);
+static int mbsadjpos(const char **, int, int, int, int, void *handle);
+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 *);
+
+struct mbnambuf {
+ char * p;
+ size_t n;
+};
+static struct mbnambuf subent[WIN_MAXSUBENTRIES];
/*
* Convert the unix version of time to dos's idea of time to be used in
@@ -239,6 +256,7 @@ dos2unixtime(dd, dt, dh, tsp)
*/
static u_char
unix2dos[256] = {
+/* iso8859-1 -> cp850 */
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 */
@@ -275,6 +293,7 @@ unix2dos[256] = {
static u_char
dos2unix[256] = {
+/* cp850 -> iso8859-1 */
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 */
@@ -311,6 +330,7 @@ dos2unix[256] = {
static u_char
u2l[256] = {
+/* tolower */
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 */
@@ -347,6 +367,7 @@ u2l[256] = {
static u_char
l2u[256] = {
+/* toupper */
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 */
@@ -394,18 +415,15 @@ l2u[256] = {
* null.
*/
int
-dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
+dos2unixfn(dn, un, lower, pmp)
u_char dn[11];
u_char *un;
int lower;
- int d2u_loaded;
- u_int8_t *d2u;
- int ul_loaded;
- u_int8_t *ul;
+ struct msdosfsmount *pmp;
{
int i;
- int thislong = 1;
- u_char c;
+ int thislong = 0;
+ u_int16_t c;
/*
* If first char of the filename is SLOT_E5 (0x05), then the real
@@ -414,26 +432,21 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
* directory slot. Another dos quirk.
*/
if (*dn == SLOT_E5)
- c = d2u_loaded ? d2u[0xe5 & 0x7f] : dos2unix[0xe5];
- else
- c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
- dos2unix[*dn];
- *un++ = (lower & LCASE_BASE) ? (ul_loaded && (c & 0x80) ?
- ul[c & 0x7f] : u2l[c]) : c;
- dn++;
+ *dn = 0xe5;
/*
* Copy the name portion into the unix filename string.
*/
- for (i = 1; i < 8 && *dn != ' '; i++) {
- c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
- dos2unix[*dn];
- dn++;
- *un++ = (lower & LCASE_BASE) ? (ul_loaded && (c & 0x80) ?
- ul[c & 0x7f] : u2l[c]) : c;
+ for (i = 8; i > 0 && *dn != ' ';) {
+ c = dos2unixchr((const u_char **)&dn, (size_t *)&i, lower, pmp);
+ if (c & 0xff00) {
+ *un++ = c >> 8;
+ thislong++;
+ }
+ *un++ = c;
thislong++;
}
- dn += 8 - i;
+ dn += i;
/*
* Now, if there is an extension then put in a period and copy in
@@ -442,12 +455,13 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
if (*dn != ' ') {
*un++ = '.';
thislong++;
- for (i = 0; i < 3 && *dn != ' '; i++) {
- c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
- dos2unix[*dn];
- dn++;
- *un++ = (lower & LCASE_EXT) ? (ul_loaded && (c & 0x80) ?
- ul[c & 0x7f] : u2l[c]) : c;
+ for (i = 3; i > 0 && *dn != ' ';) {
+ c = dos2unixchr((const u_char **)&dn, (size_t *)&i, lower, pmp);
+ if (c & 0xff00) {
+ *un++ = c >> 8;
+ thislong++;
+ }
+ *un++ = c;
thislong++;
}
}
@@ -468,22 +482,18 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
* 3 if conversion was successful and generation number was inserted
*/
int
-unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
+unix2dosfn(un, dn, unlen, gen, pmp)
const u_char *un;
u_char dn[12];
int unlen;
u_int gen;
- int u2d_loaded;
- u_int8_t *u2d;
- int lu_loaded;
- u_int8_t *lu;
+ struct msdosfsmount *pmp;
{
int i, j, l;
int conv = 1;
const u_char *cp, *dp, *dp1;
u_char gentext[6], *wcp;
- u_int8_t c;
-#define U2D(c) (u2d_loaded && ((c) & 0x80) ? u2d[(c) & 0x7f] : unix2dos[c])
+ u_int16_t c;
/*
* Fill the dos filename string with blanks. These are DOS's pad
@@ -520,14 +530,18 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
/*
* Filenames with some characters are not allowed!
*/
- for (cp = un, i = unlen; --i >= 0; cp++)
- if (U2D(*cp) == 0)
+ for (cp = un, i = unlen; i > 0;)
+ if (unix2doschr(&cp, (size_t *)&i, pmp) == 0)
return 0;
/*
* Now find the extension
* Note: dot as first char doesn't start extension
* and trailing dots and blanks are ignored
+ * Note(2003/7): It seems recent Windows has
+ * defferent rule than this code, that Windows
+ * ignores all dots before extension, and use all
+ * chars as filename except for dots.
*/
dp = dp1 = 0;
for (cp = un + 1, i = unlen - 1; --i >= 0;) {
@@ -547,20 +561,29 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
}
/*
- * Now convert it
+ * Now convert it (this part is for extension)
*/
if (dp) {
if (dp1)
l = dp1 - dp;
else
l = unlen - (dp - un);
- for (i = 0, j = 8; i < l && j < 11; i++, j++) {
- c = dp[i];
- c = lu_loaded && (c & 0x80) ?
- lu[c & 0x7f] : l2u[c];
- c = U2D(c);
- if (dp[i] != (dn[j] = c)
- && conv != 3)
+ for (cp = dp, i = l, j = 8; i > 0 && j < 11; j++) {
+ c = unix2doschr(&cp, (size_t *)&i, pmp);
+ if (c & 0xff00) {
+ dn[j] = c >> 8;
+ if (++j < 11) {
+ dn[j] = c;
+ continue;
+ } else {
+ conv = 3;
+ dn[j-1] = ' ';
+ break;
+ }
+ } else {
+ dn[j] = c;
+ }
+ if (*(cp - 1) != dn[j] && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -571,7 +594,7 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
dn[j--] = ' ';
}
}
- if (i < l)
+ if (i > 0)
conv = 3;
dp--;
} else {
@@ -582,12 +605,22 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
/*
* Now convert the rest of the name
*/
- for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
- c = lu_loaded && (*un & 0x80) ?
- lu[*un & 0x7f] : l2u[*un];
- c = U2D(c);
- if (*un != (dn[j] = c)
- && conv != 3)
+ for (i = dp - un, j = 0; un < dp && j < 8; j++) {
+ c = unix2doschr(&un, (size_t *)&i, pmp);
+ if (c & 0xff00) {
+ dn[j] = c >> 8;
+ if (++j < 8) {
+ dn[j] = c;
+ continue;
+ } else {
+ conv = 3;
+ dn[j-1] = ' ';
+ break;
+ }
+ } else {
+ dn[j] = c;
+ }
+ if (*(un - 1) != dn[j] && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -608,40 +641,56 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
dn[0] = '_';
/*
- * The first character cannot be E5,
- * because that means a deleted entry
- */
- 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;
+ conv = 0;
+ goto done;
}
/*
* Now insert the generation number into the filename part
*/
if (gen == 0)
- return conv;
+ goto done;
for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
*--wcp = gen % 10 + '0';
- if (gen)
- return 0;
+ if (gen) {
+ conv = 0;
+ goto done;
+ }
for (i = 8; dn[--i] == ' ';);
i++;
if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
i = 8 - (gentext + sizeof(gentext) - wcp + 1);
+ /*
+ * Correct posision to where insert the generation number
+ */
+ cp = dn;
+ i -= mbsadjpos((const char**)&cp, i, unlen, 1, pmp->pm_flags, pmp->pm_d2u);
+
dn[i++] = '~';
while (wcp < gentext + sizeof(gentext))
dn[i++] = *wcp++;
- return 3;
-#undef U2D
+
+ /*
+ * Tail of the filename should be space
+ */
+ while (i < 8)
+ dn[i++] = ' ';
+ conv = 3;
+
+done:
+ /*
+ * The first character cannot be E5,
+ * because that means a deleted entry
+ */
+ if (dn[0] == 0xe5)
+ dn[0] = SLOT_E5;
+
+ return conv;
}
/*
@@ -650,27 +699,28 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
* i.e. doesn't consist solely of blanks and dots
*/
int
-unix2winfn(un, unlen, wep, cnt, chksum, table_loaded, u2w)
+unix2winfn(un, unlen, wep, cnt, chksum, pmp)
const u_char *un;
int unlen;
struct winentry *wep;
int cnt;
int chksum;
- int table_loaded;
- u_int16_t *u2w;
+ struct msdosfsmount *pmp;
{
- const u_int8_t *cp;
u_int8_t *wcp;
- int i;
+ int i, end;
u_int16_t code;
/*
* Drop trailing blanks and dots
*/
- for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
+ unlen = winLenFixup(un, unlen);
- un += (cnt - 1) * WIN_CHARS;
- unlen -= (cnt - 1) * WIN_CHARS;
+ /*
+ * Cut *un for this slot
+ */
+ unlen = mbsadjpos((const char **)&un, unlen, (cnt - 1) * WIN_CHARS, 2,
+ pmp->pm_flags, pmp->pm_u2w);
/*
* Initialize winentry to some useful default
@@ -685,64 +735,32 @@ unix2winfn(un, unlen, wep, cnt, chksum, table_loaded, u2w)
/*
* Now convert the filename parts
*/
- for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
- if (--unlen < 0)
- goto done;
- if (table_loaded && (*un & 0x80)) {
- code = u2w[*un++ & 0x7f];
- *wcp++ = code;
- *wcp++ = code >> 8;
- } else {
- *wcp++ = *un++;
- *wcp++ = 0;
- }
+ end = 0;
+ for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
- if (--unlen < 0)
- goto done;
- if (table_loaded && (*un & 0x80)) {
- code = u2w[*un++ & 0x7f];
- *wcp++ = code;
- *wcp++ = code >> 8;
- } else {
- *wcp++ = *un++;
- *wcp++ = 0;
- }
+ for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
- if (--unlen < 0)
- goto done;
- if (table_loaded && (*un & 0x80)) {
- code = u2w[*un++ & 0x7f];
- *wcp++ = code;
- *wcp++ = code >> 8;
- } else {
- *wcp++ = *un++;
- *wcp++ = 0;
- }
+ for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- if (!unlen)
- wep->weCnt |= WIN_LAST;
- return unlen;
-
-done:
- *wcp++ = 0;
- *wcp++ = 0;
- wep->weCnt |= WIN_LAST;
- return 0;
-}
-
-static __inline u_int8_t
-find_lcode(code, u2w)
- u_int16_t code;
- u_int16_t *u2w;
-{
- int i;
-
- for (i = 0; i < 128; i++)
- if (u2w[i] == code)
- return (i | 0x80);
- return '?';
+ if (*un == '\0')
+ end = WIN_LAST;
+ wep->weCnt |= end;
+ return !end;
}
/*
@@ -750,116 +768,44 @@ find_lcode(code, u2w)
* Returns the checksum or -1 if no match
*/
int
-winChkName(un, unlen, wep, chksum, u2w_loaded, u2w, ul_loaded, ul)
+winChkName(un, unlen, chksum, pmp)
const u_char *un;
int unlen;
- struct winentry *wep;
int chksum;
- int u2w_loaded;
- u_int16_t *u2w;
- int ul_loaded;
- u_int8_t *ul;
+ struct msdosfsmount *pmp;
{
- u_int8_t *cp;
- int i;
- u_int16_t code;
- u_int8_t c1, c2;
+ int len;
+ u_int16_t c1, c2;
+ u_char *np;
+ struct dirent dirbuf;
/*
- * First compare checksums
+ * We alread have winentry in mbnambuf
*/
- if (wep->weCnt&WIN_LAST)
- chksum = wep->weChksum;
- else if (chksum != wep->weChksum)
- chksum = -1;
- if (chksum == -1)
+ if (!mbnambuf_flush(&dirbuf) || !dirbuf.d_namlen)
return -1;
- /*
- * Offset of this entry
- */
- i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
- un += i;
- unlen -= i;
-
- /*
- * unlen being zero must not be treated as length missmatch. It is
- * possible if the entry is WIN_LAST and contains nothing but the
- * terminating 0.
- */
- if (unlen < 0)
- return -1;
- if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS)
- return -1;
+#ifdef MSDOSFS_DEBUG
+ printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen,
+ dirbuf.d_name,
+ dirbuf.d_namlen);
+#endif
/*
* 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;
- }
- code = (cp[1] << 8) | cp[0];
- if (code & 0xff80) {
- if (u2w_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
- c1 = ul_loaded && (code & 0x80) ?
- ul[code & 0x7f] : u2l[code];
- c2 = ul_loaded && (*un & 0x80) ?
- ul[*un & 0x7f] : u2l[*un];
- if (c1 != c2)
- return -1;
- cp += 2;
- un++;
- }
- for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
- if (--unlen < 0) {
- if (!*cp++ && !*cp)
- return chksum;
- return -1;
- }
- code = (cp[1] << 8) | cp[0];
- if (code & 0xff80) {
- if (u2w_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
- c1 = ul_loaded && (code & 0x80) ?
- ul[code & 0x7f] : u2l[code];
- c2 = ul_loaded && (*un & 0x80) ?
- ul[*un & 0x7f] : u2l[*un];
- if (c1 != c2)
- return -1;
- cp += 2;
- un++;
- }
- for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
- if (--unlen < 0) {
- if (!*cp++ && !*cp)
- return chksum;
- return -1;
- }
- code = (cp[1] << 8) | cp[0];
- if (code & 0xff80) {
- if (u2w_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
- c1 = ul_loaded && (code & 0x80) ?
- ul[code & 0x7f] : u2l[code];
- c2 = ul_loaded && (*un & 0x80) ?
- ul[*un & 0x7f] : u2l[*un];
+ len = dirbuf.d_namlen;
+ if (unlen != len)
+ return -2;
+
+ for (np = dirbuf.d_name; unlen > 0 && len > 0;) {
+ /*
+ * Should comparison be case insensitive?
+ */
+ c1 = unix2winchr((const u_char **)&np, (size_t *)&len, 0, pmp);
+ c2 = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
if (c1 != c2)
- return -1;
- cp += 2;
- un++;
+ return -2;
}
return chksum;
}
@@ -869,15 +815,13 @@ winChkName(un, unlen, wep, chksum, u2w_loaded, u2w, ul_loaded, ul)
* Returns the checksum or -1 if impossible
*/
int
-win2unixfn(wep, dp, chksum, table_loaded, u2w)
+win2unixfn(wep, chksum, pmp)
struct winentry *wep;
- struct dirent *dp;
int chksum;
- int table_loaded;
- u_int16_t *u2w;
+ struct msdosfsmount *pmp;
{
u_int8_t *cp;
- u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
+ u_int8_t *np, name[WIN_CHARS * 2 + 1];
u_int16_t code;
int i;
@@ -890,54 +834,32 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
*/
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;
-
- /*
* 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';
- dp->d_namlen -= sizeof(wep->wePart2)/2
- + sizeof(wep->wePart3)/2 + i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1);
return chksum;
case '/':
*np = '\0';
return -1;
default:
- if (code & 0xff80) {
- if (table_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*np++ = code;
break;
}
- /*
- * 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;
- }
cp += 2;
}
for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
@@ -945,30 +867,18 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
switch (code) {
case 0:
*np = '\0';
- dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1);
return chksum;
case '/':
*np = '\0';
return -1;
default:
- if (code & 0xff80) {
- if (table_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*np++ = code;
break;
}
- /*
- * 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;
- }
cp += 2;
}
for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
@@ -976,31 +886,22 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
switch (code) {
case 0:
*np = '\0';
- dp->d_namlen -= i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1);
return chksum;
case '/':
*np = '\0';
return -1;
default:
- if (code & 0xff80) {
- if (table_loaded)
- code = find_lcode(code, u2w);
- else if (code & 0xff00)
- code = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*np++ = code;
break;
}
- /*
- * See above
- */
- if (WIN_MAXLEN % WIN_CHARS >= (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
- && np > ep) {
- np[-1] = 0;
- return -1;
- }
cp += 2;
}
+ *np = '\0';
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1);
return chksum;
}
@@ -1023,11 +924,25 @@ winChksum(name)
* Determine the number of slots necessary for Win95 names
*/
int
-winSlotCnt(un, unlen)
+winSlotCnt(un, unlen, pmp)
const u_char *un;
int unlen;
+ struct msdosfsmount *pmp;
{
+ size_t wlen;
+ char wn[WIN_MAXLEN * 2 + 1], *wnp;
+
unlen = winLenFixup(un, unlen);
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ wlen = WIN_MAXLEN * 2;
+ wnp = wn;
+ msdosfs_iconv->conv(pmp->pm_u2w, (const char **)&un, (size_t *)&unlen, &wnp, &wlen);
+ if (unlen > 0)
+ return 0;
+ return howmany(WIN_MAXLEN - wlen/2, WIN_CHARS);
+ }
+
if (unlen > WIN_MAXLEN)
return 0;
return howmany(unlen, WIN_CHARS);
@@ -1046,3 +961,281 @@ winLenFixup(un, unlen)
break;
return unlen;
}
+
+/*
+ * Store an area with multi byte string instr, and reterns left
+ * byte of instr and moves pointer forward. The area's size is
+ * inlen or outlen.
+ */
+static int
+mbsadjpos(const char **instr, int inlen, int outlen, int weight, int flag, void *handle)
+{
+ char *outp, outstr[outlen * weight + 1];
+
+ if (flag & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ outp = outstr;
+ outlen *= weight;
+ msdosfs_iconv->conv(handle, instr, (size_t *)&inlen, &outp, (size_t *)&outlen);
+ return (inlen);
+ }
+
+ (*instr) += min(inlen, outlen);
+ return (inlen - min(inlen, outlen));
+}
+
+/*
+ * Convert DOS char to Local char
+ */
+static u_int16_t
+dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
+{
+ u_char c;
+ char *outp, outbuf[3];
+ u_int16_t wc;
+ size_t len, olen;
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ olen = len = 2;
+ outp = outbuf;
+
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
+ ilen, &outp, &olen, KICONV_LOWER);
+ else
+ msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr,
+ ilen, &outp, &olen);
+ len -= olen;
+
+ /*
+ * return '?' if failed to convert
+ */
+ if (len == 0) {
+ (*ilen)--;
+ (*instr)++;
+ return ('?');
+ }
+
+ wc = 0;
+ while(len--)
+ wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+ return (wc);
+ }
+
+ (*ilen)--;
+ c = *(*instr)++;
+ c = dos2unix[c];
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ c = u2l[c];
+ return ((u_int16_t)c);
+}
+
+/*
+ * Convert Local char to DOS char
+ */
+static u_int16_t
+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;
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ /*
+ * to hide an invisible character, using a unicode filter
+ */
+ ulen = 2;
+ len = *ilen;
+ up = unicode;
+ msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr,
+ ilen, &up, &ulen);
+
+ /*
+ * cannot be converted
+ */
+ if (ulen == 2) {
+ (*ilen)--;
+ (*instr)++;
+ return (0);
+ }
+
+ /*
+ * return magic number for ascii char
+ */
+ if ((len - *ilen) == 1) {
+ c = *(*instr -1);
+ if (! (c & 0x80)) {
+ c = unix2dos[c];
+ if (c <= 2)
+ return (c);
+ }
+ }
+
+ /*
+ * now convert using libiconv
+ */
+ *instr -= len - *ilen;
+ *ilen = (int)len;
+
+ olen = len = 2;
+ outp = outbuf;
+ msdosfs_iconv->convchr_case(pmp->pm_u2d, (const char **)instr,
+ ilen, &outp, &olen, KICONV_FROM_UPPER);
+ len -= olen;
+ wc = 0;
+ while(len--)
+ wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+ return (wc);
+ }
+
+ (*ilen)--;
+ c = *(*instr)++;
+ c = l2u[c];
+ c = unix2dos[c];
+ return ((u_int16_t)c);
+}
+
+/*
+ * Convert Windows char to Local char
+ */
+static u_int16_t
+win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
+{
+ u_char *inp, *outp, inbuf[3], outbuf[3];
+ size_t ilen, olen, len;
+
+ if (wc == 0)
+ return (0);
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ inbuf[0] = (u_char)(wc>>8);
+ inbuf[1] = (u_char)wc;
+ inbuf[2] = '\0';
+
+ ilen = olen = len = 2;
+ inp = inbuf;
+ outp = outbuf;
+ msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
+ (char **)&outp, &olen);
+ len -= olen;
+
+ /*
+ * return '?' if failed to convert
+ */
+ if (len == 0) {
+ wc = '?';
+ return (wc);
+ }
+
+ wc = 0;
+ while(len--)
+ wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+ return (wc);
+ }
+
+ if (wc & 0xff00)
+ wc = '?';
+
+ return (wc);
+}
+
+/*
+ * Convert Local char to Windows char
+ */
+static u_int16_t
+unix2winchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
+{
+ u_char *outp, outbuf[3];
+ u_int16_t wc;
+ size_t olen;
+
+ if (*ilen == 0)
+ return (0);
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ outp = outbuf;
+ olen = 2;
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ msdosfs_iconv->convchr_case(pmp->pm_u2w, (const char **)instr,
+ ilen, (char **)&outp, &olen,
+ KICONV_FROM_LOWER);
+ else
+ msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr,
+ ilen, (char **)&outp, &olen);
+
+ /*
+ * return '0' if end of filename
+ */
+ if (olen == 2)
+ return (0);
+
+ wc = (outbuf[0]<<8) | outbuf[1];
+
+ return (wc);
+ }
+
+ (*ilen)--;
+ wc = (*instr)[0];
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ wc = u2l[wc];
+ (*instr)++;
+ return (wc);
+}
+
+/*
+ * Make subent empty
+ */
+void
+mbnambuf_init(void)
+{
+ int i;
+
+ for (i = 0; i < WIN_MAXSUBENTRIES; i++) {
+ if (subent[i].p) {
+ free(subent[i].p, M_MSDOSFSMNT);
+ subent[i].p = NULL;
+ subent[i].n = 0;
+ }
+ }
+}
+
+/*
+ * Write a subent entry from a slot
+ */
+void
+mbnambuf_write(char *name, int id)
+{
+ if (subent[id].p) {
+ printf("mbnambuf_write(): %s -> %s\n", subent[id].p, name);
+ free(subent[id].p, M_MSDOSFSMNT);
+ }
+ subent[id].n = strlen(name);
+ subent[id].p = malloc(subent[id].n + 1, M_MSDOSFSMNT, M_WAITOK);
+ strcpy(subent[id].p, name);
+}
+
+/*
+ * Combine each subents to the *dp and initialize subent
+ */
+char *
+mbnambuf_flush(struct dirent *dp)
+{
+ int i;
+ char *name = dp->d_name;
+
+ *name = '\0';
+ dp->d_namlen = 0;
+ for (i = 0; i < WIN_MAXSUBENTRIES; i++) {
+ if (subent[i].p) {
+ if (dp->d_namlen + subent[i].n > sizeof(dp->d_name) - 1) {
+ mbnambuf_init();
+ return (NULL);
+ }
+ strcpy(name, subent[i].p);
+ dp->d_namlen += subent[i].n;
+ name += subent[i].n;
+ }
+ }
+ mbnambuf_init();
+ return (dp->d_name);
+}
OpenPOWER on IntegriCloud