From 6db47c417f059fe2aab8c0c520b39b1cfa2f0bee Mon Sep 17 00:00:00 2001 From: kevlo Date: Fri, 18 Nov 2011 03:05:20 +0000 Subject: [PATCH 167/175] Add unicode support to msdosfs and smbfs; original pathes from imura, bug fixes by Kuan-Chung Chiu . Tested by me in production for several days at work. git-svn-id: http://svn.freebsd.org/base/head@227650 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f (cherry picked from commit ba1b02ac0f0feb6e38dda749d21a48708d15c02b) Signed-off-by: Xin Li --- lib/libkiconv/xlat16_iconv.c | 12 + sys/conf/files | 1 + sys/fs/msdosfs/msdosfs_conv.c | 112 ++++----- sys/fs/smbfs/smbfs_smb.c | 44 +++- sys/fs/smbfs/smbfs_subr.c | 28 ++- sys/kern/subr_mchain.c | 15 ++ sys/libkern/iconv.c | 12 + sys/libkern/iconv_ucs.c | 540 ++++++++++++++++++++++++++++++++++++++++ sys/modules/libiconv/Makefile | 5 +- sys/modules/libmchain/Makefile | 1 + sys/netsmb/smb_conn.c | 32 ++- sys/netsmb/smb_conn.h | 6 + sys/netsmb/smb_smb.c | 64 +++-- sys/netsmb/smb_subr.c | 4 + sys/sys/iconv.h | 3 +- sys/sys/mchain.h | 1 + 16 files changed, 780 insertions(+), 100 deletions(-) create mode 100644 sys/libkern/iconv_ucs.c diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c index ce06324..dc9dc86 100644 --- a/lib/libkiconv/xlat16_iconv.c +++ b/lib/libkiconv/xlat16_iconv.c @@ -74,6 +74,18 @@ kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag) struct xlat16_table xt; void *data; char *p; + const char unicode[] = ENCODING_UNICODE; + + if ((flag & KICONV_WCTYPE) == 0 && + strcmp(unicode, tocode) != 0 && + strcmp(unicode, fromcode) != 0 && + kiconv_lookupconv(unicode) == 0) { + error = kiconv_add_xlat16_cspair(unicode, fromcode, flag); + if (error) + return (-1); + error = kiconv_add_xlat16_cspair(tocode, unicode, flag); + return (error); + } if (kiconv_lookupcs(tocode, fromcode) == 0) return (0); diff --git a/sys/conf/files b/sys/conf/files index 1f2bd0b..0528139 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -2526,6 +2526,7 @@ libkern/fnmatch.c standard libkern/gets.c standard libkern/iconv.c optional libiconv libkern/iconv_converter_if.m optional libiconv +libkern/iconv_ucs.c optional libiconv libkern/iconv_xlat.c optional libiconv libkern/iconv_xlat16.c optional libiconv libkern/index.c standard 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 #include #include +#include #ifdef USE_MD5_HASH #include @@ -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); diff --git a/sys/kern/subr_mchain.c b/sys/kern/subr_mchain.c index e40e5ff..3fd265b 100644 --- a/sys/kern/subr_mchain.c +++ b/sys/kern/subr_mchain.c @@ -128,6 +128,21 @@ mb_reserve(struct mbchain *mbp, int size) } int +mb_put_padbyte(struct mbchain *mbp) +{ + caddr_t dst; + char x = 0; + + dst = mtod(mbp->mb_cur, caddr_t) + mbp->mb_cur->m_len; + + /* only add padding if address is odd */ + if ((unsigned long)dst & 1) + return mb_put_mem(mbp, (caddr_t)&x, 1, MB_MSYSTEM); + else + return 0; +} + +int mb_put_uint8(struct mbchain *mbp, uint8_t x) { return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM); diff --git a/sys/libkern/iconv.c b/sys/libkern/iconv.c index 7700937..52e5c73 100644 --- a/sys/libkern/iconv.c +++ b/sys/libkern/iconv.c @@ -377,6 +377,18 @@ iconv_sysctl_cslist(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern_iconv, OID_AUTO, cslist, CTLFLAG_RD | CTLTYPE_OPAQUE, NULL, 0, iconv_sysctl_cslist, "S,xlat", "registered charset pairs"); +int +iconv_add(const char *converter, const char *to, const char *from) +{ + struct iconv_converter_class *dcp; + struct iconv_cspair *csp; + + if (iconv_lookupconv(converter, &dcp) != 0) + return EINVAL; + + return iconv_register_cspair(to, from, dcp, NULL, &csp); +} + /* * Add new charset pair */ diff --git a/sys/libkern/iconv_ucs.c b/sys/libkern/iconv_ucs.c new file mode 100644 index 0000000..c6f2823 --- /dev/null +++ b/sys/libkern/iconv_ucs.c @@ -0,0 +1,540 @@ +/*- + * Copyright (c) 2003, 2005 Ryuichiro Imura + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include "iconv_converter_if.h" + +/* + * "UCS" converter + */ + +#define KICONV_UCS_COMBINE 0x1 +#define KICONV_UCS_FROM_UTF8 0x2 +#define KICONV_UCS_TO_UTF8 0x4 +#define KICONV_UCS_FROM_LE 0x8 +#define KICONV_UCS_TO_LE 0x10 +#define KICONV_UCS_FROM_UTF16 0x20 +#define KICONV_UCS_TO_UTF16 0x40 +#define KICONV_UCS_UCS4 0x80 + +#define ENCODING_UTF16 "UTF-16BE" +#define ENCODING_UTF8 "UTF-8" + +static struct { + const char *name; + int from_flag, to_flag; +} unicode_family[] = { + { "UTF-8", KICONV_UCS_FROM_UTF8, KICONV_UCS_TO_UTF8 }, + { "UCS-2LE", KICONV_UCS_FROM_LE, KICONV_UCS_TO_LE }, + { "UTF-16BE", KICONV_UCS_FROM_UTF16, KICONV_UCS_TO_UTF16 }, + { "UTF-16LE", KICONV_UCS_FROM_UTF16|KICONV_UCS_FROM_LE, + KICONV_UCS_TO_UTF16|KICONV_UCS_TO_LE }, + { NULL, 0, 0 } +}; + +static uint32_t utf8_to_ucs4(const char *src, size_t *utf8width, size_t srclen); +static u_char *ucs4_to_utf8(uint32_t ucs4, char * dst, size_t *utf8width, size_t dstlen); +static uint32_t encode_surrogate(uint32_t code); +static uint32_t decode_surrogate(const u_char *ucs); + +#ifdef MODULE_DEPEND +MODULE_DEPEND(iconv_ucs, libiconv, 2, 2, 2); +#endif + +/* + * UCS converter instance + */ +struct iconv_ucs { + KOBJ_FIELDS; + int convtype; + struct iconv_cspair * d_csp; + struct iconv_cspair * d_cspf; + void * f_ctp; + void * t_ctp; + void * ctype; +}; + +static int +iconv_ucs_open(struct iconv_converter_class *dcp, + struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp) +{ + struct iconv_ucs *dp; + int i; + const char *from, *to; + + dp = (struct iconv_ucs *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK); + to = csp->cp_to; + from = cspf ? cspf->cp_from : csp->cp_from; + + dp->convtype = 0; + + if (cspf) + dp->convtype |= KICONV_UCS_COMBINE; + for (i = 0; unicode_family[i].name; i++) { + if (strcmp(from, unicode_family[i].name) == 0) + dp->convtype |= unicode_family[i].from_flag; + if (strcmp(to, unicode_family[i].name) == 0) + dp->convtype |= unicode_family[i].to_flag; + } + if (strcmp(ENCODING_UNICODE, ENCODING_UTF16) == 0) + dp->convtype |= KICONV_UCS_UCS4; + else + dp->convtype &= ~KICONV_UCS_UCS4; + + dp->f_ctp = dp->t_ctp = NULL; + if (dp->convtype & KICONV_UCS_COMBINE) { + if ((dp->convtype & KICONV_UCS_FROM_UTF8) == 0 && + (dp->convtype & KICONV_UCS_FROM_LE) == 0) { + iconv_open(ENCODING_UNICODE, from, &dp->f_ctp); + } + if ((dp->convtype & KICONV_UCS_TO_UTF8) == 0 && + (dp->convtype & KICONV_UCS_TO_LE) == 0) { + iconv_open(to, ENCODING_UNICODE, &dp->t_ctp); + } + } + + dp->ctype = NULL; + if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_TO_UTF8)) + iconv_open(KICONV_WCTYPE_NAME, ENCODING_UTF8, &dp->ctype); + + dp->d_csp = csp; + if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_FROM_LE)) { + if (cspf) { + dp->d_cspf = cspf; + cspf->cp_refcount++; + } else + csp->cp_refcount++; + } + if (dp->convtype & (KICONV_UCS_TO_UTF8 | KICONV_UCS_TO_LE)) + csp->cp_refcount++; + *dpp = (void*)dp; + return 0; +} + +static int +iconv_ucs_close(void *data) +{ + struct iconv_ucs *dp = data; + + if (dp->f_ctp) + iconv_close(dp->f_ctp); + if (dp->t_ctp) + iconv_close(dp->t_ctp); + if (dp->ctype) + iconv_close(dp->ctype); + if (dp->d_cspf) + dp->d_cspf->cp_refcount--; + else if (dp->convtype & (KICONV_UCS_FROM_UTF8 | KICONV_UCS_FROM_LE)) + dp->d_csp->cp_refcount--; + if (dp->convtype & (KICONV_UCS_TO_UTF8 | KICONV_UCS_TO_LE)) + dp->d_csp->cp_refcount--; + kobj_delete((struct kobj*)data, M_ICONV); + return 0; +} + +static int +iconv_ucs_conv(void *d2p, const char **inbuf, + size_t *inbytesleft, char **outbuf, size_t *outbytesleft, + int convchar, int casetype) +{ + struct iconv_ucs *dp = (struct iconv_ucs*)d2p; + int ret = 0, i; + size_t in, on, ir, or, inlen, outlen, ucslen; + const char *src, *p; + char *dst; + u_char ucs[4], *q; + uint32_t code; + + if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL) + return 0; + ir = in = *inbytesleft; + or = on = *outbytesleft; + src = *inbuf; + dst = *outbuf; + + while (ir > 0 && or > 0) { + + /* + * The first half of conversion. + * (convert any code into ENCODING_UNICODE) + */ + code = 0; + p = src; + if (dp->convtype & KICONV_UCS_FROM_UTF8) { + /* convert UTF-8 to ENCODING_UNICODE */ + inlen = 0; + code = utf8_to_ucs4(p, &inlen, ir); + if (code == 0) { + ret = -1; + break; + } + + if (casetype == KICONV_FROM_LOWER && dp->ctype) { + code = towlower(code, dp->ctype); + } else if (casetype == KICONV_FROM_UPPER && dp->ctype) { + code = towupper(code, dp->ctype); + } + + if ((code >= 0xd800 && code < 0xe000) || code >= 0x110000 ) { + /* reserved for utf-16 surrogate pair */ + /* invalid unicode */ + ret = -1; + break; + } + + if (inlen == 4) { + if (dp->convtype & KICONV_UCS_UCS4) { + ucslen = 4; + code = encode_surrogate(code); + } else { + /* can't handle with ucs-2 */ + ret = -1; + break; + } + } else { + ucslen = 2; + } + + /* save UCS-4 into ucs[] */ + for (q = ucs, i = ucslen - 1 ; i >= 0 ; i--) + *q++ = (code >> (i << 3)) & 0xff; + + } else if (dp->convtype & KICONV_UCS_COMBINE && dp->f_ctp) { + /* convert local code to ENCODING_UNICODE */ + ucslen = 4; + inlen = ir; + q = ucs; + ret = iconv_convchr_case(dp->f_ctp, &p, &inlen, (char **)&q, + &ucslen, casetype & (KICONV_FROM_LOWER | KICONV_FROM_UPPER)); + if (ret) + break; + inlen = ir - inlen; + ucslen = 4 - ucslen; + + } else { + /* src code is a proper subset of ENCODING_UNICODE */ + q = ucs; + if (dp->convtype & KICONV_UCS_FROM_LE) { + *q = *(p + 1); + *(q + 1) = *p; + p += 2; + } else { + *q = *p++; + *(q + 1) = *p++; + } + if ((*q & 0xfc) == 0xd8) { + if (dp->convtype & KICONV_UCS_UCS4 && + dp->convtype & KICONV_UCS_FROM_UTF16) { + inlen = ucslen = 4; + } else { + /* invalid unicode */ + ret = -1; + break; + } + } else { + inlen = ucslen = 2; + } + if (ir < inlen) { + ret = -1; + break; + } + if (ucslen == 4) { + q += 2; + if (dp->convtype & KICONV_UCS_FROM_LE) { + *q = *(p + 1); + *(q + 1) = *p; + } else { + *q = *p++; + *(q + 1) = *p; + } + if ((*q & 0xfc) != 0xdc) { + /* invalid unicode */ + ret = -1; + break; + } + } + } + + /* + * The second half of conversion. + * (convert ENCODING_UNICODE into any code) + */ + p = ucs; + if (dp->convtype & KICONV_UCS_TO_UTF8) { + q = (u_char *)dst; + if (ucslen == 4 && dp->convtype & KICONV_UCS_UCS4) { + /* decode surrogate pair */ + code = decode_surrogate(p); + } else { + code = (ucs[0] << 8) | ucs[1]; + } + + if (casetype == KICONV_LOWER && dp->ctype) { + code = towlower(code, dp->ctype); + } else if (casetype == KICONV_UPPER && dp->ctype) { + code = towupper(code, dp->ctype); + } + + outlen = 0; + if (ucs4_to_utf8(code, q, &outlen, or) == NULL) { + ret = -1; + break; + } + + src += inlen; + ir -= inlen; + dst += outlen; + or -= outlen; + + } else if (dp->convtype & KICONV_UCS_COMBINE && dp->t_ctp) { + ret = iconv_convchr_case(dp->t_ctp, &p, &ucslen, &dst, + &or, casetype & (KICONV_LOWER | KICONV_UPPER)); + if (ret) + break; + + src += inlen; + ir -= inlen; + + } else { + /* dst code is a proper subset of ENCODING_UNICODE */ + if (or < ucslen) { + ret = -1; + break; + } + src += inlen; + ir -= inlen; + or -= ucslen; + if (dp->convtype & KICONV_UCS_TO_LE) { + *dst++ = *(p + 1); + *dst++ = *p; + p += 2; + } else { + *dst++ = *p++; + *dst++ = *p++; + } + if (ucslen == 4) { + if ((dp->convtype & KICONV_UCS_UCS4) == 0 || + (dp->convtype & KICONV_UCS_TO_UTF16) == 0) { + ret = -1; + break; + } + if (dp->convtype & KICONV_UCS_TO_LE) { + *dst++ = *(p + 1); + *dst++ = *p; + } else { + *dst++ = *p++; + *dst++ = *p; + } + } + } + + if (convchar == 1) + break; + } + + *inbuf += in - ir; + *outbuf += on - or; + *inbytesleft -= in - ir; + *outbytesleft -= on - or; + return (ret); +} + +static int +iconv_ucs_init(struct iconv_converter_class *dcp) +{ + int error; + + error = iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, ENCODING_UTF8); + if (error) + return (error); + error = iconv_add(ENCODING_UNICODE, ENCODING_UTF8, ENCODING_UNICODE); + if (error) + return (error); + return (0); +} + +static int +iconv_ucs_done(struct iconv_converter_class *dcp) +{ + return (0); +} + +static const char * +iconv_ucs_name(struct iconv_converter_class *dcp) +{ + return (ENCODING_UNICODE); +} + +static kobj_method_t iconv_ucs_methods[] = { + KOBJMETHOD(iconv_converter_open, iconv_ucs_open), + KOBJMETHOD(iconv_converter_close, iconv_ucs_close), + KOBJMETHOD(iconv_converter_conv, iconv_ucs_conv), + KOBJMETHOD(iconv_converter_init, iconv_ucs_init), + KOBJMETHOD(iconv_converter_done, iconv_ucs_done), + KOBJMETHOD(iconv_converter_name, iconv_ucs_name), + {0, 0} +}; + +KICONV_CONVERTER(ucs, sizeof(struct iconv_ucs)); + +static uint32_t +utf8_to_ucs4(const char *src, size_t *utf8width, size_t srclen) +{ + size_t i, w = 0; + uint32_t ucs4 = 0; + + /* + * get leading 1 byte from utf-8 + */ + if ((*src & 0x80) == 0) { + /* + * leading 1 bit is "0" + * utf-8: 0xxxxxxx + * ucs-4: 00000000 00000000 00000000 0xxxxxxx + */ + w = 1; + /* get trailing 7 bits */ + ucs4 = *src & 0x7f; + } else if ((*src & 0xe0) == 0xc0) { + /* + * leading 3 bits are "110" + * utf-8: 110xxxxx 10yyyyyy + * ucs-4: 00000000 00000000 00000xxx xxyyyyyy + */ + w = 2; + /* get trailing 5 bits */ + ucs4 = *src & 0x1f; + } else if ((*src & 0xf0) == 0xe0) { + /* + * leading 4 bits are "1110" + * utf-8: 1110xxxx 10yyyyyy 10zzzzzz + * ucs-4: 00000000 00000000 xxxxyyyy yyzzzzzz + */ + w = 3; + /* get trailing 4 bits */ + ucs4 = *src & 0x0f; + } else if ((*src & 0xf8) == 0xf0) { + /* + * leading 5 bits are "11110" + * utf-8: 11110www 10xxxxxx 10yyyyyy 10zzzzzz + * ucs-4: 00000000 000wwwxx xxxxyyyy yyzzzzzz + */ + w = 4; + /* get trailing 3 bits */ + ucs4 = *src & 0x07; + } else { + /* out of utf-16 range or having illegal bits */ + return (0); + } + if (w == 0) + return (0); + + if (srclen < w) + return (0); + + /* + * get left parts from utf-8 + */ + for (i = 1 ; i < w ; i++) { + if ((*(src + i) & 0xc0) != 0x80) { + /* invalid: leading 2 bits are not "10" */ + return (0); + } + /* concatenate trailing 6 bits into ucs4 */ + ucs4 <<= 6; + ucs4 |= *(src + i) & 0x3f; + } + + *utf8width = w; + return (ucs4); +} + +static u_char * +ucs4_to_utf8(uint32_t ucs4, char *dst, size_t *utf8width, size_t dstlen) +{ + u_char lead, *p; + size_t i, w; + + /* + * determine utf-8 width and leading bits + */ + if (ucs4 < 0x80) { + w = 1; + lead = 0; /* "0" */ + } else if (ucs4 < 0x800) { + w = 2; + lead = 0xc0; /* "11" */ + } else if (ucs4 < 0x10000) { + w = 3; + lead = 0xe0; /* "111" */ + } else if (ucs4 < 0x200000) { + w = 4; + lead = 0xf0; /* "1111" */ + } else { + return (NULL); + } + + if (dstlen < w) + return (NULL); + + /* + * construct utf-8 + */ + p = dst; + for (i = w - 1 ; i >= 1 ; i--) { + /* get trailing 6 bits and put it with leading bit as "1" */ + *(p + i) = (ucs4 & 0x3f) | 0x80; + ucs4 >>= 6; + } + *p = ucs4 | lead; + + *utf8width = w; + + return (p); +} + +static uint32_t +encode_surrogate(register uint32_t code) +{ + return ((((code - 0x10000) << 6) & 0x3ff0000) | + ((code - 0x10000) & 0x3ff) | 0xd800dc00); +} + +static uint32_t +decode_surrogate(register const u_char *ucs) +{ + return ((((ucs[0] & 0x3) << 18) | (ucs[1] << 10) | + ((ucs[2] & 0x3) << 8) | ucs[3]) + 0x10000); +} + diff --git a/sys/modules/libiconv/Makefile b/sys/modules/libiconv/Makefile index 6646064..1b51970 100644 --- a/sys/modules/libiconv/Makefile +++ b/sys/modules/libiconv/Makefile @@ -3,12 +3,13 @@ .PATH: ${.CURDIR}/../../libkern ${.CURDIR}/../../sys KMOD= libiconv -SRCS= iconv.c iconv_xlat.c iconv_xlat16.c +SRCS= iconv.c iconv_ucs.c iconv_xlat.c iconv_xlat16.c SRCS+= iconv.h SRCS+= iconv_converter_if.c iconv_converter_if.h MFILES= libkern/iconv_converter_if.m -EXPORT_SYMS= iconv_open \ +EXPORT_SYMS= iconv_add \ + iconv_open \ iconv_close \ iconv_conv \ iconv_conv_case \ diff --git a/sys/modules/libmchain/Makefile b/sys/modules/libmchain/Makefile index fd151ec..b8ab48e 100644 --- a/sys/modules/libmchain/Makefile +++ b/sys/modules/libmchain/Makefile @@ -11,6 +11,7 @@ EXPORT_SYMS= mb_init \ mb_detach \ mb_fixhdr \ mb_reserve \ + mb_put_padbyte \ mb_put_uint8 \ mb_put_uint16be \ mb_put_uint16le \ diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c index c14cb8b..01c9df4 100644 --- a/sys/netsmb/smb_conn.c +++ b/sys/netsmb/smb_conn.c @@ -444,13 +444,29 @@ smb_vc_create(struct smb_vcspec *vcspec, goto fail; if (vcspec->servercs[0]) { error = (int)iconv_open(vcspec->servercs, vcspec->localcs, - &vcp->vc_toserver); + &vcp->vc_cp_toserver); if (error) goto fail; error = (int)iconv_open(vcspec->localcs, vcspec->servercs, - &vcp->vc_tolocal); + &vcp->vc_cp_tolocal); if (error) goto fail; + vcp->vc_toserver = vcp->vc_cp_toserver; + vcp->vc_tolocal = vcp->vc_cp_tolocal; + iconv_add(ENCODING_UNICODE, ENCODING_UNICODE, SMB_UNICODE_NAME); + iconv_add(ENCODING_UNICODE, SMB_UNICODE_NAME, ENCODING_UNICODE); + error = (int)iconv_open(SMB_UNICODE_NAME, vcspec->localcs, + &vcp->vc_ucs_toserver); + if (!error) { + error = (int)iconv_open(vcspec->localcs, SMB_UNICODE_NAME, + &vcp->vc_ucs_tolocal); + } + if (error) { + if (vcp->vc_ucs_toserver) + iconv_close(vcp->vc_ucs_toserver); + vcp->vc_ucs_toserver = NULL; + vcp->vc_ucs_tolocal = NULL; + } } error = (int)smb_iod_create(vcp); if (error) @@ -486,9 +502,17 @@ smb_vc_free(struct smb_connobj *cp) if (vcp->vc_toupper) iconv_close(vcp->vc_toupper); if (vcp->vc_tolocal) - iconv_close(vcp->vc_tolocal); + vcp->vc_tolocal = NULL; if (vcp->vc_toserver) - iconv_close(vcp->vc_toserver); + vcp->vc_toserver = NULL; + if (vcp->vc_cp_tolocal) + iconv_close(vcp->vc_cp_tolocal); + if (vcp->vc_cp_toserver) + iconv_close(vcp->vc_cp_toserver); + if (vcp->vc_ucs_tolocal) + iconv_close(vcp->vc_ucs_tolocal); + if (vcp->vc_ucs_toserver) + iconv_close(vcp->vc_ucs_toserver); smb_co_done(VCTOCP(vcp)); smb_sl_destroy(&vcp->vc_stlock); free(vcp, M_SMBCONN); diff --git a/sys/netsmb/smb_conn.h b/sys/netsmb/smb_conn.h index 370f6cf..94a7a82 100644 --- a/sys/netsmb/smb_conn.h +++ b/sys/netsmb/smb_conn.h @@ -242,6 +242,10 @@ struct smb_vc { void * vc_toupper; /* local charset */ void * vc_toserver; /* local charset to server one */ void * vc_tolocal; /* server charset to local one */ + void * vc_cp_toserver; /* local charset to server one (using CodePage) */ + void * vc_cp_tolocal; /* server charset to local one (using CodePage) */ + void * vc_ucs_toserver; /* local charset to server one (using UCS-2) */ + void * vc_ucs_tolocal; /* server charset to local one (using UCS-2) */ int vc_number; /* number of this VC from the client side */ int vc_genid; uid_t vc_uid; /* user id of connection */ @@ -272,6 +276,8 @@ struct smb_vc { #define SMB_UNICODE_STRINGS(vcp) ((vcp)->vc_hflags2 & SMB_FLAGS2_UNICODE) +#define SMB_UNICODE_NAME "UCS-2LE" + /* * smb_share structure describes connection to the given SMB share (tree). * Connection to share is always built on top of the VC. diff --git a/sys/netsmb/smb_smb.c b/sys/netsmb/smb_smb.c index d3fb94a..6c732f9 100644 --- a/sys/netsmb/smb_smb.c +++ b/sys/netsmb/smb_smb.c @@ -121,9 +121,17 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) u_int8_t wc, stime[8], sblen; u_int16_t dindex, tw, tw1, swlen, bc; int error, maxqsz; + int unicode = SMB_UNICODE_STRINGS(vcp); + void * servercharset = vcp->vc_toserver; + void * localcharset = vcp->vc_tolocal; if (smb_smb_nomux(vcp, scred, __func__) != 0) return EINVAL; + /* Disable Unicode for SMB_COM_NEGOTIATE requests */ + if (unicode) { + vcp->vc_toserver = vcp->vc_cp_toserver; + vcp->vc_tolocal = vcp->vc_cp_tolocal; + } vcp->vc_hflags = 0; vcp->vc_hflags2 = 0; vcp->obj.co_flags &= ~(SMBV_ENCRYPT); @@ -180,7 +188,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) SMBERROR("Unexpected length of security blob (%d)\n", sblen); break; } - error = md_get_uint16(mdp, &bc); + error = md_get_uint16le(mdp, &bc); if (error) break; if (sp->sv_caps & SMB_CAP_EXT_SECURITY) @@ -193,6 +201,13 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) } if (sp->sv_sm & SMB_SM_SIGS_REQUIRE) vcp->vc_hflags2 |= SMB_FLAGS2_SECURITY_SIGNATURE; + if (vcp->vc_ucs_toserver && + sp->sv_caps & SMB_CAP_UNICODE) { + /* + * They do Unicode. + */ + vcp->obj.co_flags |= SMBV_UNICODE; + } vcp->vc_hflags2 |= SMB_FLAGS2_KNOWS_LONG_NAMES; if (dp->d_id == SMB_DIALECT_NTLM0_12 && sp->sv_maxtx < 4096 && @@ -200,7 +215,13 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) vcp->obj.co_flags |= SMBV_WIN95; SMBSDEBUG("Win95 detected\n"); } - } else if (dp->d_id > SMB_DIALECT_CORE) { + error = 0; + break; + } + vcp->vc_hflags2 &= ~(SMB_FLAGS2_EXT_SEC|SMB_FLAGS2_DFS| + SMB_FLAGS2_ERR_STATUS|SMB_FLAGS2_UNICODE); + unicode = 0; + if (dp->d_id > SMB_DIALECT_CORE) { md_get_uint16le(mdp, &tw); sp->sv_sm = tw; md_get_uint16le(mdp, &tw); @@ -217,7 +238,7 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) if (swlen > SMB_MAXCHALLENGELEN) break; md_get_uint16(mdp, NULL); /* mbz */ - if (md_get_uint16(mdp, &bc) != 0) + if (md_get_uint16le(mdp, &bc) != 0) break; if (bc < swlen) break; @@ -259,6 +280,12 @@ smb_smb_negotiate(struct smb_vc *vcp, struct smb_cred *scred) SMBSDEBUG("MAXTX = %d\n", sp->sv_maxtx); } bad: + /* Restore Unicode conversion state */ + if (unicode) { + vcp->vc_toserver = servercharset; + vcp->vc_tolocal = localcharset; + vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; + } smb_rq_done(rqp); return error; } @@ -273,9 +300,13 @@ smb_smb_ssnsetup(struct smb_vc *vcp, struct smb_cred *scred) smb_uniptr unipp, ntencpass = NULL; char *pp, *up, *pbuf, *encpass; int error, plen, uniplen, ulen, upper; + u_int32_t caps = 0; upper = 0; + if (vcp->obj.co_flags & SMBV_UNICODE) + caps |= SMB_CAP_UNICODE; + again: vcp->vc_smbuid = SMB_UID_UNKNOWN; @@ -374,8 +405,7 @@ again: } else { mb_put_uint16le(mbp, uniplen); mb_put_uint32le(mbp, 0); /* reserved */ - mb_put_uint32le(mbp, vcp->obj.co_flags & SMBV_UNICODE ? - SMB_CAP_UNICODE : 0); + mb_put_uint32le(mbp, caps); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_mem(mbp, pp, plen, MB_MSYSTEM); @@ -477,24 +507,13 @@ smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) upper = 0; again: - -#if 0 /* Disable Unicode for SMB_COM_TREE_CONNECT_ANDX requests */ if (SSTOVC(ssp)->vc_hflags2 & SMB_FLAGS2_UNICODE) { vcp = SSTOVC(ssp); - if (vcp->vc_toserver) { - iconv_close(vcp->vc_toserver); - /* Use NULL until UTF-8 -> ASCII works */ - vcp->vc_toserver = NULL; - } - if (vcp->vc_tolocal) { - iconv_close(vcp->vc_tolocal); - /* Use NULL until ASCII -> UTF-8 works*/ - vcp->vc_tolocal = NULL; - } + vcp->vc_toserver = vcp->vc_cp_toserver; + vcp->vc_tolocal = vcp->vc_cp_tolocal; vcp->vc_hflags2 &= ~SMB_FLAGS2_UNICODE; } -#endif ssp->ss_tid = SMB_TID_UNKNOWN; error = smb_rq_alloc(SSTOCP(ssp), SMB_COM_TREE_CONNECT_ANDX, scred, &rqp); @@ -559,6 +578,15 @@ again: ssp->ss_tid = rqp->sr_rptid; ssp->ss_vcgenid = vcp->vc_genid; ssp->ss_flags |= SMBS_CONNECTED; + /* + * If the server can speak Unicode then switch + * our converters to do Unicode <--> Local + */ + if (vcp->obj.co_flags & SMBV_UNICODE) { + vcp->vc_toserver = vcp->vc_ucs_toserver; + vcp->vc_tolocal = vcp->vc_ucs_tolocal; + vcp->vc_hflags2 |= SMB_FLAGS2_UNICODE; + } bad: if (encpass) free(encpass, M_SMBTEMP); diff --git a/sys/netsmb/smb_subr.c b/sys/netsmb/smb_subr.c index ade9e17..26372f4 100644 --- a/sys/netsmb/smb_subr.c +++ b/sys/netsmb/smb_subr.c @@ -350,6 +350,8 @@ smb_put_dmem(struct mbchain *mbp, struct smb_vc *vcp, const char *src, } mbp->mb_copy = smb_copy_iconv; mbp->mb_udata = dp; + if (SMB_UNICODE_STRINGS(vcp)) + mb_put_padbyte(mbp); return mb_put_mem(mbp, src, size, MB_MCUSTOM); } @@ -362,6 +364,8 @@ smb_put_dstring(struct mbchain *mbp, struct smb_vc *vcp, const char *src, error = smb_put_dmem(mbp, vcp, src, strlen(src), caseopt); if (error) return error; + if (SMB_UNICODE_STRINGS(vcp)) + return mb_put_uint16le(mbp, 0); return mb_put_uint8(mbp, 0); } diff --git a/sys/sys/iconv.h b/sys/sys/iconv.h index 7ca84b5..671b24e 100644 --- a/sys/sys/iconv.h +++ b/sys/sys/iconv.h @@ -47,6 +47,7 @@ #define KICONV_FROM_UPPER 8 /* toupper source character, then convert */ #define KICONV_WCTYPE 16 /* towlower/towupper characters */ +#define ENCODING_UNICODE "UTF-16BE" #define KICONV_WCTYPE_NAME "_wctype" /* @@ -85,7 +86,6 @@ struct iconv_add_out { __BEGIN_DECLS -#define ENCODING_UNICODE "UTF-16BE" #define KICONV_VENDOR_MICSFT 1 /* Microsoft Vendor Code for quirk */ int kiconv_add_xlat_table(const char *, const char *, const u_char *); @@ -162,6 +162,7 @@ int iconv_convchr(void *handle, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); int iconv_convchr_case(void *handle, const char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype); +int iconv_add(const char *converter, const char *to, const char *from); char* iconv_convstr(void *handle, char *dst, const char *src); void* iconv_convmem(void *handle, void *dst, const void *src, int size); int iconv_vfs_refcount(const char *fsname); diff --git a/sys/sys/mchain.h b/sys/sys/mchain.h index 4ee32e4..b89cbfd 100644 --- a/sys/sys/mchain.h +++ b/sys/sys/mchain.h @@ -67,6 +67,7 @@ struct mbuf *mb_detach(struct mbchain *mbp); int mb_fixhdr(struct mbchain *mbp); caddr_t mb_reserve(struct mbchain *mbp, int size); +int mb_put_padbyte(struct mbchain *mbp); int mb_put_uint8(struct mbchain *mbp, u_int8_t x); int mb_put_uint16be(struct mbchain *mbp, u_int16_t x); int mb_put_uint16le(struct mbchain *mbp, u_int16_t x); -- 1.7.9.4