Merge branch 'master' into kiconv2 kiconv2
authorAlexander Polakov <polachok@gmail.com>
Thu, 3 Sep 2009 16:43:23 +0000 (20:43 +0400)
committerAlexander Polakov <polachok@gmail.com>
Thu, 3 Sep 2009 16:43:23 +0000 (20:43 +0400)
40 files changed:
lib/Makefile
lib/libkiconv/Makefile [new file with mode: 0644]
lib/libkiconv/kiconv.3 [new file with mode: 0644]
lib/libkiconv/quirks.c [new file with mode: 0644]
lib/libkiconv/quirks.h [new file with mode: 0644]
lib/libkiconv/test.c [new file with mode: 0644]
lib/libkiconv/xlat16_iconv.c [new file with mode: 0644]
lib/libkiconv/xlat16_sysctl.c [new file with mode: 0644]
lib/libstand/cd9660.c
sbin/mount_cd9660/Makefile
sbin/mount_cd9660/mount_cd9660.8
sbin/mount_cd9660/mount_cd9660.c
sbin/mount_msdos/Makefile
sbin/mount_msdos/mount_msdos.8
sbin/mount_msdos/mount_msdos.c
sys/libiconv/Makefile
sys/libiconv/iconv.c
sys/libiconv/iconv_converter_if.m
sys/libiconv/iconv_xlat.c
sys/libiconv/iconv_xlat16.c [new file with mode: 0644]
sys/sys/iconv.h
sys/vfs/isofs/cd9660/Makefile
sys/vfs/isofs/cd9660/cd9660_iconv/Makefile [new file with mode: 0644]
sys/vfs/isofs/cd9660/cd9660_iconv/cd9660_iconv.c [new file with mode: 0644]
sys/vfs/isofs/cd9660/cd9660_lookup.c
sys/vfs/isofs/cd9660/cd9660_mount.h
sys/vfs/isofs/cd9660/cd9660_rrip.c
sys/vfs/isofs/cd9660/cd9660_util.c
sys/vfs/isofs/cd9660/cd9660_vfsops.c
sys/vfs/isofs/cd9660/cd9660_vnops.c
sys/vfs/isofs/cd9660/iso.h
sys/vfs/msdosfs/Makefile
sys/vfs/msdosfs/direntry.h
sys/vfs/msdosfs/msdosfs_conv.c
sys/vfs/msdosfs/msdosfs_iconv/Makefile [new file with mode: 0644]
sys/vfs/msdosfs/msdosfs_iconv/msdosfs_iconv.c [new file with mode: 0644]
sys/vfs/msdosfs/msdosfs_lookup.c
sys/vfs/msdosfs/msdosfs_vfsops.c
sys/vfs/msdosfs/msdosfs_vnops.c
sys/vfs/msdosfs/msdosfsmount.h

index d200ab9..332ae0b 100644 (file)
@@ -23,7 +23,7 @@ SUBDIR=       csu \
        libncurses libradius libtacplus libutil libsbuf \
        libalias libatm ${_libbind} ${_libbind9} libbz2 libc ${_libc_r} \
        libcalendar libcam libcompat libdevinfo libdevstat libedit libevent libfetch \
-       libftpio libipsec libipx libisc libkcore libkinfo libkvm libmagic \
+       libftpio libipsec libipx libisc libkcore libkiconv libkinfo libkvm libmagic \
        ${_libmilter} ${_libncp} libnetgraph libopie libpam \
        libpcap libposix1e libsdp libthread_xu libpthread librpcsvc ${_libsm} \
        ${_libsmb} ${_libsmdb} ${_libsmutil} libstand libtelnet libusbhid \
diff --git a/lib/libkiconv/Makefile b/lib/libkiconv/Makefile
new file mode 100644 (file)
index 0000000..3e7ef17
--- /dev/null
@@ -0,0 +1,18 @@
+# $FreeBSD: src/lib/libkiconv/Makefile,v 1.4.8.1 2009/04/15 03:14:26 kensmith Exp $
+
+LIB=           kiconv
+SHLIBDIR?=     /usr/lib
+SRCS=          xlat16_iconv.c xlat16_sysctl.c
+SRCS+=         quirks.c
+
+SHLIB_MAJOR=   3
+
+MAN=           kiconv.3
+
+MLINKS+=       kiconv.3 kiconv_add_xlat16_cspair.3 \
+               kiconv.3 kiconv_add_xlat16_cspairs.3 \
+               kiconv.3 kiconv_add_xlat16_table.3
+
+CFLAGS+=       -I${.CURDIR}/../../sys
+
+.include <bsd.lib.mk>
diff --git a/lib/libkiconv/kiconv.3 b/lib/libkiconv/kiconv.3
new file mode 100644 (file)
index 0000000..619f5cd
--- /dev/null
@@ -0,0 +1,130 @@
+.\"
+.\" Copyright (c) 2003 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: src/lib/libkiconv/kiconv.3,v 1.6.28.1 2009/04/15 03:14:26 kensmith Exp $
+.\"
+.Dd July 17, 2003
+.Dt KICONV 3
+.Os
+.Sh NAME
+.Nm kiconv_add_xlat16_cspair ,
+.Nm kiconv_add_xlat16_cspairs ,
+.Nm kiconv_add_xlat16_table
+.Nd kernel side iconv library
+.Sh LIBRARY
+.Lb libkiconv
+.Sh SYNOPSIS
+.In sys/iconv.h
+.Ft int
+.Fo kiconv_add_xlat16_cspair
+.Fa "const char *tocode"
+.Fa "const char *fromcode"
+.Fa "int flag"
+.Fc
+.Ft int
+.Fo kiconv_add_xlat16_cspairs
+.Fa "const char *foreigncode"
+.Fa "const char *localcode"
+.Fc
+.Ft int
+.Fo kiconv_add_xlat16_table
+.Fa "const char *tocode"
+.Fa "const char *fromcode"
+.Fa "const void *data"
+.Fa "int datalen"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm kiconv
+library provides multi-byte character conversion tables for kernel side
+iconv service.
+.Pp
+The
+.Fn kiconv_add_xlat16_cspair
+function
+defines a conversion table using
+.Xr iconv 3
+between
+.Fa fromcode
+charset and
+.Fa tocode
+charset.
+You can specify
+.Fa flag
+to determine if
+.Xr tolower 3
+/
+.Xr toupper 3
+conversion is included in the table.
+The
+.Fa flag
+has following values.
+.Pp
+.Bl -tag -width ".Dv KICONV_FROM_LOWER" -compact
+.It Dv KICONV_LOWER
+.It Dv KICONV_FROM_LOWER
+It generates a tolower table in addition to a character conversion table.
+The difference between two is tolower
+.Fa tocode
+or tolower
+.Fa fromcode .
+.It Dv KICONV_UPPER
+.It Dv KICONV_FROM_UPPER
+It generates a toupper table in addition to a character conversion table.
+The difference between two is toupper
+.Fa tocode
+or toupper
+.Fa fromcode .
+.El
+.Pp
+A tolower/toupper conversion is limited to single-byte characters.
+.Pp
+The
+.Fn kiconv_add_xlat16_cspairs
+function
+defines two conversion tables which are from
+.Fa localcode
+to
+.Fa foreigncode
+and from
+.Fa foreigncode
+to
+.Fa localcode .
+These conversion tables also contain both tolower and toupper tables.
+.Pp
+The
+.Fn kiconv_add_xlat16_table
+function
+defines a conversion table directly pointed by
+.Fa data
+whose length is
+.Fa datalen ,
+not using
+.Xr iconv 3 .
+.Sh SEE ALSO
+.Xr iconv 3 ,
+.Xr tolower 3 ,
+.Xr toupper 3 ,
+.Xr iconv 9
diff --git a/lib/libkiconv/quirks.c b/lib/libkiconv/quirks.c
new file mode 100644 (file)
index 0000000..95cc807
--- /dev/null
@@ -0,0 +1,192 @@
+/*-
+ * Copyright (c) 2003 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: src/lib/libkiconv/quirks.c,v 1.1.30.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+/*
+ * kiconv(3) requires shared linked, and reduce module size
+ * when statically linked.
+ */
+
+#ifdef PIC
+
+/*
+ * Why do we need quirks?
+ * Since each vendors has their own Unicode mapping rules,
+ * we need some quirks until iconv(3) supports them.
+ * We can define Microsoft mappings here.
+ *
+ * For example, the eucJP and Unocode mapping rule is based on
+ * the JIS standard. Since Microsoft uses cp932 for Unicode mapping
+ * witch is not truly based on the JIS standard, reading a file
+ * system created by Microsoft Windows family using eucJP/Unicode
+ * mapping rule will cause a problem. That's why we define eucJP-ms here.
+ * The eucJP-ms has been defined by The Open Group Japan Vendor Coucil.
+ *
+ * Well, Apple Mac OS also has their own Unicode mappings,
+ * but we won't require these quirks here, because HFS doesn't have
+ * Unicode and HFS+ has decomposed Unicode which can not be
+ * handled by this xlat16 converter.
+ */
+
+#include <sys/types.h>
+#include <sys/iconv.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "quirks.h"
+
+/*
+ * All lists of quirk character set
+ */
+static struct {
+       int vendor; /* reserved for non MS mapping */
+       const char *base_codeset, *quirk_codeset;
+} quirk_list[] = {
+       { KICONV_VENDOR_MICSFT, "eucJP", "eucJP-ms" },
+       { KICONV_VENDOR_MICSFT, "EUC-JP", "eucJP-ms" },
+       { KICONV_VENDOR_MICSFT, "SJIS", "SJIS-ms" },
+       { KICONV_VENDOR_MICSFT, "Shift_JIS", "SJIS-ms" },
+       { KICONV_VENDOR_MICSFT, "Big5", "Big5-ms" }
+};
+
+/*
+ * The character list to replace for Japanese MS-Windows.
+ */
+static struct quirk_replace_list quirk_jis_cp932[] = {
+       { 0x00a2, 0xffe0 }, /* Cent Sign, Fullwidth Cent Sign */
+       { 0x00a3, 0xffe1 }, /* Pound Sign, Fullwidth Pound Sign */
+       { 0x00ac, 0xffe2 }, /* Not Sign, Fullwidth Not Sign */
+       { 0x2016, 0x2225 }, /* Double Vertical Line, Parallel To */
+       { 0x203e, 0x007e }, /* Overline, Tilde */
+       { 0x2212, 0xff0d }, /* Minus Sign, Fullwidth Hyphenminus */
+       { 0x301c, 0xff5e }  /* Wave Dash, Fullwidth Tilde */
+};
+
+/*
+ * All entries of quirks
+ */
+#define        NumOf(n)        (sizeof((n)) / sizeof((n)[0]))
+static struct {
+       const char *quirk_codeset, *iconv_codeset, *pair_codeset;
+       struct quirk_replace_list (*replace_list)[];
+       size_t num_of_replaces;
+} quirk_table[] = {
+       {
+               "eucJP-ms", "eucJP", ENCODING_UNICODE,
+               (struct quirk_replace_list (*)[])&quirk_jis_cp932,
+               NumOf(quirk_jis_cp932)
+       },
+       {
+               "SJIS-ms", "CP932", ENCODING_UNICODE,
+               /* XXX - quirk_replace_list should be NULL */
+               (struct quirk_replace_list (*)[])&quirk_jis_cp932,
+               NumOf(quirk_jis_cp932)
+       },
+       {
+               "Big5-ms", "CP950", ENCODING_UNICODE,
+               NULL, 0
+       }
+};
+
+
+const char *
+kiconv_quirkcs(const char* base, int vendor)
+{
+       size_t i;
+
+       /*
+        * We should compare codeset names ignoring case here,
+        * so that quirk could be used for all of the user input
+        * patterns.
+        */
+       for (i = 0; i < NumOf(quirk_list); i++)
+               if (quirk_list[i].vendor == vendor &&
+                   strcasecmp(quirk_list[i].base_codeset, base) == 0)
+                       return (quirk_list[i].quirk_codeset);
+
+       return (base);
+}
+
+/*
+ * Internal Functions
+ */
+const char *
+search_quirk(const char *given_codeset,
+            const char *pair_codeset,
+            struct quirk_replace_list **replace_list,
+            size_t *num_of_replaces)
+{
+       size_t i;
+
+       *replace_list = NULL;
+       *num_of_replaces = 0;
+       for (i = 0; i < NumOf(quirk_table); i++)
+               if (strcmp(quirk_table[i].quirk_codeset, given_codeset) == 0) {
+                       if (strcmp(quirk_table[i].pair_codeset, pair_codeset) == 0) {
+                               *replace_list = *quirk_table[i].replace_list;
+                               *num_of_replaces = quirk_table[i].num_of_replaces;
+                       }
+                       return (quirk_table[i].iconv_codeset);
+               }
+
+       return (given_codeset);
+}
+
+uint16_t
+quirk_vendor2unix(uint16_t c, struct quirk_replace_list *replace_list, size_t num)
+{
+       size_t i;
+
+       for (i = 0; i < num; i++)
+               if (replace_list[i].vendor_code == c)
+                       return (replace_list[i].standard_code);
+
+       return (c);
+}
+
+uint16_t
+quirk_unix2vendor(uint16_t c, struct quirk_replace_list *replace_list, size_t num)
+{
+       size_t i;
+
+       for (i = 0; i < num; i++)
+               if (replace_list[i].standard_code == c)
+                       return (replace_list[i].vendor_code);
+
+       return (c);
+}
+
+#else /* statically linked */
+
+const char *
+kiconv_quirkcs(const char* base, int vendor)
+{
+       return (base);
+}
+
+#endif /* PIC */
diff --git a/lib/libkiconv/quirks.h b/lib/libkiconv/quirks.h
new file mode 100644 (file)
index 0000000..bec16fe
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2003 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: src/lib/libkiconv/quirks.h,v 1.1.30.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#ifndef _KICONV_QUIRKS_H_
+#define _KICONV_QUIRKS_H_
+
+struct quirk_replace_list {
+       uint16_t standard_code, vendor_code;
+};
+
+const char *search_quirk(const char *, const char *,
+                        struct quirk_replace_list **, size_t *);
+uint16_t quirk_vendor2unix(uint16_t,
+                         struct quirk_replace_list *,
+                         size_t);
+uint16_t quirk_unix2vendor(uint16_t,
+                         struct quirk_replace_list *,
+                         size_t);
+
+#endif /* _KICONV_QUIRKS_H_ */
diff --git a/lib/libkiconv/test.c b/lib/libkiconv/test.c
new file mode 100644 (file)
index 0000000..1e3eb30
--- /dev/null
@@ -0,0 +1,11 @@
+#include <sys/iconv.h>
+int main() {
+       int error = 0;
+       error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, "UTF-8");
+        if(error)
+               printf("fail\n");
+       error = kiconv_add_xlat16_cspairs("KOI8-R", "UTF-8");
+        if(error)
+               printf("fail\n");
+       return error;
+}
diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c
new file mode 100644 (file)
index 0000000..a550bc9
--- /dev/null
@@ -0,0 +1,394 @@
+/*-
+ * Copyright (c) 2003 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: src/lib/libkiconv/xlat16_iconv.c,v 1.4.8.1 2009/04/15 03:14:26 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>
+
+#include <ctype.h>
+#include <dlfcn.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "quirks.h"
+
+typedef void *iconv_t;
+
+struct xlat16_table {
+       uint32_t *      idx[0x200];
+       void *          data;
+       size_t          size;
+};
+
+static struct xlat16_table kiconv_xlat16_open(const char *, const char *, int);
+
+static int my_iconv_init(void);
+static iconv_t (*my_iconv_open)(const char *, const char *);
+static size_t (*my_iconv)(iconv_t, const char **, size_t *, char **, size_t *);
+static int (*my_iconv_close)(iconv_t);
+static size_t my_iconv_char(iconv_t, const u_char **, size_t *, u_char **, size_t *);
+
+int
+kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
+{
+       int error;
+       size_t i, size, idxsize;
+       struct iconv_cspair_info *csi;
+       struct xlat16_table xt;
+       void *data;
+       char *p;
+       if (sysctlbyname("kern.iconv.cslist", NULL, &size, NULL, 0) == -1)
+               return (-1);
+       if (size > 0) {
+               csi = malloc(size);
+               if (csi == NULL)
+                       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++){
+                       if (strcmp(csi->cs_to, tocode) == 0 &&
+                           strcmp(csi->cs_from, fromcode) == 0)
+                               return (0);
+               }
+       }
+
+       xt = kiconv_xlat16_open(tocode, fromcode, flag);
+       if (xt.size == 0)
+               return (-1);
+
+       idxsize = sizeof(xt.idx);
+
+       if ((idxsize + xt.size) > ICONV_CSMAXDATALEN) {
+               errno = E2BIG;
+fprintf(stderr, "%d > %d (%d)\n", (idxsize+xt.size), ICONV_CSMAXDATALEN, sizeof(u_int32_t));
+               return (-1);
+       }
+
+       if ((data = malloc(idxsize + xt.size)) != NULL) {
+               p = data;
+               memcpy(p, xt.idx, idxsize);
+               p += idxsize;
+               memcpy(p, xt.data, xt.size);
+               error = kiconv_add_xlat16_table(tocode, fromcode, data,
+                   (int)(idxsize + xt.size));
+               return (error);
+       }
+       return (-1);
+}
+
+int
+kiconv_add_xlat16_cspairs(const char *foreigncode, const char *localcode)
+{
+       int error;
+
+       error = kiconv_add_xlat16_cspair(foreigncode, localcode,
+           KICONV_FROM_LOWER | KICONV_FROM_UPPER);
+       if (error)
+               return (error);
+       error = kiconv_add_xlat16_cspair(localcode, foreigncode,
+           KICONV_LOWER | KICONV_UPPER);
+       if (error)
+               return (error);
+       return (0);
+}
+
+static struct xlat16_table
+kiconv_xlat16_open(const char *tocode, const char *fromcode, int lcase)
+{
+       u_char src[3], dst[4], *srcp, *dstp, ud, ld;
+       int us, ls, ret;
+       uint16_t c;
+       uint32_t table[0x80];
+       size_t inbytesleft, outbytesleft, pre_q_size, post_q_size;
+       struct xlat16_table xt;
+       struct quirk_replace_list *pre_q_list, *post_q_list;
+       iconv_t cd;
+       char *p;
+
+       xt.data = NULL;
+       xt.size = 0;
+
+       src[2] = '\0';
+       dst[3] = '\0';
+       ret = my_iconv_init();
+       if (ret)
+               return (xt);
+       cd = my_iconv_open(search_quirk(tocode, fromcode, &pre_q_list, &pre_q_size),
+           search_quirk(fromcode, tocode, &post_q_list, &post_q_size));
+       if (cd == (iconv_t) (-1))
+               return (xt);
+
+       if ((xt.data = malloc(0x200 * 0x80 * sizeof(uint32_t))) == NULL)
+               return (xt);
+
+       p = xt.data;
+
+       for (ls = 0 ; ls < 0x200 ; ls++) {
+               xt.idx[ls] = NULL;
+               for (us = 0 ; us < 0x80 ; us++) {
+                       srcp = src;
+                       dstp = dst;
+
+                       inbytesleft = 2;
+                       outbytesleft = 3;
+                       bzero(dst, outbytesleft);
+
+                       c = ((ls & 0x100 ? us | 0x80 : us) << 8) | (u_char)ls;
+                       c = quirk_vendor2unix(c, pre_q_list, pre_q_size);
+                       src[0] = (u_char)(c >> 8);
+                       src[1] = (u_char)c;
+
+                       ret = my_iconv_char(cd, (const u_char **)&srcp,
+                           &inbytesleft, &dstp, &outbytesleft);
+                       if (ret == -1) {
+                               table[us] = 0;
+                               continue;
+                       }
+
+                       ud = (u_char)dst[0];
+                       ld = (u_char)dst[1];
+
+                       switch(outbytesleft) {
+                       case 0:
+#ifdef XLAT16_ACCEPT_3BYTE_CHR
+                               table[us] = (ud << 8) | ld;
+                               table[us] |= (u_char)dst[2] << 16;
+                               table[us] |= XLAT16_IS_3BYTE_CHR;
+#else
+                               table[us] = 0;
+                               continue;
+#endif
+                               break;
+                       case 1:
+                               table[us] = quirk_unix2vendor((ud << 8) | ld,
+                                   post_q_list, post_q_size);
+                               if ((table[us] >> 8) == 0)
+                                       table[us] |= XLAT16_ACCEPT_NULL_OUT;
+                               break;
+                       case 2:
+                               table[us] = ud;
+                               if (lcase & KICONV_LOWER && ud != tolower(ud)) {
+                                       table[us] |= (u_char)tolower(ud) << 16;
+                                       table[us] |= XLAT16_HAS_LOWER_CASE;
+                               }
+                               if (lcase & KICONV_UPPER && ud != toupper(ud)) {
+                                       table[us] |= (u_char)toupper(ud) << 16;
+                                       table[us] |= XLAT16_HAS_UPPER_CASE;
+                               }
+                               break;
+                       }
+
+                       switch(inbytesleft) {
+                       case 0:
+                               if ((ls & 0xff) == 0)
+                                       table[us] |= XLAT16_ACCEPT_NULL_IN;
+                               break;
+                       case 1:
+                               c = ls > 0xff ? us | 0x80 : us;
+                               if (lcase & KICONV_FROM_LOWER && c != tolower(c)) {
+                                       table[us] |= (u_char)tolower(c) << 16;
+                                       table[us] |= XLAT16_HAS_FROM_LOWER_CASE;
+                               }
+                               if (lcase & KICONV_FROM_UPPER && c != toupper(c)) {
+                                       table[us] |= (u_char)toupper(c) << 16;
+                                       table[us] |= XLAT16_HAS_FROM_UPPER_CASE;
+                               }
+                               break;
+                       }
+
+                       if (table[us] == 0)
+                               continue;
+
+                       /*
+                        * store not NULL
+                        */
+                       xt.idx[ls] = table;
+               }
+               if (xt.idx[ls]) {
+                       memcpy(p, table, sizeof(table));
+                       p += sizeof(table);
+               }
+       }
+       my_iconv_close(cd);
+
+       xt.size = p - (char *)xt.data;
+       xt.data = realloc(xt.data, xt.size);
+       return (xt);
+}
+
+static int
+my_iconv_init(void)
+{
+       void *iconv_lib;
+
+       iconv_lib = dlopen("libc.so", RTLD_LAZY | RTLD_GLOBAL);
+       if (iconv_lib == NULL) {
+               warn("Unable to load iconv library: %s\n", dlerror());
+               errno = ENOENT;
+               return (-1);
+       }
+       my_iconv_open = dlsym(iconv_lib, "iconv_open");
+       my_iconv = dlsym(iconv_lib, "iconv");
+       my_iconv_close = dlsym(iconv_lib, "iconv_close");
+
+       return (0);
+}
+
+static size_t
+my_iconv_char(iconv_t cd, const u_char **ibuf, size_t * ilen, u_char **obuf,
+       size_t * olen)
+{
+       const u_char *sp;
+       u_char *dp, ilocal[3], olocal[3];
+       u_char c1, c2;
+       int ret;
+       size_t ir, or;
+
+       sp = *ibuf;
+       dp = *obuf;
+       ir = *ilen;
+
+       bzero(*obuf, *olen);
+       ret = my_iconv(cd, (const char **)&sp, ilen, (char **)&dp, olen);
+       c1 = (*obuf)[0];
+       c2 = (*obuf)[1];
+
+       if (ret == -1) {
+               if (*ilen == ir - 1 && (*ibuf)[1] == '\0' && (c1 || c2))
+                       return (0);
+               else
+                       return (-1);
+       }
+
+       /*
+        * We must judge if inbuf is a single byte char or double byte char.
+        * Here, to judge, try first byte(*sp) conversion and compare.
+        */
+       ir = 1;
+       or = 3;
+
+       bzero(olocal, or);
+       memcpy(ilocal, *ibuf, sizeof(ilocal));
+       sp = ilocal;
+       dp = olocal;
+
+       if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+               if (olocal[0] != c1)
+                       return (ret);
+
+               if (olocal[1] == c2 && (*ibuf)[1] == '\0') {
+                       /*
+                        * inbuf is a single byte char
+                        */
+                       *ilen = 1;
+                       *olen = or;
+                       return (ret);
+               }
+
+               switch(or) {
+               case 0:
+               case 1:
+                       if (olocal[1] == c2) {
+                               /*
+                                * inbuf is a single byte char,
+                                * so return false here.
+                                */
+                               return (-1);
+                       } else {
+                               /*
+                                * inbuf is a double byte char
+                                */
+                               return (ret);
+                       }
+                       break;
+               case 2:
+                       /*
+                        * should compare second byte of inbuf
+                        */
+                       break;
+               }
+       } else {
+               /*
+                * inbuf clould not be splitted, so inbuf is
+                * a double byte char.
+                */
+               return (ret);
+       }
+
+       /*
+        * try second byte(*(sp+1)) conversion, and compare
+        */
+       ir = 1;
+       or = 3;
+
+       bzero(olocal, or);
+
+       sp = ilocal + 1;
+       dp = olocal;
+
+       if ((my_iconv(cd,(const char **)&sp, &ir, (char **)&dp, &or)) != -1) {
+               if (olocal[0] == c2)
+                       /*
+                        * inbuf is a single byte char
+                        */
+                       return (-1);
+       }
+
+       return (ret);
+}
+
+#else /* statically linked */
+
+#include <errno.h>
+
+int
+kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag)
+{
+       errno = EINVAL;
+       return (-1);
+}
+
+int
+kiconv_add_xlat16_cspairs(const char *tocode, const char *fromcode)
+{
+       errno = EINVAL;
+       return (-1);
+}
+
+#endif /* PIC */
diff --git a/lib/libkiconv/xlat16_sysctl.c b/lib/libkiconv/xlat16_sysctl.c
new file mode 100644 (file)
index 0000000..8083619
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2000-2001, Boris Popov
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    This product includes software developed by Boris Popov.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * 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: src/lib/libkiconv/xlat16_sysctl.c,v 1.2.8.1 2009/04/15 03:14:26 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>
+
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+int
+kiconv_add_xlat16_table(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(from) >= ICONV_CSNMAXLEN || strlen(to) >= ICONV_CSNMAXLEN)
+               return (EINVAL);
+       din.ia_version = ICONV_ADD_VER;
+       strcpy(din.ia_converter, "xlat16");
+       strcpy(din.ia_from, from);
+       strcpy(din.ia_to, to);
+       din.ia_data = data;
+       din.ia_datalen = datalen;
+       olen = sizeof(dout);
+       if (sysctlbyname("kern.iconv.add", &dout, &olen, &din, sizeof(din)) == -1)
+               return (errno);
+       return (0);
+}
+
+#else /* statically linked */
+
+#include <errno.h>
+
+int
+kiconv_add_xlat16_table(const char *to, const char *from, const void *data, int datalen)
+{
+       return (EINVAL);
+}
+
+#endif /* PIC */
index 77ceb2c..8f2a990 100644 (file)
@@ -117,19 +117,6 @@ struct ptable_ent {
 
 #define        cdb2devb(bno)   ((bno) * ISO_DEFAULT_BLOCK_SIZE / DEV_BSIZE)
 
-/* XXX these should be in the system headers */
-static __inline int
-isonum_722(u_char *p)
-{
-       return (*p << 8)|p[1];
-}
-
-static __inline int
-isonum_732(u_char *p)
-{
-       return (*p << 24)|(p[1] << 16)|(p[2] << 8)|p[3];
-}
-
 static ISO_SUSP_HEADER *
 susp_lookup_record(struct open_file *f, const char *identifier,
     struct iso_directory_record *dp, int lenskip)
index 77705c2..a210de3 100644 (file)
@@ -5,9 +5,11 @@
 PROG=  mount_cd9660
 SRCS=  mount_cd9660.c getmntopts.c
 MAN=   mount_cd9660.8
+LDADD=  -lutil -lkiconv
 
 MOUNT= ${.CURDIR}/../mount
 CFLAGS+= -I${MOUNT}
+NOSHARED= no
 .PATH: ${MOUNT}
 
 .include <bsd.prog.mk>
index 9cdc7d8..26d6efe 100644 (file)
@@ -75,6 +75,8 @@ In either case, files may be opened without explicitly stating a
 version number.
 .It Fl j
 Do not use any Joliet extensions included in the file system.
+.It Fl L Ar locale
+Specify locale name used for internal filename conversions.
 .It Fl o
 Options are specified with a
 .Fl o
index 54b17a1..1e68732 100644 (file)
 #include <sys/file.h>
 #include <sys/param.h>
 #include <sys/mount.h>
-#include <sys/../vfs/isofs/cd9660/cd9660_mount.h>
+#include <sys/iconv.h>
+#include <sys/linker.h>
+#include <sys/module.h>
+#include <vfs/isofs/cd9660/cd9660_mount.h>
 
 #include <err.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <locale.h>
 #include <sysexits.h>
 #include <unistd.h>
 
@@ -72,6 +76,7 @@ struct mntopt mopts[] = {
 
 static int     get_ssector(const char *dev);
 static void    usage(void);
+int set_charset(struct iso_args *args, const char *cs_local, const char *cs_disk);
 
 int
 main(int argc, char **argv)
@@ -81,11 +86,15 @@ main(int argc, char **argv)
        char *dev, *dir, mntpath[MAXPATHLEN];
        struct vfsconf vfc;
        int error, verbose;
+       char *csp;
+       const char *quirk;
+       char *cs_local = NULL;
+        char *cs_disk = NULL;
 
        mntflags = opts = verbose = 0;
        memset(&args, 0, sizeof args);
        args.ssector = -1;
-       while ((ch = getopt(argc, argv, "begjo:rs:v")) != -1)
+       while ((ch = getopt(argc, argv, "begjo:rs:L:v")) != -1)
                switch (ch) {
                case 'b':
                        opts |= ISOFSMNT_BROKENJOLIET;
@@ -99,6 +108,16 @@ main(int argc, char **argv)
                case 'j':
                        opts |= ISOFSMNT_NOJOLIET;
                        break;
+               case 'L':
+                       if (setlocale(LC_CTYPE, optarg) == NULL)
+                                err(EX_CONFIG, "%s", optarg);
+                        csp = strchr(optarg,'.');
+                        if (!csp)
+                                err(EX_CONFIG, "%s", optarg);
+                        quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT);
+                        cs_local = strdup(quirk);
+                       opts |= ISOFSMNT_KICONV;
+                       break;
                case 'o':
                        getmntopts(optarg, mopts, &mntflags, &opts);
                        break;
@@ -141,6 +160,9 @@ main(int argc, char **argv)
        args.export.ex_root = DEFAULT_ROOTUID;
        args.flags = opts;
 
+       if (set_charset(&args, cs_local, cs_disk) == -1)
+               err(EX_OSERR, "msdos_iconv");
+
        if (args.ssector == -1) {
                /*
                 * The start of the session has not been specified on
@@ -176,6 +198,31 @@ main(int argc, char **argv)
        exit(0);
 }
 
+int
+set_charset(struct iso_args *args, const char *cs_local, const char *cs_disk)
+{
+        int error;
+        if (modfind("cd9660_iconv") < 0) {
+                if (kldload("cd9660_iconv") < 0 || modfind("cd9660_iconv") < 0)
+                {
+                        warnx("cannot find or load \"cd9660_iconv\" kernel module");
+                        return (-1);
+                }
+        }
+        snprintf(args->cs_local, ICONV_CSNMAXLEN, "%s", cs_local);
+        error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local);
+        if (error)
+                return (-1);
+        if (!cs_disk)
+                cs_disk = strdup(ENCODING_UNICODE);
+        snprintf(args->cs_disk, ICONV_CSNMAXLEN, "%s", cs_disk);
+        error = kiconv_add_xlat16_cspairs(cs_disk, cs_local);
+        if (error)
+                return (-1);
+        return (0);
+}
+
+
 static void
 usage(void)
 {
index 59dd979..d9651ee 100644 (file)
@@ -7,10 +7,11 @@ PROG= mount_msdos
 SRCS=  mount_msdos.c getmntopts.c
 MAN=   mount_msdos.8
 DPADD= ${LIBUTIL}
-LDADD= -lutil
+LDADD= -lutil -lkiconv
 
-MOUNT= ${.CURDIR}/../mount
-CFLAGS+= -I${MOUNT}
+MOUNT= ${.CURDIR}/../mount
+CFLAGS= -I${MOUNT}
+NOSHARED= no
 .PATH: ${MOUNT}
 
 TABDIR= ${DESTDIR}${LIBDATADIR}/msdosfs
index b503dd5..5942c7c 100644 (file)
@@ -147,36 +147,9 @@ This forces
 Specify locale name used for internal uppercase and lowercase conversions
 for DOS and Win'95 names.
 By default ISO 8859-1 assumed as local character set.
-.It Fl W Ar table
-Specify text file with 3 conversion tables:
-.Bl -enum
-.It
-Local character set to Unicode conversion table (upper half) for Win'95 long
-names, 128 Unicode codes separated by 8 per row.
-If some code not present in Unicode, use
-0x003F code ('?') as replacement.
-.It
-DOS to local character set conversion table (upper half) for DOS names,
-128 character codes separated by 8 per row.
-Code 0x3F ('?') used for impossible translations.
-.It
-Local character set to DOS conversion table (upper half) for DOS names,
-128 character codes separated by 8 per row.
-Some codes have special meaning:
-.Bl -hang
-.It 0x00
-character disallowed in DOS file name;
-.It 0x01
-character should be replaced by '_' in DOS file name;
-.It 0x02
-character should be skipped in DOS file name;
-.El
-.El
-.Pp
-By default ISO 8859-1 assumed as local character set.
-If file path isn't absolute,
-.Pa /usr/libdata/msdosfs/
-prefix prepended.
+.It Fl D Ar DOS_codepage
+Specify the MS-DOS code page (aka IBM/OEM code page) name used for
+file name conversions for DOS names.
 .El
 .Sh FILES
 .Bl -tag -width /usr/libdata/msdosfs -compact
index 9a0b4a3..d7a4d8a 100644 (file)
@@ -36,7 +36,9 @@
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
-
+#include <sys/iconv.h>
+#include <sys/linker.h>
+#include <sys/module.h>
 #include <vfs/msdosfs/msdosfsmount.h>
 
 #include <ctype.h>
@@ -56,7 +58,7 @@
 
 /*
  * XXX - no way to specify "foo=<bar>"-type options; that's what we'd
- * want for "-u", "-g", "-m", "-L", and "-W".
+ * want for "-u", "-g", "-m", "-L", and "-D".
  */
 static struct mntopt mopts[] = {
        MOPT_STDOPTS,
@@ -76,8 +78,7 @@ static gid_t  a_gid(char *);
 static uid_t   a_uid(char *);
 static mode_t  a_mask(char *);
 static void    usage(void) __dead2;
-static void     load_u2wtable(struct msdosfs_args *, char *);
-static void     load_ultable(struct msdosfs_args *, char *);
+int set_charset(struct msdosfs_args*, const char*, const char*);
 
 int
 main(int argc, char **argv)
@@ -85,14 +86,16 @@ main(int argc, char **argv)
        struct msdosfs_args args;
        struct stat sb;
        int c, error, mntflags, set_gid, set_uid, set_mask;
-       char *dev, *dir, mntpath[MAXPATHLEN];
+       char *dev, *dir, mntpath[MAXPATHLEN], *csp;
+       const char *quirk = NULL;
+        char *cs_local = NULL;
+        char *cs_dos = NULL;
        struct vfsconf vfc;
-
        mntflags = set_gid = set_uid = set_mask = 0;
        memset(&args, '\0', sizeof(args));
        args.magic = MSDOSFS_ARGSMAGIC;
 
-       while ((c = getopt(argc, argv, "sl9u:g:m:o:L:W:")) != -1) {
+       while ((c = getopt(argc, argv, "sl9u:g:m:o:L:D:")) != -1) {
                switch (c) {
 #ifdef MSDOSFSMNT_GEMDOSFS
                case 'G':
@@ -121,12 +124,19 @@ main(int argc, char **argv)
                        set_mask = 1;
                        break;
                case 'L':
-                       load_ultable(&args, optarg);
-                       args.flags |= MSDOSFSMNT_ULTABLE;
+                        if (setlocale(LC_CTYPE, optarg) == NULL)
+                                err(EX_CONFIG, "%s", optarg);
+                        csp = strchr(optarg,'.');
+                        if (!csp)
+                                err(EX_CONFIG, "%s", optarg);
+                       quirk = kiconv_quirkcs(csp + 1, KICONV_VENDOR_MICSFT);
+                       cs_local = strdup(quirk);
+                       args.flags |= MSDOSFSMNT_KICONV;
                        break;
-               case 'W':
-                       load_u2wtable(&args, optarg);
-                       args.flags |= MSDOSFSMNT_U2WTABLE;
+               case 'D':
+                       csp = optarg;
+                       cs_dos = strdup(optarg);
+                       args.flags |= MSDOSFSMNT_KICONV;
                        break;
                case 'o':
                        getmntopts(optarg, mopts, &mntflags, &args.flags);
@@ -153,6 +163,15 @@ main(int argc, char **argv)
 
        args.fspec = dev;
        args.export.ex_root = -2;       /* unchecked anyway on DOS fs */
+
+        if (cs_local != NULL) {
+                if (set_charset(&args, cs_local, cs_dos) == -1)
+                        err(EX_OSERR, "msdos_iconv");
+        } else if (cs_dos != NULL) {
+                if (set_charset(&args, "ISO8859-1", cs_dos) == -1)
+                        err(EX_OSERR, "msdos_iconv");
+        }
+
        if (mntflags & MNT_RDONLY)
                args.export.ex_flags = MNT_EXRDONLY;
        else
@@ -245,84 +264,30 @@ usage(void)
 {
        fprintf(stderr, "%s\n%s\n", 
        "usage: mount_msdos [-o options] [-u user] [-g group] [-m mask]",
-       "                   [-s] [-l] [-9] [-L locale] [-W table] bdev dir");
+       "                   [-s] [-l] [-9] [-L locale] [-D codepage] bdev dir");
        exit(EX_USAGE);
 }
 
-static void
-load_u2wtable (struct msdosfs_args *pargs, char *name)
-{
-       FILE *f;
-       int i, j, code[8];
-       size_t line = 0;
-       char buf[128];
-       char *fn, *s, *p;
-
-       if (*name == '/')
-               fn = name;
-       else {
-               snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
-               buf[127] = '\0';
-               fn = buf;
-       }
-       if ((f = fopen(fn, "r")) == NULL)
-               err(EX_NOINPUT, "%s", fn);
-       p = NULL;
-       for (i = 0; i < 16; i++) {
-               do {
-                       if (p != NULL) free(p);
-                       if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
-                               errx(EX_DATAERR, "can't read u2w table row %d near line %zu", i, line);
-                       while (isspace((unsigned char)*s))
-                               s++;
-               } while (*s == '\0');
-               if (sscanf(s, "%i%i%i%i%i%i%i%i",
-code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
-                       errx(EX_DATAERR, "u2w table: missing item(s) in row %d, line %zu", i, line);
-               for (j = 0; j < 8; j++)
-                       pargs->u2w[i * 8 + j] = code[j];
-       }
-       for (i = 0; i < 16; i++) {
-               do {
-                       free(p);
-                       if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
-                               errx(EX_DATAERR, "can't read d2u table row %d near line %zu", i, line);
-                       while (isspace((unsigned char)*s))
-                               s++;
-               } while (*s == '\0');
-               if (sscanf(s, "%i%i%i%i%i%i%i%i",
-code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
-                       errx(EX_DATAERR, "d2u table: missing item(s) in row %d, line %zu", i, line);
-               for (j = 0; j < 8; j++)
-                       pargs->d2u[i * 8 + j] = code[j];
-       }
-       for (i = 0; i < 16; i++) {
-               do {
-                       free(p);
-                       if ((p = s = fparseln(f, NULL, &line, NULL, 0)) == NULL)
-                               errx(EX_DATAERR, "can't read u2d table row %d near line %zu", i, line);
-                       while (isspace((unsigned char)*s))
-                               s++;
-               } while (*s == '\0');
-               if (sscanf(s, "%i%i%i%i%i%i%i%i",
-code, code + 1, code + 2, code + 3, code + 4, code + 5, code + 6, code + 7) != 8)
-                       errx(EX_DATAERR, "u2d table: missing item(s) in row %d, line %zu", i, line);
-               for (j = 0; j < 8; j++)
-                       pargs->u2d[i * 8 + j] = code[j];
-       }
-       free(p);
-       fclose(f);
-}
-
-static void
-load_ultable (struct msdosfs_args *pargs, char *name)
+int
+set_charset(struct msdosfs_args *args, const char *cs_local, const char *cs_dos)
 {
-       int i;
-
-       if (setlocale(LC_CTYPE, name) == NULL)
-               err(EX_CONFIG, "%s", name);
-       for (i = 0; i < 128; i++) {
-               pargs->ul[i] = tolower(i | 0x80);
-               pargs->lu[i] = toupper(i | 0x80);
+        int error;
+        if (modfind("msdos_iconv") < 0) {
+                if (kldload("msdos_iconv") < 0 || modfind("msdos_iconv") < 0)
+               {
+                        warnx("cannot find or load \"msdos_iconv\" kernel module");
+                        return (-1);
+                }
        }
+       snprintf(args->cs_local, ICONV_CSNMAXLEN, "%s", cs_local);
+        error = kiconv_add_xlat16_cspairs(ENCODING_UNICODE, cs_local);
+        if (error)
+                return (-1);
+        if (!cs_dos)
+               cs_dos = strdup("CP437");
+       snprintf(args->cs_dos, ICONV_CSNMAXLEN, "%s", cs_dos);
+       error = kiconv_add_xlat16_cspairs(cs_dos, cs_local);
+       if (error)
+               return (-1);
+        return (0);
 }
index 66ba1f0..52e5d9a 100644 (file)
@@ -4,7 +4,7 @@
 .PATH: ${.CURDIR}/../libkern ${.CURDIR}/../sys
 
 KMOD=  libiconv
-SRCS=  iconv.c iconv_xlat.c
+SRCS=  iconv.c iconv_xlat.c iconv_xlat16.c
 SRCS+= iconv.h 
 SRCS+= iconv_converter_if.c iconv_converter_if.h
 MFILES=        libiconv/iconv_converter_if.m
index d733590..2c172d1 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/libkern/iconv.c,v 1.1.2.1 2001/05/21 08:28:07 bp Exp $
+ * $FreeBSD: src/sys/libkern/iconv.c,v 1.12.2.1.2.1 2009/04/15 03:14:26 kensmith Exp $
  * $DragonFly: src/sys/libiconv/iconv.c,v 1.8 2008/01/05 14:02:38 swildner Exp $
  */
+
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/iconv.h>
 #include <sys/malloc.h>
-
+#include <sys/mount.h>
+#include <sys/syslog.h>
 #include "iconv_converter_if.h"
 
 SYSCTL_DECL(_kern_iconv);
 
 SYSCTL_NODE(_kern, OID_AUTO, iconv, CTLFLAG_RW, NULL, "kernel iconv interface");
 
-MALLOC_DEFINE(M_ICONV, "ICONV", "ICONV structures");
-MALLOC_DEFINE(M_ICONVDATA, "ICONV data", "ICONV data");
+MALLOC_DEFINE(M_ICONV, "iconv", "ICONV structures");
+MALLOC_DEFINE(M_ICONVDATA, "iconv_data", "ICONV data");
 
-MODULE_VERSION(libiconv, 1);
+MODULE_VERSION(libiconv, 2);
 
 #ifdef notnow
 /*
@@ -86,8 +88,10 @@ iconv_mod_unload(void)
        while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL) {
                if (csp->cp_refcount)
                        return EBUSY;
-               iconv_unregister_cspair(csp);
        }
+
+       while ((csp = TAILQ_FIRST(&iconv_cslist)) != NULL)
+               iconv_unregister_cspair(csp);
        return 0;
 }
 
@@ -269,7 +273,28 @@ int
 iconv_conv(void *handle, const char **inbuf,
        size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
 {
-       return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft);
+       return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, 0);
+}
+
+int
+iconv_conv_case(void *handle, const char **inbuf,
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
+{
+       return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 0, casetype);
+}
+
+int
+iconv_convchr(void *handle, const char **inbuf,
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+{
+       return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, 0);
+}
+
+int
+iconv_convchr_case(void *handle, const char **inbuf,
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype)
+{
+       return ICONV_CONVERTER_CONV(handle, inbuf, inbytesleft, outbuf, outbytesleft, 1, casetype);
 }
 
 /*
@@ -357,6 +382,8 @@ iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
        /*
         * Make sure all user-supplied strings are terminated before
         * proceeding.
+        *
+        * XXX return EINVAL if strings are not properly terminated
         */
        din.ia_converter[ICONV_CNVNMAXLEN-1] = 0;
        din.ia_to[ICONV_CSNMAXLEN-1] = 0;
@@ -377,6 +404,7 @@ iconv_sysctl_add(SYSCTL_HANDLER_ARGS)
        error = SYSCTL_OUT(req, &dout, sizeof(dout));
        if (error)
                goto bad;
+       ICDEBUG("%s => %s, %d bytes\n",din.ia_from, din.ia_to, din.ia_datalen);
        return 0;
 bad:
        iconv_unregister_cspair(csp);
@@ -427,7 +455,7 @@ iconv_converter_handler(module_t mod, int type, void *data)
 }
 
 /*
- * Common used functions
+ * Common used functions (don't use with unicode)
  */
 char *
 iconv_convstr(void *handle, char *dst, const char *src)
@@ -479,7 +507,9 @@ int
 iconv_lookupcp(char **cpp, const char *s)
 {
        if (cpp == NULL) {
-               ICDEBUG("warning a NULL list passed\n");
+               ICDEBUG("warning a NULL list passed\n", ""); /* XXX ISO variadic                                                                macros cannot
+                                                               leave out the
+                                                               variadic args */
                return ENOENT;
        }
        for (; *cpp; cpp++)
@@ -487,3 +517,17 @@ iconv_lookupcp(char **cpp, const char *s)
                        return 0;
        return ENOENT;
 }
+
+/*
+ * Return if fsname is in use of not
+ */
+int
+iconv_vfs_refcount(const char *fsname)
+{
+       struct vfsconf *vfsp;
+
+       vfsp = vfsconf_find_by_name(fsname);
+       if (vfsp != NULL && vfsp->vfc_refcount > 0)
+               return (EBUSY);
+       return (0);
+}
index 0fc94f1..8ae9bb3 100644 (file)
@@ -29,7 +29,7 @@
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 #
-# $FreeBSD: src/sys/libkern/iconv_converter_if.m,v 1.1.2.1 2001/05/21 08:28:07 bp Exp $
+# $FreeBSD: src/sys/libkern/iconv_converter_if.m,v 1.3.20.1 2009/04/15 03:14:26 kensmith Exp $
 # $DragonFly: src/sys/libiconv/iconv_converter_if.m,v 1.3 2004/03/18 18:27:47 dillon Exp $
 #
 
@@ -54,6 +54,8 @@ METHOD int conv {
         size_t *inbytesleft;
        char **outbuf;
        size_t *outbytesleft;
+       int convchar;
+       int casetype;
 };
 
 STATICMETHOD int init {
index ffa8d0e..9d4dd99 100644 (file)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/libkern/iconv_xlat.c,v 1.1.2.1 2001/05/21 08:28:07 bp Exp $
+ * $FreeBSD: src/sys/libkern/iconv_xlat.c,v 1.5.30.1 2009/04/15 03:14:26 kensmith Exp $
  * $DragonFly: src/sys/libiconv/iconv_xlat.c,v 1.3 2004/03/18 18:27:47 dillon Exp $
  */
+
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
@@ -45,7 +46,7 @@
  */
 
 #ifdef MODULE_DEPEND
-MODULE_DEPEND(iconv_xlat, libiconv, 1, 1, 1);
+MODULE_DEPEND(iconv_xlat, libiconv, 2, 2, 2);
 #endif
 
 /*
@@ -83,7 +84,8 @@ iconv_xlat_close(void *data)
 
 static int
 iconv_xlat_conv(void *d2p, const char **inbuf,
-       size_t *inbytesleft, char **outbuf, size_t *outbytesleft)
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+       int convchar, int casetype)
 {
        struct iconv_xlat *dp = (struct iconv_xlat*)d2p;
        const char *src;
@@ -92,14 +94,19 @@ iconv_xlat_conv(void *d2p, const char **inbuf,
 
        if (inbuf == NULL || *inbuf == NULL || outbuf == NULL || *outbuf == NULL)
                return 0;
-       r = n = min(*inbytesleft, *outbytesleft);
+       if (casetype != 0)
+               return -1;
+       if (convchar == 1)
+               r = n = 1;
+       else
+               r = n = min(*inbytesleft, *outbytesleft);
        src = *inbuf;
        dst = *outbuf;
        while(r--)
                *dst++ = dp->d_table[(u_char)*src++];
        *inbuf += n;
        *outbuf += n;
-       *inbytesleft += n;
+       *inbytesleft -= n;
        *outbytesleft -= n;
        return 0;
 }
diff --git a/sys/libiconv/iconv_xlat16.c b/sys/libiconv/iconv_xlat16.c
new file mode 100644 (file)
index 0000000..aec7fd9
--- /dev/null
@@ -0,0 +1,246 @@
+/*-
+ * Copyright (c) 2003, 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: src/sys/libkern/iconv_xlat16.c,v 1.3.20.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#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"
+
+/*
+ * "XLAT16" converter
+ */
+
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(iconv_xlat16, libiconv, 2, 2, 2);
+#endif
+
+/*
+ * XLAT16 converter instance
+ */
+struct iconv_xlat16 {
+       KOBJ_FIELDS;
+       uint32_t *              d_table[0x200];
+       struct iconv_cspair *   d_csp;
+};
+
+static int
+iconv_xlat16_open(struct iconv_converter_class *dcp,
+       struct iconv_cspair *csp, struct iconv_cspair *cspf, void **dpp)
+{
+       struct iconv_xlat16 *dp;
+       uint32_t *headp, **idxp;
+       int i;
+
+       dp = (struct iconv_xlat16 *)kobj_create((struct kobj_class*)dcp, M_ICONV, M_WAITOK);
+       headp = (uint32_t *)((caddr_t)csp->cp_data + sizeof(dp->d_table));
+       idxp = (uint32_t **)csp->cp_data;
+       for (i = 0 ; i < 0x200 ; i++) {
+               if (*idxp) {
+                       dp->d_table[i] = headp;
+                       headp += 0x80;
+               } else {
+                       dp->d_table[i] = NULL;
+               }
+               idxp++;
+       }
+       dp->d_csp = csp;
+       csp->cp_refcount++;
+       *dpp = (void*)dp;
+       return (0);
+}
+
+static int
+iconv_xlat16_close(void *data)
+{
+       struct iconv_xlat16 *dp = data;
+
+       dp->d_csp->cp_refcount--;
+       kobj_delete((struct kobj*)data, M_ICONV);
+       return (0);
+}
+
+static int
+iconv_xlat16_conv(void *d2p, const char **inbuf,
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft,
+       int convchar, int casetype)
+{
+       struct iconv_xlat16 *dp = (struct iconv_xlat16*)d2p;
+       const char *src;
+       char *dst;
+       int nullin, ret = 0;
+       size_t in, on, ir, or, inlen;
+       uint32_t code;
+       u_char u, l;
+       uint16_t c1, c2;
+
+       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) {
+
+               inlen = 0;
+               code = '\0';
+
+               c1 = ir > 1 ? *(src+1) & 0xff : 0;
+               c2 = *src & 0xff;
+
+               c1 = c2 & 0x80 ? c1 | 0x100 : c1;
+               c2 = c2 & 0x80 ? c2 & 0x7f : c2;
+
+               if (ir > 1 && dp->d_table[c1]) {
+                       /*
+                        * inbuf char is a double byte char
+                        */
+                       code = dp->d_table[c1][c2];
+                       if (code)
+                               inlen = 2;
+               }
+
+               if (inlen == 0) {
+                       c1 &= 0xff00;
+                       if (!dp->d_table[c1]) {
+                               ret = -1;
+                               break;
+                       }
+                       /*
+                        * inbuf char is a single byte char
+                        */
+                       inlen = 1;
+                       code = dp->d_table[c1][c2];
+                       if (!code) {
+                               ret = -1;
+                               break;
+                       }
+               }
+
+               nullin = (code & XLAT16_ACCEPT_NULL_IN) ? 1 : 0;
+               if (inlen == 1 && nullin) {
+                       /*
+                        * XLAT16_ACCEPT_NULL_IN requires inbuf has 2byte
+                        */
+                       ret = -1;
+                       break;
+               }
+
+               /*
+                * now start translation
+                */
+               if ((casetype == KICONV_FROM_LOWER && code & XLAT16_HAS_FROM_LOWER_CASE) ||
+                   (casetype == KICONV_FROM_UPPER && code & XLAT16_HAS_FROM_UPPER_CASE)) {
+                       c2 = (u_char)(code >> 16);
+                       c1 = c2 & 0x80 ? 0x100 : 0;
+                       c2 = c2 & 0x80 ? c2 & 0x7f : c2;
+                       code = dp->d_table[c1][c2];
+               }
+
+               u = (u_char)(code >> 8);
+               l = (u_char)code;
+
+#ifdef XLAT16_ACCEPT_3BYTE_CHR
+               if (code & XLAT16_IS_3BYTE_CHR) {
+                       if (or < 3) {
+                               ret = -1;
+                               break;
+                       }
+                       *dst++ = u;
+                       *dst++ = l;
+                       *dst++ = (u_char)(code >> 16);
+                       or -= 3;
+               } else
+#endif
+               if (u || code & XLAT16_ACCEPT_NULL_OUT) {
+                       if (or < 2) {
+                               ret = -1;
+                               break;
+                       }
+                       *dst++ = u;
+                       *dst++ = l;
+                       or -= 2;
+               } else {
+                       if ((casetype == KICONV_LOWER && code & XLAT16_HAS_LOWER_CASE) ||
+                           (casetype == KICONV_UPPER && code & XLAT16_HAS_UPPER_CASE))
+                               *dst++ = (u_char)(code >> 16);
+                       else
+                               *dst++ = l;
+                       or--;
+               }
+
+               if (inlen == 2) {
+                       /*
+                        * there is a case that inbuf char is a single
+                        * byte char while inlen == 2
+                        */
+                       if ((u_char)*(src+1) == 0 && !nullin ) {
+                               src++;
+                               ir--;
+                       } else {
+                               src += 2;
+                               ir -= 2;
+                       }
+               } else {
+                       src++;
+                       ir--;
+               }
+
+               if (convchar == 1)
+                       break;
+       }
+
+       *inbuf += in - ir;
+       *outbuf += on - or;
+       *inbytesleft -= in - ir;
+       *outbytesleft -= on - or;
+       return (ret);
+}
+
+static const char *
+iconv_xlat16_name(struct iconv_converter_class *dcp)
+{
+       return ("xlat16");
+}
+
+static kobj_method_t iconv_xlat16_methods[] = {
+       KOBJMETHOD(iconv_converter_open,        iconv_xlat16_open),
+       KOBJMETHOD(iconv_converter_close,       iconv_xlat16_close),
+       KOBJMETHOD(iconv_converter_conv,        iconv_xlat16_conv),
+#if 0
+       KOBJMETHOD(iconv_converter_init,        iconv_xlat16_init),
+       KOBJMETHOD(iconv_converter_done,        iconv_xlat16_done),
+#endif
+       KOBJMETHOD(iconv_converter_name,        iconv_xlat16_name),
+       {0, 0}
+};
+
+KICONV_CONVERTER(xlat16, sizeof(struct iconv_xlat16));
index 322479c..eed1477 100644 (file)
@@ -29,7 +29,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: src/sys/sys/iconv.h,v 1.1.2.1 2001/05/21 08:28:07 bp Exp $
+ * $FreeBSD: src/sys/sys/iconv.h,v 1.12.8.1 2009/04/15 03:14:26 kensmith Exp $
  * $DragonFly: src/sys/sys/iconv.h,v 1.6 2007/10/03 18:58:20 dillon Exp $
  */
 #ifndef _SYS_ICONV_H_
 
 #define        ICONV_CSNMAXLEN         31      /* maximum length of charset name */
 #define        ICONV_CNVNMAXLEN        31      /* maximum length of converter name */
-#define        ICONV_CSMAXDATALEN      1024    /* maximum size of data associated with cs pair */
+/* maximum size of data associated with cs pair */
+#define        ICONV_CSMAXDATALEN      (sizeof(caddr_t) * 0x200 + sizeof(uint32_t) * 0x200 * 0x80)
+
+#define        XLAT16_ACCEPT_NULL_OUT          0x01000000
+#define        XLAT16_ACCEPT_NULL_IN           0x02000000
+#define        XLAT16_HAS_LOWER_CASE           0x04000000
+#define        XLAT16_HAS_UPPER_CASE           0x08000000
+#define        XLAT16_HAS_FROM_LOWER_CASE      0x10000000
+#define        XLAT16_HAS_FROM_UPPER_CASE      0x20000000
+#define        XLAT16_IS_3BYTE_CHR             0x40000000
+
+#define        KICONV_LOWER            1       /* tolower converted character */
+#define        KICONV_UPPER            2       /* toupper converted character */
+#define        KICONV_FROM_LOWER       4       /* tolower source character, then convert */
+#define        KICONV_FROM_UPPER       8       /* toupper source character, then convert */
 
 /*
  * Entry for cslist sysctl
@@ -79,7 +93,14 @@ 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 *);
+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);
+const char *kiconv_quirkcs(const char *, int);
 
 __END_DECLS
 
@@ -112,9 +133,9 @@ struct iconv_cspair {
 };
 
 #define        KICONV_CONVERTER(name,size)                     \
-    static DEFINE_CLASS_EXT(iconv_ ## name, iconv_ ## name ## _class,  \
-                           iconv_ ## name ## _methods, \
-                           (size), iconv_converter_class); \
+    static struct iconv_converter_class iconv_ ## name ## _class = { \
+       "iconv_"#name, iconv_ ## name ## _methods, size, NULL \
+    };                                                 \
     static moduledata_t iconv_ ## name ## _mod = {     \
        "iconv_"#name, iconv_converter_handler,         \
        (void*)&iconv_ ## name ## _class                \
@@ -140,8 +161,74 @@ int iconv_open(const char *to, const char *from, void **handle);
 int iconv_close(void *handle);
 int iconv_conv(void *handle, const char **inbuf,
        size_t *inbytesleft, char **outbuf, size_t *outbytesleft);
+int iconv_conv_case(void *handle, const char **inbuf,
+       size_t *inbytesleft, char **outbuf, size_t *outbytesleft, int casetype);
+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);
 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);
+
+/*
+ * Bridge struct of iconv functions
+ */
+struct iconv_functions {
+       int (*open)(const char *to, const char *from, void **handle);
+       int (*close)(void *handle);
+       int (*conv)(void *handle, const char **inbuf, size_t *inbytesleft,
+               char **outbuf, size_t *outbytesleft);
+       int (*conv_case)(void *handle, const char **inbuf, size_t *inbytesleft,
+               char **outbuf, size_t *outbytesleft, int casetype);
+       int (*convchr)(void *handle, const char **inbuf, size_t *inbytesleft,
+               char **outbuf, size_t *outbytesleft);
+       int (*convchr_case)(void *handle, const char **inbuf, size_t *inbytesleft,
+               char **outbuf, size_t *outbytesleft, int casetype);
+};
+
+#define VFS_DECLARE_ICONV(fsname)                                      \
+       static struct iconv_functions fsname ## _iconv_core = {         \
+               iconv_open,                                             \
+               iconv_close,                                            \
+               iconv_conv,                                             \
+               iconv_conv_case,                                        \
+               iconv_convchr,                                          \
+               iconv_convchr_case                                      \
+       };                                                              \
+       extern struct iconv_functions *fsname ## _iconv;                \
+       static int fsname ## _iconv_mod_handler(module_t mod,           \
+               int type, void *d);                                     \
+       static int                                                      \
+       fsname ## _iconv_mod_handler(module_t mod, int type, void *d)   \
+       {                                                               \
+               int error = 0;                                          \
+               switch(type) {                                          \
+               case MOD_LOAD:                                          \
+                       fsname ## _iconv = & fsname ## _iconv_core;     \
+                       break;                                          \
+               case MOD_UNLOAD:                                        \
+                       error = iconv_vfs_refcount(#fsname);            \
+                       if (error)                                      \
+                               return (EBUSY);                         \
+                       fsname ## _iconv = NULL;                        \
+                       break;                                          \
+               default:                                                \
+                       error = EINVAL;                                 \
+                       break;                                          \
+               }                                                       \
+               return (error);                                         \
+       }                                                               \
+       static moduledata_t fsname ## _iconv_mod = {                    \
+               #fsname"_iconv",                                        \
+               fsname ## _iconv_mod_handler,                           \
+               NULL                                                    \
+       };                                                              \
+       DECLARE_MODULE(fsname ## _iconv, fsname ## _iconv_mod,          \
+                      SI_SUB_DRIVERS, SI_ORDER_ANY);                   \
+       MODULE_DEPEND(fsname ## _iconv, fsname, 1, 1, 1);               \
+       MODULE_DEPEND(fsname ## _iconv, libiconv, 2, 2, 2);             \
+       MODULE_VERSION(fsname ## _iconv, 1)
 
 /*
  * Internal functions
@@ -153,9 +240,9 @@ int iconv_converter_donestub(struct iconv_converter_class *dp);
 int iconv_converter_handler(module_t mod, int type, void *data);
 
 #ifdef ICONV_DEBUG
-#define ICDEBUG(format, args...) kprintf("%s: "format, __func__ ,## args)
+#define ICDEBUG(format, ...) kprintf("%s: "format, __func__ , __VA_ARGS__)
 #else
-#define ICDEBUG(format, args...)
+#define ICDEBUG(format, ...)
 #endif
 
 #endif /* !_KERNEL */
index ee552f7..d3c1b2a 100644 (file)
@@ -6,4 +6,6 @@ KMOD=   cd9660
 SRCS=  cd9660_bmap.c cd9660_lookup.c cd9660_node.c cd9660_rrip.c \
        cd9660_util.c cd9660_vfsops.c cd9660_vnops.c
 
+EXPORT_SYMS=    cd9660_iconv
+
 .include <bsd.kmod.mk>
diff --git a/sys/vfs/isofs/cd9660/cd9660_iconv/Makefile b/sys/vfs/isofs/cd9660/cd9660_iconv/Makefile
new file mode 100644 (file)
index 0000000..172eefd
--- /dev/null
@@ -0,0 +1,6 @@
+# $FreeBSD: src/sys/modules/msdosfs_iconv/Makefile,v 1.1.30.1 2009/04/15 03:14:26 kensmith Exp $
+
+KMOD=  cd9660_iconv
+SRCS=  cd9660_iconv.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/vfs/isofs/cd9660/cd9660_iconv/cd9660_iconv.c b/sys/vfs/isofs/cd9660/cd9660_iconv/cd9660_iconv.c
new file mode 100644 (file)
index 0000000..d4150df
--- /dev/null
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 2003 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>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
+
+VFS_DECLARE_ICONV(cd9660);
index 01661ae..e3c5553 100644 (file)
@@ -238,7 +238,12 @@ searchloop:
                                        if (namelen != 1
                                            || ep->name[0] != 0)
                                                goto notfound;
-                               } else if (!(res = isofncmp(name, len, ep->name, namelen, imp->joliet_level))) {
+                                       } else if (!(res = isofncmp(name, len,
+                                                            ep->name, namelen,
+                                                            imp->joliet_level,
+                                                            imp->im_flags,
+                                                            imp->im_d2l,
+                                                            imp->im_l2d))) {
                                        if (isoflags & 2)
                                                ino = isodirino(ep, imp);
                                        else
index 489e3fb..9134c3f 100644 (file)
@@ -39,7 +39,7 @@
  * $FreeBSD: src/sys/isofs/cd9660/cd9660_mount.h,v 1.3.2.2 2001/03/14 12:03:50 bp Exp $
  * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_mount.h,v 1.3 2004/08/17 18:57:33 dillon Exp $
  */
-
+#include <sys/iconv.h>
 /*
  * Arguments to mount ISO 9660 filesystems.
  */
@@ -48,10 +48,14 @@ struct iso_args {
        struct  export_args export;     /* network export info */
        int     flags;                  /* mounting flags, see below */
        int     ssector;                /* starting sector, 0 for 1st session */
+        char    cs_disk[ICONV_CSNMAXLEN];
+               /* disk charset for Joliet cs conversion */
+        char    cs_local[ICONV_CSNMAXLEN];
+              /* local charset for Joliet cs conversion */
 };
 #define        ISOFSMNT_NORRIP 0x00000001      /* disable Rock Ridge Ext.*/
 #define        ISOFSMNT_GENS   0x00000002      /* enable generation numbers */
 #define        ISOFSMNT_EXTATT 0x00000004      /* enable extended attributes */
 #define ISOFSMNT_NOJOLIET 0x00000008   /* disable Joliet Ext.*/
 #define ISOFSMNT_BROKENJOLIET 0x00000010/* allow broken Joliet disks */
-
+#define ISOFSMNT_KICONV 0x00000020      /* Use libiconv to convert chars */
index 5ec1a15..68f292b 100644 (file)
@@ -300,9 +300,10 @@ cd9660_rrip_altname(ISO_RRIP_ALTNAME *p, ISO_RRIP_ANALYZE *ana)
 static void
 cd9660_rrip_defname(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana)
 {
-       isofntrans(isodir->name,isonum_711(isodir->name_len),
-                  ana->outbuf,ana->outlen,
-                  1,isonum_711(isodir->flags)&4, ana->imp->joliet_level);
+        isofntrans(isodir->name,isonum_711(isodir->name_len),
+                   ana->outbuf,ana->outlen,
+                   1,isonum_711(isodir->flags)&4, ana->imp->joliet_level,
+                   ana->imp->im_flags, ana->imp->im_d2l);
        switch (*ana->outbuf) {
        default:
                break;
@@ -490,7 +491,8 @@ cd9660_rrip_loop(struct iso_directory_record *isodir, ISO_RRIP_ANALYZE *ana,
        pwhead = isodir->name + isonum_711(isodir->name_len);
        if (!(isonum_711(isodir->name_len)&1))
                pwhead++;
-       isochar(isodir->name, pwhead, ana->imp->joliet_level, &c);
+        isochar(isodir->name, pwhead, ana->imp->joliet_level, &c, NULL,
+                ana->imp->im_flags, ana->imp->im_d2l);
 
        /* If it's not the '.' entry of the root dir obey SP field */
        if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
@@ -619,8 +621,8 @@ cd9660_rrip_getname(struct iso_directory_record *isodir, char *outbuf,
        analyze.fields = ISO_SUSP_ALTNAME|ISO_SUSP_RELDIR|ISO_SUSP_CLINK|ISO_SUSP_PLINK;
        *outlen = 0;
 
-       isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
-               imp->joliet_level, &c);
+        isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
+                imp->joliet_level, &c, NULL, imp->im_flags, imp->im_d2l);
        tab = rrip_table_getname;
        if (c == 0 || c == 1) {
                cd9660_rrip_defname(isodir,&analyze);
index c8181af..43527c0 100644 (file)
 #include <sys/param.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
+#include <sys/iconv.h>
 
 #include "iso.h"
+#include "cd9660_mount.h"
 
-/*
- * XXX: limited support for loading of Unicode
- * conversion routine as a kld at a run-time.
- * Should be removed when native Unicode kernel
- * interfaces have been introduced.
- */
-u_char (*cd9660_wchar2char)(u_int32_t wchar) = NULL;
+extern struct iconv_functions *cd9660_iconv;
 
 /*
  * Get one character out of an iso filename
@@ -61,26 +57,45 @@ u_char (*cd9660_wchar2char)(u_int32_t wchar) = NULL;
  * Return number of bytes consumed
  */
 int
-isochar(u_char *isofn, u_char *isoend, int joliet_level, u_char *c)
+isochar(isofn, isoend, joliet_level, c, clen, flags, handle)
+      u_char *isofn;
+      u_char *isoend;
+      int joliet_level;
+      u_short *c;
+      int *clen;
+      int flags;
+      void *handle;
 {
+      size_t i, j, len;
+      char inbuf[3], outbuf[3], *inp, *outp;
       *c = *isofn++;
+      if (clen) *clen = 1;
       if (joliet_level == 0 || isofn == isoend)
               /* (00) and (01) are one byte in Joliet, too */
               return 1;
-
-      /* No Unicode support yet :-( */
-      switch (*c) {
-      default:
-              *c = '?';
-              break;
-      case '\0':
-              *c = *isofn;
-              break;
+      if (flags & ISOFSMNT_KICONV && cd9660_iconv) {
+              i = j = len = 2;
+              inbuf[0]=(char)*(isofn - 1);
+              inbuf[1]=(char)*isofn;
+              inbuf[2]='\0';
+              inp = inbuf;
+              outp = outbuf;
+              cd9660_iconv->convchr(handle, (const char **)&inp, &i, &outp, &j);
+              len -= j;
+              if (clen) *clen = len;
+              *c = '\0';
+              while(len--)
+                      *c |= (*(outp - len - 1) & 0xff) << (len << 3);
+      } else {
+              switch (*c) {
+              default:
+                      *c = '?';
+                      break;
+              case '\0':
+                      *c = *isofn;
+                      break;
+              }
       }
-      /* XXX: if Unicode conversion routine is loaded then use it */
-      if (cd9660_wchar2char != NULL)
-            *c = cd9660_wchar2char((*(isofn - 1) << 8) | *isofn);
-
       return 2;
 }
 
@@ -90,84 +105,133 @@ isochar(u_char *isofn, u_char *isoend, int joliet_level, u_char *c)
  * Note: Version number plus ';' may be omitted.
  */
 int
-isofncmp(u_char *fn, int fnlen, u_char *isofn, int isolen, int joliet_level)
+isofncmp(fn, fnlen, isofn, isolen, joliet_level, flags, handle, lhandle)
+        u_char *fn;
+        int fnlen;
+        u_char *isofn;
+        int isolen;
+        int joliet_level;
+        int flags;
+        void *handle;
+        void *lhandle;
 {
-       int i, j;
-       u_char c, *fnend = fn + fnlen, *isoend = isofn + isolen;
-
-       for (; fn != fnend; fn++) {
-               if (isofn == isoend)
-                       return *fn;
-               isofn += isochar(isofn, isoend, joliet_level, &c);
-               if (c == ';') {
-                       if (*fn++ != ';')
-                               return fn[-1];
-                       for (i = 0; fn != fnend; i = i * 10 + *fn++ - '0') {
-                               if (*fn < '0' || *fn > '9') {
-                                       return -1;
-                               }
-                       }
-                       for (j = 0; isofn != isoend; j = j * 10 + c - '0')
-                               isofn += isochar(isofn, isoend,
-                                                joliet_level, &c);
-                       return i - j;
-               }
-               if (c != *fn) {
-                       if (c >= 'A' && c <= 'Z') {
-                               if (c + ('a' - 'A') != *fn) {
-                                       if (*fn >= 'a' && *fn <= 'z')
-                                               return *fn - ('a' - 'A') - c;
-                                       else
-                                               return *fn - c;
-                               }
-                       } else
-                               return *fn - c;
-               }
-       }
-       if (isofn != isoend) {
-               isofn += isochar(isofn, isoend, joliet_level, &c);
-               switch (c) {
-               default:
-                       return -c;
-               case '.':
-                       if (isofn != isoend) {
-                               isochar(isofn, isoend, joliet_level, &c);
-                               if (c == ';')
-                                       return 0;
-                       }
-                       return -1;
-               case ';':
-                       return 0;
-               }
-       }
-       return 0;
+        int i, j;
+        u_short c, d;
+        u_char *fnend = fn + fnlen, *isoend = isofn + isolen;
+        for (; fn < fnend; ) {
+                d = sgetrune(fn, fnend - fn, (char const **)&fn, flags, lhandle)
+;
+                if (isofn == isoend)
+                        return d;
+                isofn += isochar(isofn, isoend, joliet_level, &c, NULL, flags, handle);
+                if (c == ';') {
+                        if (d != ';')
+                                return d;
+                        for (i = 0; fn < fnend; i = i * 10 + *fn++ - '0') {
+                                if (*fn < '0' || *fn > '9') {
+                                        return -1;
+                                }
+                        }
+                        for (j = 0; isofn != isoend; j = j * 10 + c - '0')
+                                isofn += isochar(isofn, isoend,
+                                                 joliet_level, &c,
+                                                 NULL, flags, handle);
+                        return i - j;
+                }
+                if (c != d) {
+                        if (c >= 'A' && c <= 'Z') {
+                                if (c + ('a' - 'A') != d) {
+                                        if (d >= 'a' && d <= 'z')
+                                                return d - ('a' - 'A') - c;
+                                  else
+                                                return d - c;
+                                }
+                        } else
+                                return d - c;
+                }
+        }
+        if (isofn != isoend) {
+                isofn += isochar(isofn, isoend, joliet_level, &c, NULL, flags, handle);
+                switch (c) {
+                default:
+                        return -c;
+                case '.':
+                        if (isofn != isoend) {
+                                isochar(isofn, isoend, joliet_level, &c,
+                                        NULL, flags, handle);
+                                if (c == ';')
+                                        return 0;
+                        }
+                        return -1;
+                case ';':
+ return 0;
+                }
+        }
+        return 0;
 }
 
 /*
  * translate a filename of length > 0
  */
-void
-isofntrans(u_char *infn, int infnlen, u_char *outfn, u_short *outfnlen,
-          int original, int assoc, int joliet_level)
+isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level, flags,
+ handle)
+        u_char *infn;
+        int infnlen;
+        u_char *outfn;
+        u_short *outfnlen;
+        int original;
+        int assoc;
+        int joliet_level;
+        int flags;
+        void *handle;
 {
-       int fnidx = 0;
-       u_char c, d = '\0', *infnend = infn + infnlen;
-
-       if (assoc) {
-               *outfn++ = ASSOCCHAR;
-               fnidx++;
-       }
-       for (; infn != infnend; fnidx++) {
-               infn += isochar(infn, infnend, joliet_level, &c);
+        u_short c, d = '\0';
+        u_char *outp = outfn, *infnend = infn + infnlen;
+        int clen;
+        if (assoc) {
+                *outp++ = ASSOCCHAR;
+        }
+        for (; infn != infnend; ) {
+                infn += isochar(infn, infnend, joliet_level, &c, &clen, flags, handle);
+                if (!original && !joliet_level && c >= 'A' && c <= 'Z')
+        c += ('a' - 'A');
+                else if (!original && c == ';') {
+                        outp -= (d == '.');
+                        break;
+                }
+                d = c;
+                while(clen--)
+                        *outp++ = c >> (clen << 3);
+        }
+        *outfnlen = outp - outfn;
+}
 
-               if (!original && !joliet_level && c >= 'A' && c <= 'Z')
-                       *outfn++ = c + ('a' - 'A');
-               else if (!original && c == ';') {
-                       fnidx -= (d == '.');
-                       break;
-               } else
-                       *outfn++ = c;
-               d = c;
-       }
-       *outfnlen = fnidx;
+/*
+ * same as sgetrune(3)
+ */
+u_short
+sgetrune(string, n, result, flags, handle)
+        const char *string;
+        size_t n;
+        char const **result;
+        int flags;
+        void *handle;
+{
+        size_t i, j, len;
+        char outbuf[3], *outp;
+        u_short c = '\0';
+        len = i = (n < 2) ? n : 2;
+        j = 2;
+        outp = outbuf;
+        if (flags & ISOFSMNT_KICONV && cd9660_iconv) {
+                cd9660_iconv->convchr(handle, (const char **)&string,
+                        &i, &outp, &j);
+                len -= i;
+        } else {
+                len = 1;
+                string++;
+        }
+        if (result) *result = string;
+        while(len--) c |= (*(string - len - 1) & 0xff) << (len << 3);
+        return (c);
 }
index cfab5de..9c09c56 100644 (file)
@@ -55,6 +55,7 @@
 #include <sys/malloc.h>
 #include <sys/stat.h>
 #include <sys/syslog.h>
+#include <sys/iconv.h>
 
 #include <vm/vm_zone.h>
 
@@ -70,6 +71,8 @@ extern struct vop_ops cd9660_fifo_vops;
 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure");
 MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part");
 
+struct iconv_functions *cd9660_iconv = NULL;
+
 static int cd9660_mount (struct mount *, char *, caddr_t, struct ucred *);
 static int cd9660_unmount (struct mount *, int);
 static int cd9660_root (struct mount *, struct vnode **);
@@ -283,6 +286,8 @@ iso_mountfs(struct vnode *devvp, struct mount *mp, struct iso_args *argp)
        struct iso_supplementary_descriptor *sup = NULL;
        struct iso_directory_record *rootp;
        int logical_block_size;
+       char cs_local[ICONV_CSNMAXLEN];
+       char cs_disk[ICONV_CSNMAXLEN];
 
        if (!(mp->mnt_flag & MNT_RDONLY))
                return EROFS;
@@ -467,7 +472,17 @@ iso_mountfs(struct vnode *devvp, struct mount *mp, struct iso_args *argp)
                bp = NULL;
        }
        isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
-                                        ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
+                                        ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET |
+                                        ISOFSMNT_KICONV);
+       if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
+                bcopy(argp->cs_local, cs_local, sizeof(cs_local));
+                bcopy(argp->cs_disk, cs_disk, sizeof(cs_disk));
+                cd9660_iconv->open(cs_local, cs_disk, &isomp->im_d2l);
+                cd9660_iconv->open(cs_disk, cs_local, &isomp->im_l2d);
+        } else {
+                isomp->im_d2l = NULL;
+                isomp->im_l2d = NULL;
+        }
 
        if (high_sierra) {
                /* this effectively ignores all the mount flags */
@@ -549,6 +564,13 @@ cd9660_unmount(struct mount *mp, int mntflags)
 
        isomp = VFSTOISOFS(mp);
 
+       if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
+                if (isomp->im_d2l)
+                        cd9660_iconv->close(isomp->im_d2l);
+                if (isomp->im_l2d)
+                        cd9660_iconv->close(isomp->im_l2d);
+        }
+
        isomp->im_devvp->v_rdev->si_mountpoint = NULL;
        error = VOP_CLOSE(isomp->im_devvp, FREAD);
        vrele(isomp->im_devvp);
index be863c8..c59ec54 100644 (file)
@@ -543,11 +543,13 @@ cd9660_readdir(struct vop_readdir_args *ap)
                                idp->current.de.d_namlen = 2;
                                error = iso_uiodir(idp,&idp->current.de,idp->curroff);
                        } else {
-                               isofntrans(ep->name,idp->current.de.d_namlen,
-                                          idp->current.de.d_name, &namelen,
-                                          imp->iso_ftype == ISO_FTYPE_9660,
-                                          isonum_711(ep->flags)&4,
-                                          imp->joliet_level);
+                                isofntrans(ep->name,idp->current.de.d_namlen,
+                                           idp->current.de.d_name, &namelen,
+                                           imp->iso_ftype == ISO_FTYPE_9660,
+                                           isonum_711(ep->flags)&4,
+                                           imp->joliet_level,
+                                           imp->im_flags,
+                                           imp->im_d2l);
                                idp->current.de.d_namlen = namelen;
                                if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
                                        error = iso_shipdir(idp);
index 8407bdb..15969d7 100644 (file)
@@ -247,6 +247,9 @@ struct iso_mnt {
        int rr_skip0;
 
        int joliet_level;
+
+        void *im_d2l;
+        void *im_l2d;
 };
 
 #define VFSTOISOFS(mp) ((struct iso_mnt *)((mp)->mnt_data))
@@ -264,10 +267,11 @@ int cd9660_uninit (struct vfsconf *);
 #define cd9660_sysctl ((int (*) (int *, u_int, void *, size_t *, void *, \
                                     size_t, struct proc *))eopnotsupp)
 
-int isochar (u_char *, u_char *, int, u_char *);
-int isofncmp (u_char *, int, u_char *, int, int);
-void isofntrans (u_char *, int, u_char *, u_short *, int, int, int);
+int isochar(u_char *, u_char *, int, u_short *, 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 *);
 
 #endif /* _KERNEL */
 
@@ -276,34 +280,58 @@ ino_t isodirino (struct iso_directory_record *, struct iso_mnt *);
  * outside the kernel.  Thus we don't hide them here.
  */
 
-static __inline int isonum_711 (u_char *);
-static __inline int
-isonum_711(u_char *p)
+static __inline uint8_t
+isonum_711(unsigned char *p)
 {
-       return *p;
+        return p[0];
 }
 
-static __inline int isonum_712 (char *);
-static __inline int
-isonum_712(char *p)
+static __inline uint8_t
+isonum_712(unsigned char *p)
 {
-       return *p;
+        return p[0];
 }
 
-#ifndef UNALIGNED_ACCESS
+static __inline uint8_t
+isonum_713(unsigned char *p)
+{
+        return p[0];
+}
 
-static __inline int isonum_723 (u_char *);
-static __inline int
-isonum_723(u_char *p)
+static __inline uint16_t
+isonum_721(unsigned char *p)
 {
-       return *p|(p[1] << 8);
+        return (p[0] | p[1] << 8);
 }
 
-static __inline int isonum_733 (u_char *);
-static __inline int
-isonum_733(u_char *p)
+static __inline uint16_t
+isonum_722(unsigned char *p)
+{
+        return (p[1] | p[0] << 8);
+}
+
+static __inline uint16_t
+isonum_723(unsigned char *p)
+{
+        return (p[0] | p[1] << 8);
+}
+
+#ifndef UNALIGNED_ACCESS
+
+static __inline uint32_t
+isonum_731(unsigned char *p)
+{
+        return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
+}
+static __inline uint32_t
+isonum_732(unsigned char *p)
+{
+        return (p[3] | p[2] << 8 | p[1] << 16 | p[0] << 24);
+}
+static __inline uint32_t
+isonum_733(unsigned char *p)
 {
-       return *p|(p[1] << 8)|(p[2] << 16)|(p[3] << 24);
+        return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
 }
 
 #else /* UNALIGNED_ACCESS */
index cb20645..7a244e0 100644 (file)
@@ -4,5 +4,6 @@
 KMOD=  msdos
 SRCS=  msdosfs_conv.c msdosfs_denode.c msdosfs_fat.c msdosfs_lookup.c \
        msdosfs_vfsops.c msdosfs_vnops.c opt_msdosfs.h
+EXPORT_SYMS=    msdos_iconv
 
 .include <bsd.kmod.mk>
index c26b88b..c57f127 100644 (file)
@@ -129,16 +129,28 @@ struct winentry {
 #define DD_YEAR_SHIFT          9
 
 #ifdef _KERNEL
+struct mbnambuf {
+        size_t  nb_len;
+        int     nb_last_id;
+        char    nb_buf[WIN_MAXLEN + 1];
+};
 struct dirent;
+struct msdosfsmount;
+
+char   *mbnambuf_flush(struct mbnambuf *nbp, char *d_name, u_int16_t *d_namlen);
+void    mbnambuf_init(struct mbnambuf *nbp);
+void    mbnambuf_write(struct mbnambuf *nbp, char *name, int id);
 void unix2dostime (struct timespec *tsp, u_int16_t *ddp, 
             u_int16_t *dtp, u_int8_t *dhp);
 void dos2unixtime (u_int dd, u_int dt, u_int dh, struct timespec *tsp);
-int dos2unixfn (u_char dn[11], u_char *un, int lower, int d2u_loaded, u_int8_t *d2u, int ul_loaded, u_int8_t *ul);
-int unix2dosfn (const u_char *un, u_char dn[12], int unlen, u_int gen, int u2d_loaded, u_int8_t *u2d, int lu_loaded, u_int8_t *lu);
-int unix2winfn (const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum, int table_loaded, u_int16_t *u2w);
-int winChkName (const u_char *un, int unlen, struct winentry *wep, int chksum, int u2w_loaded, u_int16_t *u2w, int ul_loaded, u_int8_t *ul);
-int win2unixfn (struct winentry *wep, char *d_name, uint16_t *d_namlen, int chksum, int table_loaded, u_int16_t *u2w);
+int dos2unixfn (u_char dn[11], u_char *un, int lower, struct msdosfsmount *pmp);
+int unix2dosfn (const u_char *un, u_char dn[12], int unlen, u_int gen, struct msdosfsmount *pmp);
+int unix2winfn (const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum, struct msdosfsmount *pmp);
+int     winChkName(struct mbnambuf *nbp, const u_char *un, size_t unlen,
+            int chksum, struct msdosfsmount *pmp);
+int     win2unixfn(struct mbnambuf *nbp, struct winentry *wep, int chksum,
+            struct msdosfsmount *pmp);
 u_int8_t winChksum (u_int8_t *name);
-int winSlotCnt (const u_char *un, int unlen);
+int winSlotCnt (const u_char *un, int unlen, struct msdosfsmount *pmp);
 int winLenFixup (const u_char *un, int unlen);
 #endif /* _KERNEL */
index 72c9915..f66efce 100644 (file)
 #include <sys/time.h>
 #include <sys/kernel.h>                /* defines tz */
 #include <sys/systm.h>
+#include <sys/iconv.h>
 #include <machine/clock.h>
 #include <sys/dirent.h>
-
+#include <sys/mount.h>
 /*
  * MSDOSFS include files.
  */
+#include "bpb.h"
+#include "msdosfsmount.h"
 #include "direntry.h"
 
+extern struct iconv_functions *msdos_iconv;
+
 /*
  * Total number of days that have passed for each month in a regular year.
  */
@@ -168,6 +173,74 @@ static u_short lastdosdate;
 static u_long  lastseconds;
 
 /*
+ * Initialize the temporary concatenation buffer.
+ */
+void
+mbnambuf_init(struct mbnambuf *nbp)
+{
+        nbp->nb_len = 0;
+        nbp->nb_last_id = -1;
+        nbp->nb_buf[sizeof(nbp->nb_buf) - 1] = '\0';
+}
+/*
+ * Fill out our concatenation buffer with the given substring, at the offset
+ * specified by its id.  Since this function must be called with ids in
+ * descending order, we take advantage of the fact that ASCII substrings are
+ * exactly WIN_CHARS in length.  For non-ASCII substrings, we shift all
+ * previous (i.e. higher id) substrings upwards to make room for this one.
+ * This only penalizes portions of substrings that contain more than
+ * WIN_CHARS bytes when they are first encountered.
+ */
+void
+mbnambuf_write(struct mbnambuf *nbp, char *name, int id)
+{
+        char *slot;
+        size_t count, newlen;
+        if (nbp->nb_len != 0 && id != nbp->nb_last_id - 1) {
+                kprintf("msdosfs: non-decreasing id: id %d, last id %d\n",
+                    id, nbp->nb_last_id);
+                return;
+        }
+        /* Will store this substring in a WIN_CHARS-aligned slot. */
+        slot = &nbp->nb_buf[id * WIN_CHARS];
+        count = strlen(name);
+        newlen = nbp->nb_len + count;
+        if (newlen > WIN_MAXLEN || newlen > 127) {
+                kprintf("msdosfs: file name length %zu too large\n", newlen);
+                return;
+        }
+        /* Shift suffix upwards by the amount length exceeds WIN_CHARS. */
+        if (count > WIN_CHARS && nbp->nb_len != 0)
+                bcopy(slot + WIN_CHARS, slot + count, nbp->nb_len);
+        /* Copy in the substring to its slot and update length so far. */
+        bcopy(name, slot, count);
+        nbp->nb_len = newlen;
+        nbp->nb_last_id = id;
+}
+/*
+ * Take the completed string and use it to setup the struct dirent.
+ * Be sure to always nul-terminate the d_name and then copy the string
+ * from our buffer.  Note that this function assumes the full string has
+ * been reassembled in the buffer.  If it's called before all substrings
+ * have been written via mbnambuf_write(), the result will be incorrect.
+ */
+char *
+mbnambuf_flush(struct mbnambuf *nbp, char *d_name, u_int16_t *d_namlen)
+{
+#if 0
+        if (nbp->nb_len > 127) {
+                mbnambuf_init(nbp);
+                return (NULL);
+        }
+#endif
+        bcopy(&nbp->nb_buf[0], d_name, nbp->nb_len);
+       d_name[nbp->nb_len] = '\0';
+        *d_namlen = nbp->nb_len;
+        mbnambuf_init(nbp);
+        return (d_name);
+}
+
+/*
  * Convert from dos' idea of time to unix'. This will probably only be
  * called from the stat(), and fstat() system calls and so probably need
  * not be too efficient.
@@ -375,6 +448,48 @@ l2u[256] = {
 };
 
 /*
+ * Convert DOS char to Local char
+ */
+static u_int16_t
+dos2unixchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *
+pmp)
+{
+        u_char c;
+        char *outp, outbuf[3];
+        u_int16_t wc;
+        size_t len, olen;
+        if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+                olen = len = 2;
+                outp = outbuf;
+                if (lower & (LCASE_BASE | LCASE_EXT))
+                        msdos_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
+                                                  ilen, &outp, &olen, KICONV_LOWER);
+                else
+                        msdos_iconv->convchr(pmp->pm_d2u, (const char **)instr,
+                                             ilen, &outp, &olen);
+                len -= olen;
+                /*
+                 * return '?' if failed to convert
+                */
+                if (len == 0) {
+                        (*ilen)--;
+                        (*instr)++;
+                        return ('?');
+                }
+               wc = 0;
+                while(len--)
+                        wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+                return (wc);
+        }
+        (*ilen)--;
+        c = *(*instr)++;
+        c = dos2unix[c];
+        if (lower & (LCASE_BASE | LCASE_EXT))
+                c = u2l[c];
+        return ((u_int16_t)c);
+}
+
+/*
  * DOS filenames are made of 2 parts, the name part and the extension part.
  * The name part is 8 characters long and the extension part is 3
  * characters long.  They may contain trailing blanks if the name or
@@ -387,8 +502,7 @@ l2u[256] = {
  * null.
  */
 int
-dos2unixfn(u_char dn[11], u_char *un, int lower, int d2u_loaded, u_int8_t *d2u,
-          int ul_loaded, u_int8_t *ul)
+dos2unixfn(u_char dn[11], u_char *un, int lower, struct msdosfsmount *pmp)
 {
        int i;
        int thislong = 1;
@@ -401,49 +515,141 @@ dos2unixfn(u_char dn[11], u_char *un, int lower, int d2u_loaded, u_int8_t *d2u,
         * directory slot. Another dos quirk.
         */
        if (*dn == SLOT_E5)
-               c = d2u_loaded ? d2u[0xe5 & 0x7f] : dos2unix[0xe5];
-       else
-               c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
-                   dos2unix[*dn];
-       *un++ = (lower & LCASE_BASE) ? (ul_loaded && (c & 0x80) ?
-                        ul[c & 0x7f] : u2l[c]) : c;
-       dn++;
-
+                *dn = 0xe5;
        /*
         * Copy the name portion into the unix filename string.
-        */
-       for (i = 1; i < 8 && *dn != ' '; i++) {
-               c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
-                   dos2unix[*dn];
-               dn++;
-               *un++ = (lower & LCASE_BASE) ? (ul_loaded && (c & 0x80) ?
-                                ul[c & 0x7f] : u2l[c]) : c;
-               thislong++;
-       }
-       dn += 8 - i;
+         */
+       for(i  = 8; i > 0 && *dn != ' ';) {
+                c = dos2unixchr((const u_char **)&dn, &i, lower & LCASE_BASE,
+                    pmp);
+                if (c & 0xff00) {
+                        *un++ = c >> 8;
+                        thislong++;
+                }
+                *un++ = c;
+                thislong++;
+        }
+        dn += i;
 
        /*
         * Now, if there is an extension then put in a period and copy in
         * the extension.
         */
-       if (*dn != ' ') {
-               *un++ = '.';
-               thislong++;
-               for (i = 0; i < 3 && *dn != ' '; i++) {
-                       c = d2u_loaded && (*dn & 0x80) ? d2u[*dn & 0x7f] :
-                           dos2unix[*dn];
-                       dn++;
-                       *un++ = (lower & LCASE_EXT) ? (ul_loaded && (c & 0x80) ?
-                                        ul[c & 0x7f] : u2l[c]) : c;
-                       thislong++;
-               }
-       }
+        if (*dn != ' ') {
+                *un++ = '.';
+                thislong++;
+                for (i = 3; i > 0 && *dn != ' ';) {
+                        c = dos2unixchr((const u_char **)&dn, &i,
+                            lower & LCASE_EXT, pmp);
+                        if (c & 0xff00) {
+                                *un++ = c >> 8;
+                                thislong++;
+                        }
+                        *un++ = c;
+                        thislong++;
+                }
+        }
        *un++ = 0;
-
+/*
+       for(i = 0; un[i] != 0; i++)
+               kprintf("0x%x", un[i]);
+       kprintf(" ->%s\n", dn);
+*/
        return (thislong);
 }
 
 /*
+ * Store an area with multi byte string instr, and reterns left
+ * byte of instr and moves pointer forward. The area's size is
+ * inlen or outlen.
+ */
+static int
+mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag,
+ void *handle)
+{
+        char *outp, outstr[outlen * weight + 1];
+       bzero(outstr, outlen*weight+1);
+        if (flag & MSDOSFSMNT_KICONV && msdos_iconv) {
+                outp = outstr;
+                outlen *= weight;
+                msdos_iconv->conv(handle, instr, &inlen, &outp, &outlen);
+                return (inlen);
+        }
+        (*instr) += min(inlen, outlen);
+        return (inlen - min(inlen, outlen));
+}
+
+/*
+ * Convert Local char to DOS char
+ */
+static u_int16_t
+unix2doschr(const u_char **instr, size_t *ilen, struct msdosfsmount *pmp)
+{
+        u_char c;
+        char *up, *outp, unicode[3], outbuf[3];
+        u_int16_t wc;
+        size_t len, ucslen, unixlen, olen;
+        if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+                /*
+                 * to hide an invisible character, using a unicode filter
+                 */
+                ucslen = 2;
+                len = *ilen;
+                up = unicode;
+                msdos_iconv->convchr(pmp->pm_u2w, (const char **)instr,
+                                     ilen, &up, &ucslen);
+                unixlen = len - *ilen;
+
+                /*
+                 * cannot be converted
+                 */
+                if (unixlen == 0) {
+                        (*ilen)--;
+                        (*instr)++;
+                        return (0);
+                }
+                /*
+                 * return magic number for ascii char
+                 */
+                if (unixlen == 1) {
+                        c = *(*instr -1);
+                        if (! (c & 0x80)) {
+                                c = unix2dos[c];
+                                if (c <= 2)
+                                        return (c);
+                        }
+                }
+                /*
+                 * now convert using libiconv
+                 */
+                *instr -= unixlen;
+                *ilen = len;
+                olen = len = 2;
+                outp = outbuf;
+                msdos_iconv->convchr_case(pmp->pm_u2d, (const char **)instr,
+                                          ilen, &outp, &olen, KICONV_FROM_UPPER);
+                len -= olen;
+                /*
+                 * cannot be converted, but has unicode char, should return magic number
+                */
+                if (len == 0) {
+                        (*ilen) -= unixlen;
+                        (*instr) += unixlen;
+                        return (1);
+                }
+                wc = 0;
+                while(len--)
+                        wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+ return (wc);
+        }
+        (*ilen)--;
+        c = *(*instr)++;
+        c = l2u[c];
+        c = unix2dos[c];
+        return ((u_int16_t)c);
+}
+
+/*
  * Convert a unix filename to a DOS filename according to Win95 rules.
  * If applicable and gen is not 0, it is inserted into the converted
  * filename as a generation number.
@@ -454,174 +660,244 @@ dos2unixfn(u_char dn[11], u_char *un, int lower, int d2u_loaded, u_int8_t *d2u,
  *     2 if conversion was successful
  *     3 if conversion was successful and generation number was inserted
  */
+
 int
-unix2dosfn(const u_char *un, u_char dn[12], int unlen, u_int gen, int u2d_loaded,
-          u_int8_t *u2d, int lu_loaded, u_int8_t *lu)
+unix2dosfn(const u_char *un, u_char dn[12], int unlen, u_int gen, struct msdosfsmount *pmp)
 {
-       int i, j, l;
-       int conv = 1;
-       const u_char *cp, *dp, *dp1;
-       u_char gentext[6], *wcp;
-       u_int8_t c;
-#define U2D(c) (u2d_loaded && ((c) & 0x80) ? u2d[(c) & 0x7f] : unix2dos[c])
-
-       /*
-        * Fill the dos filename string with blanks. These are DOS's pad
-        * characters.
-        */
-       for (i = 0; i < 11; i++)
-               dn[i] = ' ';
-       dn[11] = 0;
-
-       /*
-        * The filenames "." and ".." are handled specially, since they
-        * don't follow dos filename rules.
-        */
-       if (un[0] == '.' && unlen == 1) {
-               dn[0] = '.';
-               return gen <= 1;
-       }
-       if (un[0] == '.' && un[1] == '.' && unlen == 2) {
-               dn[0] = '.';
-               dn[1] = '.';
-               return gen <= 1;
-       }
-
-       /*
-        * Filenames with only blanks and dots are not allowed!
-        */
-       for (cp = un, i = unlen; --i >= 0; cp++)
-               if (*cp != ' ' && *cp != '.')
-                       break;
-       if (i < 0)
-               return 0;
-
-
-       /*
-        * Filenames with some characters are not allowed!
-        */
-       for (cp = un, i = unlen; --i >= 0; cp++)
-               if (U2D(*cp) == 0)
-                       return 0;
-
-       /*
-        * Now find the extension
-        * Note: dot as first char doesn't start extension
-        *       and trailing dots and blanks are ignored
-        */
-       dp = dp1 = 0;
-       for (cp = un + 1, i = unlen - 1; --i >= 0;) {
-               switch (*cp++) {
-               case '.':
-                       if (!dp1)
-                               dp1 = cp;
-                       break;
-               case ' ':
-                       break;
-               default:
-                       if (dp1)
-                               dp = dp1;
-                       dp1 = 0;
-                       break;
-               }
-       }
-
-       /*
-        * Now convert it
-        */
-       if (dp) {
-               if (dp1)
-                       l = dp1 - dp;
-               else
-                       l = unlen - (dp - un);
-               for (i = 0, j = 8; i < l && j < 11; i++, j++) {
-                       c = dp[i];
-                       c = lu_loaded && (c & 0x80) ?
-                           lu[c & 0x7f] : l2u[c];
-                       c = U2D(c);
-                       if (dp[i] != (dn[j] = c)
-                           && conv != 3)
-                               conv = 2;
-                       if (dn[j] == 1) {
-                               conv = 3;
-                               dn[j] = '_';
-                       }
-                       if (dn[j] == 2) {
-                               conv = 3;
-                               dn[j--] = ' ';
-                       }
-               }
-               if (i < l)
-                       conv = 3;
-               dp--;
-       } else {
-               for (dp = cp; *--dp == ' ' || *dp == '.';);
-               dp++;
-       }
-
-       /*
-        * Now convert the rest of the name
-        */
-       for (i = j = 0; un < dp && j < 8; i++, j++, un++) {
-               c = lu_loaded && (*un & 0x80) ?
-                   lu[*un & 0x7f] : l2u[*un];
-               c = U2D(c);
-               if (*un != (dn[j] = c)
-                   && conv != 3)
-                       conv = 2;
-               if (dn[j] == 1) {
-                       conv = 3;
-                       dn[j] = '_';
-               }
-               if (dn[j] == 2) {
-                       conv = 3;
-                       dn[j--] = ' ';
-               }
-       }
-       if (un < dp)
-               conv = 3;
-       /*
-        * If we didn't have any chars in filename,
-        * generate a default
-        */
-       if (!j)
-               dn[0] = '_';
-
-       /*
-        * The first character cannot be E5,
-        * because that means a deleted entry
-        */
-       if (dn[0] == 0xe5)
-               dn[0] = SLOT_E5;
-
-       /*
-        * If there wasn't any char dropped,
-        * there is no place for generation numbers
-        */
-       if (conv != 3) {
-               if (gen > 1)
-                       return 0;
-               return conv;
-       }
+       ssize_t i, j;
+        int l;
+        int conv = 1;
+        const u_char *cp, *dp, *dp1;
+        u_char gentext[6], *wcp;
+        u_int16_t c;
+        /*
+         * Fill the dos filename string with blanks. These are DOS's pad
+         * characters.
+         */
+        for (i = 0; i < 11; i++)
+                dn[i] = ' ';
+        dn[11] = 0;
+        /*
+         * The filenames "." and ".." are handled specially, since they
+         * don't follow dos filename rules.
+         */
+        if (un[0] == '.' && unlen == 1) {
+                dn[0] = '.';
+                return gen <= 1;
+        }
+        if (un[0] == '.' && un[1] == '.' && unlen == 2) {
+                dn[0] = '.';
+                dn[1] = '.';
+                return gen <= 1;
+        }
+        /*
+         * Filenames with only blanks and dots are not allowed!
+         */
+        for (cp = un, i = unlen; --i >= 0; cp++)
+                if (*cp != ' ' && *cp != '.')
+                        break;
+        if (i < 0)
+                return 0;
+        /*
+         * Filenames with some characters are not allowed!
+         */
+        for (cp = un, i = unlen; i > 0;)
+                if (unix2doschr(&cp, (size_t *)&i, pmp) == 0)
+                        return 0;
+        /*
+         * Now find the extension
+         * Note: dot as first char doesn't start extension
+         *       and trailing dots and blanks are ignored
+         * Note(2003/7): It seems recent Windows has
+         *       defferent rule than this code, that Windows
+         *       ignores all dots before extension, and use all
+         *       chars as filename except for dots.
+         */
+        dp = dp1 = 0;
+        for (cp = un + 1, i = unlen - 1; --i >= 0;) {
+                switch (*cp++) {
+                case '.':
+                        if (!dp1)
+                                dp1 = cp;
+                        break;
+                case ' ':
+                        break;
+                default:
+                        if (dp1)
+                                dp = dp1;
+                        dp1 = 0;
+                        break;
+                }
+        }
+        /*
+         * Now convert it (this part is for extension).
+         * As Windows XP do, if it's not ascii char,
+         * this function should return 2 or 3, so that checkng out Unicode name.
+         */
+        if (dp) {
+                if (dp1)
+                        l = dp1 - dp;
+                else
+                        l = unlen - (dp - un);
+                for (cp = dp, i = l, j = 8; i > 0 && j < 11; j++) {
+                        c = unix2doschr(&cp, (size_t *)&i, pmp);
+                        if (c & 0xff00) {
+                                dn[j] = c >> 8;
+                                if (++j < 11) {
+                                        dn[j] = c;
+                                        if (conv != 3)
+                                                conv = 2;
+                                        continue;
+                                } else {
+                                        conv = 3;
+                                        dn[j-1] = ' ';
+                                        break;
+                                }
+                        } else {
+                                dn[j] = c;
+                        }
+                        if (((dn[j] & 0x80) || *(cp - 1) != dn[j]) && conv != 3)
+                                conv = 2;
+                        if (dn[j] == 1) {
+                                conv = 3;
+                                dn[j] = '_';
+                        }
+                        if (dn[j] == 2) {
+                                conv = 3;
+                                dn[j--] = ' ';
+                        }
+                }
+                if (i > 0)
+                        conv = 3;
+                dp--;
+        } else {
+                for (dp = cp; *--dp == ' ' || *dp == '.';);
+                dp++;
+        }
+        /*
+         * Now convert the rest of the name
+         */
+        for (i = dp - un, j = 0; un < dp && j < 8; j++) {
+                c = unix2doschr(&un, &i, pmp);
+                if (c & 0xff00) {
+                        dn[j] = c >> 8;
+                        if (++j < 8) {
+                                dn[j] = c;
+                                if (conv != 3)
+                                        conv = 2;
+                                continue;
+                        } else {
+                                conv = 3;
+                                dn[j-1] = ' ';
+                                break;
+                        }
+                } else {
+                        dn[j] = c;
+                }
+                if (((dn[j] & 0x80) || *(un - 1) != dn[j]) && conv != 3)
+                        conv = 2;
+                if (dn[j] == 1) {
+                        conv = 3;
+                        dn[j] = '_';
+                }
+                if (dn[j] == 2) {
+                        conv = 3;
+                        dn[j--] = ' ';
+                }
+        }
+        if (un < dp)
+                conv = 3;
+        /*
+         * If we didn't have any chars in filename,
+         * generate a default
+         */
+        if (!j)
+                dn[0] = '_';
+        /*
+         * If there wasn't any char dropped,
+         * there is no place for generation numbers
+         */
+        if (conv != 3) {
+                if (gen > 1)
+                        conv = 0;
+                goto done;
+        }
+        /*
+         * Now insert the generation number into the filename part
+         */
+        if (gen == 0)
+                goto done;
+        for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
+                *--wcp = gen % 10 + '0';
+        if (gen) {
+                conv = 0;
+                goto done;
+        }
+        for (i = 8; dn[--i] == ' ';);
+        i++;
+        if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
+                i = 8 - (gentext + sizeof(gentext) - wcp + 1);
+        /*
+         * Correct posision to where insert the generation number
+         */
+        cp = dn;
+        i -= mbsadjpos((const char**)&cp, i, unlen, 1, pmp->pm_flags, pmp->pm_d2u);
+        dn[i++] = '~';
+        while (wcp < gentext + sizeof(gentext))
+                dn[i++] = *wcp++;
+        /*
+         * Tail of the filename should be space
+         */
+        while (i < 8)
+                dn[i++] = ' ';
+        conv = 3;
+done:
+        /*
+         * The first character cannot be E5,
+         * because that means a deleted entry
+         */
+        if (dn[0] == 0xe5)
+                dn[0] = SLOT_E5;
+        return conv;
+}
 
-       /*
-        * Now insert the generation number into the filename part
-        */
-       if (gen == 0)
-               return conv;
-       for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
-               *--wcp = gen % 10 + '0';
-       if (gen)
-               return 0;
-       for (i = 8; dn[--i] == ' ';);
-       i++;
-       if (gentext + sizeof(gentext) - wcp + 1 > 8 - i)
-               i = 8 - (gentext + sizeof(gentext) - wcp + 1);
-       dn[i++] = '~';
-       while (wcp < gentext + sizeof(gentext))
-               dn[i++] = *wcp++;
-       return 3;
-#undef U2D
+/*
+ * Convert Local char to Windows char
+ */
+static u_int16_t
+unix2winchr(const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *
+pmp)
+{
+        u_char *outp, outbuf[3];
+        u_int16_t wc;
+        size_t olen;
+        if (*ilen == 0)
+                return (0);
+        if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+                outp = outbuf;
+                olen = 2;
+                if (lower & (LCASE_BASE | LCASE_EXT))
+                        msdos_iconv->convchr_case(pmp->pm_u2w, (const char **)
+instr,
+                                                  ilen, (char **)&outp, &olen,
+                                                  KICONV_FROM_LOWER);
+                else
+                        msdos_iconv->convchr(pmp->pm_u2w, (const char **)instr,
+                                             ilen, (char **)&outp, &olen);
+                /*
+                 * return '0' if end of filename
+                 */
+                if (olen == 2)
+                        return (0);
+                wc = (outbuf[0]<<8) | outbuf[1];
+                return (wc);
+        }
+        (*ilen)--;
+        wc = (*instr)[0];
+        if (lower & (LCASE_BASE | LCASE_EXT))
+                wc = u2l[wc];
+        (*instr)++;
+        return (wc);
 }
 
 /*
@@ -630,80 +906,65 @@ unix2dosfn(const u_char *un, u_char dn[12], int unlen, u_int gen, int u2d_loaded
  *      i.e. doesn't consist solely of blanks and dots
  */
 int
-unix2winfn(const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum,
-          int table_loaded, u_int16_t *u2w)
+unix2winfn(const u_char *un, int unlen, struct winentry *wep, int cnt, int chksum, struct msdosfsmount *pmp)
 {
-       const u_int8_t *cp;
-       u_int8_t *wcp;
-       int i;
-       u_int16_t code;
+        u_int8_t *wcp;
+        int i, end;
+        u_int16_t code;
 
-       /*
-        * Drop trailing blanks and dots
-        */
-       for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
+        /*
+         * Drop trailing blanks and dots
+         */
+        unlen = winLenFixup(un, unlen);
 
-       un += (cnt - 1) * WIN_CHARS;
-       unlen -= (cnt - 1) * WIN_CHARS;
+        /*
+         * Cut *un for this slot
+         */
+        unlen = mbsadjpos((const char **)&un, unlen, (cnt - 1) * WIN_CHARS, 2,
+                          pmp->pm_flags, pmp->pm_u2w);
 
-       /*
-        * Initialize winentry to some useful default
-        */
-       for (wcp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *wcp++ = 0xff);
-       wep->weCnt = cnt;
-       wep->weAttributes = ATTR_WIN95;
-       wep->weReserved1 = 0;
-       wep->weChksum = chksum;
+        /*
+         * Initialize winentry to some useful default
+         */
+        for (wcp = (u_int8_t *)wep, i = sizeof(*wep); --i >= 0; *wcp++ = 0xff);
+        wep->weCnt = cnt;
+        wep->weAttributes = ATTR_WIN95;
+        wep->weReserved1 = 0;
+        wep->weChksum = chksum;
        wep->weReserved2 = 0;
 
-       /*
-        * Now convert the filename parts
-        */
-       for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
-               if (--unlen < 0)
-                       goto done;
-               if (table_loaded && (*un & 0x80)) {
-                       code = u2w[*un++ & 0x7f];
-                       *wcp++ = code;
-                       *wcp++ = code >> 8;
-               } else {
-                       *wcp++ = *un++;
-                       *wcp++ = 0;
-               }
-       }
-       for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
-               if (--unlen < 0)
-                       goto done;
-               if (table_loaded && (*un & 0x80)) {
-                       code = u2w[*un++ & 0x7f];
-                       *wcp++ = code;
-                       *wcp++ = code >> 8;
-               } else {
-                       *wcp++ = *un++;
-                       *wcp++ = 0;
-               }
-       }
-       for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
-               if (--unlen < 0)
-                       goto done;
-               if (table_loaded && (*un & 0x80)) {
-                       code = u2w[*un++ & 0x7f];
-                       *wcp++ = code;
-                       *wcp++ = code >> 8;
-               } else {
-                       *wcp++ = *un++;
-                       *wcp++ = 0;
-               }
-       }
-       if (!unlen)
-               wep->weCnt |= WIN_LAST;
-       return unlen;
-
-done:
-       *wcp++ = 0;
-       *wcp++ = 0;
-       wep->weCnt |= WIN_LAST;
-       return 0;
+        /*
+         * Now convert the filename parts
+         */
+        end = 0;
+        for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0 && !end;)
+       {
+                code = unix2winchr(&un, &unlen, 0, pmp);
+                *wcp++ = code;
+                *wcp++ = code >> 8;
+                if (!code)
+                        end = WIN_LAST;
+        }
+        for (wcp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0 && !end;)
+       {
+                code = unix2winchr(&un, &unlen, 0, pmp);
+                *wcp++ = code;
+                *wcp++ = code >> 8;
+                if (!code)
+                        end = WIN_LAST;
+        }
+        for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0 && !end;)
+       {
+                code = unix2winchr(&un, &unlen, 0, pmp);
+               *wcp++ = code;
+                *wcp++ = code >> 8;
+                if (!code)
+                        end = WIN_LAST;
+        }
+        if (*un == '\0')
+                end = WIN_LAST;
+        wep->weCnt |= end;
+        return !end;
 }
 
 static __inline u_int8_t
@@ -722,111 +983,85 @@ find_lcode(u_int16_t code, u_int16_t *u2w)
  * Returns the checksum or -1 if no match
  */
 int
-winChkName(const u_char *un, int unlen, struct winentry *wep, int chksum,
-          int u2w_loaded, u_int16_t *u2w, int ul_loaded, u_int8_t *ul)
+winChkName(nbp, un, unlen, chksum, pmp)
+        struct mbnambuf *nbp;
+        const u_char *un;
+        size_t unlen;
+        int chksum;
+        struct msdosfsmount *pmp;
 {
-       u_int8_t *cp;
-       int i;
-       u_int16_t code;
-       u_int8_t c1, c2;
-
-       /*
-        * First compare checksums
-        */
-       if (wep->weCnt&WIN_LAST)
-               chksum = wep->weChksum;
-       else if (chksum != wep->weChksum)
-               chksum = -1;
-       if (chksum == -1)
-               return -1;
-
-       /*
-        * Offset of this entry
-        */
-       i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
-       un += i;
-       unlen -= i;
+        size_t len;
+        u_int16_t c1, c2;
+        u_char *np;
+       u_int16_t d_namlen;
+       char d_name[127];
+       bzero(d_name, 127);
+        /*
+         * We already have winentry in *nbp.
+         */
+        if (!mbnambuf_flush(nbp, d_name, &d_namlen) || d_namlen == 0)
+                return -1;
+#ifdef MSDOSFS_DEBUG
+        kprintf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen,
+                                                        d_name,
+                                                        d_namlen);
+#endif
+        /*
+         * Compare the name parts
+         */
+        len = d_namlen;
+        if (unlen != len)
+                return -2;
+        for (np = d_name; unlen > 0 && len > 0;) {
+                /*
+                 * Comparison must be case insensitive, because FAT disallows
+                 * to look up or create files in case sensitive even when
+                 * it's a long file name.
+                 */
+                c1 = unix2winchr((const u_char **)&np, &len, LCASE_BASE, pmp);
+                c2 = unix2winchr(&un, &unlen, LCASE_BASE, pmp);
+                if (c1 != c2)
+                        return -2;
+        }
+        return chksum;
+}
 
-       /*
-        * unlen being zero must not be treated as length missmatch. It is
-        * possible if the entry is WIN_LAST and contains nothing but the
-        * terminating 0.
-        */
-       if (unlen < 0)
-               return -1;
-       if ((wep->weCnt&WIN_LAST) && unlen > WIN_CHARS)
-               return -1;
+/*
+ * Convert Windows char to Local char
+ */
+static u_int16_t
+win2unixchr(u_int16_t wc, struct msdosfsmount *pmp)
+{
+        u_char *inp, *outp, inbuf[3], outbuf[3];
+        size_t ilen, olen, len;
+        if (wc == 0)
+                return (0);
+        if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+                inbuf[0] = (u_char)(wc>>8);
+                inbuf[1] = (u_char)wc;
+                inbuf[2] = '\0';
+                ilen = olen = len = 2;
+                inp = inbuf;
+                outp = outbuf;
+                msdos_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
+                                     (char **)&outp, &olen);
+                len -= olen;
 
-       /*
-        * Compare the name parts
-        */
-       for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
-               if (--unlen < 0) {
-                       if (!*cp++ && !*cp)
-                               return chksum;
-                       return -1;
-               }
-               code = (cp[1] << 8) | cp[0];
-               if (code & 0xff80) {
-                       if (u2w_loaded)
-                               code = find_lcode(code, u2w);
-                       else if (code & 0xff00)
-                               code = '?';
-               }
-               c1 = ul_loaded && (code & 0x80) ?
-                    ul[code & 0x7f] : u2l[code];
-               c2 = ul_loaded && (*un & 0x80) ?
-                    ul[*un & 0x7f] : u2l[*un];
-               if (c1 != c2)
-                       return -1;
-               cp += 2;
-               un++;
-       }
-       for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
-               if (--unlen < 0) {
-                       if (!*cp++ && !*cp)
-                               return chksum;
-                       return -1;
-               }
-               code = (cp[1] << 8) | cp[0];
-               if (code & 0xff80) {
-                       if (u2w_loaded)
-                               code = find_lcode(code, u2w);
-                       else if (code & 0xff00)
-                               code = '?';
-               }
-               c1 = ul_loaded && (code & 0x80) ?
-                    ul[code & 0x7f] : u2l[code];
-               c2 = ul_loaded && (*un & 0x80) ?
-                    ul[*un & 0x7f] : u2l[*un];
-               if (c1 != c2)
-                       return -1;
-               cp += 2;
-               un++;
-       }
-       for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
-               if (--unlen < 0) {
-                       if (!*cp++ && !*cp)
-                               return chksum;
-                       return -1;
-               }
-               code = (cp[1] << 8) | cp[0];
-               if (code & 0xff80) {
-                       if (u2w_loaded)
-                               code = find_lcode(code, u2w);
-                       else if (code & 0xff00)
-                               code = '?';
-               }
-               c1 = ul_loaded && (code & 0x80) ?
-                    ul[code & 0x7f] : u2l[code];
-               c2 = ul_loaded && (*un & 0x80) ?
-                    ul[*un & 0x7f] : u2l[*un];
-               if (c1 != c2)
-                       return -1;
-               cp += 2;
-               un++;
-       }
-       return chksum;
+                /*
+                 * return '?' if failed to convert
+                 */
+                if (len == 0) {
+                        wc = '?';
+                        return (wc);
+                }
+                wc = 0;
+                while(len--)
+                        wc |= (*(outp - len - 1) & 0xff) << (len << 3);
+                return (wc);
+        }
+        if (wc & 0xff00)
+                wc = '?';
+        return (wc);
 }
 
 /*
@@ -834,137 +1069,93 @@ winChkName(const u_char *un, int unlen, struct winentry *wep, int chksum,
  * Returns the checksum or -1 if impossible
  */
 int
-win2unixfn(struct winentry *wep, char *d_name, uint16_t *d_namlen, int chksum, int table_loaded,
-          u_int16_t *u2w)
+win2unixfn(nbp, wep, chksum, pmp)
+        struct mbnambuf *nbp;
+        struct winentry *wep;
+        int chksum;
+        struct msdosfsmount *pmp;
 {
-       u_int8_t *cp;
-       u_int8_t *np, *ep = d_name + WIN_MAXLEN;
-       u_int16_t code;
-       int i;
-
-       if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
-           || !(wep->weCnt&WIN_CNT))
-               return -1;
-
-       /*
-        * First compare checksums
-        */
-       if (wep->weCnt&WIN_LAST) {
-               chksum = wep->weChksum;
-               /*
-                * This works even though d_namlen is one byte!
-                */
-               *d_namlen = (wep->weCnt&WIN_CNT) * WIN_CHARS;
-       } else if (chksum != wep->weChksum)
-               chksum = -1;
-       if (chksum == -1)
-               return -1;
-
-       /*
-        * Offset of this entry
-        */
-       i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
-       np = (u_int8_t *)d_name + i;
-
-       /*
-        * Convert the name parts
-        */
-       for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
-               code = (cp[1] << 8) | cp[0];
-               switch (code) {
-               case 0:
-                       *np = '\0';
-                       *d_namlen -= sizeof(wep->wePart2)/2
-                           + sizeof(wep->wePart3)/2 + i + 1;
-                       return chksum;
-               case '/':
-                       *np = '\0';
-                       return -1;
-               default:
-                       if (code & 0xff80) {
-                               if (table_loaded)
-                                       code = find_lcode(code, u2w);
-                               else if (code & 0xff00)
-                                       code = '?';
-                       }
-                       *np++ = code;
-                       break;
-               }
-               /*
-                * The size comparison should result in the compiler
-                * optimizing the whole if away
-                */
-               if (WIN_MAXLEN % WIN_CHARS < sizeof(wep->wePart1) / 2
-                   && np > ep) {
-                       np[-1] = 0;
-                       return -1;
-               }
-               cp += 2;
-       }
-       for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
-               code = (cp[1] << 8) | cp[0];
-               switch (code) {
-               case 0:
-                       *np = '\0';
-                       *d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
-                       return chksum;
-               case '/':
-                       *np = '\0';
-                       return -1;
-               default:
-                       if (code & 0xff80) {
-                               if (table_loaded)
-                                       code = find_lcode(code, u2w);
-                               else if (code & 0xff00)
-                                       code = '?';
-                       }
-                       *np++ = code;
-                       break;
-               }
-               /*
-                * The size comparisons should be optimized away
-                */
-               if (WIN_MAXLEN % WIN_CHARS >= sizeof(wep->wePart1) / 2
-                   && WIN_MAXLEN % WIN_CHARS < (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
-                   && np > ep) {
-                       np[-1] = 0;
-                       return -1;
-               }
-               cp += 2;
-       }
-       for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
-               code = (cp[1] << 8) | cp[0];
-               switch (code) {
-               case 0:
-                       *np = '\0';
-                       *d_namlen -= i + 1;
-                       return chksum;
-               case '/':
-                       *np = '\0';
-                       return -1;
-               default:
-                       if (code & 0xff80) {
-                               if (table_loaded)
-                                       code = find_lcode(code, u2w);
-                               else if (code & 0xff00)
-                                       code = '?';
-                       }
-                       *np++ = code;
-                       break;
-               }
-               /*
-                * See above
-                */
-               if (WIN_MAXLEN % WIN_CHARS >= (sizeof(wep->wePart1) + sizeof(wep->wePart2)) / 2
-                   && np > ep) {
-                       np[-1] = 0;
-                       return -1;
-               }
-               cp += 2;
-       }
-       return chksum;
+        u_int8_t *cp;
+        u_int8_t *np, name[WIN_CHARS * 2 + 1];
+        u_int16_t code;
+        int i;
+        if ((wep->weCnt&WIN_CNT) > howmany(WIN_MAXLEN, WIN_CHARS)
+            || !(wep->weCnt&WIN_CNT))
+                return -1;
+        /*
+         * First compare checksums
+         */
+        if (wep->weCnt&WIN_LAST) {
+                chksum = wep->weChksum;
+        } else if (chksum != wep->weChksum)
+                chksum = -1;
+        if (chksum == -1)
+                return -1;
+        /*
+         * Convert the name parts
+         */
+        np = name;
+        for (cp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0;) {
+                code = (cp[1] << 8) | cp[0];
+                switch (code) {
+                case 0:
+                        *np = '\0';
+                        mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+                        return chksum;
+                case '/':
+                        *np = '\0';
+                        return -1;
+                default:
+                        code = win2unixchr(code, pmp);
+                        if (code & 0xff00)
+                                *np++ = code >> 8;
+                        *np++ = code;
+                        break;
+                }
+                cp += 2;
+        }
+        for (cp = wep->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0;) {
+                code = (cp[1] << 8) | cp[0];
+                switch (code) {
+                case 0:
+                        *np = '\0';
+                        mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+                        return chksum;
+                case '/':
+                        *np = '\0';
+                        return -1;
+                default:
+                        code = win2unixchr(code, pmp);
+                        if (code & 0xff00)
+                                *np++ = code >> 8;
+                        *np++ = code;
+                        break;
+                }
+                cp += 2;
+        }
+        for (cp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0;) {
+                code = (cp[1] << 8) | cp[0];
+                switch (code) {
+                case 0:
+                        *np = '\0';
+                        mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+                        return chksum;
+                case '/':
+                        *np = '\0';
+                        return -1;
+                default:
+                        code = win2unixchr(code, pmp);
+                        if (code & 0xff00)
+                                *np++ = code >> 8;
+                        *np++ = code;
+                        break;
+                }
+                cp += 2;
+        }
+        *np = '\0';
+        mbnambuf_write(nbp, name, (wep->weCnt & WIN_CNT) - 1);
+        return chksum;
 }
-
 /*
  * Compute the checksum of a DOS filename for Win95 use
  */
@@ -983,12 +1174,25 @@ winChksum(u_int8_t *name)
  * Determine the number of slots necessary for Win95 names
  */
 int
-winSlotCnt(const u_char *un, int unlen)
+winSlotCnt(un, unlen, pmp)
+        const u_char *un;
+        int unlen;
+        struct msdosfsmount *pmp;
 {
-       unlen = winLenFixup(un, unlen);
-       if (unlen > WIN_MAXLEN)
-               return 0;
-       return howmany(unlen, WIN_CHARS);
+        size_t wlen;
+        char wn[WIN_MAXLEN * 2 + 1], *wnp;
+        unlen = winLenFixup(un, unlen);
+        if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+                wlen = WIN_MAXLEN * 2;
+                wnp = wn;
+                msdos_iconv->conv(pmp->pm_u2w, (const char **)&un, &unlen, &wnp, &wlen);
+                if (unlen > 0)
+                        return 0;
+                return howmany(WIN_MAXLEN - wlen/2, WIN_CHARS);
+        }
+        if (unlen > WIN_MAXLEN)
+                return 0;
+        return howmany(unlen, WIN_CHARS);
 }
 
 /*
diff --git a/sys/vfs/msdosfs/msdosfs_iconv/Makefile b/sys/vfs/msdosfs/msdosfs_iconv/Makefile
new file mode 100644 (file)
index 0000000..1714612
--- /dev/null
@@ -0,0 +1,6 @@
+# $FreeBSD: src/sys/modules/msdosfs_iconv/Makefile,v 1.1.30.1 2009/04/15 03:14:26 kensmith Exp $
+
+KMOD=  msdos_iconv
+SRCS=  msdosfs_iconv.c
+
+.include <bsd.kmod.mk>
diff --git a/sys/vfs/msdosfs/msdosfs_iconv/msdosfs_iconv.c b/sys/vfs/msdosfs/msdosfs_iconv/msdosfs_iconv.c
new file mode 100644 (file)
index 0000000..f33c07b
--- /dev/null
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2003 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.
+ * __FBSDID("$FreeBSD: src/sys/fs/msdosfs/msdosfs_iconv.c,v 1.4.8.1 2009/04/15 03:14:26 kensmith Exp $");
+ */
+
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/iconv.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+
+VFS_DECLARE_ICONV(msdos);
index 01cb43d..3659369 100644 (file)
@@ -84,6 +84,7 @@
 int
 msdosfs_lookup(struct vop_old_lookup_args *ap)
 {
+       struct mbnambuf nb;
        struct vnode *vdp = ap->a_dvp;
        struct vnode **vpp = ap->a_vpp;
        struct componentname *cnp = ap->a_cnp;
@@ -146,23 +147,20 @@ msdosfs_lookup(struct vop_old_lookup_args *ap)
                blkoff = MSDOSFSROOT_OFS;
                goto foundroot;
        }
-
        switch (unix2dosfn((const u_char *)cnp->cn_nameptr, dosfilename,
-           cnp->cn_namelen, 0,
-           pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
-           pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu)) {
+           cnp->cn_namelen, 0, pmp)) {
        case 0:
                return (EINVAL);
        case 1:
                break;
        case 2:
                wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
-                   cnp->cn_namelen) + 1;
+                   cnp->cn_namelen, pmp) + 1;
                break;
        case 3:
                olddos = 0;
                wincnt = winSlotCnt((const u_char *)cnp->cn_nameptr,
-                   cnp->cn_namelen) + 1;
+                   cnp->cn_namelen, pmp) + 1;
                break;
        }
        if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME) {
@@ -190,6 +188,7 @@ msdosfs_lookup(struct vop_old_lookup_args *ap)
         * by cnp->cn_nameptr.
         */
        tdp = NULL;
+       mbnambuf_init(&nb);
        /*
         * The outer loop ranges over the clusters that make up the
         * directory.  Note that the root directory is different from all
@@ -229,6 +228,7 @@ msdosfs_lookup(struct vop_old_lookup_args *ap)
                                 * Drop memory of previous long matches
                                 */
                                chksum = -1;
+                               mbnambuf_init(&nb);
 
                                if (slotcount < wincnt) {
                                        slotcount++;
@@ -250,20 +250,22 @@ msdosfs_lookup(struct vop_old_lookup_args *ap)
                                 * Check for Win95 long filename entry
                                 */
                                if (dep->deAttributes == ATTR_WIN95) {
-                                       if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
+                               if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
                                                continue;
-
-                                       chksum = winChkName((const u_char *)cnp->cn_nameptr,
-                                                           unlen,
-                                                           (struct winentry *)dep,
-                                                           chksum,
-                                                           pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
-                                                           pmp->pm_u2w,
-                                                           pmp->pm_flags & MSDOSFSMNT_ULTABLE,
-                                                           pmp->pm_ul);
+                                       chksum = win2unixfn(&nb,
+                                            (struct winentry *)dep, chksum,
+                                            pmp);
                                        continue;
                                }
 
+                                chksum = winChkName(&nb,
+                                    (const u_char *)cnp->cn_nameptr, unlen,
+                                    chksum, pmp);
+                               if (chksum == -2) {
+                                        chksum = -1;
+                                        continue;
+                                }
+
                                /*
                                 * Ignore volume labels (anywhere, not just
                                 * the root directory).
@@ -639,8 +641,7 @@ createde(struct denode *dep, struct denode *ddep, struct denode **depp,
                        }
                        if (!unix2winfn(un, unlen, (struct winentry *)ndep,
                                        cnt++, chksum,
-                                       pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
-                                       pmp->pm_u2w))
+                                       pmp))
                                break;
                }
        }
@@ -959,9 +960,7 @@ uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
        
        if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
                return (unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
-                   cnp->cn_namelen, 0,
-                   pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
-                   pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu) ?
+                   cnp->cn_namelen, 0, pmp) ?
                    0 : EINVAL);
 
        for (gen = 1;; gen++) {
@@ -969,9 +968,7 @@ uniqdosname(struct denode *dep, struct componentname *cnp, u_char *cp)
                 * Generate DOS name with generation number
                 */
                if (!unix2dosfn((const u_char *)cnp->cn_nameptr, cp,
-                   cnp->cn_namelen, gen,
-                   pmp->pm_flags & MSDOSFSMNT_U2WTABLE, pmp->pm_u2d,
-                   pmp->pm_flags & MSDOSFSMNT_ULTABLE, pmp->pm_lu))
+                   cnp->cn_namelen, gen, pmp))
                        return gen == 1 ? EINVAL : EEXIST;
 
                /*
index 7cdc8ce..35232bd 100644 (file)
@@ -56,6 +56,7 @@
 #include <sys/nlookup.h>
 #include <sys/kernel.h>
 #include <sys/vnode.h>
+#include <sys/iconv.h>
 #include <sys/mount.h>
 #include <sys/buf.h>
 #include <sys/fcntl.h>
 #include "fat.h"
 
 extern struct vop_ops msdosfs_vnode_vops;
+struct iconv_functions *msdos_iconv;
 
 #define MSDOSFS_DFLTBSIZE       4096
-
+#define ENCODING_UNICODE        "UTF-16BE"
 #if 1 /*def PC98*/
 /*
  * XXX - The boot signature formatted by NEC PC-98 DOS looks like a
@@ -109,19 +111,29 @@ update_mp(struct mount *mp, struct msdosfs_args *argp)
 {
        struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
        int error;
+        char cs_local[ICONV_CSNMAXLEN];
+        char cs_dos[ICONV_CSNMAXLEN];
 
        pmp->pm_gid = argp->gid;
        pmp->pm_uid = argp->uid;
        pmp->pm_mask = argp->mask & ALLPERMS;
        pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
-       if (pmp->pm_flags & MSDOSFSMNT_U2WTABLE) {
-               bcopy(argp->u2w, pmp->pm_u2w, sizeof(pmp->pm_u2w));
-               bcopy(argp->d2u, pmp->pm_d2u, sizeof(pmp->pm_d2u));
-               bcopy(argp->u2d, pmp->pm_u2d, sizeof(pmp->pm_u2d));
-       }
-       if (pmp->pm_flags & MSDOSFSMNT_ULTABLE) {
-               bcopy(argp->ul, pmp->pm_ul, sizeof(pmp->pm_ul));
-               bcopy(argp->lu, pmp->pm_lu, sizeof(pmp->pm_lu));
+       if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+               bcopy(argp->cs_local, cs_local, sizeof(cs_local));
+               bcopy(argp->cs_dos, cs_dos, sizeof(cs_dos));
+               kprintf("local: %s dos: %s\n",argp->cs_local, argp->cs_dos);
+               error = msdos_iconv->open(cs_local, ENCODING_UNICODE, &pmp->pm_w2u);
+               if(error)
+                       return error;
+               error = msdos_iconv->open(ENCODING_UNICODE, cs_local, &pmp->pm_u2w);
+               if(error)
+                       return error;
+               error = msdos_iconv->open(cs_dos, cs_local, &pmp->pm_u2d);
+               if(error)
+                       return error;
+               error = msdos_iconv->open(cs_local, cs_dos, &pmp->pm_d2u);
+               if(error)
+                       return error;
        }
 
        if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
@@ -622,6 +634,16 @@ msdosfs_unmount(struct mount *mp, int mntflags)
                return error;
        pmp = VFSTOMSDOSFS(mp);
        pmp->pm_devvp->v_rdev->si_mountpoint = NULL;
+       if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdos_iconv) {
+               if(pmp->pm_w2u)
+                       msdos_iconv->close(pmp->pm_w2u);
+               if(pmp->pm_u2w)
+                       msdos_iconv->close(pmp->pm_u2w);
+               if(pmp->pm_d2u)
+                       msdos_iconv->close(pmp->pm_d2u);
+               if(pmp->pm_u2d)
+                       msdos_iconv->close(pmp->pm_u2d);
+       }
 #ifdef MSDOSFS_DEBUG
        {
                struct vnode *vp = pmp->pm_devvp;
index fdb549c..f0c6aff 100644 (file)
@@ -1490,6 +1490,7 @@ msdosfs_symlink(struct vop_old_symlink_args *ap)
 static int
 msdosfs_readdir(struct vop_readdir_args *ap)
 {
+       struct mbnambuf nb;
        int error = 0;
        int diff;
        long n;
@@ -1512,7 +1513,7 @@ msdosfs_readdir(struct vop_readdir_args *ap)
        uint16_t d_namlen;
        uint8_t d_type;
        char *d_name_storage = NULL;
-       char *d_name;
+       char *d_name = NULL;
 
        if ((error = vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY)) != 0)
                return (error);
@@ -1586,7 +1587,7 @@ msdosfs_readdir(struct vop_readdir_args *ap)
                                if (n == 0) {
                                        d_namlen = 1;
                                        d_name = ".";
-                               } else /* if (n == 1) */{
+                               } else if (n == 1) {
                                        d_namlen = 2;
                                        d_name = "..";
                                }
@@ -1607,6 +1608,7 @@ msdosfs_readdir(struct vop_readdir_args *ap)
        }
 
        d_name_storage = kmalloc(WIN_MAXLEN, M_TEMP, M_WAITOK);
+       mbnambuf_init(&nb);
        off = offset;
 
        while (uio->uio_resid > 0) {
@@ -1640,6 +1642,7 @@ msdosfs_readdir(struct vop_readdir_args *ap)
                            dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
 #endif
                        d_name = d_name_storage;
+                       d_namlen = 0;
                        /*
                         * If this is an unused entry, we can stop.
                         */
@@ -1652,19 +1655,19 @@ msdosfs_readdir(struct vop_readdir_args *ap)
                         */
                        if (dentp->deName[0] == SLOT_DELETED) {
                                chksum = -1;
+                               mbnambuf_init(&nb);
                                continue;
                        }
-
                        /*
                         * Handle Win95 long directory entries
                         */
                        if (dentp->deAttributes == ATTR_WIN95) {
                                if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
                                        continue;
-                               chksum = win2unixfn((struct winentry *)dentp,
-                                       d_name, &d_namlen, chksum,
-                                       pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
-                                       pmp->pm_u2w);
+                               chksum = win2unixfn(&nb,
+                                       (struct winentry *)dentp,
+                                       chksum,
+                                       pmp);
                                continue;
                        }
 
@@ -1673,6 +1676,7 @@ msdosfs_readdir(struct vop_readdir_args *ap)
                         */
                        if (dentp->deAttributes & ATTR_VOLUME) {
                                chksum = -1;
+                               mbnambuf_init(&nb);
                                continue;
                        }
                        /*
@@ -1703,11 +1707,11 @@ msdosfs_readdir(struct vop_readdir_args *ap)
                                    dentp->deLowerCase |
                                        ((pmp->pm_flags & MSDOSFSMNT_SHORTNAME) ?
                                        (LCASE_BASE | LCASE_EXT) : 0),
-                                   pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
-                                   pmp->pm_d2u,
-                                   pmp->pm_flags & MSDOSFSMNT_ULTABLE,
-                                   pmp->pm_ul);
-                       }
+                                       pmp);
+                                       mbnambuf_init(&nb);
+                       } else {
+                                       mbnambuf_flush(&nb, d_name, &d_namlen);
+}
                        chksum = -1;
                        if (vop_write_dirent(&error, uio, d_ino, d_type,
                            d_namlen, d_name)) {
index a751ca6..d67fd29 100644 (file)
@@ -58,9 +58,8 @@
 MALLOC_DECLARE(M_MSDOSFSMNT);
 #endif
 #endif
-
+#include <sys/iconv.h>
 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
-
 /*
  * Layout of the mount control block for a msdos file system.
  */
@@ -97,11 +96,10 @@ struct msdosfsmount {
        u_int *pm_inusemap;     /* ptr to bitmap of in-use clusters */
        u_int pm_flags;         /* see below */
        struct netexport pm_export;     /* export information */
-       u_int16_t pm_u2w[128];  /* Local->Unicode table */
-       u_int8_t  pm_ul[128];   /* Local upper->lower table */
-       u_int8_t  pm_lu[128];   /* Local lower->upper table */
-       u_int8_t  pm_d2u[128];  /* DOS->local table */
-       u_int8_t  pm_u2d[128];  /* Local->DOS table */
+       void *pm_u2w;  /* Local->Unicode handle */
+       void *pm_w2u;  /* Unicode->Local handle */
+       void *pm_d2u;  /* DOS->local handle */
+       void *pm_u2d;  /* Local->DOS handle */
 };
 /* Byte offset in FAT on filesystem pmp, cluster cn */
 #define        FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv)
@@ -248,11 +246,8 @@ struct msdosfs_args {
        mode_t  mask;           /* mask to be applied for msdosfs perms */
        int     flags;          /* see below */
        int magic;              /* version number */
-       u_int16_t u2w[128];     /* Local->Unicode table */
-       u_int8_t  ul[128];      /* Local upper->lower table */
-       u_int8_t  lu[128];      /* Local lower->upper table */
-       u_int8_t  d2u[128];     /* DOS->local table */
-       u_int8_t  u2d[128];     /* Local->DOS table */
+        char cs_local[ICONV_CSNMAXLEN];
+        char cs_dos[ICONV_CSNMAXLEN];
 };
 
 /*
@@ -261,13 +256,12 @@ struct msdosfs_args {
 #define        MSDOSFSMNT_SHORTNAME    1       /* Force old DOS short names only */
 #define        MSDOSFSMNT_LONGNAME     2       /* Force Win'95 long names */
 #define        MSDOSFSMNT_NOWIN95      4       /* Completely ignore Win95 entries */
-#define MSDOSFSMNT_U2WTABLE     0x10    /* Local->Unicode and local<->DOS   */
+#define MSDOSFSMNT_KICONV     0x10    /* Local->Unicode and local<->DOS   */
                                        /* tables loaded                    */
-#define MSDOSFSMNT_ULTABLE      0x20    /* Local upper<->lower table loaded */
 /* All flags above: */
 #define        MSDOSFSMNT_MNTOPT \
        (MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \
-        /*|MSDOSFSMNT_GEMDOSFS*/|MSDOSFSMNT_U2WTABLE|MSDOSFSMNT_ULTABLE)
+        /*|MSDOSFSMNT_GEMDOSFS*/|MSDOSFSMNT_KICONV)
 #define        MSDOSFSMNT_RONLY        0x80000000      /* mounted read-only    */
 #define        MSDOSFSMNT_WAITONFAT    0x40000000      /* mounted synchronous  */
 #define        MSDOSFS_FATMIRROR       0x20000000      /* FAT is mirrored */