Subject: kern/7951: cd9660 does not understand Microsoft Joliet extensions
To: None <gnats-bugs@gnats.netbsd.org>
From: None <kuebart@mathematik.uni-ulm.de>
List: netbsd-bugs
Date: 07/09/1999 18:22:50
>Number: 7951
>Category: kern
>Synopsis: Read Microsoft Joliet extensions from CDs if available
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Fri Jul 9 18:20:00 1999
>Last-Modified:
>Originator: Joachim Kuebart
>Organization:
>Release: Thu Jul 8 13:51:47 UTC 1999
>Environment:
i386, NetBSD-current (ELF)
System: NetBSD yacht 1.4E NetBSD 1.4E (YACHT) #34: Sat Jul 10 02:07:59 CEST 1999 joki@yacht:/usr/src/sys/arch/i386/compile/YACHT i386
>Description:
Some CDs use Microsoft Joliet extensions for long filenames
and Unicode characters in file names.
>How-To-Repeat:
Mount a current Windows-originated CD. Either you will see no
files at all or just short file names that have been written
to the "compatibility tree".
>Fix:
The following patch allows to read the long file names from
Joliet extensions. Unicode characters are not supported.
I have been using a similar version of the patch on FreeBSD
for quite a while with no trouble.
Index: cd9660_extern.h
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_extern.h,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- cd9660_extern.h 1999/06/14 20:07:07 1.1.1.1
+++ cd9660_extern.h 1999/07/10 00:52:03 1.3
@@ -53,6 +53,7 @@
struct iso_mnt {
int im_flags;
+ int im_joliet_level;
struct mount *im_mountp;
dev_t im_dev;
@@ -106,6 +107,7 @@
extern int (**cd9660_specop_p) __P((void *));
extern int (**cd9660_fifoop_p) __P((void *));
-int isofncmp __P((const u_char *, int, const u_char *, int));
-void isofntrans __P((u_char *, int, u_char *, u_short *, int, int));
+int isochar __P((const u_char *, const u_char *, int, u_char *));
+int isofncmp __P((const u_char *, int, const u_char *, int, int));
+void isofntrans __P((u_char *, int, u_char *, u_short *, int, int, int));
ino_t isodirino __P((struct iso_directory_record *, struct iso_mnt *));
Index: cd9660_lookup.c
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_lookup.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -r1.1.1.2 -r1.2
--- cd9660_lookup.c 1999/07/09 11:38:51 1.1.1.2
+++ cd9660_lookup.c 1999/07/09 21:15:31 1.2
@@ -321,7 +321,8 @@
|| ep->name[0] != 0)
goto notfound;
} else if (!(res = isofncmp(name,len,
- ep->name,namelen))) {
+ ep->name,namelen,
+ imp->im_joliet_level))) {
if (isonum_711(ep->flags)&2)
ino = isodirino(ep, imp);
else
Index: cd9660_mount.h
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_mount.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- cd9660_mount.h 1999/06/14 20:07:07 1.1.1.1
+++ cd9660_mount.h 1999/07/09 21:15:31 1.2
@@ -50,3 +50,4 @@
#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 extensions */
Index: cd9660_rrip.c
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_rrip.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- cd9660_rrip.c 1999/06/14 20:07:07 1.1.1.1
+++ cd9660_rrip.c 1999/07/10 00:52:03 1.3
@@ -298,17 +298,19 @@
{
struct iso_directory_record *isodir = v;
- strcpy(ana->outbuf, "..");
- switch (*isodir->name) {
+ isofntrans(isodir->name, isonum_711(isodir->name_len),
+ ana->outbuf, ana->outlen,
+ 1, isonum_711(isodir->flags) & 4,
+ ana->imp->im_joliet_level);
+ switch (ana->outbuf[0]) {
default:
- isofntrans(isodir->name, isonum_711(isodir->name_len),
- ana->outbuf, ana->outlen,
- 1, isonum_711(isodir->flags) & 4);
break;
case 0:
+ ana->outbuf[0] = '.';
*ana->outlen = 1;
break;
case 1:
+ strcpy(ana->outbuf, "..");
*ana->outlen = 2;
break;
}
@@ -518,6 +520,7 @@
register ISO_SUSP_HEADER *pend;
struct buf *bp = NULL;
char *pwhead;
+ u_char c;
int result;
/*
@@ -527,10 +530,10 @@
pwhead = isodir->name + isonum_711(isodir->name_len);
if (!(isonum_711(isodir->name_len) & 1))
pwhead++;
+ isochar(isodir->name, pwhead, ana->imp->im_joliet_level, &c);
/* If it's not the '.' entry of the root dir obey SP field */
- if (*isodir->name != 0
- || isonum_733(isodir->extent) != ana->imp->root_extent)
+ if (c != 0 || isonum_733(isodir->extent) != ana->imp->root_extent)
pwhead += ana->imp->rr_skip;
else
pwhead += ana->imp->rr_skip0;
@@ -648,6 +651,7 @@
{
ISO_RRIP_ANALYZE analyze;
RRIP_TABLE *tab;
+ u_char c;
analyze.outbuf = outbuf;
analyze.outlen = outlen;
@@ -657,9 +661,10 @@
analyze.fields = ISO_SUSP_ALTNAME | ISO_SUSP_RELDIR | ISO_SUSP_CLINK | ISO_SUSP_PLINK;
*outlen = 0;
+ isochar(isodir->name, isodir->name + isonum_711(isodir->name_len),
+ imp->im_joliet_level, &c);
tab = rrip_table_getname;
- if (*isodir->name == 0
- || *isodir->name == 1) {
+ if (c == 0 || c == 1) {
cd9660_rrip_defname(isodir, &analyze);
analyze.fields &= ~ISO_SUSP_ALTNAME;
Index: cd9660_util.c
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_util.c,v
retrieving revision 1.1.1.1
retrieving revision 1.3
diff -u -r1.1.1.1 -r1.3
--- cd9660_util.c 1999/06/14 20:07:07 1.1.1.1
+++ cd9660_util.c 1999/07/10 00:52:03 1.3
@@ -59,21 +59,51 @@
#include <isofs/cd9660/cd9660_extern.h>
/*
+ * Get one character out of an iso filename
+ * Return number of bytes consumed
+ */
+int
+isochar(isofn, isoend, joliet_level, c)
+ const u_char *isofn;
+ const u_char *isoend;
+ int joliet_level;
+ u_char *c;
+{
+ *c = *isofn++;
+ 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;
+ }
+ return 2;
+}
+
+/*
* translate and compare a filename
* Note: Version number plus ';' may be omitted.
*/
int
-isofncmp(fn, fnlen, isofn, isolen)
+isofncmp(fn, fnlen, isofn, isolen, joliet_level)
const u_char *fn, *isofn;
- int fnlen, isolen;
+ int fnlen, isolen, joliet_level;
{
int i, j;
char c;
-
+ const u_char *isoend = isofn + isolen;
+
while (--fnlen >= 0) {
- if (--isolen < 0)
+ if (isofn == isoend)
return *fn;
- if ((c = *isofn++) == ';') {
+ isofn += isochar(isofn, isoend, joliet_level, &c);
+ if (c == ';') {
switch (*fn++) {
default:
return *--fn;
@@ -87,7 +117,9 @@
return -1;
}
}
- for (j = 0; --isolen >= 0; j = j * 10 + *isofn++ - '0');
+ for (j = 0; isofn != isoend; j = j * 10 + c - '0')
+ isofn += isochar(isofn, isoend,
+ joliet_level, &c);
return i - j;
}
if (((u_char) c) != *fn) {
@@ -103,13 +135,18 @@
}
fn++;
}
- if (isolen > 0) {
- switch (*isofn) {
+ if (isofn != isoend) {
+ isofn += isochar(isofn, isoend, joliet_level, &c);
+ switch (c) {
default:
return -1;
case '.':
- if (isofn[1] != ';')
- return -1;
+ if (isofn != isoend) {
+ isochar(isofn, isoend, joliet_level, &c);
+ if (c == ';')
+ return 0;
+ }
+ return -1;
case ';':
return 0;
}
@@ -121,30 +158,33 @@
* translate a filename
*/
void
-isofntrans(infn, infnlen, outfn, outfnlen, original, assoc)
+isofntrans(infn, infnlen, outfn, outfnlen, original, assoc, joliet_level)
u_char *infn, *outfn;
int infnlen;
u_short *outfnlen;
int original;
int assoc;
+ int joliet_level;
{
int fnidx = 0;
+ u_char *infnend = infn + infnlen;
if (assoc) {
*outfn++ = ASSOCCHAR;
fnidx++;
- infnlen++;
}
- for (; fnidx < infnlen; fnidx++) {
- char c = *infn++;
-
- if (!original && c >= 'A' && c <= 'Z')
+ for (; infn != infnend; fnidx++) {
+ char c;
+
+ infn += isochar(infn, infnend, joliet_level, &c);
+
+ if (!original && joliet_level == 0 && c >= 'A' && c <= 'Z')
*outfn++ = c + ('a' - 'A');
- else if (!original && c == '.' && *infn == ';')
- break;
- else if (!original && c == ';')
+ else if (!original && c == ';') {
+ if (fnidx > 0 && outfn[-1] == '.')
+ fnidx--;
break;
- else
+ } else
*outfn++ = c;
}
*outfnlen = fnidx;
Index: cd9660_vfsops.c
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_vfsops.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- cd9660_vfsops.c 1999/07/09 11:38:52 1.1.1.2
+++ cd9660_vfsops.c 1999/07/10 00:52:03 1.3
@@ -242,7 +242,7 @@
struct iso_args *argp;
{
register struct iso_mnt *isomp = (struct iso_mnt *)0;
- struct buf *bp = NULL;
+ struct buf *bp = NULL, *pribp = NULL, *supbp = NULL;
dev_t dev = devvp->v_rdev;
int error = EINVAL;
int needclose = 0;
@@ -250,8 +250,10 @@
extern struct vnode *rootvp;
int iso_bsize;
int iso_blknum;
+ int joliet_level;
struct iso_volume_descriptor *vdp;
struct iso_primary_descriptor *pri;
+ struct iso_supplementary_descriptor *sup;
struct iso_directory_record *rootp;
int logical_block_size;
int sess = 0;
@@ -301,23 +303,70 @@
error = EINVAL;
goto out;
}
-
- if (isonum_711 (vdp->type) == ISO_VD_END) {
- error = EINVAL;
- goto out;
+
+ switch (isonum_711(vdp->type)) {
+ case ISO_VD_PRIMARY:
+ if (pribp == NULL) {
+ pribp = bp;
+ bp = NULL;
+ }
+ break;
+
+ case ISO_VD_SUPPLEMENTARY:
+ if (supbp == NULL) {
+ supbp = bp;
+ bp = NULL;
+ }
+ break;
+
+ default:
+ break;
}
-
- if (isonum_711 (vdp->type) == ISO_VD_PRIMARY)
+
+ if (isonum_711 (vdp->type) == ISO_VD_END) {
+ brelse(bp);
+ bp = NULL;
break;
- brelse(bp);
+ }
+
+ if (bp != NULL) {
+ brelse(bp);
+ bp = NULL;
+ }
}
-
- if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) {
+
+ /* Check the Joliet Extension support */
+ joliet_level = 0;
+ if ((argp->flags & ISOFSMNT_NOJOLIET) == 0 && supbp != NULL) {
+ sup = (struct iso_supplementary_descriptor *)supbp->b_data;
+
+ if ((isonum_711(sup->flags) & 1) == 0) {
+ if (memcmp(sup->escape, "%/@", 3) == 0)
+ joliet_level = 1;
+ if (memcmp(sup->escape, "%/C", 3) == 0)
+ joliet_level = 2;
+ if (memcmp(sup->escape, "%/E", 3) == 0)
+ joliet_level = 3;
+ }
+ if (joliet_level != 0) {
+ if (pribp != NULL)
+ brelse(pribp);
+ pribp = supbp;
+ supbp = NULL;
+ }
+ }
+
+ if (supbp != NULL) {
+ brelse(supbp);
+ supbp = NULL;
+ }
+
+ if (pribp == NULL) {
error = EINVAL;
goto out;
}
-
- pri = (struct iso_primary_descriptor *)vdp;
+
+ pri = (struct iso_primary_descriptor *)pribp->b_data;
logical_block_size = isonum_723 (pri->logical_block_size);
@@ -336,15 +385,16 @@
memcpy(isomp->root, rootp, sizeof(isomp->root));
isomp->root_extent = isonum_733 (rootp->extent);
isomp->root_size = isonum_733 (rootp->size);
+ isomp->im_joliet_level = joliet_level;
isomp->im_bmask = logical_block_size - 1;
isomp->im_bshift = 0;
while ((1 << isomp->im_bshift) < isomp->logical_block_size)
isomp->im_bshift++;
- bp->b_flags |= B_AGE;
- brelse(bp);
- bp = NULL;
+ pribp->b_flags |= B_AGE;
+ brelse(pribp);
+ pribp = NULL;
mp->mnt_data = (qaddr_t)isomp;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
@@ -382,7 +432,8 @@
brelse(bp);
bp = NULL;
}
- isomp->im_flags = argp->flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS|ISOFSMNT_EXTATT);
+ isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
+ ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
default:
isomp->iso_ftype = ISO_FTYPE_DEFAULT;
@@ -399,6 +450,10 @@
out:
if (bp)
brelse(bp);
+ if (pribp)
+ brelse(pribp);
+ if (supbp)
+ brelse(supbp);
if (needclose)
(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
if (isomp) {
Index: cd9660_vnops.c
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/cd9660_vnops.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- cd9660_vnops.c 1999/07/09 11:38:52 1.1.1.2
+++ cd9660_vnops.c 1999/07/10 00:52:03 1.3
@@ -550,21 +550,23 @@
error = iso_uiodir(idp,&idp->current,idp->curroff);
break;
default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
- strcpy(idp->current.d_name,"..");
- switch (ep->name[0]) {
+ isofntrans(ep->name,idp->current.d_namlen,
+ idp->current.d_name, &namelen,
+ imp->iso_ftype == ISO_FTYPE_9660,
+ isonum_711(ep->flags)&4,
+ imp->im_joliet_level);
+ switch (idp->current.d_name[0]) {
case 0:
+ idp->current.d_name[0] = '.';
idp->current.d_namlen = 1;
error = iso_uiodir(idp,&idp->current,idp->curroff);
break;
case 1:
+ strcpy(idp->current.d_name,"..");
idp->current.d_namlen = 2;
error = iso_uiodir(idp,&idp->current,idp->curroff);
break;
default:
- isofntrans(ep->name,idp->current.d_namlen,
- idp->current.d_name, &namelen,
- imp->iso_ftype == ISO_FTYPE_9660,
- isonum_711(ep->flags)&4);
idp->current.d_namlen = (u_char)namelen;
if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
error = iso_shipdir(idp);
Index: iso.h
===================================================================
RCS file: /home/cvs/netbsd/src/sys/isofs/cd9660/iso.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- iso.h 1999/06/14 20:07:07 1.1.1.1
+++ iso.h 1999/07/09 21:15:31 1.2
@@ -57,6 +57,7 @@
/* volume descriptor types */
#define ISO_VD_PRIMARY 1
+#define ISO_VD_SUPPLEMENTARY 2
#define ISO_VD_END 255
#define ISO_STANDARD_ID "CD001"
@@ -98,6 +99,42 @@
char unused5 [ISODCL (1396, 2048)];
};
#define ISO_DEFAULT_BLOCK_SIZE 2048
+
+struct iso_supplementary_descriptor {
+ char type [ISODCL ( 1, 1)]; /* 711 */
+ char id [ISODCL ( 2, 6)];
+ char version [ISODCL ( 7, 7)]; /* 711 */
+ char flags [ISODCL ( 8, 8)]; /* 711? */
+ char system_id [ISODCL ( 9, 40)]; /* achars */
+ char volume_id [ISODCL ( 41, 72)]; /* dchars */
+ char unused2 [ISODCL ( 73, 80)];
+ char volume_space_size [ISODCL ( 81, 88)]; /* 733 */
+ char escape [ISODCL ( 89, 120)];
+ char volume_set_size [ISODCL (121, 124)]; /* 723 */
+ char volume_sequence_number [ISODCL (125, 128)]; /* 723 */
+ char logical_block_size [ISODCL (129, 132)]; /* 723 */
+ char path_table_size [ISODCL (133, 140)]; /* 733 */
+ char type_l_path_table [ISODCL (141, 144)]; /* 731 */
+ char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */
+ char type_m_path_table [ISODCL (149, 152)]; /* 732 */
+ char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */
+ char root_directory_record [ISODCL (157, 190)]; /* 9.1 */
+ char volume_set_id [ISODCL (191, 318)]; /* dchars */
+ char publisher_id [ISODCL (319, 446)]; /* achars */
+ char preparer_id [ISODCL (447, 574)]; /* achars */
+ char application_id [ISODCL (575, 702)]; /* achars */
+ char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */
+ char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */
+ char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */
+ char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */
+ char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */
+ char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */
+ char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */
+ char file_structure_version [ISODCL (882, 882)]; /* 711 */
+ char unused4 [ISODCL (883, 883)];
+ char application_data [ISODCL (884, 1395)];
+ char unused5 [ISODCL (1396, 2048)];
+};
struct iso_directory_record {
char length [ISODCL (1, 1)]; /* 711 */
Index: /usr/src/sbin/mount_cd9660/mount_cd9660.c
===================================================================
RCS file: /home/cvs/netbsd/src/sbin/mount_cd9660/mount_cd9660.c,v
retrieving revision 1.1.1.2
retrieving revision 1.2
diff -u -r1.1.1.2 -r1.2
--- mount_cd9660.c 1999/06/28 23:40:40 1.1.1.2
+++ mount_cd9660.c 1999/07/10 00:53:44 1.2
@@ -86,13 +86,16 @@
char *dev, *dir;
mntflags = opts = 0;
- while ((ch = getopt(argc, argv, "ego:r")) != -1)
+ while ((ch = getopt(argc, argv, "egjo:r")) != -1)
switch (ch) {
case 'e':
opts |= ISOFSMNT_EXTATT;
break;
case 'g':
opts |= ISOFSMNT_GENS;
+ break;
+ case 'j':
+ opts |= ISOFSMNT_NOJOLIET;
break;
case 'o':
getmntopts(optarg, mopts, &mntflags, 0);
>Audit-Trail:
>Unformatted: