Index: sys/msdosfs/direntry.h =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/direntry.h,v retrieving revision 1.14 diff -u -r1.14 direntry.h --- sys/msdosfs/direntry.h 1997/11/17 15:36:32 1.14 +++ sys/msdosfs/direntry.h 2002/10/14 07:59:04 @@ -122,14 +122,18 @@ void unix2dostime __P((struct timespec *tsp, u_int16_t *ddp, u_int16_t *dtp, u_int8_t *dhp)); void dos2unixtime __P((u_int dd, u_int dt, u_int dh, struct timespec *tsp)); -int dos2unixfn __P((u_char dn[11], u_char *un, int lower)); +int dos2unixfn __P((u_char dn[11], u_char *un, int lower, int d2u_loaded, + u_int8_t *d2u, int ul_loaded, u_int8_t *ul)); int unix2dosfn __P((const u_char *un, u_char dn[12], int unlen, - u_int gen)); + u_int gen, int u2d_loaded, u_int8_t *u2d, int lu_loaded, + u_int8_t *lu)); int unix2winfn __P((const u_char *un, int unlen, struct winentry *wep, - int cnt, int chksum)); + int cnt, int chksum, int table_loaded, u_int16_t *u2w)); int winChkName __P((const u_char *un, int unlen, struct winentry *wep, - int chksum)); -int win2unixfn __P((struct winentry *wep, struct dirent *dp, int chksum)); + int chksum, int u2w_loaded, u_int16_t *u2w, int ul_loaded, + u_int8_t *ul)); +int win2unixfn __P((struct winentry *wep, struct dirent *dp, int chksum, + int table_loaded, u_int16_t *u2w)); u_int8_t winChksum __P((u_int8_t *name)); int winSlotCnt __P((const u_char *un, int unlen)); #endif /* _KERNEL */ Index: sys/msdosfs/msdosfs_conv.c =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/msdosfs_conv.c,v retrieving revision 1.32 diff -u -r1.32 msdosfs_conv.c --- sys/msdosfs/msdosfs_conv.c 2002/01/08 20:44:13 1.32 +++ sys/msdosfs/msdosfs_conv.c 2002/10/14 07:59:05 @@ -1,4 +1,4 @@ -/* $NetBSD: msdosfs_conv.c,v 1.32 2002/01/08 20:44:13 jdolecek Exp $ */ +/* $NetBSD$ */ /*- * Copyright (C) 1995, 1997 Wolfgang Solfrank. @@ -86,11 +86,13 @@ * Variables used to remember parts of the last time conversion. Maybe we * can avoid a full conversion. */ -u_long lasttime; -u_long lastday; -u_short lastddate; -u_short lastdtime; +static u_long lasttime; +static u_long lastday; +static u_short lastddate; +static u_short lastdtime; +static inline u_int8_t find_lcode __P((u_int16_t code, u_int16_t *u2w)); + /* * Convert the unix version of time to dos's idea of time to be used in * file timestamps. The passed in unix time is assumed to be in GMT. @@ -340,6 +342,42 @@ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ }; +static u_char +l2u[256] = { + 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 */ + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 18-1f */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */ + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 28-2f */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */ + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 38-3f */ + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 40-47 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 48-4f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 50-57 */ + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 58-5f */ + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 60-67 */ + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 68-6f */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 70-77 */ + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 78-7f */ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */ + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */ + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */ + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */ + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */ + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */ + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */ + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* c0-c7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* c8-cf */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* d0-d7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* d8-df */ + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */ + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */ + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */ + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* f8-ff */ +}; + /* * DOS filenames are made of 2 parts, the name part and the extension part. * The name part is 8 characters long and the extension part is 3 @@ -353,12 +391,16 @@ * null. */ int -dos2unixfn(dn, un, lower) +dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul) u_char dn[11]; u_char *un; int lower; + int d2u_loaded; + u_int8_t *d2u; + int ul_loaded; + u_int8_t *ul; { - int i, j; + int i; int thislong = 1; u_char c; @@ -369,26 +411,27 @@ * directory slot. Another dos quirk. */ if (*dn == SLOT_E5) - c = dos2unix[0xe5]; + c = d2u_loaded ? d2u[0xe5 & 0x7f] : dos2unix[0xe5]; else - c = dos2unix[*dn]; - *un++ = lower ? u2l[c] : c; + c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] : + dos2unix[*dn]; + *un++ = lower ? (ul_loaded && (c & 0x80) ? + ul[c & 0x7f] : u2l[c]) : c; + dn++; /* - * Copy the rest into the unix filename string, ignoring - * trailing blanks. - */ - - for (j=7; (j >= 0) && (dn[j] == ' '); j--) - ; - - for (i = 1; i <= j; i++) { - c = dos2unix[dn[i]]; - *un++ = lower ? u2l[c] : c; + * 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 ? (ul_loaded && (c & 0x80) ? + ul[c & 0x7f] : u2l[c]) : c; thislong++; } - dn += 8; - + dn += 8 - i; + /* * Now, if there is an extension then put in a period and copy in * the extension. @@ -397,8 +440,11 @@ *un++ = '.'; thislong++; for (i = 0; i < 3 && *dn != ' '; i++) { - c = dos2unix[*dn++]; - *un++ = lower ? u2l[c] : c; + c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] : + dos2unix[*dn]; + dn++; + *un++ = lower ? (ul_loaded && (c & 0x80) ? + ul[c & 0x7f] : u2l[c]) : c; thislong++; } } @@ -419,17 +465,21 @@ * 3 if conversion was successful and generation number was inserted */ int -unix2dosfn(un, dn, unlen, gen) +unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu) 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; { int i, j, l; int conv = 1; const u_char *cp, *dp, *dp1; u_char gentext[6], *wcp; - int shortlen; + u_int8_t c; /* * Fill the dos filename string with blanks. These are DOS's pad @@ -493,7 +543,12 @@ else l = unlen - (dp - un); for (i = 0, j = 8; i < l && j < 11; i++, j++) { - if (dp[i] != (dn[j] = unix2dos[dp[i]]) + c = dp[i]; + c = lu_loaded && (c & 0x80) ? + lu[c & 0x7f] : l2u[c]; + c = u2d_loaded && (c & 0x80) ? + u2d[c & 0x7f] : unix2dos[c]; + if (dp[i] != (dn[j] = c) && conv != 3) conv = 2; if (!dn[j]) { @@ -509,17 +564,15 @@ dp++; } - shortlen = (dp - un) <= 8; - /* * Now convert the rest of the name */ for (i = j = 0; un < dp && j < 8; i++, j++, un++) { - if ((*un == ' ') && shortlen) - dn[j] = ' '; - else - dn[j] = unix2dos[*un]; - if ((*un != dn[j]) + c = lu_loaded && (*un & 0x80) ? + lu[*un & 0x7f] : l2u[*un]; + c = u2d_loaded && (c & 0x80) ? + u2d[c & 0x7f] : unix2dos[c]; + if (*un != (dn[j] = c) && conv != 3) conv = 2; if (!dn[j]) { @@ -576,16 +629,19 @@ * i.e. doesn't consist solely of blanks and dots */ int -unix2winfn(un, unlen, wep, cnt, chksum) +unix2winfn(un, unlen, wep, cnt, chksum, table_loaded, u2w) const u_char *un; int unlen; struct winentry *wep; int cnt; int chksum; + int table_loaded; + u_int16_t *u2w; { const u_int8_t *cp; u_int8_t *wcp; int i; + u_int16_t code; /* * Drop trailing blanks and dots @@ -611,20 +667,38 @@ for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { if (--unlen < 0) goto done; - *wcp++ = *un++; - *wcp++ = 0; + 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;) { if (--unlen < 0) goto done; - *wcp++ = *un++; - *wcp++ = 0; + 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;) { if (--unlen < 0) goto done; - *wcp++ = *un++; - *wcp++ = 0; + if (table_loaded && (*un & 0x80)) { + code = u2w[*un++ & 0x7f]; + *wcp++ = code; + *wcp++ = code >> 8; + } else { + *wcp++ = *un++; + *wcp++ = 0; + } } if (!unlen) wep->weCnt |= WIN_LAST; @@ -637,19 +711,38 @@ 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 '?'; +} + /* * Compare our filename to the one in the Win95 entry * Returns the checksum or -1 if no match */ int -winChkName(un, unlen, wep, chksum) +winChkName(un, unlen, wep, chksum, u2w_loaded, u2w, ul_loaded, ul) 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; { u_int8_t *cp; int i; + u_int16_t code; + u_int8_t c1, c2; /* * First compare checksums @@ -693,8 +786,21 @@ return chksum; return -1; } - if (u2l[*cp++] != u2l[*un++] || *cp++) + 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) { @@ -702,8 +808,21 @@ return chksum; return -1; } - if (u2l[*cp++] != u2l[*un++] || *cp++) + 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) { @@ -711,8 +830,21 @@ return chksum; return -1; } - if (u2l[*cp++] != u2l[*un++] || *cp++) + 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++; } return chksum; } @@ -722,13 +854,16 @@ * Returns the checksum or -1 if impossible */ int -win2unixfn(wep, dp, chksum) +win2unixfn(wep, dp, chksum, table_loaded, u2w) struct winentry *wep; struct dirent *dp; int chksum; + int table_loaded; + u_int16_t *u2w; { u_int8_t *cp; u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN; + u_int16_t code; int i; if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS) @@ -759,14 +894,25 @@ * Convert the name parts */ for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) { - switch (*np++ = *cp++) { + 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; return chksum; case '/': - np[-1] = 0; + *np = '\0'; return -1; + default: + if (code & 0xff80) { + if (table_loaded) + code = find_lcode(code, u2w); + else if (code & 0xff00) + code = '?'; + } + *np++ = code; + break; } /* * The size comparison should result in the compiler @@ -777,17 +923,27 @@ np[-1] = 0; return -1; } - if (*cp++) - return -1; + cp += 2; } for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) { - switch (*np++ = *cp++) { + code = (cp[1] << 8) | cp[0]; + switch (code) { case 0: + *np = '\0'; dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1; return chksum; case '/': - np[-1] = 0; + *np = '\0'; return -1; + default: + if (code & 0xff80) { + if (table_loaded) + code = find_lcode(code, u2w); + else if (code & 0xff00) + code = '?'; + } + *np++ = code; + break; } /* * The size comparisons should be optimized away @@ -798,17 +954,27 @@ np[-1] = 0; return -1; } - if (*cp++) - return -1; + cp += 2; } for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) { - switch (*np++ = *cp++) { + code = (cp[1] << 8) | cp[0]; + switch (code) { case 0: + *np = '\0'; dp->d_namlen -= i + 1; return chksum; case '/': - np[-1] = 0; + *np = '\0'; return -1; + default: + if (code & 0xff80) { + if (table_loaded) + code = find_lcode(code, u2w); + else if (code & 0xff00) + code = '?'; + } + *np++ = code; + break; } /* * See above @@ -818,8 +984,7 @@ np[-1] = 0; return -1; } - if (*cp++) - return -1; + cp += 2; } return chksum; } Index: sys/msdosfs/msdosfs_lookup.c =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/msdosfs_lookup.c,v retrieving revision 1.52 diff -u -r1.52 msdosfs_lookup.c --- sys/msdosfs/msdosfs_lookup.c 2001/11/10 13:26:45 1.52 +++ sys/msdosfs/msdosfs_lookup.c 2002/10/14 07:59:05 @@ -173,7 +173,9 @@ } switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename, - cnp->cn_namelen, 0)) { + cnp->cn_namelen, 0, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d, + pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu)) { case 0: return (EINVAL); case 1: @@ -275,7 +277,11 @@ chksum = winChkName((const u_char *)cnp->cn_nameptr, cnp->cn_namelen, (struct winentry *)dep, - chksum); + chksum, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, + pmp->pm_u2w, + pmp->pm_flags & MSDOSFSMNT_ULTABLE, + pmp->pm_ul); continue; } @@ -697,7 +703,9 @@ fndoffset -= sizeof(struct direntry); } if (!unix2winfn(un, unlen, (struct winentry *)ndep, - wcnt, chksum)) + wcnt, chksum, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, + pmp->pm_u2w)) break; } } @@ -1097,7 +1105,9 @@ * Generate DOS name with generation number */ if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp, - cnp->cn_namelen, gen)) + cnp->cn_namelen, gen, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d, + pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu)) return gen == 1 ? EINVAL : EEXIST; /* Index: sys/msdosfs/msdosfs_vfsops.c =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/msdosfs_vfsops.c,v retrieving revision 1.84 diff -u -r1.84 msdosfs_vfsops.c --- sys/msdosfs/msdosfs_vfsops.c 2002/09/21 18:13:25 1.84 +++ sys/msdosfs/msdosfs_vfsops.c 2002/10/14 07:59:05 @@ -144,6 +144,15 @@ pmp->pm_uid = argp->uid; pmp->pm_mask = argp->mask & ALLPERMS; pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; + if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) { + memcpy(pmp->pm_u2w, argp->u2w, sizeof(pmp->pm_u2w)); + memcpy(pmp->pm_d2u, argp->d2u, sizeof(pmp->pm_d2u)); + memcpy(pmp->pm_u2d, argp->u2d, sizeof(pmp->pm_u2d)); + } + if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) { + memcpy(pmp->pm_ul, argp->ul, sizeof(pmp->pm_ul)); + memcpy(pmp->pm_lu, argp->lu, sizeof(pmp->pm_lu)); + } /* * GEMDOS knows nothing (yet) about win95 Index: sys/msdosfs/msdosfs_vnops.c =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/msdosfs_vnops.c,v retrieving revision 1.122 diff -u -r1.122 msdosfs_vnops.c --- sys/msdosfs/msdosfs_vnops.c 2002/09/27 15:37:49 1.122 +++ sys/msdosfs/msdosfs_vnops.c 2002/10/14 07:59:06 @@ -1557,7 +1557,10 @@ if (dentp->deAttributes == ATTR_WIN95) { if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) continue; - chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum); + chksum = win2unixfn((struct winentry *)dentp, + &dirbuf, chksum, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, + pmp->pm_u2w); continue; } @@ -1596,7 +1599,11 @@ if (chksum != winChksum(dentp->deName)) dirbuf.d_namlen = dos2unixfn(dentp->deName, (u_char *)dirbuf.d_name, - pmp->pm_flags & MSDOSFSMNT_SHORTNAME); + pmp->pm_flags & MSDOSFSMNT_SHORTNAME, + pmp->pm_flags & MSDOSFSMNT_U2WTABLE, + pmp->pm_d2u, + pmp->pm_flags & MSDOSFSMNT_ULTABLE, + pmp->pm_ul); else dirbuf.d_name[dirbuf.d_namlen] = 0; chksum = -1; Index: sys/msdosfs/msdosfsmount.h =================================================================== RCS file: /cvsroot/syssrc/sys/msdosfs/msdosfsmount.h,v retrieving revision 1.23 diff -u -r1.23 msdosfsmount.h --- sys/msdosfs/msdosfsmount.h 2002/09/21 18:13:26 1.23 +++ sys/msdosfs/msdosfsmount.h 2002/10/14 07:59:06 @@ -57,6 +57,11 @@ gid_t gid; /* gid that owns msdosfs files */ mode_t mask; /* mask to be applied for msdosfs perms */ int flags; /* see below */ + u_int16_t u2w[128]; /* Local->Unicode table */ + u_int8_t ul[128]; /* Local upper->lower table */ + u_int8_t lu[128]; /* Local lower->upper table */ + u_int8_t d2u[128]; /* DOS->local table */ + u_int8_t u2d[128]; /* Local->DOS table */ }; /* @@ -66,11 +71,14 @@ #define MSDOSFSMNT_LONGNAME 2 /* Force Win'95 long names */ #define MSDOSFSMNT_NOWIN95 4 /* Completely ignore Win95 entries */ #define MSDOSFSMNT_GEMDOSFS 8 /* This is a gemdos-flavour */ +#define MSDOSFSMNT_U2WTABLE 0x10 /* Local->Unicode and local<->DOS */ + /* tables loaded */ +#define MSDOSFSMNT_ULTABLE 0x20 /* Local upper<->lower table loaded */ /* All flags above: */ #define MSDOSFSMNT_MNTOPT \ (MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \ - |MSDOSFSMNT_GEMDOSFS) + |MSDOSFSMNT_GEMDOSFS|MSDOSFSMNT_U2WTABLE|MSDOSFSMNT_ULTABLE) #define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */ #define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */ #define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */ @@ -116,6 +124,11 @@ u_int *pm_inusemap; /* ptr to bitmap of in-use clusters */ u_int pm_flags; /* see below */ struct netexport pm_export; /* export information */ + u_int16_t pm_u2w[128]; /* Local->Unicode table */ + u_int8_t pm_ul[128]; /* Local upper->lower table */ + u_int8_t pm_lu[128]; /* Local lower->upper table */ + u_int8_t pm_d2u[128]; /* DOS->local table */ + u_int8_t pm_u2d[128]; /* Local->DOS table */ }; /* Byte offset in FAT on filesystem pmp, cluster cn */ #define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv) Index: sbin/mount_msdos/mount_msdos.8 =================================================================== RCS file: /cvsroot/basesrc/sbin/mount_msdos/mount_msdos.8,v retrieving revision 1.23 diff -u -r1.23 mount_msdos.8 --- sbin/mount_msdos/mount_msdos.8 2002/10/01 13:40:40 1.23 +++ sbin/mount_msdos/mount_msdos.8 2002/10/14 09:35:15 @@ -32,7 +32,7 @@ .\" .\" <> .\" -.Dd April 7, 1994 +.Dd October 14, 2002 .Dt MOUNT_MSDOS 8 .Os .Sh NAME @@ -48,6 +48,8 @@ .Op Fl l .Op Fl 9 .Op Fl G +.Op Fl L Ar locale +.Op Fl W Ar table .Pa special .Pa node .Sh DESCRIPTION @@ -135,6 +137,45 @@ limited to the boot block. This option enforces .Fl s . +.It Fl L Ar locale +Specify locale name used for internal uppercase and lowercase conversions +for DOS and Win'95 names. +By default ISO 8859-1 assumed as local character set. +.It Fl W Ar table +Specify text file with 3 conversion tables: +.Bl -enum +.It +Local character set to Unicode conversion table (upper half) for Win'95 long +names, 128 Unicode codes separated by 8 per row. +If some code not present in Unicode, use +0x003F code ('?') as replacement. +.It +DOS to local character set conversion table (upper half) for DOS names, +128 character codes separated by 8 per row. +Code 0x3F ('?') used for impossible translations. +.It +Local character set to DOS conversion table (upper half) for DOS names, +128 character codes separated by 8 per row. +Some codes have special meaning: +.Bl -hang +.It 0x00 +character disallowed in DOS file name; +.It 0x01 +character should be replaced by '_' in DOS file name; +.It 0x02 +character should be skipped in DOS file name; +.El +.El +.Pp +By default ISO 8859-1 assumed as local character set. +If file path isn't absolute, +.Pa /usr/libdata/msdosfs/ +prefix prepended. +.El +.Sh FILES +.Bl -tag -width /usr/libdata/msdosfs -compact +.It Pa /usr/libdata/msdosfs +default place for character sets conversion tables .El .Sh SEE ALSO .Xr mount 2 , Index: sbin/mount_msdos/mount_msdos.c =================================================================== RCS file: /cvsroot/basesrc/sbin/mount_msdos/mount_msdos.c,v retrieving revision 1.25 diff -u -r1.25 mount_msdos.c --- sbin/mount_msdos/mount_msdos.c 2002/09/21 18:43:35 1.25 +++ sbin/mount_msdos/mount_msdos.c 2002/10/14 09:35:16 @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,8 @@ int main __P((int, char *[])); int mount_msdos __P((int argc, char **argv)); static void usage __P((void)); +static void load_u2wtable __P((struct msdosfs_args *, char *)); +static void load_ultable __P((struct msdosfs_args *, char *)); #ifndef MOUNT_NOMAIN int @@ -92,7 +95,7 @@ mntflags = set_gid = set_uid = set_mask = 0; (void)memset(&args, '\0', sizeof(args)); - while ((c = getopt(argc, argv, "Gsl9u:g:m:o:")) != -1) { + while ((c = getopt(argc, argv, "Gsl9u:g:m:o:L:W:")) != -1) { switch (c) { case 'G': args.flags |= MSDOSFSMNT_GEMDOSFS; @@ -118,6 +121,14 @@ args.mask = a_mask(optarg); set_mask = 1; break; + case 'L': + load_ultable(&args, optarg); + args.flags |= MSDOSFSMNT_ULTABLE; + break; + case 'W': + load_u2wtable(&args, optarg); + args.flags |= MSDOSFSMNT_U2WTABLE; + break; case 'o': getmntopts(optarg, mopts, &mntflags, 0); break; @@ -178,6 +189,89 @@ usage() { - fprintf(stderr, "usage: mount_msdos [-o options] [-u user] [-g group] [-m mask] bdev dir\n"); + fprintf(stderr, "usage: mount_msdos [-o options] [-u user] [-g group] " + "[-m mask] [-s] [-l] [-9] [-G] [-L locale] [-W table] bdev dir\n"); exit(1); +} + +void +load_u2wtable (pargs, name) + struct msdosfs_args *pargs; + char *name; +{ + FILE *f; + int i, j, code[8]; + size_t line = 0; + char buf[MAXPATHLEN+1]; + char *fn, *s, *p; + + if (*name == '/') + fn = name; + else { + snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name); + buf[MAXPATHLEN+1] = '\0'; + fn = buf; + } + if ((f = fopen(fn, "r")) == NULL) + err(EXIT_FAILURE, "%s", fn); + p = NULL; + for (i = 0; i < 16; i++) { + do { + if (p != NULL) free(p); + if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) + errx(EXIT_FAILURE, "can't read u2w table row %d near line %d", i, line); + while (isspace((unsigned char)*s)) + s++; + } while (*s == '\0'); + if (sscanf(s, "%i%i%i%i%i%i%i%i", +code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) + errx(EXIT_FAILURE, "u2w table: missing item(s) in row %d, line %d", i, line); + for (j = 0; j < 8; j++) + pargs->u2w[i * 8 + j] = code[j]; + } + for (i = 0; i < 16; i++) { + do { + free(p); + if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) + errx(EXIT_FAILURE, "can't read d2u table row %d near line %d", i, line); + while (isspace((unsigned char)*s)) + s++; + } while (*s == '\0'); + if (sscanf(s, "%i%i%i%i%i%i%i%i", +code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) + errx(EXIT_FAILURE, "d2u table: missing item(s) in row %d, line %d", i, line); + for (j = 0; j < 8; j++) + pargs->d2u[i * 8 + j] = code[j]; + } + for (i = 0; i < 16; i++) { + do { + free(p); + if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL) + errx(EXIT_FAILURE, "can't read u2d table row %d near line %d", i, line); + while (isspace((unsigned char)*s)) + s++; + } while (*s == '\0'); + if (sscanf(s, "%i%i%i%i%i%i%i%i", +code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8) + errx(EXIT_FAILURE, "u2d table: missing item(s) in row %d, line %d", i, line); + for (j = 0; j < 8; j++) + pargs->u2d[i * 8 + j] = code[j]; + } + free(p); + fclose(f); +} + +void +load_ultable (pargs, name) + struct msdosfs_args *pargs; + char *name; +{ + int i; + + if (setlocale(LC_CTYPE, name) == NULL) + errx(EXIT_FAILURE, "%s: Unsupported locale", name); + for (i = 0; i < 128; i++) { + pargs->ul[i] = tolower(i | 0x80); + pargs->lu[i] = toupper(i | 0x80); + } }