From owner-FreeBSD-users-jp@jp.FreeBSD.org Sun Aug 14 15:15:29 2011
Received: (from daemon@localhost)
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) id p7E6FTp35760;
	Sun, 14 Aug 2011 15:15:29 +0900 (JST)
	(envelope-from owner-FreeBSD-users-jp@jp.FreeBSD.org)
Received: from mv-osn-hcb005.ocn.ad.jp (mv-osn-hcb005.ocn.ad.jp [222.146.51.141])
	by castle.jp.FreeBSD.org (8.11.6p2+3.4W/8.11.3) with ESMTP/inet id p7E6FS335755
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Sun, 14 Aug 2011 15:15:28 +0900 (JST)
	(envelope-from t-matubara@miracle.ocn.ne.jp)
Received: from vcmiracle.ocn.ne.jp (mv-osn-hcb005 [222.146.51.141])
	by mv-osn-hcb005.ocn.ad.jp (Postfix) with ESMTP id DE4AC20430A
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Sun, 14 Aug 2011 15:15:26 +0900 (JST)
Received: from localhost (p3128-ipad12okayamaima.okayama.ocn.ne.jp [220.105.76.128])
	by vcmiracle.ocn.ne.jp (Postfix) with ESMTP
	for <FreeBSD-users-jp@jp.FreeBSD.org>; Sun, 14 Aug 2011 15:15:26 +0900 (JST)
Message-Id: <20110814.151527.389634436423553161.t-matubara@miracle.ocn.ne.jp>
To: FreeBSD-users-jp@jp.FreeBSD.org
From: Takashi Matsubara <t-matubara@miracle.ocn.ne.jp>
X-Mailer: Mew version 6.3 on Emacs 23.3 / Mule 6.0 (HANACHIRUSATO)
Mime-Version: 1.0
Content-Type: Multipart/Mixed;
 boundary="--Next_Part(Sun_Aug_14_15_15_27_2011_750)--"
Content-Transfer-Encoding: 7bit
Reply-To: FreeBSD-users-jp@jp.FreeBSD.org
Precedence: list
Date: Sun, 14 Aug 2011 15:15:27 +0900
X-Sequence: FreeBSD-users-jp 93488
Subject: [FreeBSD-users-jp 93488] mount_smbfs
 =?ISO-2022-JP?B?GyRCJEcbKEI=?= CP932
 =?ISO-2022-JP?B?GyRCJHIbKEI=?= UTF-8
 =?ISO-2022-JP?B?GyRCJEgkNyRGGyhC?= mount(FreeBSD9)
Sender: owner-FreeBSD-users-jp@jp.FreeBSD.org
X-Originator: t-matubara@miracle.ocn.ne.jp
X-Distribute: distribute version 2.1 (Alpha) patchlevel 24e+060209

----Next_Part(Sun_Aug_14_15_15_27_2011_750)--
Content-Type: Text/Plain; charset=iso-2022-jp
Content-Transfer-Encoding: 7bit

$B>>86$H?=$7$^$9!#(B

FreeBSD8$BMQ$N%Q%C%A$r!"(BFreeBSD9-BATA1$BMQ$KJQ99$7$F$_$^$7$?!#(B
$B3'MM$N$*NO$K$J$l$l$P$H;W$$!"%a!<%kCW$7$^$9!#(B
$B85$K$7$?%Q%C%A!'(Bkiconv_enhancement_RELENG_8-20100916.diff

2011/08/06 $B;~E@(BFreeBSD9-BETA1 $B$G$N%Q%C%A$G$9!#(B

$B0J>e!"59$7$/$*4j$$CW$7$^$9!#(B

----Next_Part(Sun_Aug_14_15_15_27_2011_750)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="kiconv_enhancement_RELENG_9-20110806.diff"

diff -ubdwrN src.orig/etc/defaults/rc.conf src/etc/defaults/rc.conf
--- src.orig/etc/defaults/rc.conf	2010-09-01 14:39:56.000000000 +0900
+++ src/etc/defaults/rc.conf	2010-09-16 13:49:59.000000000 +0900
@@ -655,6 +655,9 @@
 newsyslog_enable="YES"	# Run newsyslog at startup.
 newsyslog_flags="-CN"	# Newsyslog flags to create marked files
 mixer_enable="YES"	# Run the sound mixer.
+kiconv_load="NO"	# Load kiconv tables at startup.
+#kiconv_locale="ja_JP.UTF-8"	# Locale names to be loaded.
+#kiconv_encoding="CP932"	# Encoding names to be loaded.
 opensm_enable="NO"	# Opensm(8) for infiniband devices defaults to off
 
 ##############################################################
diff -ubdwrN src.orig/etc/rc.d/Makefile src/etc/rc.d/Makefile
--- src.orig/etc/rc.d/Makefile	2010-04-20 21:07:16.000000000 +0900
+++ src/etc/rc.d/Makefile	2010-09-16 13:49:59.000000000 +0900
@@ -18,7 +18,7 @@
 	ip6addrctl ipfilter ipfs ipfw ipmon \
 	ipnat ipsec ipxrouted \
 	jail \
-	kadmind kerberos keyserv kld kldxref kpasswdd \
+	kadmind kerberos keyserv kiconv kld kldxref kpasswdd \
 	ldconfig local localpkg lockd lpd \
 	mixer motd mountcritlocal mountcritremote mountlate \
 	mdconfig mdconfig2 mountd moused mroute6d mrouted msgs \
diff -ubdwrN src.orig/etc/rc.d/kiconv src/etc/rc.d/kiconv
--- src.orig/etc/rc.d/kiconv	1970-01-01 09:00:00.000000000 +0900
+++ src/etc/rc.d/kiconv	2010-09-16 13:49:59.000000000 +0900
@@ -0,0 +1,56 @@
+#!/bin/sh
+#
+# Copyright (c) 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.
+#
+# $FreeBSD$
+#
+
+# PROVIDE: kiconv
+# REQUIRE: ldconfig
+# KEYWORD: nojail
+
+. /etc/rc.subr
+
+name="kiconv"
+kiconv_command="/usr/sbin/kiconvctl"
+rcvar="kiconv_load"
+start_cmd="kiconv_load"
+stop_cmd=":"
+
+kiconv_load() {
+	kiconv=${kiconv_command}
+	kldstat -m iconv >/dev/null 2>&1 || ${kiconv} load || exit
+	echo -n 'Loading kiconv tables'
+	for i in ${kiconv_locale}; do
+		${kiconv} add -l ${i}
+	done
+	for i in ${kiconv_encoding}; do
+		${kiconv} add ${i}
+	done
+	echo '.'
+}
+
+load_rc_config $name
+run_rc_command "$1"
diff -ubdwrN src.orig/lib/libkiconv/Makefile src/lib/libkiconv/Makefile
--- src.orig/lib/libkiconv/Makefile	2009-08-03 17:13:06.000000000 +0900
+++ src/lib/libkiconv/Makefile	2010-09-16 13:49:59.000000000 +0900
@@ -2,7 +2,7 @@
 
 LIB=		kiconv
 SHLIBDIR?=	/lib
-SRCS=		kiconv_sysctl.c xlat16_iconv.c xlat16_sysctl.c
+SRCS=		kiconv_alias.c kiconv_sysctl.c xlat16_iconv.c xlat16_sysctl.c
 SRCS+=		quirks.c
 
 SHLIB_MAJOR=	4
diff -ubdwrN src.orig/lib/libkiconv/kiconv_alias.c src/lib/libkiconv/kiconv_alias.c
--- src.orig/lib/libkiconv/kiconv_alias.c	1970-01-01 09:00:00.000000000 +0900
+++ src/lib/libkiconv/kiconv_alias.c	2010-09-16 13:49:59.000000000 +0900
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 2006 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+#include "kiconv_alias.h"
+
+int
+kiconv_add_aliases(const char *to, const char *from, const char *aliasto,
+    const char *aliasfrom)
+{
+	size_t len;
+	int ret;
+	char data[ICONV_CSNMAXLEN * 2], *dp;
+
+	len = (strlen(aliasfrom) + 1) + (strlen(aliasto) + 1);
+	dp = stpcpy(data, aliasfrom);
+	dp++;
+	strcpy(dp, aliasto);
+
+	ret = kiconv_add("alias", to, from, (const void *)data, len);
+	return (ret);
+}
+
+int
+kiconv_aliascmp(const char *str1, const char *str2)
+{
+	int i;
+	const char *c1, *c2;
+
+	for (i = 0, c1 = str1, c2 = str2; i < ICONV_CSNMAXLEN;) {
+		if (*c1 == '\0' && *c2 == '\0' && i > 0) {
+			return (0);
+		} else if (*c1 == '\0' || *c2 == '\0') {
+			return (ENOENT);
+		}
+		if (*c1 == '-' || *c1 == '_') {
+			i++;
+			c1++;
+			continue;
+		}
+		if (*c2 == '-' || *c2 == '_') {
+			c2++;
+			continue;
+		}
+		if (toupper(*c1) == toupper(*c2)) {
+			i++;
+			c1++;
+			c2++;
+			continue;
+		}
+		return (ENOENT);
+	}
+	return (ENOENT);
+}
diff -ubdwrN src.orig/lib/libkiconv/kiconv_alias.h src/lib/libkiconv/kiconv_alias.h
--- src.orig/lib/libkiconv/kiconv_alias.h	1970-01-01 09:00:00.000000000 +0900
+++ src/lib/libkiconv/kiconv_alias.h	2010-09-16 13:49:59.000000000 +0900
@@ -0,0 +1,30 @@
+/*-
+ * Copyright (c) 2006 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.
+ *
+ * $FreeBSD$
+ */
+
+int kiconv_add_aliases(const char *, const char *, const char *, const char *);
+int kiconv_aliascmp(const char *, const char *);
diff -ubdwrN src.orig/lib/libkiconv/kiconv_sysctl.c src/lib/libkiconv/kiconv_sysctl.c
--- src.orig/lib/libkiconv/kiconv_sysctl.c	2009-08-03 17:13:06.000000000 +0900
+++ src/lib/libkiconv/kiconv_sysctl.c	2010-09-16 13:49:59.000000000 +0900
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2005 Ryuichiro Imura
+ * Copyright (c) 2005, 2006 Ryuichiro Imura
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "kiconv_alias.h"
+
 int
 kiconv_lookupconv(const char *drvname)
 {
@@ -87,3 +89,36 @@
 	}
 	return (ENOENT);
 }
+
+int
+kiconv_lookup_aliases(const char *tocode, const char *fromcode)
+{
+	size_t i, size;
+	struct iconv_cspair_info *csi, *csip;
+	int error, j;
+	const char *kp, *lp;
+
+	if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1)
+		return (errno);
+	if (size > 0) {
+		csi = malloc(size);
+		if (csi == NULL)
+			return (ENOMEM);
+		if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) {
+			error = errno;
+			free(csi);
+			return (error);
+		}
+		for (i = 0, csip = csi; i < (size/sizeof(*csi)); i++, csip++) {
+			if (kiconv_aliascmp(csip->cs_to, tocode) == 0 &&
+			    kiconv_aliascmp(csip->cs_from, fromcode) == 0) {
+				error = kiconv_add_aliases(tocode, fromcode,
+				    csip->cs_to, csip->cs_from);
+				free(csi);
+				return (error);
+			}
+		}
+		free(csi);
+	}
+	return (ENOENT);
+}
diff -ubdwrN src.orig/lib/libkiconv/xlat16_iconv.c src/lib/libkiconv/xlat16_iconv.c
--- src.orig/lib/libkiconv/xlat16_iconv.c	2009-08-03 17:13:06.000000000 +0900
+++ src/lib/libkiconv/xlat16_iconv.c	2010-09-16 13:49:59.000000000 +0900
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003, 2005 Ryuichiro Imura
+ * Copyright (c) 2003, 2005, 2006 Ryuichiro Imura
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,10 +74,31 @@
 	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);
 
+	if (kiconv_lookupconv("alias") == 0) {
+		if (flag & KICONV_WCTYPE)
+			error = kiconv_lookup_aliases(fromcode, fromcode);
+		else
+			error = kiconv_lookup_aliases(tocode, fromcode);
+		if (error == 0)
+			return (0);
+	}
+
 	if (flag & KICONV_WCTYPE)
 		xt = kiconv_xlat16_open(fromcode, fromcode, flag);
 	else
diff -ubdwrN src.orig/lib/libkiconv/xlat16_sysctl.c src/lib/libkiconv/xlat16_sysctl.c
--- src.orig/lib/libkiconv/xlat16_sysctl.c	2009-08-03 17:13:06.000000000 +0900
+++ src/lib/libkiconv/xlat16_sysctl.c	2010-09-16 13:49:59.000000000 +0900
@@ -32,13 +32,6 @@
  * $FreeBSD: src/lib/libkiconv/xlat16_sysctl.c,v 1.3.2.1 2009/08/03 08:13:06 kensmith Exp $
  */
 
-/*
- * kiconv(3) requires shared linked, and reduce module size
- * when statically linked.
- */
-
-#ifdef PIC
-
 #include <sys/types.h>
 #include <sys/iconv.h>
 #include <sys/sysctl.h>
@@ -48,16 +41,19 @@
 #include <string.h>
 
 int
-kiconv_add_xlat16_table(const char *to, const char *from, const void *data, int datalen)
+kiconv_add(const char *drv, const char *to, const char *from, const void *data,
+    int datalen)
 {
 	struct iconv_add_in din;
 	struct iconv_add_out dout;
 	size_t olen;
 
+	if (strlen(drv) >= ICONV_CNVNMAXLEN)
+		return (EINVAL);
 	if (strlen(from) >= ICONV_CSNMAXLEN || strlen(to) >= ICONV_CSNMAXLEN)
 		return (EINVAL);
 	din.ia_version = ICONV_ADD_VER;
-	strcpy(din.ia_converter, "xlat16");
+	strcpy(din.ia_converter, drv);
 	strcpy(din.ia_from, from);
 	strcpy(din.ia_to, to);
 	din.ia_data = data;
@@ -68,11 +64,23 @@
 	return (0);
 }
 
-#else /* statically linked */
+/*
+ * kiconv(3) requires shared linked, and reduce module size
+ * when statically linked.
+ */
 
-#include <sys/types.h>
-#include <sys/iconv.h>
-#include <errno.h>
+#ifdef PIC
+
+int
+kiconv_add_xlat16_table(const char *to, const char *from, const void *data, int datalen)
+{
+	int ret;
+
+	ret = kiconv_add("xlat16", to, from, data, datalen);
+	return (ret);
+ }
+
+#else /* statically linked */
 
 int
 kiconv_add_xlat16_table(const char *to __unused, const char *from __unused,
diff -ubdwrN src.orig/share/man/man5/rc.conf.5 src/share/man/man5/rc.conf.5
--- src.orig/share/man/man5/rc.conf.5	2010-09-13 03:37:34.000000000 +0900
+++ src/share/man/man5/rc.conf.5	2010-09-16 13:49:59.000000000 +0900
@@ -4042,6 +4042,36 @@
 If set to
 .Dq Li YES ,
 enable support for sound mixer.
+.\" ----- kiconv settings ---------------------------------------
+.It Va kiconv_load
+.Pq Vt bool
+If set to
+.Dq Li YES ,
+load
+.Xr kiconv 3
+tables at startup.
+If no plan to use
+.Va vfs.usermount
+.Xr sysctl 8
+feature, you need not to set to
+.Dq Li YES
+this variable.
+.It Va kiconv_locale
+.Pq Vt str
+Specify locale names to be loaded, when
+.Va kiconv_load
+is set to
+.Dq Li YES .
+Character conversion tables of encoding of this locale
+and tolower/toupper tables are loaded.
+.It Va kiconv_encoding
+.Pq Vt str
+Specify encoding names to be loaded, when
+.Va kiconv_load
+is set to
+.Dq Li YES .
+Character conversion tables of this encoding are loaded.
+.\" -------------------------------------------------------------
 .It Va hcsecd_enable
 .Pq Vt bool
 If set to
diff -ubdwrN src.orig/sys/conf/files src/sys/conf/files
--- src.orig/sys/conf/files	2010-08-13 05:18:06.000000000 +0900
+++ src/sys/conf/files	2010-09-16 13:49:59.000000000 +0900
@@ -2277,7 +2277,9 @@
 libkern/fnmatch.c		standard
 libkern/gets.c			standard
 libkern/iconv.c			optional libiconv
+libkern/iconv_alias.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 -ubdwrN src.orig/sys/fs/cd9660/cd9660_rrip.c src/sys/fs/cd9660/cd9660_rrip.c
--- src.orig/sys/fs/cd9660/cd9660_rrip.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/cd9660/cd9660_rrip.c	2010-09-16 13:49:59.000000000 +0900
@@ -496,7 +496,7 @@
 	ISO_SUSP_HEADER *pend;
 	struct buf *bp = NULL;
 	char *pwhead;
-	u_short c;
+	uint32_t c;
 	int result;
 
 	/*
@@ -633,7 +633,7 @@
 {
 	ISO_RRIP_ANALYZE analyze;
 	RRIP_TABLE *tab;
-	u_short c;
+	uint32_t c;
 
 	analyze.outbuf = outbuf;
 	analyze.outlen = outlen;
diff -ubdwrN src.orig/sys/fs/cd9660/cd9660_util.c src/sys/fs/cd9660/cd9660_util.c
--- src.orig/sys/fs/cd9660/cd9660_util.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/cd9660/cd9660_util.c	2010-09-16 13:49:59.000000000 +0900
@@ -44,8 +44,8 @@
 #include <sys/vnode.h>
 #include <sys/iconv.h>
 
-#include <fs/cd9660/iso.h>
 #include <fs/cd9660/cd9660_mount.h>
+#include <fs/cd9660/iso.h>
 
 extern struct iconv_functions *cd9660_iconv;
 
@@ -59,7 +59,7 @@
       u_char *isofn;
       u_char *isoend;
       int joliet_level;
-      u_short *c;
+      uint32_t *c;
       int *clen;
       int flags;
       void *handle;
@@ -74,7 +74,8 @@
               return 1;
 
       if (flags & ISOFSMNT_KICONV && cd9660_iconv) {
-              i = j = len = 2;
+              i = 2;
+              j = len = sizeof(*c);
               inbuf[0]=(char)*(isofn - 1);
               inbuf[1]=(char)*isofn;
               inbuf[2]='\0';
@@ -117,7 +118,7 @@
 	void *lhandle;
 {
 	int i, j;
-	u_short c, d;
+	uint32_t c, d;
 	u_char *fnend = fn + fnlen, *isoend = isofn + isolen;
 
 	for (; fn < fnend; ) {
@@ -186,7 +187,7 @@
 	int flags;
 	void *handle;
 {
-	u_short c, d = '\0';
+	uint32_t c, d = '\0';
 	u_char *outp = outfn, *infnend = infn + infnlen;
 	int clen;
 
@@ -212,7 +213,7 @@
 /*
  * same as sgetrune(3)
  */
-u_short
+uint32_t
 sgetrune(string, n, result, flags, handle)
 	const char *string;
 	size_t n;
@@ -222,9 +223,9 @@
 {
 	size_t i, j, len;
 	char outbuf[3], *outp;
-	u_short c = '\0';
+	uint32_t c = '\0';
 
-	len = i = (n < 2) ? n : 2;
+	len = i = (n < sizeof(c)) ? n : sizeof(c);
 	j = 2;
 	outp = outbuf;
 
diff -ubdwrN src.orig/sys/fs/cd9660/iso.h src/sys/fs/cd9660/iso.h
--- src.orig/sys/fs/cd9660/iso.h	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/cd9660/iso.h	2010-09-16 13:49:59.000000000 +0900
@@ -271,11 +271,11 @@
 extern struct vop_vector cd9660_vnodeops;
 extern struct vop_vector cd9660_fifoops;
 
-int isochar(u_char *, u_char *, int, u_short *, int *, int, void *);
+int isochar(u_char *, u_char *, int, uint32_t *, int *, int, void *);
 int isofncmp(u_char *, int, u_char *, int, int, int, void *, void *);
 void isofntrans(u_char *, int, u_char *, u_short *, int, int, int, int, void *);
 ino_t isodirino(struct iso_directory_record *, struct iso_mnt *);
-u_short sgetrune(const char *, size_t, char const **, int, void *);
+uint32_t sgetrune(const char *, size_t, char const **, int, void *);
 
 #endif /* _KERNEL */
 
diff -ubdwrN src.orig/sys/fs/msdosfs/msdosfs_conv.c src/sys/fs/msdosfs/msdosfs_conv.c
--- src.orig/sys/fs/msdosfs/msdosfs_conv.c	2010-02-28 01:51:23.000000000 +0900
+++ src/sys/fs/msdosfs/msdosfs_conv.c	2010-09-16 13:49:59.000000000 +0900
@@ -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(u_char *, 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_char *, u_int16_t, struct msdosfsmount *);
 static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *);
 
 /*
@@ -242,7 +242,7 @@
 {
 	size_t i;
 	int thislong = 0;
-	u_int16_t c;
+	u_char *c, tmpbuf[5];
 
 	/*
 	 * If first char of the filename is SLOT_E5 (0x05), then the real
@@ -257,14 +257,12 @@
 	 * Copy the name portion into the unix filename string.
 	 */
 	for (i = 8; i > 0 && *dn != ' ';) {
-		c = dos2unixchr((const u_char **)&dn, &i, lower & LCASE_BASE,
+		c = dos2unixchr(tmpbuf,(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;
 
@@ -276,14 +274,12 @@
 		*un++ = '.';
 		thislong++;
 		for (i = 3; i > 0 && *dn != ' ';) {
-			c = dos2unixchr((const u_char **)&dn, &i,
+			c = dos2unixchr(tmpbuf,(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 @@
 	int chksum;
 	struct msdosfsmount *pmp;
 {
+	u_char *c, tmpbuf[5];
 	u_int8_t *cp;
-	u_int8_t *np, name[WIN_CHARS * 2 + 1];
+	u_int8_t *np, name[WIN_CHARS * 4 + 1];
 	u_int16_t code;
 	int i;
 
@@ -686,10 +683,9 @@
 			*np = '\0';
 			return -1;
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			c = win2unixchr(tmpbuf, code, pmp);
+			while (*c != '\0')
+				*np++ = *c++;
 			break;
 		}
 		cp += 2;
@@ -705,10 +701,9 @@
 			*np = '\0';
 			return -1;
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			c = win2unixchr(tmpbuf, code, pmp);
+			while (*c != '\0')
+				*np++ = *c++;
 			break;
 		}
 		cp += 2;
@@ -724,10 +719,9 @@
 			*np = '\0';
 			return -1;
 		default:
-			code = win2unixchr(code, pmp);
-			if (code & 0xff00)
-				*np++ = code >> 8;
-			*np++ = code;
+			c = win2unixchr(tmpbuf, code, pmp);
+			while (*c != '\0')
+				*np++ = *c++;
 			break;
 		}
 		cp += 2;
@@ -817,24 +811,22 @@
 /*
  * Convert DOS char to Local char
  */
-static u_int16_t
-dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
+static u_char *
+dos2unixchr(u_char *outbuf, 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;
 	size_t len, olen;
 
-	if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
-		olen = len = 2;
 		outp = outbuf;
+	if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+		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 @@
 		if (len == 0) {
 			(*ilen)--;
 			(*instr)++;
-			return ('?');
-		}
-
-		wc = 0;
-		while(len--)
-			wc |= (*(outp - len - 1) & 0xff) << (len << 3);
-		return (wc);
+			*outp++ = '?';
 	}
-
+	} else {
 	(*ilen)--;
 	c = *(*instr)++;
 	c = dos2unix[c];
 	if (lower & (LCASE_BASE | LCASE_EXT))
 		c = u2l[c];
-	return ((u_int16_t)c);
+		*outp++ = c;
+		outbuf[1] = '\0';
+	}
+
+	*outp = '\0';
+	outp = outbuf;
+	return (outp);
 }
 
 /*
@@ -940,23 +932,21 @@
 /*
  * Convert Windows char to Local char
  */
-static u_int16_t
-win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
+static u_char *
+win2unixchr(u_char *outbuf, u_int16_t wc, struct msdosfsmount *pmp)
 {
-	u_char *inp, *outp, inbuf[3], outbuf[3];
+	u_char *inp, *outp, inbuf[3];
 	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 @@
 		/*
 		 * 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 -ubdwrN src.orig/sys/fs/ntfs/ntfs_subr.c src/sys/fs/ntfs/ntfs_subr.c
--- src.orig/sys/fs/ntfs/ntfs_subr.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/ntfs/ntfs_subr.c	2010-09-16 13:49:59.000000000 +0900
@@ -666,23 +666,18 @@
 	const char *astr;
 	size_t astrlen;
 {
-	int len;
+	const char *astrp = astr;
+	int len, res;
 	size_t i, j, mbstrlen = astrlen;
-	int res;
-	wchar wc;
+	char tmpbuf[5];
 
 	if (ntmp->ntm_ic_l2u) {
-		for (i = 0, j = 0; i < ustrlen && j < astrlen; i++, j++) {
-			if (j < astrlen -1) {
-				wc = (wchar)astr[j]<<8 | (astr[j+1]&0xFF);
-				len = 2;
-			} else {
-				wc = (wchar)astr[j]<<8 & 0xFF00;
-				len = 1;
-			}
+		for (i = 0, j = 0; i < ustrlen && j < astrlen; i++) {
+			len = 4;
 			res = ((int) NTFS_TOUPPER(ustr[i])) -
-				((int)NTFS_TOUPPER(NTFS_82U(wc, &len)));
-			j += len - 1;
+				((int)NTFS_TOUPPER(NTFS_82U(astrp, &len)));
+			astrp += len;
+			j += len;
 			mbstrlen -= len - 1;
 
 			if (res)
@@ -695,7 +690,8 @@
 		 */
 		for (i = 0; i < ustrlen && i < astrlen; i++) {
 			res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i]), &len))) -
-				((int)NTFS_TOUPPER(NTFS_82U((wchar)astr[i], &len)));
+				((int)NTFS_TOUPPER(NTFS_82U(astrp, &len)));
+			astrp++;
 			if (res)
 				return res;
 		}
@@ -714,23 +710,18 @@
 	const char *astr;
 	size_t astrlen;
 {
-	char u, l;
+	char *c, tmpbuf[5];
 	size_t i, j, mbstrlen = astrlen;
 	int res;
-	wchar wc;
 
-	for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, j++) {
-		res = 0;
-		wc = NTFS_U28(ustr[i]);
-		u = (char)(wc>>8);
-		l = (char)wc;
-		if (u != '\0' && j < astrlen -1) {
-			res = (int) (u - astr[j++]);
-			mbstrlen--;
-		}
-		res = (res<<8) + (int) (l - astr[j]);
+	for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, mbstrlen++) {
+		c = NTFS_U28(ustr[i]);
+		while (*c != '\0') {
+			res = (int) (*c++ - astr[j++]);
 		if (res)
 			return res;
+			mbstrlen--;
+		}
 	}
 	return (ustrlen - mbstrlen);
 }
@@ -2131,50 +2122,48 @@
 }
 
 /*
- * maps the Unicode char to 8bit equivalent
- * XXX currently only gets lower 8bit from the Unicode char
- * and substitutes a '_' for it if the result would be '\0';
- * something better has to be definitely though out
+ * maps the Unicode char to local character
  */
-wchar
+char *
 ntfs_u28(
+	char *outbuf,
 	struct ntfsmount *ntmp, 
 	wchar wc)
 {
-	char *p, *outp, inbuf[3], outbuf[3];
+	char *p, *outp, inbuf[3];
 	size_t ilen, olen;
 
+	outp = outbuf;
 	if (ntfs_iconv && ntmp->ntm_ic_u2l) {
-		ilen = olen = 2;
+		ilen = 2;
+		olen = 4;
 
 		inbuf[0] = (char)(wc>>8);
 		inbuf[1] = (char)wc;
 		inbuf[2] = '\0';
 		p = inbuf;
-		outp = outbuf;
 		ntfs_iconv->convchr(ntmp->ntm_ic_u2l, (const char **)&p, &ilen,
 				    &outp, &olen);
-		if (olen == 1) {
-			return ((wchar)(outbuf[0]&0xFF));
-		} else if (olen == 0) {
-			return ((wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF)));
-		}
-		return ('?');
+		if (olen == 4)
+			*outp++ = '?';
+		*outp = '\0';
+		outp = outbuf;
+		return (outp);
 	}
 
 	p = ntmp->ntm_u28[(wc>>8)&0xFF];
-	if (p == NULL)
-		return ('_');
-	return (p[wc&0xFF]&0xFF);
+	outbuf[0] = (p == NULL) ? '_' : p[wc&0xFF] & 0xFF;
+	outbuf[1] = '\0';
+	return (outp);
 }
 
 wchar
 ntfs_82u(
 	struct ntfsmount *ntmp, 
-	wchar wc,
+	const char *c,
 	int *len)
 {
-	char *p, *outp, inbuf[3], outbuf[3];
+	char *outp, outbuf[3];
 	wchar uc;
 	size_t ilen, olen;
 
@@ -2182,13 +2171,8 @@
 		ilen = (size_t)*len;
 		olen = 2;
 
-		inbuf[0] = (char)(wc>>8);
-		inbuf[1] = (char)wc;
-		inbuf[2] = '\0';
-		p = inbuf;
 		outp = outbuf;
-		ntfs_iconv->convchr(ntmp->ntm_ic_l2u, (const char **)&p, &ilen,
-				    &outp, &olen);
+		ntfs_iconv->convchr(ntmp->ntm_ic_l2u, &c, &ilen, &outp, &olen);
 		*len -= (int)ilen;
 		uc = (wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF));
 
@@ -2196,7 +2180,7 @@
 	}
 
 	if (ntmp->ntm_82u != NULL)
-		return (ntmp->ntm_82u[wc&0xFF]);
+		return (ntmp->ntm_82u[*c&0xFF]);
 
 	return ('?');
 }
diff -ubdwrN src.orig/sys/fs/ntfs/ntfs_subr.h src/sys/fs/ntfs/ntfs_subr.h
--- src.orig/sys/fs/ntfs/ntfs_subr.h	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/ntfs/ntfs_subr.h	2010-09-16 13:49:59.000000000 +0900
@@ -112,9 +112,9 @@
 int ntfs_u28_uninit(struct ntfsmount *ntmp);
 int ntfs_82u_init(struct ntfsmount *ntmp, char *cs_local, char *cs_ntfs);
 int ntfs_82u_uninit(struct ntfsmount *ntmp);
-wchar ntfs_u28(struct ntfsmount *ntmp, wchar wc);
-wchar ntfs_82u(struct ntfsmount *ntmp, wchar wc, int *len);
-#define NTFS_U28(ch)		ntfs_u28(ntmp, (ch))
+char * ntfs_u28(char *, struct ntfsmount *ntmp, wchar wc);
+wchar ntfs_82u(struct ntfsmount *ntmp, const char *c, int *len);
+#define NTFS_U28(ch)		ntfs_u28(tmpbuf, ntmp, (ch))
 #define NTFS_82U(ch, len)	ntfs_82u(ntmp, (ch), len)
 #define	NTFS_UASTRCMP(ustr, ustrlen, astr, astrlen)	\
 	ntfs_uastrcmp(ntmp, (ustr), (ustrlen), (astr), (astrlen))
diff -ubdwrN src.orig/sys/fs/ntfs/ntfs_vnops.c src/sys/fs/ntfs/ntfs_vnops.c
--- src.orig/sys/fs/ntfs/ntfs_vnops.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/ntfs/ntfs_vnops.c	2010-09-16 13:49:59.000000000 +0900
@@ -489,7 +489,7 @@
 	struct uio *uio = ap->a_uio;
 	struct ntfsmount *ntmp = ip->i_mp;
 	int i, j, error = 0;
-	wchar c;
+	char *c, tmpbuf[5];
 	u_int32_t faked = 0, num;
 	int ncookies = 0;
 	struct dirent cde;
@@ -546,11 +546,10 @@
 			if(!ntfs_isnamepermitted(ntmp,iep))
 				continue;
 
-			for(i=0, j=0; i<iep->ie_fnamelen; i++, j++) {
+			for(i=0, j=0; i<iep->ie_fnamelen; i++) {
 				c = NTFS_U28(iep->ie_fname[i]);
-				if (c&0xFF00)
-					cde.d_name[j++] = (char)(c>>8);
-				cde.d_name[j] = (char)c&0xFF;
+				while (*c != '\0')
+					cde.d_name[j++] = *c++;
 			}
 			cde.d_name[j] = '\0';
 			dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
diff -ubdwrN src.orig/sys/fs/smbfs/smbfs_smb.c src/sys/fs/smbfs/smbfs_smb.c
--- src.orig/sys/fs/smbfs/smbfs_smb.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/smbfs/smbfs_smb.c	2010-09-16 13:49:59.000000000 +0900
@@ -40,6 +40,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>
@@ -509,6 +510,10 @@
 		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);
@@ -1025,6 +1030,10 @@
 		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);
@@ -1185,7 +1194,7 @@
 		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
@@ -1268,6 +1277,9 @@
 smbfs_findopenLM2(struct smbfs_fctx *ctx, struct smbnode *dnp,
 	const char *wildcard, int wclen, int attr, struct smb_cred *scred)
 {
+	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;
@@ -1347,6 +1359,9 @@
 		SMBERROR("unexpected info level %d\n", ctx->f_infolevel);
 		return EINVAL;
 	}
+	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);
@@ -1361,6 +1376,10 @@
 			return EBADRPC;
 		}
 	}
+	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)
@@ -1446,6 +1465,13 @@
 			error = smbfs_findnextLM2(ctx, limit);
 		if (error)
 			return error;
+		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] == '.'))
diff -ubdwrN src.orig/sys/fs/smbfs/smbfs_subr.c src/sys/fs/smbfs/smbfs_subr.c
--- src.orig/sys/fs/smbfs/smbfs_subr.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/fs/smbfs/smbfs_subr.c	2010-09-16 13:50:00.000000000 +0900
@@ -136,6 +136,9 @@
 		return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
 	while (i--) {
 		np = *--npp;
+		if (SMB_UNICODE_STRINGS(vcp))
+			error = mb_put_uint16le(mbp, '\\');
+		else
 		error = mb_put_uint8(mbp, '\\');
 		if (error)
 			break;
@@ -154,6 +157,11 @@
 	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) {
@@ -162,6 +170,9 @@
 			return error;
 	}
 	if (name) {
+		if (SMB_UNICODE_STRINGS(vcp))
+			error = mb_put_uint16le(mbp, '\\');
+		else
 		error = mb_put_uint8(mbp, '\\');
 		if (error)
 			return error;
@@ -170,6 +181,8 @@
 			return error;
 	}
 	error = mb_put_uint8(mbp, 0);
+	if (SMB_UNICODE_STRINGS(vcp) && error == 0)
+		error = mb_put_uint8(mbp, 0);
 	return error;
 }
 
@@ -197,6 +210,17 @@
 
 		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 -ubdwrN src.orig/sys/kern/subr_mchain.c src/sys/kern/subr_mchain.c
--- src.orig/sys/kern/subr_mchain.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/kern/subr_mchain.c	2010-09-16 13:50:00.000000000 +0900
@@ -128,6 +128,21 @@
 }
 
 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 -ubdwrN src.orig/sys/libkern/iconv.c src/sys/libkern/iconv.c
--- src.orig/sys/libkern/iconv.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/libkern/iconv.c	2010-09-16 13:50:00.000000000 +0900
@@ -383,6 +383,18 @@
 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 -ubdwrN src.orig/sys/libkern/iconv_alias.c src/sys/libkern/iconv_alias.c
--- src.orig/sys/libkern/iconv_alias.c	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/libkern/iconv_alias.c	2010-09-16 13:50:00.000000000 +0900
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 2006 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/iconv.h>
+
+#include "iconv_converter_if.h"
+
+/*
+ * alias converter
+ */
+
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(iconv_alias, libiconv, 2, 2, 2);
+#endif
+
+struct iconv_alias {
+        KICONV_DRV_COM_FIELDS;
+};
+
+static int
+iconv_alias_open(struct iconv_converter_class *dcp,
+	struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
+{
+	void *dp;
+	const char *cp, *from, *to;
+	struct iconv_alias *dp_base;
+
+	cp = from = (const char *)csp->cp_data;
+	if (from == '\0' || strlen(from) >= ICONV_CSNMAXLEN)
+		goto bad;
+	to = from + strlen(from) + 1;
+	if (to == '\0' || strlen(to) >= ICONV_CSNMAXLEN)
+		goto bad;
+
+	iconv_open(to, from, &dp);
+	if (dp) {
+		dp_base = (struct iconv_alias *)dp;
+		csp->cp_base = dp_base->d_csp;
+		*dpp = dp;
+		return 0;
+	}
+
+bad:
+	*dpp = NULL;
+	return -1;
+}
+
+static int
+iconv_alias_close(void *data)
+{
+	return 0;
+}
+
+static int
+iconv_alias_conv(void *d2p, const char **inbuf,
+	size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+	int convchar, int casetype)
+{
+	return -1;
+}
+
+static const char *
+iconv_alias_name(struct iconv_converter_class *dcp)
+{
+	return ("alias");
+}
+
+static kobj_method_t iconv_alias_methods[] = {
+	KOBJMETHOD(iconv_converter_open,	iconv_alias_open),
+	KOBJMETHOD(iconv_converter_close,	iconv_alias_close),
+	KOBJMETHOD(iconv_converter_conv,	iconv_alias_conv),
+	KOBJMETHOD(iconv_converter_name,	iconv_alias_name),
+	{ NULL, NULL }
+};
+
+KICONV_CONVERTER(alias, sizeof(struct iconv_alias));
diff -ubdwrN src.orig/sys/libkern/iconv_ucs.c src/sys/libkern/iconv_ucs.c
--- src.orig/sys/libkern/iconv_ucs.c	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/libkern/iconv_ucs.c	2010-09-16 13:50:00.000000000 +0900
@@ -0,0 +1,538 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/iconv.h>
+
+#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 {
+	KICONV_DRV_COM_FIELDS;
+	int			convtype;
+	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 (ucs4 == 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 -ubdwrN src.orig/sys/libkern/iconv_xlat.c src/sys/libkern/iconv_xlat.c
--- src.orig/sys/libkern/iconv_xlat.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/libkern/iconv_xlat.c	2010-09-16 13:50:00.000000000 +0900
@@ -53,9 +53,8 @@
  * XLAT converter instance
  */
 struct iconv_xlat {
-	KOBJ_FIELDS;
+	KICONV_DRV_COM_FIELDS;
 	u_char *		d_table;
-	struct iconv_cspair *	d_csp;
 };
 
 static int
diff -ubdwrN src.orig/sys/libkern/iconv_xlat16.c src/sys/libkern/iconv_xlat16.c
--- src.orig/sys/libkern/iconv_xlat16.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/libkern/iconv_xlat16.c	2010-09-16 13:50:00.000000000 +0900
@@ -50,11 +50,10 @@
  * XLAT16 converter instance
  */
 struct iconv_xlat16 {
-	KOBJ_FIELDS;
+	KICONV_DRV_COM_FIELDS;
 	uint32_t *		d_table[0x200];
 	void *			f_ctp;
 	void *			t_ctp;
-	struct iconv_cspair *	d_csp;
 };
 
 static int
diff -ubdwrN src.orig/sys/modules/libiconv/Makefile src/sys/modules/libiconv/Makefile
--- src.orig/sys/modules/libiconv/Makefile	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/modules/libiconv/Makefile	2010-09-16 13:50:00.000000000 +0900
@@ -3,12 +3,13 @@
 .PATH: ${.CURDIR}/../../libkern ${.CURDIR}/../../sys
 
 KMOD=	libiconv
-SRCS=	iconv.c iconv_xlat.c iconv_xlat16.c
+SRCS=	iconv.c iconv_alias.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 -ubdwrN src.orig/sys/modules/libmchain/Makefile src/sys/modules/libmchain/Makefile
--- src.orig/sys/modules/libmchain/Makefile	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/modules/libmchain/Makefile	2010-09-16 13:50:00.000000000 +0900
@@ -11,6 +11,7 @@
 		mb_detach	\
 		mb_fixhdr	\
 		mb_reserve	\
+		mb_put_padbyte	\
 		mb_put_uint8	\
 		mb_put_uint16be	\
 		mb_put_uint16le	\
diff -ubdwrN src.orig/sys/netsmb/smb_conn.c src/sys/netsmb/smb_conn.c
--- src.orig/sys/netsmb/smb_conn.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/netsmb/smb_conn.c	2010-09-16 13:50:00.000000000 +0900
@@ -450,13 +450,29 @@
 		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)
@@ -492,9 +508,17 @@
 	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 -ubdwrN src.orig/sys/netsmb/smb_conn.h src/sys/netsmb/smb_conn.h
--- src.orig/sys/netsmb/smb_conn.h	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/netsmb/smb_conn.h	2010-09-16 13:50:00.000000000 +0900
@@ -248,6 +248,10 @@
 	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 */
@@ -278,6 +282,8 @@
 
 #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 -ubdwrN src.orig/sys/netsmb/smb_smb.c src/sys/netsmb/smb_smb.c
--- src.orig/sys/netsmb/smb_smb.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/netsmb/smb_smb.c	2010-09-16 13:50:00.000000000 +0900
@@ -127,9 +127,17 @@
 	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);
@@ -186,7 +194,7 @@
 					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)
@@ -199,6 +207,13 @@
 			}
 			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 &&
@@ -206,7 +221,13 @@
 				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);
@@ -223,7 +244,7 @@
 				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;
@@ -265,6 +286,12 @@
 		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;
 }
@@ -279,9 +306,13 @@
 	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;
@@ -380,8 +411,7 @@
 	} 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);
@@ -483,24 +513,13 @@
 	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);
@@ -565,6 +584,15 @@
 	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 -ubdwrN src.orig/sys/netsmb/smb_subr.c src/sys/netsmb/smb_subr.c
--- src.orig/sys/netsmb/smb_subr.c	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/netsmb/smb_subr.c	2010-09-16 13:50:00.000000000 +0900
@@ -354,6 +354,8 @@
 	}
 	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);
 }
 
@@ -366,6 +368,8 @@
 	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 -ubdwrN src.orig/sys/sys/iconv.h src/sys/sys/iconv.h
--- src.orig/sys/sys/iconv.h	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/sys/iconv.h	2010-09-16 13:50:00.000000000 +0900
@@ -53,6 +53,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"
 
 /*
@@ -91,13 +92,14 @@
 
 __BEGIN_DECLS
 
-#define	ENCODING_UNICODE	"UTF-16BE"
 #define	KICONV_VENDOR_MICSFT	1	/* Microsoft Vendor Code for quirk */
 
+int   kiconv_add(const char *, const char *, const char *, const void *, int);
 int   kiconv_add_xlat_table(const char *, const char *, const u_char *);
 int   kiconv_add_xlat16_cspair(const char *, const char *, int);
 int   kiconv_add_xlat16_cspairs(const char *, const char *);
 int   kiconv_add_xlat16_table(const char *, const char *, const void *, int);
+int   kiconv_lookup_aliases(const char *tocode, const char *fromcode);
 int   kiconv_lookupconv(const char *drvname);
 int   kiconv_lookupcs(const char *tocode, const char *fromcode);
 const char *kiconv_quirkcs(const char *, int);
@@ -133,6 +135,11 @@
 	TAILQ_ENTRY(iconv_cspair)	cp_link;
 };
 
+/* for the alias converter to look at other instances */
+#define	KICONV_DRV_COM_FIELDS				\
+	KOBJ_FIELDS;					\
+	struct iconv_cspair *	d_csp
+
 #define	KICONV_CONVERTER(name,size)			\
     static struct iconv_converter_class iconv_ ## name ## _class = { \
 	"iconv_"#name, iconv_ ## name ## _methods, size, NULL \
@@ -168,6 +175,7 @@
 	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 -ubdwrN src.orig/sys/sys/mchain.h src/sys/sys/mchain.h
--- src.orig/sys/sys/mchain.h	2009-08-03 17:13:06.000000000 +0900
+++ src/sys/sys/mchain.h	2010-09-16 13:50:00.000000000 +0900
@@ -73,6 +73,7 @@
 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);
diff -ubdwrN src.orig/usr.sbin/Makefile src/usr.sbin/Makefile
--- src.orig/usr.sbin/Makefile	2010-05-26 05:16:36.000000000 +0900
+++ src/usr.sbin/Makefile	2010-09-16 13:50:00.000000000 +0900
@@ -33,6 +33,7 @@
 	ifmcstat \
 	inetd \
 	iostat \
+	kiconvctl \
 	kldxref \
 	mailwrapper \
 	makefs \
diff -ubdwrN src.orig/usr.sbin/kiconvctl/Makefile src/usr.sbin/kiconvctl/Makefile
--- src.orig/usr.sbin/kiconvctl/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ src/usr.sbin/kiconvctl/Makefile	2010-09-16 13:50:00.000000000 +0900
@@ -0,0 +1,14 @@
+#
+# $FreeBSD$
+#
+
+PROG=	kiconvctl
+SRCS=	kiconvctl.c
+MAN=	kiconvctl.8
+DPADD=	${LIBKICONV}
+LDADD=	-lkiconv
+CFLAGS+=	-I../../sys
+
+WARNS?=	2
+
+.include <bsd.prog.mk>
diff -ubdwrN src.orig/usr.sbin/kiconvctl/kiconvctl.8 src/usr.sbin/kiconvctl/kiconvctl.8
--- src.orig/usr.sbin/kiconvctl/kiconvctl.8	1970-01-01 09:00:00.000000000 +0900
+++ src/usr.sbin/kiconvctl/kiconvctl.8	2010-09-16 13:50:00.000000000 +0900
@@ -0,0 +1,97 @@
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd Aug 23, 2005
+.Dt KICONVCTL 8
+.Os
+.Sh NAME
+.Nm kiconvctl
+.Nd kiconv conversion table control program
+.Sh SYNOPSIS
+.Nm
+.Ic add
+.Op Fl v
+.Ar encoding
+.Nm
+.Ic add
+.Op Fl v
+.Fl l Ar locale-name
+.Nm
+.Ic drvlist
+.Nm
+.Ic list
+.Op Fl u
+.Nm
+.Ic load
+.Nm
+.Ic unload
+.Op Fl f
+.Sh DESCRIPTION
+The
+.Nm
+utility provides a way to maintain
+.Xr kiconv 3
+conversion tables.
+.Pp
+The following commands are supported:
+.Bl -tag -width "remove"
+.It Ic add
+Add conversion tables to the kernel.
+If you specify
+.Ar locale-name
+with
+.Fl l
+option, tolower/toupper table is additionally registered.
+.It Ic drvlist
+List all available kiconv drivers.
+.It Ic list
+Show info about all conversion tables in the kernel.
+.It Ic load
+Load LIBICONV kernel module.
+.It Ic unload
+Unload LIBICONV kernel module.
+If you specify
+.Fl f
+option, all related kernel modules will be also unloaded before
+unloading LIBICONV kernel module.
+.El
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with a status of 0 on success
+and with a nonzero status if an error occurs.
+.Sh SEE ALSO
+.Xr iconv 3 ,
+.Xr kiconv 3
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 6.1 .
+.Sh AUTHORS
+.An Ryuichiro Imura
+.Aq imura@ryu16.org .
diff -ubdwrN src.orig/usr.sbin/kiconvctl/kiconvctl.c src/usr.sbin/kiconvctl/kiconvctl.c
--- src.orig/usr.sbin/kiconvctl/kiconvctl.c	1970-01-01 09:00:00.000000000 +0900
+++ src/usr.sbin/kiconvctl/kiconvctl.c	2010-09-16 13:50:00.000000000 +0900
@@ -0,0 +1,420 @@
+/*-
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/iconv.h>
+#include <sys/linker.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static int cspair_add(int, char **);
+#if has_remove_mib
+static int cspair_flush(void);
+#endif
+static int driver_list(void);
+static int cspair_list(int, char **);
+#if has_remove_mib
+static int cspair_remove(int);
+#endif
+static int load_libiconv(void);
+static int unload_libiconv(int, char **);
+static void usage(void);
+
+static const char *iconv_klds[] = {
+	"cd9660_iconv",
+	"msdosfs_iconv",
+	"ntfs_iconv",
+	"smbfs",
+	"udf_iconv"
+};
+
+static int
+cspair_add(int argc, char **argv)
+{
+	int ch, error, verbose;
+	char *locale, *csp;
+
+	error = verbose = 0;
+	locale = NULL;
+	while ((ch = getopt(argc, argv, "l:v")) != -1)
+		switch (ch) {
+		case 'l':
+			locale = optarg;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (locale) {
+		if (argc)
+			usage();
+
+		if (setlocale(LC_CTYPE, locale) == NULL) {
+			warnx("wrong locale name: %s", locale);
+			return (-1);
+		}
+		csp = strchr(locale, '.');
+		if (!csp++)
+			return (-1);
+	} else {
+		csp = *argv;
+
+		if (--argc)
+			usage();
+	}
+
+	if (verbose)
+		printf("Adding tables \"%s\" <-> \"%s\"\n", ENCODING_UNICODE, csp);
+
+	error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE,
+	    kiconv_quirkcs(csp, KICONV_VENDOR_MICSFT));
+	if (error)
+		return (error);
+	error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, csp);
+	if (error)
+		return (error);
+
+	return (error);
+}
+
+#if has_remove_mib
+static int
+cspair_flush(void)
+{
+        struct iconv_cspair_info *csi;
+        size_t i, size;
+	int rval = 0, error;
+
+        if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1)
+                return (-1);
+        if (size > 0) {
+                csi = malloc(size);
+                if (csi == NULL) {
+			warnc(EX_OSERR, "malloc()");
+                        return (-1);
+		}
+                if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) {
+                        free(csi);
+                        return (-1);
+                }
+                for (i = 0; i < (size/sizeof(*csi)); i++, csi++)
+			error = cspair_remove(csi->cs_id);
+			if (error)
+				rval = 1;
+	}
+
+	return (rval);
+}
+#endif
+
+static int
+driver_list(void)
+{
+	char *name;
+	size_t size;
+
+        if (sysctlbyname("kern.iconv.drvlist", NULL, &size, NULL, 0) == -1)
+                return (-1);
+        if (size > 0) {
+		name = malloc(size);
+		if (name == NULL) {
+			warnc(EX_OSERR, "malloc()");
+			return (-1);
+		}
+                if (sysctlbyname("kern.iconv.drvlist", name, &size, NULL, 0) == -1) {
+                        free(name);
+                        return (-1);
+                }
+		while (*name != '\0') {
+			printf("%s\n",name);
+			name += strlen(name) + 1;
+		}
+        }
+
+	return (0);
+}
+
+static int
+cspair_list(int argc, char **argv)
+{
+        struct iconv_cspair_info *csi;
+        size_t i, size;
+	int ch, reg = 1, list = 0;
+	char **fromlist, **tolist, **fp, **tp;
+	char unicode[] = ENCODING_UNICODE;
+
+	while ((ch = getopt(argc, argv, "u")) != -1)
+		switch (ch) {
+		case 'u':
+			if (kiconv_lookupconv(unicode) != 0) {
+				printf("Unicode converter doesn't exist\n");
+				exit(0);
+			}
+			reg = 0;
+			break;
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc)
+		usage();
+
+        if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1)
+                return (-1);
+        if (size > 0) {
+                csi = malloc(size);
+                if (csi == NULL) {
+			warnc(EX_OSERR, "malloc()");
+                        return (-1);
+		}
+                if (sysctlbyname("kern.iconv.cslist", csi, &size, NULL, 0) == -1) {
+                        free(csi);
+                        return (-1);
+                }
+		if (reg) {
+			printf("Loaded Tables\n");
+			printf("Id Refs %-16s %-16s\n", "From","To");
+		} else {
+			printf("Non Unicode Conversion Tables\n");
+			printf(" %-16s|%-16s\n", "From","To");
+			printf(" ----------------+----------------\n");
+			fromlist = malloc(sizeof(*fromlist) * size/sizeof(*csi));
+			if (fromlist == NULL) {
+				warnc(EX_OSERR, "malloc()");
+	                        return (-1);
+			}
+			tolist = malloc(sizeof(*tolist) * size/sizeof(*csi));
+			if (tolist == NULL) {
+				warnc(EX_OSERR, "malloc()");
+	                        return (-1);
+			}
+			fp = fromlist;
+			tp = tolist;
+			*fp++ = unicode;
+			*tp++ = unicode;
+		}
+                for (i = 0; i < (size/sizeof(*csi)); i++, csi++) {
+			if (reg) {
+				printf("%2d %4d %-16s %-16s\n",
+				       csi->cs_id, csi->cs_refcount, csi->cs_from,
+				       csi->cs_to);
+			} else {
+				if (strcmp(csi->cs_to, unicode) == 0) {
+					*fp++ = csi->cs_from;
+				} else if (strcmp(csi->cs_from, unicode) == 0) {
+					*tp++ = csi->cs_to;
+				} else {
+					if (strcmp(csi->cs_to, KICONV_WCTYPE_NAME) == 0)
+						printf(" %-16s|%-16s\n", csi->cs_from, "[de]capitalize");
+					else
+						printf(" %-16s|%-16s\n", csi->cs_from, csi->cs_to);
+					list = 1;
+				}
+			}
+                }
+        }
+	if (!reg) {
+		if (!list)
+			printf("None\n");
+		fp = fromlist;
+		tp = tolist;
+		printf("\n");
+		printf("Possible Conversions using Unicode Converter\n");
+		printf(" %-16s|%-16s\n", "From","To");
+		printf(" ----------------+----------------\n");
+		while (*fp || *tp) {
+			if (*fp)
+				printf(" %-16s|",*fp++);
+			else
+				printf(" %-16s|"," ");
+			if (*tp)
+				printf("%-16s\n",*tp++);
+			else
+				printf("%-16s"," ");
+		}
+		free(fromlist);
+		free(tolist);
+	}
+
+	return (0);
+}
+
+#if has_remove_mib
+static int
+cspair_remove(int id)
+{
+	if (sysctlbyname("kern.iconv.remove", NULL, 0, &id, sizeof(id)) == -1) {
+		warn("Can't remove id %d", id);
+		return (-1);
+	}
+	return (0);
+}
+#endif
+
+static int
+load_libiconv(void)
+{
+	int fileid;
+
+	fileid = kldload("libiconv");
+	if (fileid < 0)
+		return (-1);
+	else
+		return (0);
+}
+
+static int
+unload_libiconv(int argc, char **argv)
+{
+	int ch, i, error = 0, fileid, force = 0;
+
+	while ((ch = getopt(argc, argv, "f")) != -1)
+		switch (ch) {
+		case 'f':
+			force = 1;
+			break;
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+
+	if (argc)
+		usage();
+
+	if ((fileid = kldfind("libiconv")) < 0)
+		return (0);
+
+	if (force) {
+		for (i = 0; i < sizeof(iconv_klds)/sizeof(iconv_klds[0]); i++) {
+			if ((fileid = kldfind(iconv_klds[i])) < 0)
+				continue;
+			if (kldunload(fileid) < 0) {
+				warn("Unloading %s failed.", iconv_klds[i]);
+				error = 1;
+			}
+		}
+		if (error)
+			return (-1);
+	}
+
+	if ((fileid = kldfind("libiconv")) < 0)
+		return (0);
+	if (kldunload(fileid) < 0) {
+		warn("Unloading libiconv failed.");
+		return (-1);
+	}
+	return (0);
+}
+
+int
+main(int argc, char **argv)
+{
+	int error;
+
+	if (argc < 2)
+		usage();
+
+	if (!strcmp(argv[1], "list") && argc >= 2) {
+		error = cspair_list(argc - 1, argv + 1);
+		if (error)
+			err(1, "list failed");
+	} else if (!strcmp(argv[1], "add") && argc >= 3) {
+		error = cspair_add(argc - 1, argv + 1);
+		if (error)
+			err(1, "register failed");
+#if has_remove_mib
+	} else if (!strcmp(argv[1], "flush") && argc == 2) {
+		error = cspair_flush();
+		if (error)
+			err(1, "flush failed");
+	} else if (!strcmp(argv[1], "remove") && argc == 3) {
+		int id;
+		if ((id = (int)strtol(argv[2], (char **)NULL, 10)) == 0)
+			err(1, "%s", argv[2]);
+		error = cspair_remove(id);
+		if (error)
+			err(1, "unregister failed");
+#endif
+	} else if (!strcmp(argv[1], "load") && argc == 2) {
+		error = load_libiconv();
+		if (error)
+			err(1, "can't load libiconv");
+	} else if (!strcmp(argv[1], "unload") && argc >= 2) {
+		error = unload_libiconv(argc - 1, argv + 1);
+		if (error)
+			err(1, "unload failed");
+	} else if (!strcmp(argv[1], "drvlist") && argc == 2) {
+		error = driver_list();
+		if (error)
+			err(1, "list failed");
+	} else
+		usage();
+
+	exit (0);
+}
+
+static void
+usage(void)
+{
+#if has_remove_mib
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+	"usage: kiconvctl add [-v] encoding",
+	"       kiconvctl add [-v] -l locale-name",
+	"       kiconvctl drvlist",
+	"       kiconvctl flush",
+	"       kiconvctl list [-u]",
+	"       kiconvctl load",
+	"       kiconvctl remove id",
+	"       kiconvctl unload [-f]");
+#else
+	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
+	"usage: kiconvctl add [-v] encoding",
+	"       kiconvctl add [-v] -l locale-name",
+	"       kiconvctl drvlist",
+	"       kiconvctl list [-u]",
+	"       kiconvctl load",
+	"       kiconvctl unload [-f]");
+#endif
+	exit(EX_USAGE);
+}

----Next_Part(Sun_Aug_14_15_15_27_2011_750)----
