libiconv: convert cd9660 to libiconv.
authorAlexander Polakov <polachok@gmail.com>
Thu, 3 Sep 2009 21:09:33 +0000 (01:09 +0400)
committerAlexander Polakov <polachok@gmail.com>
Sat, 5 Sep 2009 09:50:40 +0000 (13:50 +0400)
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

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..a1ad595 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,39 @@ 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[0];
+}
+static __inline uint8_t
+isonum_712(unsigned char *p)
 {
-       return *p;
+        return p[0];
 }
 
-static __inline int isonum_712 (char *);
-static __inline int
-isonum_712(char *p)
+static __inline uint16_t
+isonum_723(unsigned char *p)
 {
-       return *p;
+        return (p[0] | p[1] << 8);
 }
 
 #ifndef UNALIGNED_ACCESS
 
-static __inline int isonum_723 (u_char *);
-static __inline int
-isonum_723(u_char *p)
+static __inline uint32_t
+isonum_731(unsigned char *p)
 {
-       return *p|(p[1] << 8);
+        return (p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24);
 }
-
-static __inline int isonum_733 (u_char *);
-static __inline int
-isonum_733(u_char *p)
+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 */