summaryrefslogtreecommitdiffstats
path: root/sys/fs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/cd9660/cd9660_iconv.c36
-rw-r--r--sys/fs/cd9660/cd9660_lookup.c7
-rw-r--r--sys/fs/cd9660/cd9660_mount.h3
-rw-r--r--sys/fs/cd9660/cd9660_rrip.c12
-rw-r--r--sys/fs/cd9660/cd9660_util.c155
-rw-r--r--sys/fs/cd9660/cd9660_vfsops.c20
-rw-r--r--sys/fs/cd9660/cd9660_vnops.c4
-rw-r--r--sys/fs/cd9660/iso.h10
-rw-r--r--sys/fs/msdosfs/direntry.h20
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c771
-rw-r--r--sys/fs/msdosfs/msdosfs_iconv.c36
-rw-r--r--sys/fs/msdosfs/msdosfs_lookup.c43
-rw-r--r--sys/fs/msdosfs/msdosfs_vfsops.c34
-rw-r--r--sys/fs/msdosfs/msdosfs_vnops.c21
-rw-r--r--sys/fs/msdosfs/msdosfsmount.h22
-rw-r--r--sys/fs/ntfs/ntfs.h2
-rw-r--r--sys/fs/ntfs/ntfs_iconv.c36
-rw-r--r--sys/fs/ntfs/ntfs_subr.c166
-rw-r--r--sys/fs/ntfs/ntfs_subr.h9
-rw-r--r--sys/fs/ntfs/ntfs_vfsops.c13
-rw-r--r--sys/fs/ntfs/ntfs_vnops.c14
-rw-r--r--sys/fs/ntfs/ntfsmount.h5
-rw-r--r--sys/fs/smbfs/smbfs_vfsops.c2
23 files changed, 981 insertions, 460 deletions
diff --git a/sys/fs/cd9660/cd9660_iconv.c b/sys/fs/cd9660/cd9660_iconv.c
new file mode 100644
index 0000000..43a5a0d
--- /dev/null
+++ b/sys/fs/cd9660/cd9660_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/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
+
+VFS_DECLARE_ICONV(cd9660);
diff --git a/sys/fs/cd9660/cd9660_lookup.c b/sys/fs/cd9660/cd9660_lookup.c
index 056e893..49308ea 100644
--- a/sys/fs/cd9660/cd9660_lookup.c
+++ b/sys/fs/cd9660/cd9660_lookup.c
@@ -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
diff --git a/sys/fs/cd9660/cd9660_mount.h b/sys/fs/cd9660/cd9660_mount.h
index 8cc6a86..0397d06 100644
--- a/sys/fs/cd9660/cd9660_mount.h
+++ b/sys/fs/cd9660/cd9660_mount.h
@@ -47,9 +47,12 @@ 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 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 */
diff --git a/sys/fs/cd9660/cd9660_rrip.c b/sys/fs/cd9660/cd9660_rrip.c
index 7f7ea15..1546e8d 100644
--- a/sys/fs/cd9660/cd9660_rrip.c
+++ b/sys/fs/cd9660/cd9660_rrip.c
@@ -293,7 +293,8 @@ cd9660_rrip_defname(isodir,ana)
{
isofntrans(isodir->name,isonum_711(isodir->name_len),
ana->outbuf,ana->outlen,
- 1,isonum_711(isodir->flags)&4, ana->imp->joliet_level);
+ 1,isonum_711(isodir->flags)&4, ana->imp->joliet_level,
+ ana->imp->im_flags, ana->imp->im_d2l);
switch (*ana->outbuf) {
default:
break;
@@ -491,7 +492,7 @@ cd9660_rrip_loop(isodir,ana,table)
register ISO_SUSP_HEADER *pend;
struct buf *bp = NULL;
char *pwhead;
- u_char c;
+ u_short c;
int result;
/*
@@ -501,7 +502,8 @@ cd9660_rrip_loop(isodir,ana,table)
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)
@@ -627,7 +629,7 @@ cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
{
ISO_RRIP_ANALYZE analyze;
RRIP_TABLE *tab;
- u_char c;
+ u_short c;
analyze.outbuf = outbuf;
analyze.outlen = outlen;
@@ -638,7 +640,7 @@ cd9660_rrip_getname(isodir,outbuf,outlen,inump,imp)
*outlen = 0;
isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
- imp->joliet_level, &c);
+ 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);
diff --git a/sys/fs/cd9660/cd9660_util.c b/sys/fs/cd9660/cd9660_util.c
index 8a132c0..dccb14c 100644
--- a/sys/fs/cd9660/cd9660_util.c
+++ b/sys/fs/cd9660/cd9660_util.c
@@ -46,16 +46,12 @@ __FBSDID("$FreeBSD$");
#include <sys/systm.h>
#include <sys/mount.h>
#include <sys/vnode.h>
+#include <sys/iconv.h>
#include <isofs/cd9660/iso.h>
+#include <isofs/cd9660/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
@@ -63,29 +59,47 @@ u_char (*cd9660_wchar2char)(u_int32_t wchar) = NULL;
* Return number of bytes consumed
*/
int
-isochar(isofn, isoend, joliet_level, c)
+isochar(isofn, isoend, joliet_level, c, clen, flags, handle)
u_char *isofn;
u_char *isoend;
int joliet_level;
- u_char *c;
+ 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;
}
@@ -96,53 +110,60 @@ isochar(isofn, isoend, joliet_level, c)
* Note: Version number plus ';' may be omitted.
*/
int
-isofncmp(fn, fnlen, isofn, isolen, 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;
+ u_short c, d;
+ u_char *fnend = fn + fnlen, *isoend = isofn + isolen;
- for (; fn != fnend; fn++) {
+ for (; fn < fnend; ) {
+ d = sgetrune(fn, fnend - fn, (char const **)&fn, flags, lhandle);
if (isofn == isoend)
- return *fn;
- isofn += isochar(isofn, isoend, joliet_level, &c);
+ return d;
+ isofn += isochar(isofn, isoend, joliet_level, &c, NULL, flags, handle);
if (c == ';') {
- if (*fn++ != ';')
- return fn[-1];
- for (i = 0; fn != fnend; i = i * 10 + *fn++ - '0') {
+ 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);
+ joliet_level, &c,
+ NULL, flags, handle);
return i - j;
}
- if (c != *fn) {
+ if (c != d) {
if (c >= 'A' && c <= 'Z') {
- if (c + ('a' - 'A') != *fn) {
- if (*fn >= 'a' && *fn <= 'z')
- return *fn - ('a' - 'A') - c;
+ if (c + ('a' - 'A') != d) {
+ if (d >= 'a' && d <= 'z')
+ return d - ('a' - 'A') - c;
else
- return *fn - c;
+ return d - c;
}
} else
- return *fn - c;
+ return d - c;
}
}
if (isofn != isoend) {
- isofn += isochar(isofn, isoend, joliet_level, &c);
+ 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);
+ isochar(isofn, isoend, joliet_level, &c,
+ NULL, flags, handle);
if (c == ';')
return 0;
}
@@ -158,7 +179,7 @@ isofncmp(fn, fnlen, isofn, isolen, joliet_level)
* translate a filename of length > 0
*/
void
-isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level)
+isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level, flags, handle)
u_char *infn;
int infnlen;
u_char *outfn;
@@ -166,25 +187,61 @@ isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level)
int original;
int assoc;
int joliet_level;
+ int flags;
+ void *handle;
{
- int fnidx = 0;
- u_char c, d = '\0', *infnend = infn + infnlen;
+ u_short c, d = '\0';
+ u_char *outp = outfn, *infnend = infn + infnlen;
+ int clen;
if (assoc) {
- *outfn++ = ASSOCCHAR;
- fnidx++;
+ *outp++ = ASSOCCHAR;
}
- for (; infn != infnend; fnidx++) {
- infn += isochar(infn, infnend, joliet_level, &c);
+ for (; infn != infnend; ) {
+ infn += isochar(infn, infnend, joliet_level, &c, &clen, flags, handle);
if (!original && !joliet_level && c >= 'A' && c <= 'Z')
- *outfn++ = c + ('a' - 'A');
+ c += ('a' - 'A');
else if (!original && c == ';') {
- fnidx -= (d == '.');
+ outp -= (d == '.');
break;
- } else
- *outfn++ = c;
+ }
d = c;
+ while(clen--)
+ *outp++ = c >> (clen << 3);
}
- *outfnlen = fnidx;
+ *outfnlen = outp - outfn;
+}
+
+/*
+ * 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);
}
diff --git a/sys/fs/cd9660/cd9660_vfsops.c b/sys/fs/cd9660/cd9660_vfsops.c
index 8df32e0..0f8f3c9 100644
--- a/sys/fs/cd9660/cd9660_vfsops.c
+++ b/sys/fs/cd9660/cd9660_vfsops.c
@@ -56,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/stat.h>
#include <sys/syslog.h>
+#include <sys/iconv.h>
#include <isofs/cd9660/iso.h>
@@ -66,6 +67,8 @@ __FBSDID("$FreeBSD$");
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 vfs_mount_t cd9660_mount;
static vfs_unmount_t cd9660_unmount;
static vfs_root_t cd9660_root;
@@ -471,7 +474,16 @@ iso_mountfs(devvp, mp, td, 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) {
+ cd9660_iconv->open(argp->cs_local, argp->cs_disk, &isomp->im_d2l);
+ cd9660_iconv->open(argp->cs_disk, argp->cs_local, &isomp->im_l2d);
+ } else {
+ isomp->im_d2l = NULL;
+ isomp->im_l2d = NULL;
+ }
if (high_sierra) {
/* this effectively ignores all the mount flags */
@@ -551,6 +563,12 @@ cd9660_unmount(mp, mntflags, td)
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, NOCRED, td);
vrele(isomp->im_devvp);
diff --git a/sys/fs/cd9660/cd9660_vnops.c b/sys/fs/cd9660/cd9660_vnops.c
index bf95bf7..c18b664 100644
--- a/sys/fs/cd9660/cd9660_vnops.c
+++ b/sys/fs/cd9660/cd9660_vnops.c
@@ -562,7 +562,9 @@ cd9660_readdir(ap)
idp->current.d_name, &namelen,
imp->iso_ftype == ISO_FTYPE_9660,
isonum_711(ep->flags)&4,
- imp->joliet_level);
+ imp->joliet_level,
+ imp->im_flags,
+ imp->im_d2l);
idp->current.d_namlen = (u_char)namelen;
if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
error = iso_shipdir(idp);
diff --git a/sys/fs/cd9660/iso.h b/sys/fs/cd9660/iso.h
index b41cd0c..15766ef 100644
--- a/sys/fs/cd9660/iso.h
+++ b/sys/fs/cd9660/iso.h
@@ -245,6 +245,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))
@@ -265,10 +268,11 @@ extern vop_t **cd9660_vnodeop_p;
extern vop_t **cd9660_specop_p;
extern vop_t **cd9660_fifoop_p;
-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 */
diff --git a/sys/fs/msdosfs/direntry.h b/sys/fs/msdosfs/direntry.h
index 8ed5335..c54cbe3 100644
--- a/sys/fs/msdosfs/direntry.h
+++ b/sys/fs/msdosfs/direntry.h
@@ -98,6 +98,11 @@ struct winentry {
#define WIN_CHARS 13 /* Number of chars per winentry */
/*
+ * Maximum number of winentries for a filename
+ */
+#define WIN_MAXSUBENTRIES 20
+
+/*
* Maximum filename length in Win95
* Note: Must be < sizeof(dirent.d_name)
*/
@@ -132,12 +137,15 @@ struct dirent;
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, struct dirent *dp, 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(const u_char *un, int unlen, int chksum, struct msdosfsmount *pmp);
+int win2unixfn(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 *);
int winLenFixup(const u_char *un, int unlen);
+void mbnambuf_init(void);
+void mbnambuf_write(char *name, int id);
+char * mbnambuf_flush(struct dirent *dp);
#endif /* _KERNEL */
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index d135bfa..5c663c8 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -57,10 +57,17 @@
#include <sys/systm.h>
#include <machine/clock.h>
#include <sys/dirent.h>
+#include <sys/iconv.h>
+#include <sys/mount.h>
+#include <sys/malloc.h>
+
+extern struct iconv_functions *msdosfs_iconv;
/*
* MSDOSFS include files.
*/
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
/*
@@ -88,7 +95,17 @@ static u_long lastday;
static u_short lastddate;
static u_short lastdtime;
-static __inline u_int8_t find_lcode(u_int16_t code, u_int16_t *u2w);
+static int mbsadjpos(const char **, int, int, int, int, void *handle);
+static u_int16_t dos2unixchr(const u_char **, size_t *, int, struct msdosfsmount *);
+static u_int16_t unix2doschr(const u_char **, size_t *, struct msdosfsmount *);
+static u_int16_t win2unixchr(u_int16_t, struct msdosfsmount *);
+static u_int16_t unix2winchr(const u_char **, size_t *, int, struct msdosfsmount *);
+
+struct mbnambuf {
+ char * p;
+ size_t n;
+};
+static struct mbnambuf subent[WIN_MAXSUBENTRIES];
/*
* Convert the unix version of time to dos's idea of time to be used in
@@ -239,6 +256,7 @@ dos2unixtime(dd, dt, dh, tsp)
*/
static u_char
unix2dos[256] = {
+/* iso8859-1 -> cp850 */
0, 0, 0, 0, 0, 0, 0, 0, /* 00-07 */
0, 0, 0, 0, 0, 0, 0, 0, /* 08-0f */
0, 0, 0, 0, 0, 0, 0, 0, /* 10-17 */
@@ -275,6 +293,7 @@ unix2dos[256] = {
static u_char
dos2unix[256] = {
+/* cp850 -> iso8859-1 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 00-07 */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 08-0f */
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, /* 10-17 */
@@ -311,6 +330,7 @@ dos2unix[256] = {
static u_char
u2l[256] = {
+/* tolower */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
@@ -347,6 +367,7 @@ u2l[256] = {
static u_char
l2u[256] = {
+/* toupper */
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 00-07 */
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 08-0f */
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 10-17 */
@@ -394,18 +415,15 @@ l2u[256] = {
* null.
*/
int
-dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
+dos2unixfn(dn, un, lower, pmp)
u_char dn[11];
u_char *un;
int lower;
- int d2u_loaded;
- u_int8_t *d2u;
- int ul_loaded;
- u_int8_t *ul;
+ struct msdosfsmount *pmp;
{
int i;
- int thislong = 1;
- u_char c;
+ int thislong = 0;
+ u_int16_t c;
/*
* If first char of the filename is SLOT_E5 (0x05), then the real
@@ -414,26 +432,21 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
* 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;
+ for (i = 8; i > 0 && *dn != ' ';) {
+ c = dos2unixchr((const u_char **)&dn, (size_t *)&i, lower, pmp);
+ if (c & 0xff00) {
+ *un++ = c >> 8;
+ thislong++;
+ }
+ *un++ = c;
thislong++;
}
- dn += 8 - i;
+ dn += i;
/*
* Now, if there is an extension then put in a period and copy in
@@ -442,12 +455,13 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
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;
+ for (i = 3; i > 0 && *dn != ' ';) {
+ c = dos2unixchr((const u_char **)&dn, (size_t *)&i, lower, pmp);
+ if (c & 0xff00) {
+ *un++ = c >> 8;
+ thislong++;
+ }
+ *un++ = c;
thislong++;
}
}
@@ -468,22 +482,18 @@ dos2unixfn(dn, un, lower, d2u_loaded, d2u, ul_loaded, ul)
* 3 if conversion was successful and generation number was inserted
*/
int
-unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
+unix2dosfn(un, dn, unlen, gen, pmp)
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;
+ 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])
+ u_int16_t c;
/*
* Fill the dos filename string with blanks. These are DOS's pad
@@ -520,14 +530,18 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
/*
* Filenames with some characters are not allowed!
*/
- for (cp = un, i = unlen; --i >= 0; cp++)
- if (U2D(*cp) == 0)
+ 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;) {
@@ -547,20 +561,29 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
}
/*
- * Now convert it
+ * Now convert it (this part is for extension)
*/
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)
+ 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;
+ continue;
+ } else {
+ conv = 3;
+ dn[j-1] = ' ';
+ break;
+ }
+ } else {
+ dn[j] = c;
+ }
+ if (*(cp - 1) != dn[j] && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -571,7 +594,7 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
dn[j--] = ' ';
}
}
- if (i < l)
+ if (i > 0)
conv = 3;
dp--;
} else {
@@ -582,12 +605,22 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
/*
* 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)
+ for (i = dp - un, j = 0; un < dp && j < 8; j++) {
+ c = unix2doschr(&un, (size_t *)&i, pmp);
+ if (c & 0xff00) {
+ dn[j] = c >> 8;
+ if (++j < 8) {
+ dn[j] = c;
+ continue;
+ } else {
+ conv = 3;
+ dn[j-1] = ' ';
+ break;
+ }
+ } else {
+ dn[j] = c;
+ }
+ if (*(un - 1) != dn[j] && conv != 3)
conv = 2;
if (dn[j] == 1) {
conv = 3;
@@ -608,40 +641,56 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
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;
+ conv = 0;
+ goto done;
}
/*
* Now insert the generation number into the filename part
*/
if (gen == 0)
- return conv;
+ goto done;
for (wcp = gentext + sizeof(gentext); wcp > gentext && gen; gen /= 10)
*--wcp = gen % 10 + '0';
- if (gen)
- return 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++;
- return 3;
-#undef U2D
+
+ /*
+ * 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;
}
/*
@@ -650,27 +699,28 @@ unix2dosfn(un, dn, unlen, gen, u2d_loaded, u2d, lu_loaded, lu)
* i.e. doesn't consist solely of blanks and dots
*/
int
-unix2winfn(un, unlen, wep, cnt, chksum, table_loaded, u2w)
+unix2winfn(un, unlen, wep, cnt, chksum, pmp)
const u_char *un;
int unlen;
struct winentry *wep;
int cnt;
int chksum;
- int table_loaded;
- u_int16_t *u2w;
+ struct msdosfsmount *pmp;
{
- const u_int8_t *cp;
u_int8_t *wcp;
- int i;
+ int i, end;
u_int16_t code;
/*
* Drop trailing blanks and dots
*/
- for (cp = un + unlen; *--cp == ' ' || *cp == '.'; unlen--);
+ 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
@@ -685,64 +735,32 @@ unix2winfn(un, unlen, wep, cnt, chksum, table_loaded, u2w)
/*
* 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;
- }
+ end = 0;
+ for (wcp = wep->wePart1, i = sizeof(wep->wePart1)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- 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->wePart2, i = sizeof(wep->wePart2)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- 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;
- }
+ for (wcp = wep->wePart3, i = sizeof(wep->wePart3)/2; --i >= 0 && !end;) {
+ code = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
+ *wcp++ = code;
+ *wcp++ = code >> 8;
+ if (!code)
+ end = WIN_LAST;
}
- if (!unlen)
- wep->weCnt |= WIN_LAST;
- return unlen;
-
-done:
- *wcp++ = 0;
- *wcp++ = 0;
- wep->weCnt |= WIN_LAST;
- return 0;
-}
-
-static __inline u_int8_t
-find_lcode(code, u2w)
- u_int16_t code;
- u_int16_t *u2w;
-{
- int i;
-
- for (i = 0; i < 128; i++)
- if (u2w[i] == code)
- return (i | 0x80);
- return '?';
+ if (*un == '\0')
+ end = WIN_LAST;
+ wep->weCnt |= end;
+ return !end;
}
/*
@@ -750,116 +768,44 @@ find_lcode(code, u2w)
* Returns the checksum or -1 if no match
*/
int
-winChkName(un, unlen, wep, chksum, u2w_loaded, u2w, ul_loaded, ul)
+winChkName(un, unlen, chksum, pmp)
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;
+ struct msdosfsmount *pmp;
{
- u_int8_t *cp;
- int i;
- u_int16_t code;
- u_int8_t c1, c2;
+ int len;
+ u_int16_t c1, c2;
+ u_char *np;
+ struct dirent dirbuf;
/*
- * First compare checksums
+ * We alread have winentry in mbnambuf
*/
- if (wep->weCnt&WIN_LAST)
- chksum = wep->weChksum;
- else if (chksum != wep->weChksum)
- chksum = -1;
- if (chksum == -1)
+ if (!mbnambuf_flush(&dirbuf) || !dirbuf.d_namlen)
return -1;
- /*
- * Offset of this entry
- */
- i = ((wep->weCnt&WIN_CNT) - 1) * WIN_CHARS;
- un += i;
- unlen -= i;
-
- /*
- * 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;
+#ifdef MSDOSFS_DEBUG
+ printf("winChkName(): un=%s:%d,d_name=%s:%d\n", un, unlen,
+ dirbuf.d_name,
+ dirbuf.d_namlen);
+#endif
/*
* 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];
+ len = dirbuf.d_namlen;
+ if (unlen != len)
+ return -2;
+
+ for (np = dirbuf.d_name; unlen > 0 && len > 0;) {
+ /*
+ * Should comparison be case insensitive?
+ */
+ c1 = unix2winchr((const u_char **)&np, (size_t *)&len, 0, pmp);
+ c2 = unix2winchr(&un, (size_t *)&unlen, 0, pmp);
if (c1 != c2)
- return -1;
- cp += 2;
- un++;
+ return -2;
}
return chksum;
}
@@ -869,15 +815,13 @@ winChkName(un, unlen, wep, chksum, u2w_loaded, u2w, ul_loaded, ul)
* Returns the checksum or -1 if impossible
*/
int
-win2unixfn(wep, dp, chksum, table_loaded, u2w)
+win2unixfn(wep, chksum, pmp)
struct winentry *wep;
- struct dirent *dp;
int chksum;
- int table_loaded;
- u_int16_t *u2w;
+ struct msdosfsmount *pmp;
{
u_int8_t *cp;
- u_int8_t *np, *ep = dp->d_name + WIN_MAXLEN;
+ u_int8_t *np, name[WIN_CHARS * 2 + 1];
u_int16_t code;
int i;
@@ -890,54 +834,32 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
*/
if (wep->weCnt&WIN_LAST) {
chksum = wep->weChksum;
- /*
- * This works even though d_namlen is one byte!
- */
- dp->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 *)dp->d_name + i;
-
- /*
* 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';
- dp->d_namlen -= sizeof(wep->wePart2)/2
- + sizeof(wep->wePart3)/2 + i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 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 = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*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;) {
@@ -945,30 +867,18 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
switch (code) {
case 0:
*np = '\0';
- dp->d_namlen -= sizeof(wep->wePart3)/2 + i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 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 = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*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;) {
@@ -976,31 +886,22 @@ win2unixfn(wep, dp, chksum, table_loaded, u2w)
switch (code) {
case 0:
*np = '\0';
- dp->d_namlen -= i + 1;
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 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 = '?';
- }
+ code = win2unixchr(code, pmp);
+ if (code & 0xff00)
+ *np++ = code >> 8;
*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;
}
+ *np = '\0';
+ mbnambuf_write(name, (wep->weCnt & WIN_CNT) - 1);
return chksum;
}
@@ -1023,11 +924,25 @@ winChksum(name)
* Determine the number of slots necessary for Win95 names
*/
int
-winSlotCnt(un, unlen)
+winSlotCnt(un, unlen, pmp)
const u_char *un;
int unlen;
+ struct msdosfsmount *pmp;
{
+ size_t wlen;
+ char wn[WIN_MAXLEN * 2 + 1], *wnp;
+
unlen = winLenFixup(un, unlen);
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ wlen = WIN_MAXLEN * 2;
+ wnp = wn;
+ msdosfs_iconv->conv(pmp->pm_u2w, (const char **)&un, (size_t *)&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);
@@ -1046,3 +961,281 @@ winLenFixup(un, unlen)
break;
return unlen;
}
+
+/*
+ * 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, int inlen, int outlen, int weight, int flag, void *handle)
+{
+ char *outp, outstr[outlen * weight + 1];
+
+ if (flag & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ outp = outstr;
+ outlen *= weight;
+ msdosfs_iconv->conv(handle, instr, (size_t *)&inlen, &outp, (size_t *)&outlen);
+ return (inlen);
+ }
+
+ (*instr) += min(inlen, outlen);
+ return (inlen - min(inlen, outlen));
+}
+
+/*
+ * 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 && msdosfs_iconv) {
+ olen = len = 2;
+ outp = outbuf;
+
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
+ ilen, &outp, &olen, KICONV_LOWER);
+ else
+ msdosfs_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);
+}
+
+/*
+ * 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, ulen, olen;
+
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ /*
+ * to hide an invisible character, using a unicode filter
+ */
+ ulen = 2;
+ len = *ilen;
+ up = unicode;
+ msdosfs_iconv->convchr(pmp->pm_u2w, (const char **)instr,
+ ilen, &up, &ulen);
+
+ /*
+ * cannot be converted
+ */
+ if (ulen == 2) {
+ (*ilen)--;
+ (*instr)++;
+ return (0);
+ }
+
+ /*
+ * return magic number for ascii char
+ */
+ if ((len - *ilen) == 1) {
+ c = *(*instr -1);
+ if (! (c & 0x80)) {
+ c = unix2dos[c];
+ if (c <= 2)
+ return (c);
+ }
+ }
+
+ /*
+ * now convert using libiconv
+ */
+ *instr -= len - *ilen;
+ *ilen = (int)len;
+
+ olen = len = 2;
+ outp = outbuf;
+ msdosfs_iconv->convchr_case(pmp->pm_u2d, (const char **)instr,
+ ilen, &outp, &olen, KICONV_FROM_UPPER);
+ len -= olen;
+ 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 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 && msdosfs_iconv) {
+ inbuf[0] = (u_char)(wc>>8);
+ inbuf[1] = (u_char)wc;
+ inbuf[2] = '\0';
+
+ ilen = olen = len = 2;
+ inp = inbuf;
+ outp = outbuf;
+ msdosfs_iconv->convchr(pmp->pm_w2u, (const char **)&inp, &ilen,
+ (char **)&outp, &olen);
+ len -= olen;
+
+ /*
+ * 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);
+}
+
+/*
+ * 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 && msdosfs_iconv) {
+ outp = outbuf;
+ olen = 2;
+ if (lower & (LCASE_BASE | LCASE_EXT))
+ msdosfs_iconv->convchr_case(pmp->pm_u2w, (const char **)instr,
+ ilen, (char **)&outp, &olen,
+ KICONV_FROM_LOWER);
+ else
+ msdosfs_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);
+}
+
+/*
+ * Make subent empty
+ */
+void
+mbnambuf_init(void)
+{
+ int i;
+
+ for (i = 0; i < WIN_MAXSUBENTRIES; i++) {
+ if (subent[i].p) {
+ free(subent[i].p, M_MSDOSFSMNT);
+ subent[i].p = NULL;
+ subent[i].n = 0;
+ }
+ }
+}
+
+/*
+ * Write a subent entry from a slot
+ */
+void
+mbnambuf_write(char *name, int id)
+{
+ if (subent[id].p) {
+ printf("mbnambuf_write(): %s -> %s\n", subent[id].p, name);
+ free(subent[id].p, M_MSDOSFSMNT);
+ }
+ subent[id].n = strlen(name);
+ subent[id].p = malloc(subent[id].n + 1, M_MSDOSFSMNT, M_WAITOK);
+ strcpy(subent[id].p, name);
+}
+
+/*
+ * Combine each subents to the *dp and initialize subent
+ */
+char *
+mbnambuf_flush(struct dirent *dp)
+{
+ int i;
+ char *name = dp->d_name;
+
+ *name = '\0';
+ dp->d_namlen = 0;
+ for (i = 0; i < WIN_MAXSUBENTRIES; i++) {
+ if (subent[i].p) {
+ if (dp->d_namlen + subent[i].n > sizeof(dp->d_name) - 1) {
+ mbnambuf_init();
+ return (NULL);
+ }
+ strcpy(name, subent[i].p);
+ dp->d_namlen += subent[i].n;
+ name += subent[i].n;
+ }
+ }
+ mbnambuf_init();
+ return (dp->d_name);
+}
diff --git a/sys/fs/msdosfs/msdosfs_iconv.c b/sys/fs/msdosfs/msdosfs_iconv.c
new file mode 100644
index 0000000..26ef1a4
--- /dev/null
+++ b/sys/fs/msdosfs/msdosfs_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/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
+
+VFS_DECLARE_ICONV(msdosfs);
diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c
index 00598c8..1492098 100644
--- a/sys/fs/msdosfs/msdosfs_lookup.c
+++ b/sys/fs/msdosfs/msdosfs_lookup.c
@@ -57,9 +57,9 @@
#include <sys/mount.h>
#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
-#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/fat.h>
/*
@@ -150,21 +150,19 @@ msdosfs_lookup(ap)
}
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) {
@@ -193,6 +191,7 @@ msdosfs_lookup(ap)
* by cnp->cn_nameptr.
*/
tdp = NULL;
+ mbnambuf_init();
/*
* The outer loop ranges over the clusters that make up the
* directory. Note that the root directory is different from all
@@ -232,6 +231,7 @@ msdosfs_lookup(ap)
* Drop memory of previous long matches
*/
chksum = -1;
+ mbnambuf_init();
if (slotcount < wincnt) {
slotcount++;
@@ -256,14 +256,18 @@ msdosfs_lookup(ap)
if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
continue;
- chksum = winChkName((const u_char *)cnp->cn_nameptr,
- unlen,
- (struct winentry *)dep,
+ chksum = win2unixfn((struct winentry *)dep,
chksum,
- pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
- pmp->pm_u2w,
- pmp->pm_flags & MSDOSFSMNT_ULTABLE,
- pmp->pm_ul);
+ pmp);
+ continue;
+ }
+
+ chksum = winChkName((const u_char *)cnp->cn_nameptr,
+ unlen,
+ chksum,
+ pmp);
+ if (chksum == -2) {
+ chksum = -1;
continue;
}
@@ -659,9 +663,7 @@ createde(dep, ddep, depp, cnp)
ddep->de_fndoffset -= sizeof(struct direntry);
}
if (!unix2winfn(un, unlen, (struct winentry *)ndep,
- cnt++, chksum,
- pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
- pmp->pm_u2w))
+ cnt++, chksum, pmp))
break;
}
}
@@ -992,19 +994,14 @@ uniqdosname(dep, cnp, 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) ?
- 0 : EINVAL);
+ cnp->cn_namelen, 0, pmp) ? 0 : EINVAL);
for (gen = 1;; gen++) {
/*
* 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;
/*
diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c
index 11a3d6d..875d580 100644
--- a/sys/fs/msdosfs/msdosfs_vfsops.c
+++ b/sys/fs/msdosfs/msdosfs_vfsops.c
@@ -61,13 +61,14 @@
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/stat.h> /* defines ALLPERMS */
+#include <sys/iconv.h>
#include <sys/mutex.h>
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/bootsect.h>
+#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
-#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/fat.h>
#define MSDOSFS_DFLTBSIZE 4096
@@ -86,6 +87,8 @@
MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure");
static MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table");
+struct iconv_functions *msdosfs_iconv = NULL;
+
static int update_mp(struct mount *mp, struct msdosfs_args *argp);
static int mountmsdosfs(struct vnode *devvp, struct mount *mp,
struct thread *td, struct msdosfs_args *argp);
@@ -110,14 +113,16 @@ update_mp(mp, argp)
pmp->pm_mask = argp->mask & ALLPERMS;
pmp->pm_dirmask = argp->dirmask & 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 && msdosfs_iconv) {
+ msdosfs_iconv->open(argp->cs_win, argp->cs_local , &pmp->pm_u2w);
+ msdosfs_iconv->open(argp->cs_local, argp->cs_win , &pmp->pm_w2u);
+ msdosfs_iconv->open(argp->cs_dos, argp->cs_local , &pmp->pm_u2d);
+ msdosfs_iconv->open(argp->cs_local, argp->cs_dos , &pmp->pm_d2u);
+ } else {
+ pmp->pm_w2u = NULL;
+ pmp->pm_u2w = NULL;
+ pmp->pm_d2u = NULL;
+ pmp->pm_u2d = NULL;
}
if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
@@ -651,6 +656,16 @@ msdosfs_unmount(mp, mntflags, td)
if (error)
return error;
pmp = VFSTOMSDOSFS(mp);
+ if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
+ if (pmp->pm_w2u)
+ msdosfs_iconv->close(pmp->pm_w2u);
+ if (pmp->pm_u2w)
+ msdosfs_iconv->close(pmp->pm_u2w);
+ if (pmp->pm_d2u)
+ msdosfs_iconv->close(pmp->pm_d2u);
+ if (pmp->pm_u2d)
+ msdosfs_iconv->close(pmp->pm_u2d);
+ }
pmp->pm_devvp->v_rdev->si_mountpoint = NULL;
#ifdef MSDOSFS_DEBUG
{
@@ -864,3 +879,4 @@ static struct vfsops msdosfs_vfsops = {
};
VFS_SET(msdosfs_vfsops, msdosfs, 0);
+MODULE_VERSION(msdosfs, 1);
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index ba36c5b..a4c60cc 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -71,9 +71,9 @@
#include <machine/mutex.h>
#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/direntry.h>
#include <fs/msdosfs/denode.h>
-#include <fs/msdosfs/msdosfsmount.h>
#include <fs/msdosfs/fat.h>
#define DOS_FILESIZE_MAX 0xffffffff
@@ -1554,6 +1554,7 @@ msdosfs_readdir(ap)
}
}
+ mbnambuf_init();
off = offset;
while (uio->uio_resid > 0) {
lbn = de_cluster(pmp, offset - bias);
@@ -1600,6 +1601,7 @@ msdosfs_readdir(ap)
*/
if (dentp->deName[0] == SLOT_DELETED) {
chksum = -1;
+ mbnambuf_init();
continue;
}
@@ -1610,9 +1612,7 @@ msdosfs_readdir(ap)
if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
continue;
chksum = win2unixfn((struct winentry *)dentp,
- &dirbuf, chksum,
- pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
- pmp->pm_u2w);
+ chksum, pmp);
continue;
}
@@ -1621,6 +1621,7 @@ msdosfs_readdir(ap)
*/
if (dentp->deAttributes & ATTR_VOLUME) {
chksum = -1;
+ mbnambuf_init();
continue;
}
/*
@@ -1648,18 +1649,16 @@ msdosfs_readdir(ap)
dirbuf.d_fileno = offset / sizeof(struct direntry);
dirbuf.d_type = DT_REG;
}
- if (chksum != winChksum(dentp->deName))
+ if (chksum != winChksum(dentp->deName)) {
dirbuf.d_namlen = dos2unixfn(dentp->deName,
(u_char *)dirbuf.d_name,
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);
- else
- dirbuf.d_name[dirbuf.d_namlen] = 0;
+ pmp);
+ mbnambuf_init();
+ } else
+ mbnambuf_flush(&dirbuf);
chksum = -1;
dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
if (uio->uio_resid < dirbuf.d_reclen) {
diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h
index d525771..468677a 100644
--- a/sys/fs/msdosfs/msdosfsmount.h
+++ b/sys/fs/msdosfs/msdosfsmount.h
@@ -95,11 +95,10 @@ struct msdosfsmount {
u_int pm_curfat; /* current fat for FAT32 (0 otherwise) */
u_int *pm_inusemap; /* ptr to bitmap of in-use clusters */
u_int pm_flags; /* see below */
- 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 iconv handle */
+ void *pm_w2u; /* Unicode->Local iconv handle */
+ void *pm_u2d; /* Unicode->DOS iconv handle */
+ void *pm_d2u; /* DOS->Local iconv handle */
};
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) ((cn) * (pmp)->pm_fatmult / (pmp)->pm_fatdiv)
@@ -218,10 +217,9 @@ struct msdosfs_args {
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_win; /* Windows(Unicode) Charset */
+ char *cs_dos; /* DOS Charset */
+ char *cs_local; /* Local Charset */
};
/*
@@ -230,13 +228,11 @@ 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 */
- /* tables loaded */
-#define MSDOSFSMNT_ULTABLE 0x20 /* Local upper<->lower table loaded */
+#define MSDOSFSMNT_KICONV 0x10 /* Use libiconv to convert chars */
/* All flags above: */
#define MSDOSFSMNT_MNTOPT \
(MSDOSFSMNT_SHORTNAME|MSDOSFSMNT_LONGNAME|MSDOSFSMNT_NOWIN95 \
- |MSDOSFSMNT_U2WTABLE|MSDOSFSMNT_ULTABLE)
+ |MSDOSFSMNT_KICONV)
#define MSDOSFSMNT_RONLY 0x80000000 /* mounted read-only */
#define MSDOSFSMNT_WAITONFAT 0x40000000 /* mounted synchronous */
#define MSDOSFS_FATMIRROR 0x20000000 /* FAT is mirrored */
diff --git a/sys/fs/ntfs/ntfs.h b/sys/fs/ntfs/ntfs.h
index fba06c1..6e19029 100644
--- a/sys/fs/ntfs/ntfs.h
+++ b/sys/fs/ntfs/ntfs.h
@@ -254,6 +254,8 @@ struct ntfsmount {
int ntm_adnum;
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/fs/ntfs/ntfs_iconv.c b/sys/fs/ntfs/ntfs_iconv.c
new file mode 100644
index 0000000..347306e
--- /dev/null
+++ b/sys/fs/ntfs/ntfs_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/kernel.h>
+#include <sys/module.h>
+#include <sys/mount.h>
+#include <sys/iconv.h>
+
+VFS_DECLARE_ICONV(ntfs);
diff --git a/sys/fs/ntfs/ntfs_subr.c b/sys/fs/ntfs/ntfs_subr.c
index cf2879c..aff97a3 100644
--- a/sys/fs/ntfs/ntfs_subr.c
+++ b/sys/fs/ntfs/ntfs_subr.c
@@ -40,6 +40,7 @@
#include <sys/file.h>
#include <sys/malloc.h>
#include <sys/lock.h>
+#include <sys/iconv.h>
/* #define NTFS_DEBUG 1 */
#include <fs/ntfs/ntfs.h>
@@ -67,6 +68,8 @@ static wchar *ntfs_toupper_tab;
static struct lock ntfs_toupper_lock;
static signed int ntfs_toupper_usecount;
+struct iconv_functions *ntfs_iconv = NULL;
+
/* support macro for ntfs_ntvattrget() */
#define NTFS_AALPCMP(aalp,type,name,namelen) ( \
(aalp->al_type == type) && (aalp->al_namelen == namelen) && \
@@ -665,20 +668,41 @@ ntfs_uastricmp(ntmp, ustr, ustrlen, astr, astrlen)
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);
}
/*
@@ -692,15 +716,25 @@ ntfs_uastrcmp(ntmp, ustr, ustrlen, astr, astrlen)
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);
}
/*
@@ -2003,11 +2037,18 @@ ntfs_toupper_unuse()
int
ntfs_u28_init(
struct ntfsmount *ntmp,
- wchar *u2w)
+ 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++) {
@@ -2034,8 +2075,12 @@ ntfs_u28_uninit(struct ntfsmount *ntmp)
char ** u28;
int i;
- if (ntmp->ntm_u28 == NULL)
+ if (ntmp->ntm_u28 == NULL) {
+ if (ntfs_iconv && ntmp->ntm_ic_u2l) {
+ ntfs_iconv->close(ntmp->ntm_ic_u2l);
+ }
return (0);
+ }
u28 = ntmp->ntm_u28;
@@ -2051,22 +2096,21 @@ ntfs_u28_uninit(struct ntfsmount *ntmp)
int
ntfs_82u_init(
struct ntfsmount *ntmp,
- u_int16_t *u2w)
+ 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++)
+ for (i=0; i<256; i++)
_82u[i] = i;
- for (i=0; i<128; i++)
- _82u[i+128] = u2w[i];
- }
ntmp->ntm_82u = _82u;
@@ -2076,6 +2120,14 @@ ntfs_82u_init(
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);
}
@@ -2086,12 +2138,31 @@ 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]));
+ } else if (olen == 0) {
+ return ((wchar)((outbuf[0]<<8) | (outbuf[1]&0xFF)));
+ }
+ return ('?');
+ }
p = ntmp->ntm_u28[(wc>>8)&0xFF];
if (p == NULL)
@@ -2099,3 +2170,36 @@ ntfs_u28(
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 ('?');
+}
+
diff --git a/sys/fs/ntfs/ntfs_subr.h b/sys/fs/ntfs/ntfs_subr.h
index 1d676ab..c0ecc75 100644
--- a/sys/fs/ntfs/ntfs_subr.h
+++ b/sys/fs/ntfs/ntfs_subr.h
@@ -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) \
diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c
index cd5e062..a959e8c 100644
--- a/sys/fs/ntfs/ntfs_vfsops.c
+++ b/sys/fs/ntfs/ntfs_vfsops.c
@@ -350,15 +350,15 @@ ntfs_mountfs(devvp, mp, argsp, td)
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);
+ /* Initialize Unicode to 8-bit table from 8toU table */
+ if (argsp->flag & NTFS_MFLAG_KICONV) {
+ ntfs_82u_init(ntmp, argsp->cs_local, argsp->cs_ntfs);
+ ntfs_u28_init(ntmp, NULL, argsp->cs_local, argsp->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",
@@ -794,3 +794,4 @@ static struct vfsops ntfs_vfsops = {
.vfs_vptofh = ntfs_vptofh,
};
VFS_SET(ntfs_vfsops, ntfs, 0);
+MODULE_VERSION(ntfs, 1);
diff --git a/sys/fs/ntfs/ntfs_vnops.c b/sys/fs/ntfs/ntfs_vnops.c
index c24c9bf..4333c36 100644
--- a/sys/fs/ntfs/ntfs_vnops.c
+++ b/sys/fs/ntfs/ntfs_vnops.c
@@ -495,7 +495,8 @@ ntfs_readdir(ap)
register 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;
int ncookies = 0;
struct dirent cde;
@@ -552,14 +553,17 @@ ntfs_readdir(ap)
if(!ntfs_isnamepermitted(ntmp,iep))
continue;
- for(i=0; i<iep->ie_fnamelen; i++) {
- cde.d_name[i] = NTFS_U28(iep->ie_fname[i]);
+ for(i=0, j=0; i<iep->ie_fnamelen; i++, j++) {
+ c = NTFS_U28(iep->ie_fname[i]);
+ if (c&0xFF00)
+ cde.d_name[j++] = (char)(c>>8);
+ cde.d_name[j] = (char)c&0xFF;
}
- cde.d_name[i] = '\0';
+ cde.d_name[j] = '\0';
dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
num, cde.d_name, iep->ie_fnametype,
iep->ie_flag));
- cde.d_namlen = iep->ie_fnamelen;
+ cde.d_namlen = j;
cde.d_fileno = iep->ie_number;
cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
cde.d_reclen = sizeof(struct dirent);
diff --git a/sys/fs/ntfs/ntfsmount.h b/sys/fs/ntfs/ntfsmount.h
index 0c143ed..5497ad9 100644
--- a/sys/fs/ntfs/ntfsmount.h
+++ b/sys/fs/ntfs/ntfsmount.h
@@ -30,7 +30,7 @@
#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 */
@@ -39,5 +39,6 @@ struct ntfs_args {
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 */
+ char *cs_ntfs; /* NTFS Charset */
+ char *cs_local; /* Local Charset */
};
diff --git a/sys/fs/smbfs/smbfs_vfsops.c b/sys/fs/smbfs/smbfs_vfsops.c
index 5bc646a..1a279f1 100644
--- a/sys/fs/smbfs/smbfs_vfsops.c
+++ b/sys/fs/smbfs/smbfs_vfsops.c
@@ -101,7 +101,7 @@ static struct vfsops smbfs_vfsops = {
VFS_SET(smbfs_vfsops, smbfs, VFCF_NETWORK);
MODULE_DEPEND(smbfs, netsmb, NSMB_VERSION, NSMB_VERSION, NSMB_VERSION);
-MODULE_DEPEND(smbfs, libiconv, 1, 1, 1);
+MODULE_DEPEND(smbfs, libiconv, 1, 1, 2);
MODULE_DEPEND(smbfs, libmchain, 1, 1, 1);
int smbfs_pbuf_freecnt = -1; /* start out unlimited */
OpenPOWER on IntegriCloud