Hi, Several days ago I got a CD with Russian filenames on it and discovered that I'm unable to read those filenames. After some hacking I produced a patch, which should solve this problem in the manner similar to what we have in msdosfs module (i.e. user-provided conversion table). I have to emphasize that it's a temporary solution until we will have iconv support in kernel. Please somebody review attached patches. -Maxim
Index: cd9660/cd9660_lookup.c =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_lookup.c,v retrieving revision 1.25 diff -d -u -r1.25 cd9660_lookup.c --- cd9660/cd9660_lookup.c 2000/10/03 04:39:50 1.25 +++ cd9660/cd9660_lookup.c 2000/12/27 10:03:04 @@ -239,7 +239,7 @@ 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->ctable))) { if (isoflags & 2) ino = isodirino(ep, imp); else Index: cd9660/cd9660_mount.h =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_mount.h,v retrieving revision 1.4 diff -d -u -r1.4 cd9660_mount.h --- cd9660/cd9660_mount.h 2000/05/01 20:05:04 1.4 +++ cd9660/cd9660_mount.h 2000/12/27 10:03:04 @@ -47,6 +47,7 @@ struct export_args export; /* network export info */ int flags; /* mounting flags, see below */ int ssector; /* starting sector, 0 for 1st session */ + u_char *ctable[256]; /* Table for converting unicode filenames */ }; #define ISOFSMNT_NORRIP 0x00000001 /* disable Rock Ridge Ext.*/ #define ISOFSMNT_GENS 0x00000002 /* enable generation numbers */ Index: cd9660/cd9660_rrip.c =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_rrip.c,v retrieving revision 1.18 diff -d -u -r1.18 cd9660_rrip.c --- cd9660/cd9660_rrip.c 2000/05/05 09:58:17 1.18 +++ cd9660/cd9660_rrip.c 2000/12/27 10:03:05 @@ -301,7 +301,7 @@ { 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->ctable); switch (*ana->outbuf) { default: break; @@ -509,7 +509,7 @@ 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, ana->imp->ctable); /* If it's not the '.' entry of the root dir obey SP field */ if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent) @@ -646,7 +646,7 @@ *outlen = 0; isochar(isodir->name, isodir->name + isonum_711(isodir->name_len), - imp->joliet_level, &c); + imp->joliet_level, &c, imp->ctable); tab = rrip_table_getname; if (c == 0 || c == 1) { cd9660_rrip_defname(isodir,&analyze); Index: cd9660/cd9660_util.c =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_util.c,v retrieving revision 1.15 diff -d -u -r1.15 cd9660_util.c --- cd9660/cd9660_util.c 2000/10/29 13:56:43 1.15 +++ cd9660/cd9660_util.c 2000/12/27 10:03:05 @@ -52,25 +52,28 @@ * Return number of bytes consumed */ int -isochar(isofn, isoend, joliet_level, c) +isochar(isofn, isoend, joliet_level, c, ctable) u_char *isofn; u_char *isoend; int joliet_level; u_char *c; + u_char **ctable; { *c = *isofn++; if (joliet_level == 0 || isofn == isoend) /* (00) and (01) are one byte in Joliet, too */ return 1; - /* No Unicode support yet :-( */ + /* Limited Unicode support yet :-( */ + /* (requires user-supplied conversion table) */ switch (*c) { - default: - *c = '?'; - break; - case '\0': + case '\0': /* ANSI */ *c = *isofn; break; + default: + if ((ctable[*c] == NULL) || ((*c = ctable[*c][*isofn]) == '\0')) + *c = '?'; + break; } return 2; } @@ -81,12 +84,13 @@ * Note: Version number plus ';' may be omitted. */ int -isofncmp(fn, fnlen, isofn, isolen, joliet_level) +isofncmp(fn, fnlen, isofn, isolen, joliet_level, ctable) u_char *fn; int fnlen; u_char *isofn; int isolen; int joliet_level; + u_char **ctable; { int i, j; u_char c, *fnend = fn + fnlen, *isoend = isofn + isolen; @@ -94,7 +98,7 @@ for (; fn != fnend; fn++) { if (isofn == isoend) return *fn; - isofn += isochar(isofn, isoend, joliet_level, &c); + isofn += isochar(isofn, isoend, joliet_level, &c, ctable); if (c == ';') { if (*fn++ != ';') return fn[-1]; @@ -105,7 +109,7 @@ } for (j = 0; isofn != isoend; j = j * 10 + c - '0') isofn += isochar(isofn, isoend, - joliet_level, &c); + joliet_level, &c, ctable); return i - j; } if (c != *fn) { @@ -121,13 +125,13 @@ } } if (isofn != isoend) { - isofn += isochar(isofn, isoend, joliet_level, &c); + isofn += isochar(isofn, isoend, joliet_level, &c, ctable); switch (c) { default: return -c; case '.': if (isofn != isoend) { - isochar(isofn, isoend, joliet_level, &c); + isochar(isofn, isoend, joliet_level, &c, ctable); if (c == ';') return 0; } @@ -143,7 +147,7 @@ * 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, ctable) u_char *infn; int infnlen; u_char *outfn; @@ -151,6 +155,7 @@ int original; int assoc; int joliet_level; + u_char **ctable; { int fnidx = 0; u_char c, d = '\0', *infnend = infn + infnlen; @@ -160,7 +165,7 @@ fnidx++; } for (; infn != infnend; fnidx++) { - infn += isochar(infn, infnend, joliet_level, &c); + infn += isochar(infn, infnend, joliet_level, &c, ctable); if (!original && !joliet_level && c >= 'A' && c <= 'Z') *outfn++ = c + ('a' - 'A'); Index: cd9660/cd9660_vfsops.c =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_vfsops.c,v retrieving revision 1.81 diff -d -u -r1.81 cd9660_vfsops.c --- cd9660/cd9660_vfsops.c 2000/12/08 21:50:31 1.81 +++ cd9660/cd9660_vfsops.c 2000/12/27 10:03:06 @@ -284,6 +284,7 @@ struct iso_supplementary_descriptor *sup = NULL; struct iso_directory_record *rootp; int logical_block_size; + int i; if (!(mp->mnt_flag & MNT_RDONLY)) return EROFS; @@ -502,6 +503,13 @@ supbp = NULL; } + for (i = 0; i < 256; i++) + if (argp->ctable[i] != NULL) { + isomp->ctable[i] = malloc(256 * sizeof(u_char), M_ISOFSMNT, +M_WAITOK); + if (error = copyin(argp->ctable[i], isomp->ctable[i], 256 * +sizeof(u_char))) + goto out; + } + return 0; out: devvp->v_rdev->si_mountpoint = NULL; @@ -514,6 +522,9 @@ if (needclose) (void)VOP_CLOSE(devvp, FREAD, NOCRED, p); if (isomp) { + for (i = 0; i < 256; i++) + if (isomp->ctable[i] != NULL) + free((caddr_t)isomp->ctable[i], M_ISOFSMNT); free((caddr_t)isomp, M_ISOFSMNT); mp->mnt_data = (qaddr_t)0; } @@ -530,7 +541,7 @@ struct proc *p; { register struct iso_mnt *isomp; - int error, flags = 0; + int i, error, flags = 0; if (mntflags & MNT_FORCE) flags |= FORCECLOSE; @@ -547,6 +558,9 @@ isomp->im_devvp->v_rdev->si_mountpoint = NULL; error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p); vrele(isomp->im_devvp); + for (i = 0; i < 256; i++) + if (isomp->ctable[i] != NULL) + free((caddr_t)isomp->ctable[i], M_ISOFSMNT); free((caddr_t)isomp, M_ISOFSMNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; Index: cd9660/cd9660_vnops.c =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/cd9660_vnops.c,v retrieving revision 1.67 diff -d -u -r1.67 cd9660_vnops.c --- cd9660/cd9660_vnops.c 2000/08/29 14:45:47 1.67 +++ cd9660/cd9660_vnops.c 2000/12/27 10:03:08 @@ -556,7 +556,7 @@ idp->current.d_name, &namelen, imp->iso_ftype == ISO_FTYPE_9660, isonum_711(ep->flags)&4, - imp->joliet_level); + imp->joliet_level, imp->ctable); idp->current.d_namlen = (u_char)namelen; if (imp->iso_ftype == ISO_FTYPE_DEFAULT) error = iso_shipdir(idp); Index: cd9660/iso.h =================================================================== RCS file: /home/ncvs/src/sys/isofs/cd9660/iso.h,v retrieving revision 1.20 diff -d -u -r1.20 iso.h --- cd9660/iso.h 2000/06/29 01:19:12 1.20 +++ cd9660/iso.h 2000/12/27 10:03:08 @@ -246,6 +246,8 @@ int rr_skip0; int joliet_level; + + u_char *ctable[256]; }; #define VFSTOISOFS(mp) ((struct iso_mnt *)((mp)->mnt_data)) @@ -266,9 +268,10 @@ extern vop_t **cd9660_specop_p; extern vop_t **cd9660_fifoop_p; -int isochar __P((u_char *, u_char *, int, u_char *)); -int isofncmp __P((u_char *, int, u_char *, int, int)); -void isofntrans __P((u_char *, int, u_char *, u_short *, int, int, int)); +int isochar __P((u_char *, u_char *, int, u_char *, u_char **)); +int isofncmp __P((u_char *, int, u_char *, int, int, u_char **)); +void isofntrans __P((u_char *, int, u_char *, u_short *, int, int, int, \ + u_char **)); ino_t isodirino __P((struct iso_directory_record *, struct iso_mnt *)); #endif /* _KERNEL */ Index: mount_cd9660/Makefile =================================================================== RCS file: /home/ncvs/src/sbin/mount_cd9660/Makefile,v retrieving revision 1.4 diff -d -u -r1.4 Makefile --- mount_cd9660/Makefile 1998/01/20 10:39:58 1.4 +++ mount_cd9660/Makefile 2000/12/27 10:03:08 @@ -1,11 +1,23 @@ -# @(#)Makefile 8.3 (Berkeley) 3/27/94 +# +# $FreeBSD$ +# PROG= mount_cd9660 SRCS= mount_cd9660.c getmntopts.c MAN8= mount_cd9660.8 +DPADD= ${LIBUTIL} +LDADD= -lutil MOUNT= ${.CURDIR}/../mount CFLAGS+= -I${MOUNT} .PATH: ${MOUNT} + +TABDIR= ${DESTDIR}${LIBDATADIR}/cd9660 +TABLES= unic2koi + +afterinstall: + cd ${.CURDIR} && \ + ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m ${SHAREMODE} \ + ${TABLES} ${TABDIR} .include <bsd.prog.mk> Index: mount_cd9660/mount_cd9660.8 =================================================================== RCS file: /home/ncvs/src/sbin/mount_cd9660/mount_cd9660.8,v retrieving revision 1.13 diff -d -u -r1.13 mount_cd9660.8 --- mount_cd9660/mount_cd9660.8 2000/11/20 16:47:32 1.13 +++ mount_cd9660/mount_cd9660.8 2000/12/27 10:03:08 @@ -47,6 +47,7 @@ .Op Fl egjrv .Op Fl o Ar options .Op Fl s Ar startsector +.Op Fl W Ar table .Ar special | node .Sh DESCRIPTION The @@ -114,6 +115,13 @@ is printing. .It Fl v Be verbose about the starting sector decisions made. +.It Fl W Ar table +Specify text file with conversion tables for Unicode filenames. +.El +.Sh FILES +.Bl -tag -width /usr/libdata/cd9660 -compact +.It Pa /usr/libdata/cd9660 +default place for character sets conversion tables .El .Sh SEE ALSO .Xr cdcontrol 1 , Index: mount_cd9660/mount_cd9660.c =================================================================== RCS file: /home/ncvs/src/sbin/mount_cd9660/mount_cd9660.c,v retrieving revision 1.15 diff -d -u -r1.15 mount_cd9660.c --- mount_cd9660/mount_cd9660.c 1999/10/09 11:54:08 1.15 +++ mount_cd9660/mount_cd9660.c 2000/12/27 10:03:09 @@ -58,12 +58,14 @@ #include <sys/mount.h> #include <sys/../isofs/cd9660/cd9660_mount.h> +#include <ctype.h> #include <err.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <sysexits.h> #include <unistd.h> +#include <libutil.h> #include "mntopts.h" @@ -79,6 +81,7 @@ int get_ssector(const char *dev); void usage(void); +int load_ctable(const char *name, u_char *ctable[256]); int main(int argc, char **argv) @@ -92,7 +95,7 @@ mntflags = opts = verbose = 0; memset(&args, 0, sizeof args); args.ssector = -1; - while ((ch = getopt(argc, argv, "egjo:rs:v")) != -1) + while ((ch = getopt(argc, argv, "egjo:rs:vW:")) != -1) switch (ch) { case 'e': opts |= ISOFSMNT_EXTATT; @@ -115,6 +118,9 @@ case 'v': verbose++; break; + case 'W': + load_ctable(optarg, args.ctable); + break; case '?': default: usage(); @@ -184,7 +190,8 @@ usage(void) { (void)fprintf(stderr, - "usage: mount_cd9660 [-egrv] [-o options] [-s startsector] special node\n"); + "usage: mount_cd9660 [-egrv] [-o options] [-s startsector] " \ + "[-W table] special node\n"); exit(EX_USAGE); } @@ -228,4 +235,73 @@ return -1; return ntohl(toc_buffer[i].addr.lba); +} + +int +load_ctable (const char *name, u_char *ctable[256]) +{ + FILE *f; + int i, j, base, num; + int ci[16]; + size_t line = 0; + char buf[128]; + char *fn, *s, *p; + u_char *code, *cp; + + if (*name == '/') + fn = (char *)name; + else { + snprintf(buf, sizeof(buf), "/usr/libdata/cd9660/%s", name); + buf[127] = '\0'; + fn = buf; + } + if ((f = fopen(fn, "r")) == NULL) + err(EX_NOINPUT, "%s", fn); + p = NULL; + code = NULL; + num = 0; + do { + base = -1; + if (code == NULL) + code = malloc(256); + cp = code; + for (i = 0; i < 17; i++) { + do { + if (p != NULL) free(p); + p = s = fparseln(f, NULL, &line, NULL, 0); + if (s == NULL) + break; + while (isspace((unsigned char)*s)) + s++; + } while (*s == '\0'); + if (s == NULL) + break; + if (base == -1) { + if ((sscanf(s, "Base: %i", &base) != 1) || (base < 0) \ + || (base > 255)) + errx(EX_DATAERR, "unicode conversion table: +missing" \ + " or invalid base in line %d", line); + } else { + if (sscanf(s, "%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i%i", + ci, ci + 1, ci + 2, ci + 3, ci + 4, ci + 5, + \ + ci + 6, ci + 7, ci + 8, ci + 9, ci + 10, ci + 11, + \ + ci + 12, ci + 13, ci + 14, ci + 15) != 16) + errx(EX_DATAERR, "unicode conversion table: +missing" \ + " or invalid item(s) in row %d, line %d", i, +line); + for (j = 0; j < 16; j++) + *cp++ = ci[j]; + } + } + if (cp == code + 256) { + ctable[base] = code; + code = NULL; + num++; + } else if (base != -1) + errx(EX_DATAERR, "truncated unicode conversion table near line +%d", \ + line); + } while (feof(f) == 0); + free(p); + fclose(f); + + return num; } Index: mount_cd9660/unic2koi =================================================================== RCS file: unic2koi diff -N unic2koi --- /dev/null Wed Dec 27 02:00:25 2000 +++ unic2koi Wed Dec 27 02:03:09 2000 @@ -0,0 +1,25 @@ +# $FreeBSD$ +# +# unic2koi: 16 rows of Unicode -> KOI8-U conversion table +# +# `Base' specifies the first byte of Unicode charcode, so for example the +# second value in the table `0xb3' means that Unicode character with code +# `0x0401' should be maped into single byte character `0xb3'. + +Base: 0x04 +0x00 0xb3 0x00 0x00 0xb4 0x00 0xb6 0xb7 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0xe1 0xe2 0xf7 0xe7 0xe4 0xe5 0xf6 0xfa 0xe9 0xea 0xeb 0xec 0xed 0xee 0xef 0xf0 +0xf2 0xf3 0xf4 0xf5 0xe6 0xe8 0xe3 0xfe 0xfb 0xfd 0xff 0xf9 0xf8 0xfc 0xe0 0xf1 +0xc1 0xc2 0xd7 0xc7 0xc4 0xc5 0xd6 0xda 0xc9 0xca 0xcb 0xcc 0xcd 0xce 0xcf 0xd0 +0xd2 0xd3 0xd4 0xd5 0xc6 0xc8 0xc3 0xde 0xdb 0xdd 0xdf 0xd9 0xd8 0xdc 0xc0 0xd1 +0x00 0xa3 0x00 0x00 0xa4 0x00 0xa6 0xa7 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0xbd 0xad 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00