diff options
author | kevlo <kevlo@FreeBSD.org> | 2011-11-18 03:05:20 +0000 |
---|---|---|
committer | kevlo <kevlo@FreeBSD.org> | 2011-11-18 03:05:20 +0000 |
commit | 1a26b28a9b13239c0dcae74ac1f94a5969fd2b3c (patch) | |
tree | 91e05f3019c9e61d84d991446d61ad595184fef3 /sys/fs | |
parent | 3985e4e2af3096b00750b1a32f61f92d109f9372 (diff) | |
download | FreeBSD-src-1a26b28a9b13239c0dcae74ac1f94a5969fd2b3c.zip FreeBSD-src-1a26b28a9b13239c0dcae74ac1f94a5969fd2b3c.tar.gz |
Add unicode support to msdosfs and smbfs; original pathes from imura,
bug fixes by Kuan-Chung Chiu <buganini at gmail dot com>.
Tested by me in production for several days at work.
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/msdosfs/msdosfs_conv.c | 112 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_smb.c | 44 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_subr.c | 28 |
3 files changed, 109 insertions, 75 deletions
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c index 8dc1d07..fde6512 100644 --- a/sys/fs/msdosfs/msdosfs_conv.c +++ b/sys/fs/msdosfs/msdosfs_conv.c @@ -61,9 +61,9 @@ extern struct iconv_functions *msdosfs_iconv; static int mbsadjpos(const char **, size_t, size_t, int, int, void *handle); -static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *); +static u_char * 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_char * win2unixchr(u_int16_t, struct msdosfsmount *); static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *); /* @@ -242,7 +242,7 @@ dos2unixfn(dn, un, lower, pmp) { size_t i; int thislong = 0; - u_int16_t c; + u_char *c; /* * If first char of the filename is SLOT_E5 (0x05), then the real @@ -259,12 +259,10 @@ dos2unixfn(dn, un, lower, pmp) for (i = 8; i > 0 && *dn != ' ';) { c = dos2unixchr((const u_char **)&dn, &i, lower & LCASE_BASE, pmp); - if (c & 0xff00) { - *un++ = c >> 8; + while (*c != '\0') { + *un++ = *c++; thislong++; } - *un++ = c; - thislong++; } dn += i; @@ -278,12 +276,10 @@ dos2unixfn(dn, un, lower, pmp) for (i = 3; i > 0 && *dn != ' ';) { c = dos2unixchr((const u_char **)&dn, &i, lower & LCASE_EXT, pmp); - if (c & 0xff00) { - *un++ = c >> 8; + while (*c != '\0') { + *un++ = *c++; thislong++; } - *un++ = c; - thislong++; } } *un++ = 0; @@ -652,8 +648,9 @@ win2unixfn(nbp, wep, chksum, pmp) int chksum; struct msdosfsmount *pmp; { + u_char *c; u_int8_t *cp; - u_int8_t *np, name[WIN_CHARS * 2 + 1]; + u_int8_t *np, name[WIN_CHARS * 3 + 1]; u_int16_t code; int i; @@ -686,10 +683,9 @@ win2unixfn(nbp, wep, chksum, pmp) *np = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + c = win2unixchr(code, pmp); + while (*c != '\0') + *np++ = *c++; break; } cp += 2; @@ -705,10 +701,9 @@ win2unixfn(nbp, wep, chksum, pmp) *np = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + c = win2unixchr(code, pmp); + while (*c != '\0') + *np++ = *c++; break; } cp += 2; @@ -724,10 +719,9 @@ win2unixfn(nbp, wep, chksum, pmp) *np = '\0'; return -1; default: - code = win2unixchr(code, pmp); - if (code & 0xff00) - *np++ = code >> 8; - *np++ = code; + c = win2unixchr(code, pmp); + while (*c != '\0') + *np++ = *c++; break; } cp += 2; @@ -817,24 +811,22 @@ mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag, /* * Convert DOS char to Local char */ -static u_int16_t +static u_char * dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp) { - u_char c; - char *outp, outbuf[3]; - u_int16_t wc; + u_char c, *outp, outbuf[5]; size_t len, olen; + outp = outbuf; if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) { - olen = len = 2; - outp = outbuf; + olen = len = 4; if (lower & (LCASE_BASE | LCASE_EXT)) msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr, - ilen, &outp, &olen, KICONV_LOWER); + ilen, (char **)&outp, &olen, KICONV_LOWER); else msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr, - ilen, &outp, &olen); + ilen, (char **)&outp, &olen); len -= olen; /* @@ -843,21 +835,21 @@ dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount * if (len == 0) { (*ilen)--; (*instr)++; - return ('?'); + *outp++ = '?'; } - - wc = 0; - while(len--) - wc |= (*(outp - len - 1) & 0xff) << (len << 3); - return (wc); + } else { + (*ilen)--; + c = *(*instr)++; + c = dos2unix[c]; + if (lower & (LCASE_BASE | LCASE_EXT)) + c = u2l[c]; + *outp++ = c; + outbuf[1] = '\0'; } - (*ilen)--; - c = *(*instr)++; - c = dos2unix[c]; - if (lower & (LCASE_BASE | LCASE_EXT)) - c = u2l[c]; - return ((u_int16_t)c); + *outp = '\0'; + outp = outbuf; + return (outp); } /* @@ -940,23 +932,21 @@ unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp) /* * Convert Windows char to Local char */ -static u_int16_t +static u_char * win2unixchr(u_int16_t wc, struct msdosfsmount *pmp) { - u_char *inp, *outp, inbuf[3], outbuf[3]; + u_char *inp, *outp, inbuf[3], outbuf[5]; size_t ilen, olen, len; - if (wc == 0) - return (0); - + outp = outbuf; 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; + ilen = 2; + olen = len = 4; inp = inbuf; - outp = outbuf; msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen, (char **)&outp, &olen); len -= olen; @@ -964,21 +954,15 @@ win2unixchr(u_int16_t wc, struct msdosfsmount *pmp) /* * 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 (len == 0) + *outp++ = '?'; + } else { + *outp++ = (wc & 0xff00) ? '?' : (u_char)(wc & 0xff); } - if (wc & 0xff00) - wc = '?'; - - return (wc); + *outp = '\0'; + outp = outbuf; + return (outp); } /* diff --git a/sys/fs/smbfs/smbfs_smb.c b/sys/fs/smbfs/smbfs_smb.c index bebc8ee..05162d5 100644 --- a/sys/fs/smbfs/smbfs_smb.c +++ b/sys/fs/smbfs/smbfs_smb.c @@ -34,6 +34,7 @@ #include <sys/vnode.h> #include <sys/mbuf.h> #include <sys/mount.h> +#include <sys/endian.h> #ifdef USE_MD5_HASH #include <sys/md5.h> @@ -393,6 +394,10 @@ smbfs_smb_setpattr(struct smbnode *np, u_int16_t attr, struct timespec *mtime, if (error) break; mb_put_uint8(mbp, SMB_DT_ASCII); + if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { + mb_put_padbyte(mbp); + mb_put_uint8(mbp, 0); /* 1st byte of NULL Unicode char */ + } mb_put_uint8(mbp, 0); smb_rq_bend(rqp); error = smb_rq_simple(rqp); @@ -909,6 +914,10 @@ smbfs_smb_search(struct smbfs_fctx *ctx) mb_put_uint16le(mbp, 0); /* context length */ ctx->f_flags &= ~SMBFS_RDD_FINDFIRST; } else { + if (SMB_UNICODE_STRINGS(vcp)) { + mb_put_padbyte(mbp); + mb_put_uint8(mbp, 0); + } mb_put_uint8(mbp, 0); /* file name length */ mb_put_uint8(mbp, SMB_DT_VARIABLE); mb_put_uint16le(mbp, SMB_SKEYLEN); @@ -1069,7 +1078,7 @@ smbfs_smb_trans2find2(struct smbfs_fctx *ctx) mb_put_uint32le(mbp, 0); /* resume key */ mb_put_uint16le(mbp, flags); if (ctx->f_rname) - mb_put_mem(mbp, ctx->f_rname, strlen(ctx->f_rname) + 1, MB_MSYSTEM); + mb_put_mem(mbp, ctx->f_rname, ctx->f_rnamelen + 1, MB_MSYSTEM); else mb_put_uint8(mbp, 0); /* resume file name */ #if 0 @@ -1152,7 +1161,10 @@ static int smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp, const char *wildcard, int wclen, int attr, struct smb_cred *scred) { - ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + ctx->f_name = malloc(SMB_MAXFNAMELEN * 2, M_SMBFSDATA, M_WAITOK); + } else + ctx->f_name = malloc(SMB_MAXFNAMELEN, M_SMBFSDATA, M_WAITOK); if (ctx->f_name == NULL) return ENOMEM; ctx->f_infolevel = SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_NTLM0_12 ? @@ -1231,7 +1243,10 @@ smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) SMBERROR("unexpected info level %d\n", ctx->f_infolevel); return EINVAL; } - nmlen = min(size, SMB_MAXFNAMELEN); + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + nmlen = min(size, SMB_MAXFNAMELEN * 2); + } else + nmlen = min(size, SMB_MAXFNAMELEN); cp = ctx->f_name; error = md_get_mem(mbp, cp, nmlen, MB_MSYSTEM); if (error) @@ -1245,8 +1260,12 @@ smbfs_findnextLM2(struct smbfs_fctx *ctx, int limit) return EBADRPC; } } - if (nmlen && cp[nmlen - 1] == 0) - nmlen--; + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + if (nmlen > 1 && cp[nmlen - 1] == 0 && cp[nmlen - 2] == 0) + nmlen -= 2; + } else + if (nmlen && cp[nmlen - 1] == 0) + nmlen--; if (nmlen == 0) return EBADRPC; @@ -1330,10 +1349,17 @@ smbfs_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scred) error = smbfs_findnextLM2(ctx, limit); if (error) return error; - if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || - (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && - ctx->f_name[1] == '.')) - continue; + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) { + if ((ctx->f_nmlen == 2 && + *(u_int16_t *)ctx->f_name == htole16(0x002e)) || + (ctx->f_nmlen == 4 && + *(u_int32_t *)ctx->f_name == htole32(0x002e002e))) + continue; + } else + if ((ctx->f_nmlen == 1 && ctx->f_name[0] == '.') || + (ctx->f_nmlen == 2 && ctx->f_name[0] == '.' && + ctx->f_name[1] == '.')) + continue; break; } smbfs_fname_tolocal(SSTOVC(ctx->f_ssp), ctx->f_name, &ctx->f_nmlen, diff --git a/sys/fs/smbfs/smbfs_subr.c b/sys/fs/smbfs/smbfs_subr.c index b775dff..51ee4d5 100644 --- a/sys/fs/smbfs/smbfs_subr.c +++ b/sys/fs/smbfs/smbfs_subr.c @@ -130,7 +130,10 @@ smb_fphelp(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *np, return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/ while (i--) { np = *--npp; - error = mb_put_uint8(mbp, '\\'); + if (SMB_UNICODE_STRINGS(vcp)) + error = mb_put_uint16le(mbp, '\\'); + else + error = mb_put_uint8(mbp, '\\'); if (error) break; error = smb_put_dmem(mbp, vcp, np->n_name, np->n_nmlen, caseopt); @@ -148,6 +151,11 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, int caseopt = SMB_CS_NONE; int error; + if (SMB_UNICODE_STRINGS(vcp)) { + error = mb_put_padbyte(mbp); + if (error) + return error; + } if (SMB_DIALECT(vcp) < SMB_DIALECT_LANMAN1_0) caseopt |= SMB_CS_UPPER; if (dnp != NULL) { @@ -156,7 +164,10 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, return error; } if (name) { - error = mb_put_uint8(mbp, '\\'); + if (SMB_UNICODE_STRINGS(vcp)) + error = mb_put_uint16le(mbp, '\\'); + else + error = mb_put_uint8(mbp, '\\'); if (error) return error; error = smb_put_dmem(mbp, vcp, name, nmlen, caseopt); @@ -164,6 +175,8 @@ smbfs_fullpath(struct mbchain *mbp, struct smb_vc *vcp, struct smbnode *dnp, return error; } error = mb_put_uint8(mbp, 0); + if (SMB_UNICODE_STRINGS(vcp) && error == 0) + error = mb_put_uint8(mbp, 0); return error; } @@ -191,6 +204,17 @@ smbfs_fname_tolocal(struct smb_vc *vcp, char *name, int *nmlen, int caseopt) error = iconv_conv_case (vcp->vc_tolocal, (const char **)&ibuf, &ilen, &obuf, &olen, copt); + if (error && SMB_UNICODE_STRINGS(vcp)) { + /* + * If using unicode, leaving a file name as it was when + * convert fails will cause a problem because the file name + * will contain NULL. + * Here, put '?' and give converted file name. + */ + *obuf = '?'; + olen--; + error = 0; + } if (!error) { *nmlen = sizeof(outbuf) - olen; memcpy(name, outbuf, *nmlen); |