libiconv: convert NTFS to libiconv.
authorAlexander Polakov <polachok@gmail.com>
Sat, 12 Sep 2009 23:22:09 +0000 (03:22 +0400)
committerAlexander Polakov <polachok@gmail.com>
Sat, 12 Sep 2009 23:40:41 +0000 (03:40 +0400)
Partly-taken-from: FreeBSD

sys/vfs/ntfs/Makefile
sys/vfs/ntfs/ntfs.h
sys/vfs/ntfs/ntfs_iconv/Makefile [new file with mode: 0644]
sys/vfs/ntfs/ntfs_iconv/ntfs_iconv.c [copied from sys/vfs/ntfs/ntfsmount.h with 63% similarity]
sys/vfs/ntfs/ntfs_subr.c
sys/vfs/ntfs/ntfs_subr.h
sys/vfs/ntfs/ntfs_vfsops.c
sys/vfs/ntfs/ntfs_vnops.c
sys/vfs/ntfs/ntfsmount.h

index 49370d6..91220b9 100644 (file)
@@ -5,4 +5,5 @@ KMOD=   ntfs
 SRCS=  ntfs_vfsops.c ntfs_vnops.c ntfs_subr.c ntfs_ihash.c \
        ntfs_compr.c
 
+SUBDIR= ntfs_iconv
 .include <bsd.kmod.mk>
index 8dda76f..516d260 100644 (file)
@@ -262,6 +262,8 @@ struct ntfsmount {
        struct netexport ntm_export;    /* export information */
        wchar *         ntm_82u;        /* 8bit to Unicode */
        char **         ntm_u28;        /* Unicode to 8 bit */
+       void *          ntm_ic_l2u;     /* Local to Unicode (iconv) */
+       void *          ntm_ic_u2l;     /* Unicode to Local (iconv) */
 };
 
 #define ntm_mftcn      ntm_bootfile.bf_mftcn
diff --git a/sys/vfs/ntfs/ntfs_iconv/Makefile b/sys/vfs/ntfs/ntfs_iconv/Makefile
new file mode 100644 (file)
index 0000000..0e79905
--- /dev/null
@@ -0,0 +1,7 @@
+# $FreeBSD: src/sys/modules/ntfs_iconv/Makefile,v 1.1 2003/09/26 20:26:25 fjoe Exp $
+
+.PATH: ${.CURDIR}/../../fs/ntfs
+KMOD=  ntfs_iconv
+SRCS=  ntfs_iconv.c
+
+.include <bsd.kmod.mk>
similarity index 63%
copy from sys/vfs/ntfs/ntfsmount.h
copy to sys/vfs/ntfs/ntfs_iconv/ntfs_iconv.c
index 2f78b38..23d906f 100644 (file)
@@ -1,7 +1,5 @@
-/*     $NetBSD: ntfsmount.h,v 1.3 1999/07/26 14:02:32 jdolecek Exp $   */
-
 /*-
- * Copyright (c) 1998, 1999 Semen Ustimenko
+ * Copyright (c) 2003 Ryuichiro Imura
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * 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/ntfs/ntfsmount.h,v 1.6.2.1 2001/10/12 22:08:49 semenu Exp $
- * $DragonFly: src/sys/vfs/ntfs/ntfsmount.h,v 1.2 2003/06/17 04:28:54 dillon Exp $
+ * $FreeBSD: src/sys/fs/ntfs/ntfs_iconv.c,v 1.1 2003/09/26 20:26:23 fjoe Exp $
  */
 
-#define        NTFS_MFLAG_CASEINS      0x00000001
-#define        NTFS_MFLAG_ALLNAMES     0x00000002
-#define        NTFSMNT_U2WTABLE        0x00000004
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
 
-struct ntfs_args {
-       char    *fspec;                 /* block special device to mount */
-       struct  export_args export;     /* network export information */
-       uid_t   uid;                    /* uid that owns ntfs files */
-       gid_t   gid;                    /* gid that owns ntfs files */
-       mode_t  mode;                   /* mask to be applied for ntfs perms */
-       u_long  flag;                   /* additional flags */
-       u_int16_t u2w[256];             /* Unix to Wchar */
-};
+VFS_DECLARE_ICONV(ntfs);
index 44a26a9..427dcda 100644 (file)
@@ -43,6 +43,7 @@
 #include <sys/lock.h>
 #include <sys/spinlock.h>
 #include <sys/spinlock2.h>
+#include <sys/iconv.h>
 
 #include <machine/inttypes.h>
 
@@ -77,6 +78,7 @@ static wchar *ntfs_toupper_tab;
 #define NTFS_TOUPPER(ch)       (ntfs_toupper_tab[(ch)])
 static struct lock ntfs_toupper_lock;
 static signed int ntfs_toupper_usecount;
+extern struct iconv_functions *ntfs_iconv;
 
 /* support macro for ntfs_ntvattrget() */
 #define NTFS_AALPCMP(aalp,type,name,namelen) (                         \
@@ -646,20 +648,41 @@ static int
 ntfs_uastricmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
               const char *astr, size_t astrlen)
 {
-       size_t             i;
-       int             res;
+       int len;
+       size_t i, j, mbstrlen = astrlen;
+       int res;
+       wchar wc;
+
+       if (ntmp->ntm_ic_l2u) {
+               for (i = 0, j = 0; i < ustrlen && j < astrlen; i++, j++) {
+                       if (j < astrlen -1) {
+                               wc = (wchar)astr[j]<<8 | (astr[j+1]&0xFF);
+                               len = 2;
+                       } else {
+                               wc = (wchar)astr[j]<<8 & 0xFF00;
+                               len = 1;
+                       }
+                       res = ((int) NTFS_TOUPPER(ustr[i])) -
+                               ((int)NTFS_TOUPPER(NTFS_82U(wc, &len)));
+                       j += len - 1;
+                       mbstrlen -= len - 1;
 
-       /*
-        * XXX We use NTFS_82U(NTFS_U28(c)) to get rid of unicode
-        * symbols not covered by translation table
-        */
-       for (i = 0; i < ustrlen && i < astrlen; i++) {
-               res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i])))) -
-                       ((int)NTFS_TOUPPER(NTFS_82U(astr[i])));
-               if (res)
-                       return res;
+                       if (res)
+                               return res;
+               }
+       } else {
+               /*
+                * We use NTFS_82U(NTFS_U28(c)) to get rid of unicode
+                * symbols not covered by translation table
+                */
+               for (i = 0; i < ustrlen && i < astrlen; i++) {
+                       res = ((int) NTFS_TOUPPER(NTFS_82U(NTFS_U28(ustr[i]), &len))) -
+                               ((int)NTFS_TOUPPER(NTFS_82U((wchar)astr[i], &len)));
+                       if (res)
+                               return res;
+               }
        }
-       return (ustrlen - astrlen);
+       return (ustrlen - mbstrlen);
 }
 
 /*
@@ -669,15 +692,25 @@ static int
 ntfs_uastrcmp(struct ntfsmount *ntmp, const wchar *ustr, size_t ustrlen,
              const char *astr, size_t astrlen)
 {
-       size_t             i;
-       int             res;
-
-       for (i = 0; (i < ustrlen) && (i < astrlen); i++) {
-               res = (int) (((char)NTFS_U28(ustr[i])) - astr[i]);
+       char u, l;
+       size_t i, j, mbstrlen = astrlen;
+       int res;
+       wchar wc;
+
+       for (i = 0, j = 0; (i < ustrlen) && (j < astrlen); i++, j++) {
+               res = 0;
+               wc = NTFS_U28(ustr[i]);
+               u = (char)(wc>>8);
+               l = (char)wc;
+               if (u != '\0' && j < astrlen -1) {
+                       res = (int) (u - astr[j++]);
+                       mbstrlen--;
+               }
+               res = (res<<8) + (int) (l - astr[j]);
                if (res)
                        return res;
        }
-       return (ustrlen - astrlen);
+       return (ustrlen - mbstrlen);
 }
 
 /* 
@@ -811,7 +844,7 @@ ntfs_ntlookupattr(struct ntfsmount *ntmp, const char *name, int namelen,
  */
 int
 ntfs_ntlookupfile(struct ntfsmount *ntmp, struct vnode *vp,
-                 struct componentname *cnp, struct vnode **vpp)
+                 struct componentname *cnp, struct vnode **vpp)
 {
        struct fnode   *fp = VTOF(vp);
        struct ntnode  *ip = FTONT(fp);
@@ -1660,7 +1693,7 @@ ntfs_readattr(struct ntfsmount *ntmp, struct ntnode *ip, u_int32_t attrnum,
                while (left) {
                        error = ntfs_readattr_plain(ntmp, ip, attrnum,
                                                  attrname, ntfs_cntob(cn),
-                                                 ntfs_cntob(NTFS_COMPUNIT_CL),
+                                                 ntfs_cntob(NTFS_COMPUNIT_CL),
                                                  cup, &init, NULL);
                        if (error)
                                break;
@@ -1905,11 +1938,17 @@ ntfs_toupper_unuse(void)
 } 
 
 int
-ntfs_u28_init(struct ntfsmount *ntmp, wchar *u2w)
+ntfs_u28_init(struct ntfsmount *ntmp, wchar *u2w, char *cs_local,
+        char *cs_ntfs)
 {
        char ** u28;
        int i, j, h, l;
 
+       if (ntfs_iconv && cs_local) {
+               ntfs_iconv->open(cs_local, cs_ntfs, &ntmp->ntm_ic_u2l);
+               return (0);
+       }
+
        MALLOC(u28, char **, 256 * sizeof(char*), M_TEMP, M_WAITOK | M_ZERO);
 
        for (i=0; i<256; i++) {
@@ -1936,6 +1975,13 @@ ntfs_u28_uninit(struct ntfsmount *ntmp)
        char ** u28;
        int i;
 
+       if (ntmp->ntm_u28 == NULL) {
+               if (ntfs_iconv && ntmp->ntm_ic_u2l) {
+                       ntfs_iconv->close(ntmp->ntm_ic_u2l);
+               }
+               return (0);
+       }
+
        if (ntmp->ntm_u28 == NULL)
                return (0);
 
@@ -1951,22 +1997,21 @@ ntfs_u28_uninit(struct ntfsmount *ntmp)
 }
 
 int
-ntfs_82u_init(struct ntfsmount *ntmp, u_int16_t *u2w)
+ntfs_82u_init(struct ntfsmount *ntmp, char *cs_local, char *cs_ntfs)
+
 {
        wchar * _82u;
        int i;
 
+       if (ntfs_iconv && cs_local) {
+               ntfs_iconv->open(cs_ntfs, cs_local, &ntmp->ntm_ic_l2u);
+               return (0);
+       }
+
        MALLOC(_82u, wchar *, 256 * sizeof(wchar), M_TEMP, M_WAITOK);
 
-       if (u2w == NULL) {
-               for (i=0; i<256; i++)
-                       _82u[i] = i;
-       } else {
-               for (i=0; i<128; i++)
-                       _82u[i] = i;
-               for (i=0; i<128; i++)
-                       _82u[i+128] = u2w[i];
-       }
+       for (i=0; i<256; i++)
+               _82u[i] = i;
 
        ntmp->ntm_82u = _82u;
 
@@ -1976,6 +2021,13 @@ ntfs_82u_init(struct ntfsmount *ntmp, u_int16_t *u2w)
 int
 ntfs_82u_uninit(struct ntfsmount *ntmp)
 {
+       if (ntmp->ntm_82u == NULL) {
+               if (ntfs_iconv && ntmp->ntm_ic_l2u) {
+                       ntfs_iconv->close(ntmp->ntm_ic_l2u);
+               }
+               return (0);
+       }
+
        FREE(ntmp->ntm_82u, M_TEMP);
        return (0);
 }
@@ -1986,10 +2038,28 @@ ntfs_82u_uninit(struct ntfsmount *ntmp)
  * and substitutes a '_' for it if the result would be '\0';
  * something better has to be definitely though out
  */
-char
+wchar
 ntfs_u28(struct ntfsmount *ntmp, wchar wc)
 {
-       char * p;
+       char *p, *outp, inbuf[3], outbuf[3];
+       size_t ilen, olen;
+
+       if (ntfs_iconv && ntmp->ntm_ic_u2l) {
+               ilen = olen = 2;
+               inbuf[0] = (char)(wc>>8);
+               inbuf[1] = (char)wc;
+               inbuf[2] = '\0';
+               p = inbuf;
+               outp = outbuf;
+               ntfs_iconv->convchr(ntmp->ntm_ic_u2l, (const char **)&p, &ilen,
+                                   &outp, &olen);
+               if (olen == 1) {
+                       return ((wchar)(outbuf[0]&0xFF));
+               } else if (olen == 0) {
+                       return ((wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF)));
+               }
+               return ('?');
+       }
 
        p = ntmp->ntm_u28[(wc>>8)&0xFF];
        if (p == NULL)
@@ -1997,3 +2067,34 @@ ntfs_u28(struct ntfsmount *ntmp, wchar wc)
        return (p[wc&0xFF]);
 }
 
+wchar
+ntfs_82u(struct ntfsmount *ntmp,
+       wchar wc,
+       int *len)
+{
+       char *p, *outp, inbuf[3], outbuf[3];
+       wchar uc;
+       size_t ilen, olen;
+
+       if (ntfs_iconv && ntmp->ntm_ic_l2u) {
+               ilen = (size_t)*len;
+               olen = 2;
+
+               inbuf[0] = (char)(wc>>8);
+               inbuf[1] = (char)wc;
+               inbuf[2] = '\0';
+               p = inbuf;
+               outp = outbuf;
+               ntfs_iconv->convchr(ntmp->ntm_ic_l2u, (const char **)&p, &ilen,
+                                   &outp, &olen);
+               *len -= (int)ilen;
+               uc = (wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF));
+
+               return (uc);
+       }
+
+       if (ntmp->ntm_82u != NULL)
+               return (ntmp->ntm_82u[wc&0xFF]);
+
+       return ('?');
+}
index 04962b3..46de35f 100644 (file)
@@ -108,13 +108,14 @@ void ntfs_toupper_unuse (void);
 int ntfs_fget (struct ntfsmount *, struct ntnode *, int, char *, struct fnode **);
 void ntfs_frele (struct fnode *);
 
-int ntfs_u28_init(struct ntfsmount *ntmp, wchar *u2w);
+int ntfs_u28_init(struct ntfsmount *ntmp, wchar *u2w, char *cs_local, char *cs_ntfs);
 int ntfs_u28_uninit(struct ntfsmount *ntmp);
-int ntfs_82u_init(struct ntfsmount *ntmp, u_int16_t *u2w);
+int ntfs_82u_init(struct ntfsmount *ntmp, char *cs_local, char *cs_ntfs);
 int ntfs_82u_uninit(struct ntfsmount *ntmp);
-char ntfs_u28(struct ntfsmount *ntmp, wchar wc);
+wchar ntfs_u28(struct ntfsmount *ntmp, wchar wc);
+wchar ntfs_82u(struct ntfsmount *ntmp, wchar wc, int *len);
 #define NTFS_U28(ch)           ntfs_u28(ntmp, (ch))
-#define NTFS_82U(ch)           (ntmp->ntm_82u[(ch)&0xFF])
+#define NTFS_82U(ch, len)       ntfs_82u(ntmp, (ch), len)
 #define        NTFS_UASTRCMP(ustr, ustrlen, astr, astrlen)     \
        ntfs_uastrcmp(ntmp, (ustr), (ustrlen), (astr), (astrlen))
 #define        NTFS_UASTRICMP(ustr, ustrlen, astr, astrlen)    \
index 17fd2e8..c20db7b 100644 (file)
@@ -79,6 +79,8 @@ MALLOC_DEFINE(M_NTFSFNODE,"NTFS fnode",  "NTFS fnode information");
 MALLOC_DEFINE(M_NTFSDIR,"NTFS dir",  "NTFS dir buffer");
 #endif
 
+struct iconv_functions *ntfs_iconv = NULL;
+
 static int     ntfs_root (struct mount *, struct vnode **);
 static int     ntfs_statfs (struct mount *, struct statfs *, struct ucred *cred);
 static int     ntfs_unmount (struct mount *, int);
@@ -397,6 +399,8 @@ ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
        cdev_t dev;
        int error, ronly, ncount, i;
        struct vnode *vp;
+       char cs_local[ICONV_CSNMAXLEN];
+       char cs_ntfs[ICONV_CSNMAXLEN];
 
        /*
         * Disallow multiple mounts of the same device.
@@ -469,16 +473,16 @@ ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
        ntmp->ntm_mode = argsp->mode;
        ntmp->ntm_flag = argsp->flag;
 
-       /* Copy in the 8-bit to Unicode conversion table */
-       if (argsp->flag & NTFSMNT_U2WTABLE) {
-               ntfs_82u_init(ntmp, argsp->u2w);
+       if (argsp->flag & NTFS_MFLAG_KICONV && ntfs_iconv) {
+               bcopy(argsp->cs_local, cs_local, sizeof(cs_local));
+               bcopy(argsp->cs_ntfs, cs_ntfs, sizeof(cs_ntfs));
+               ntfs_82u_init(ntmp, cs_local, cs_ntfs);
+               ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs);
        } else {
-               ntfs_82u_init(ntmp, NULL);
+               ntfs_82u_init(ntmp, NULL, NULL);
+               ntfs_u28_init(ntmp, ntmp->ntm_82u, NULL, NULL);
        }
 
-       /* Initialize Unicode to 8-bit table from 8toU table */
-       ntfs_u28_init(ntmp, ntmp->ntm_82u);
-
        mp->mnt_data = (qaddr_t)ntmp;
 
        dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
@@ -941,6 +945,7 @@ static struct vfsops ntfs_vfsops = {
        .vfs_uninit =           ntfs_nthash_uninit /* see ntfs_ihash.c */
 };
 VFS_SET(ntfs_vfsops, ntfs, 0);
+MODULE_VERSION(ntfs, 1);
 #elif defined(__NetBSD__)
 extern struct vnodeopv_desc ntfs_vnodeop_opv_desc;
 
index 92a22fc..e865403 100644 (file)
@@ -545,7 +545,8 @@ ntfs_readdir(struct vop_readdir_args *ap)
        struct ntnode *ip = FTONT(fp);
        struct uio *uio = ap->a_uio;
        struct ntfsmount *ntmp = ip->i_mp;
-       int i, error = 0;
+       int i, j, error = 0;
+       wchar c;
        u_int32_t faked = 0, num, off;
        int ncookies = 0;
        char convname[NTFS_MAXFILENAME + 1];
@@ -620,14 +621,16 @@ ntfs_readdir(struct vop_readdir_args *ap)
                {
                        if(!ntfs_isnamepermitted(ntmp,iep))
                                continue;
-
-                       for (i=0; i < iep->ie_fnamelen; i++)
-                               convname[i] = NTFS_U28(iep->ie_fname[i]);
-                       convname[i] = '\0';
-
+                       for(i=0, j=0; i < iep->ie_fnamelen; i++, j++) {
+                               c = NTFS_U28(iep->ie_fname[i]);
+                               if (c&0xFF00)
+                                       convname[j++] = (char)(c>>8);
+                               convname[j] = (char)c&0xFF;
+                       }
+                       convname[j] = '\0';
                        if (vop_write_dirent(&error, uio, iep->ie_number,
                            (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG,
-                           iep->ie_fnamelen, convname))
+                           j, convname))
                                goto readdone;
 
                        dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, "
index 2f78b38..b51f891 100644 (file)
  * $DragonFly: src/sys/vfs/ntfs/ntfsmount.h,v 1.2 2003/06/17 04:28:54 dillon Exp $
  */
 
+#include <sys/iconv.h>
+
 #define        NTFS_MFLAG_CASEINS      0x00000001
 #define        NTFS_MFLAG_ALLNAMES     0x00000002
-#define        NTFSMNT_U2WTABLE        0x00000004
+#define        NTFS_MFLAG_KICONV       0x00000004
 
 struct ntfs_args {
        char    *fspec;                 /* block special device to mount */
@@ -41,4 +43,6 @@ struct ntfs_args {
        mode_t  mode;                   /* mask to be applied for ntfs perms */
        u_long  flag;                   /* additional flags */
        u_int16_t u2w[256];             /* Unix to Wchar */
+       char    cs_ntfs[ICONV_CSNMAXLEN]; /* disk charset for cs conversion */
+       char    cs_local[ICONV_CSNMAXLEN]; /* local charset for cs conversion */
 };