Convert cd9660 to libiconv. Part 1.
authorAlexander Polakov <polachok@gmail.com>
Tue, 7 Jul 2009 13:46:15 +0000 (17:46 +0400)
committerSimon Schubert <corecode@dragonflybsd.org>
Thu, 23 Jul 2009 10:08:34 +0000 (12:08 +0200)
sys/vfs/isofs/cd9660/Makefile
sys/vfs/isofs/cd9660/cd9660_mount.h
sys/vfs/isofs/cd9660/cd9660_util.c
sys/vfs/isofs/cd9660/cd9660_vfsops.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>
index 489e3fb..de15568 100644 (file)
@@ -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;               /* disk charset for Joliet cs conversion
+ */
+        char    *cs_local;              /* local charset for Joliet cs conversio
+n */
 };
 #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 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 c38e038..783e574 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 **);
@@ -281,6 +284,7 @@ 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, *cs_disk;
 
        if (!(mp->mnt_flag & MNT_RDONLY))
                return EROFS;
@@ -466,6 +470,15 @@ iso_mountfs(struct vnode *devvp, struct mount *mp, struct iso_args *argp)
        }
        isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
                                         ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
+       if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
+               cs_local = "UTF-8";
+               cs_disk = "UTF-16BE";
+                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 */
@@ -547,6 +560,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 8407bdb..59fdca0 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,33 @@ 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 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 */