diff options
author | scottl <scottl@FreeBSD.org> | 2003-11-05 06:56:08 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2003-11-05 06:56:08 +0000 |
commit | aa058296bcb3ac9e303628d7414f4634cdba452e (patch) | |
tree | 0b543d04f8a1e099f6c425d001765859a22ff579 | |
parent | c7d964d2cef031c840960d17686a8247a9528514 (diff) | |
download | FreeBSD-src-aa058296bcb3ac9e303628d7414f4634cdba452e.zip FreeBSD-src-aa058296bcb3ac9e303628d7414f4634cdba452e.tar.gz |
Add hooks for translating directories entries using the iconv methods.
Submitted by: imura@ryu16.org
-rw-r--r-- | sys/fs/udf/udf.h | 4 | ||||
-rw-r--r-- | sys/fs/udf/udf_iconv.c | 36 | ||||
-rw-r--r-- | sys/fs/udf/udf_mount.h | 29 | ||||
-rw-r--r-- | sys/fs/udf/udf_vfsops.c | 47 | ||||
-rw-r--r-- | sys/fs/udf/udf_vnops.c | 88 |
5 files changed, 172 insertions, 32 deletions
diff --git a/sys/fs/udf/udf.h b/sys/fs/udf/udf.h index f214c14..540a3a6 100644 --- a/sys/fs/udf/udf.h +++ b/sys/fs/udf/udf.h @@ -58,6 +58,10 @@ struct udf_mnt { int p_sectors; int s_table_entries; struct udf_sparing_table *s_table; + void *im_d2l; /* disk->local iconv handle */ +#if 0 + void *im_l2d; /* local->disk iconv handle */ +#endif }; struct udf_dirstream { diff --git a/sys/fs/udf/udf_iconv.c b/sys/fs/udf/udf_iconv.c new file mode 100644 index 0000000..9345169 --- /dev/null +++ b/sys/fs/udf/udf_iconv.c @@ -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. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/iconv.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/mount.h> + +VFS_DECLARE_ICONV(udf); diff --git a/sys/fs/udf/udf_mount.h b/sys/fs/udf/udf_mount.h new file mode 100644 index 0000000..1c34694 --- /dev/null +++ b/sys/fs/udf/udf_mount.h @@ -0,0 +1,29 @@ +/*- + * 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$ + */ + +#define UDFMNT_KICONV 0x00000001 diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c index c8f7e49..0c093d6 100644 --- a/sys/fs/udf/udf_vfsops.c +++ b/sys/fs/udf/udf_vfsops.c @@ -79,6 +79,7 @@ #include <sys/conf.h> #include <sys/dirent.h> #include <sys/fcntl.h> +#include <sys/iconv.h> #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/mount.h> @@ -90,12 +91,15 @@ #include <vm/uma.h> #include <fs/udf/ecma167-udf.h> -#include <fs/udf/udf.h> #include <fs/udf/osta.h> +#include <fs/udf/udf.h> +#include <fs/udf/udf_mount.h> MALLOC_DEFINE(M_UDFMOUNT, "UDF mount", "UDF mount structure"); MALLOC_DEFINE(M_UDFFENTRY, "UDF fentry", "UDF file entry structure"); +struct iconv_functions *udf_iconv = NULL; + /* Zones */ uma_zone_t udf_zone_trans = NULL; uma_zone_t udf_zone_node = NULL; @@ -125,6 +129,8 @@ static struct vfsops udf_vfsops = { }; VFS_SET(udf_vfsops, udf, VFCF_READONLY); +MODULE_VERSION(udf, 1); + static int udf_mountfs(struct vnode *, struct mount *, struct thread *); static int @@ -183,9 +189,9 @@ udf_mount(struct mount *mp, struct nameidata *ndp, struct thread *td) struct udf_mnt *imp = 0; struct export_args *export; struct vfsoptlist *opts; - char *fspec; + char *fspec, *cs_disk, *cs_local; size_t size; - int error, len; + int error, len, *udf_flags; opts = mp->mnt_optnew; @@ -246,6 +252,28 @@ udf_mount(struct mount *mp, struct nameidata *ndp, struct thread *td) } imp = VFSTOUDFFS(mp); + + udf_flags = NULL; + error = vfs_getopt(opts, "flags", (void **)&udf_flags, &len); + if (error || len != sizeof(int)) + return (EINVAL); + imp->im_flags = *udf_flags; + + if (imp->im_flags & UDFMNT_KICONV && udf_iconv) { + cs_disk = NULL; + error = vfs_getopt(opts, "cs_disk", (void **)&cs_disk, &len); + if (!error && cs_disk[len - 1] != '\0') + return (EINVAL); + cs_local = NULL; + error = vfs_getopt(opts, "cs_local", (void **)&cs_local, &len); + if (!error && cs_local[len - 1] != '\0') + return (EINVAL); + udf_iconv->open(cs_local, cs_disk, &imp->im_d2l); +#if 0 + udf_iconv->open(cs_disk, cs_local, &imp->im_l2d); +#endif + } + copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); udf_statfs(mp, &mp->mnt_stat, td); @@ -326,6 +354,10 @@ udf_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td) { udfmp->im_mountp = mp; udfmp->im_dev = devvp->v_rdev; udfmp->im_devvp = devvp; + udfmp->im_d2l = NULL; +#if 0 + udfmp->im_l2d = NULL; +#endif bsize = 2048; /* XXX Should probe the media for it's size */ @@ -471,6 +503,15 @@ udf_unmount(struct mount *mp, int mntflags, struct thread *td) if ((error = vflush(mp, 0, flags))) return (error); + if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) { + if (udfmp->im_d2l) + udf_iconv->close(udfmp->im_d2l); +#if 0 + if (udfmp->im_l2d) + udf_iconv->close(udfmp->im_l2d); +#endif + } + udfmp->im_devvp->v_rdev->si_mountpoint = NULL; error = VOP_CLOSE(udfmp->im_devvp, FREAD, NOCRED, td); vrele(udfmp->im_devvp); diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c index 6c22663..c0a018e 100644 --- a/sys/fs/udf/udf_vnops.c +++ b/sys/fs/udf/udf_vnops.c @@ -37,6 +37,7 @@ #include <sys/stat.h> #include <sys/bio.h> #include <sys/buf.h> +#include <sys/iconv.h> #include <sys/mount.h> #include <sys/vnode.h> #include <sys/dirent.h> @@ -48,6 +49,9 @@ #include <fs/udf/ecma167-udf.h> #include <fs/udf/osta.h> #include <fs/udf/udf.h> +#include <fs/udf/udf_mount.h> + +extern struct iconv_functions *udf_iconv; static int udf_access(struct vop_access_args *); static int udf_getattr(struct vop_getattr_args *); @@ -446,41 +450,65 @@ udf_dumpblock(void *data, int len) /* * Call the OSTA routines to translate the name from a CS0 dstring to a * 16-bit Unicode String. Hooks need to be placed in here to translate from - * Unicode to the encoding that the kernel/user expects. For now, compact - * the encoding to 8 bits if possible. Return the length of the translated - * string. - * XXX This horribly pessimizes the 8bit case + * Unicode to the encoding that the kernel/user expects. Return the length + * of the translated string. */ static int -udf_transname(char *cs0string, char *destname, int len) +udf_transname(char *cs0string, char *destname, int len, struct udf_mnt *udfmp) { unicode_t *transname; - int i, unilen = 0; + char *unibuf, *unip; + int i, unilen = 0, destlen; + size_t destleft = MAXNAMLEN; + + /* Convert 16-bit Unicode to destname */ + if (udfmp->im_flags & UDFMNT_KICONV && udf_iconv) { + /* allocate a buffer big enough to hold an 8->16 bit expansion */ + unibuf = uma_zalloc(udf_zone_trans, M_WAITOK); + unip = unibuf; + if ((unilen = udf_UncompressUnicodeByte(len, cs0string, unibuf)) == -1) { + printf("udf: Unicode translation failed\n"); + uma_zfree(udf_zone_trans, unibuf); + return 0; + } - /* allocate a buffer big enough to hold an 8->16 bit expansion */ - transname = uma_zalloc(udf_zone_trans, M_WAITOK); + while (unilen > 0 && destleft > 0) { + udf_iconv->conv(udfmp->im_d2l, (const char **)&unibuf, + (size_t *)&unilen, (char **)&destname, &destleft); + /* Unconverted character found */ + if (unilen > 0 && destleft > 0) { + *destname++ = '?'; + destleft--; + unibuf += 2; + unilen -= 2; + } + } + uma_zfree(udf_zone_trans, unip); + *destname = '\0'; + destlen = MAXNAMLEN - (int)destleft; + } else { + /* allocate a buffer big enough to hold an 8->16 bit expansion */ + transname = uma_zalloc(udf_zone_trans, M_WAITOK); - if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) { - printf("udf: Unicode translation failed\n"); - uma_zfree(udf_zone_trans, transname); - return 0; - } + if ((unilen = udf_UncompressUnicode(len, cs0string, transname)) == -1) { + printf("udf: Unicode translation failed\n"); + uma_zfree(udf_zone_trans, transname); + return 0; + } - /* At this point, the name is in 16-bit Unicode. Compact it down - * to 8-bit - */ - for (i = 0; i < unilen ; i++) { - if (transname[i] & 0xff00) { - destname[i] = '.'; /* Fudge the 16bit chars */ - } else { - destname[i] = transname[i] & 0xff; + for (i = 0; i < unilen ; i++) { + if (transname[i] & 0xff00) { + destname[i] = '.'; /* Fudge the 16bit chars */ + } else { + destname[i] = transname[i] & 0xff; + } } + uma_zfree(udf_zone_trans, transname); + destname[unilen] = 0; + destlen = unilen; } - destname[unilen] = 0; - uma_zfree(udf_zone_trans, transname); - - return unilen; + return (destlen); } /* @@ -489,7 +517,7 @@ udf_transname(char *cs0string, char *destname, int len) * here also. */ static int -udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen) +udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen, struct udf_mnt *udfmp) { char *transname; int error = 0; @@ -497,7 +525,7 @@ udf_cmpname(char *cs0string, char *cmpname, int cs0len, int cmplen) /* This is overkill, but not worth creating a new zone */ transname = uma_zalloc(udf_zone_trans, M_WAITOK); - cs0len = udf_transname(cs0string, transname, cs0len); + cs0len = udf_transname(cs0string, transname, cs0len, udfmp); /* Easy check. If they aren't the same length, they aren't equal */ if ((cs0len == 0) || (cs0len != cmplen)) @@ -686,6 +714,7 @@ udf_readdir(struct vop_readdir_args *a) struct uio *uio; struct dirent dir; struct udf_node *node; + struct udf_mnt *udfmp; struct fileid_desc *fid; struct udf_uiodir uiodir; struct udf_dirstream *ds; @@ -696,6 +725,7 @@ udf_readdir(struct vop_readdir_args *a) vp = a->a_vp; uio = a->a_uio; node = VTON(vp); + udfmp = node->udfmp; uiodir.eofflag = 1; if (a->a_ncookies != NULL) { @@ -762,7 +792,7 @@ udf_readdir(struct vop_readdir_args *a) error = udf_uiodir(&uiodir, dir.d_reclen, uio, 2); } else { dir.d_namlen = udf_transname(&fid->data[fid->l_iu], - &dir.d_name[0], fid->l_fi); + &dir.d_name[0], fid->l_fi, udfmp); dir.d_fileno = udf_getid(&fid->icb); dir.d_type = (fid->file_char & UDF_FILE_CHAR_DIR) ? DT_DIR : DT_UNKNOWN; @@ -946,7 +976,7 @@ lookloop: } } else { if (!(udf_cmpname(&fid->data[fid->l_iu], - nameptr, fid->l_fi, namelen))) { + nameptr, fid->l_fi, namelen, udfmp))) { id = udf_getid(&fid->icb); break; } |