Joliet patch

Gordon Chaffee (chaffee@cs.berkeley.edu)
Tue, 25 Aug 1998 20:13:38 -0700


I took a look into the problems with Joliet people are running into,
and I found that one of the patches I sent Linus at 2.1.101 never got
applied, and I didn't notice. It takes care of a few problems:

1. It fixed deep relocated RockRidge filenames.
2. The periods at the end of Joliet filenames are removed.
3. It makes the Joliet CDs case insensitive by default in the same
manner as the vfat and msdos filesystems.

Here is the updated patch.

- Gordon

diff -ur linux-2.1.116-clean/fs/isofs/inode.c linux/fs/isofs/inode.c
--- linux-2.1.116-clean/fs/isofs/inode.c Tue Jul 28 10:17:03 1998
+++ linux/fs/isofs/inode.c Tue Aug 25 19:57:17 1998
@@ -25,6 +25,7 @@
#include <linux/cdrom.h>
#include <linux/init.h>
#include <linux/nls.h>
+#include <linux/ctype.h>

#include <asm/system.h>
#include <asm/uaccess.h>
@@ -41,6 +42,15 @@
static int check_bread = 0;
#endif

+static int isofs_hashi(struct dentry *parent, struct qstr *qstr);
+static int isofs_hash(struct dentry *parent, struct qstr *qstr);
+static int isofs_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr);
+static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr);
+static int isofs_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
+static int isofs_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b);
+
void isofs_put_super(struct super_block *sb)
{
#ifdef CONFIG_JOLIET
@@ -71,21 +81,213 @@
NULL
};

+static struct dentry_operations isofs_dentry_ops[] = {
+ {
+ NULL, /* d_revalidate */
+ isofs_hash,
+ isofs_cmp,
+ NULL /* d_delete */
+ },
+ {
+ NULL, /* d_revalidate */
+ isofs_hashi,
+ isofs_cmpi,
+ NULL /* d_delete */
+ },
+#ifdef CONFIG_JOLIET
+ {
+ NULL, /* d_revalidate */
+ isofs_hash_ms,
+ isofs_cmp_ms,
+ NULL /* d_delete */
+ },
+ {
+ NULL, /* d_revalidate */
+ isofs_hashi_ms,
+ isofs_cmpi_ms,
+ NULL /* d_delete */
+ }
+#endif
+};
+
struct iso9660_options{
- char map;
- char rock;
- char joliet;
- char cruft;
- char unhide;
- unsigned char check;
- unsigned int blocksize;
- mode_t mode;
- gid_t gid;
- uid_t uid;
- char *iocharset;
- unsigned char utf8;
+ char map;
+ char rock;
+ char joliet;
+ char cruft;
+ char unhide;
+ unsigned char check;
+ unsigned int blocksize;
+ mode_t mode;
+ gid_t gid;
+ uid_t uid;
+ char *iocharset;
+ unsigned char utf8;
};

+static int strnicmp(const char *s1, const char *s2, int len)
+{
+ int n = 0;
+ while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) {
+ s1++; s2++; n++;
+ if (n == len) return 0;
+ }
+ if (*s1 == 0 && *s2 == 0) return 0;
+ if (*s1 && *s2) {
+ if (*s1 > *s2) return 1;
+ return -1;
+ }
+ if (*s1) return 1;
+ return -1;
+}
+
+/*
+ * Compute the hash for the isofs name corresponding to the dentry.
+ */
+static int
+isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms)
+{
+ const char *name;
+ int len;
+
+ len = qstr->len;
+ name = qstr->name;
+ if (ms) {
+ while (len && name[len-1] == '.')
+ len--;
+ }
+
+ qstr->hash = full_name_hash(name, len);
+
+ return 0;
+}
+
+/*
+ * Compute the hash for the isofs name corresponding to the dentry.
+ */
+static int
+isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms)
+{
+ const char *name;
+ int len;
+ char c;
+ unsigned long hash;
+
+ len = qstr->len;
+ name = qstr->name;
+ if (ms) {
+ while (len && name[len-1] == '.')
+ len--;
+ }
+
+ hash = init_name_hash();
+ while (len--) {
+ c = tolower(*name++);
+ hash = partial_name_hash(tolower(c), hash);
+ }
+ qstr->hash = end_name_hash(hash);
+
+ return 0;
+}
+
+/*
+ * Case insensitive compare of two isofs names.
+ */
+static int
+isofs_cmpi_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+{
+ int alen, blen;
+
+ /* A filename cannot end in '.' or we treat it like it has none */
+ alen = a->len;
+ blen = b->len;
+ if (ms) {
+ while (alen && a->name[alen-1] == '.')
+ alen--;
+ while (blen && b->name[blen-1] == '.')
+ blen--;
+ }
+ if (alen == blen) {
+ if (strnicmp(a->name, b->name, alen) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Case sensitive compare of two isofs names.
+ */
+static int
+isofs_cmp_common(struct dentry *dentry,struct qstr *a,struct qstr *b,int ms)
+{
+ int alen, blen;
+
+ /* A filename cannot end in '.' or we treat it like it has none */
+ alen = a->len;
+ blen = b->len;
+ if (ms) {
+ while (alen && a->name[alen-1] == '.')
+ alen--;
+ while (blen && b->name[blen-1] == '.')
+ blen--;
+ }
+ if (alen == blen) {
+ if (strncmp(a->name, b->name, alen) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static int
+isofs_hash(struct dentry *dentry, struct qstr *qstr)
+{
+ return isofs_hash_common(dentry, qstr, 0);
+}
+
+static int
+isofs_hashi(struct dentry *dentry, struct qstr *qstr)
+{
+ return isofs_hashi_common(dentry, qstr, 0);
+}
+
+static int
+isofs_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b)
+{
+ return isofs_cmp_common(dentry, a, b, 0);
+}
+
+static int
+isofs_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b)
+{
+ return isofs_cmpi_common(dentry, a, b, 0);
+}
+
+#ifdef CONFIG_JOLIET
+static int
+isofs_hash_ms(struct dentry *dentry, struct qstr *qstr)
+{
+ return isofs_hash_common(dentry, qstr, 1);
+}
+
+static int
+isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr)
+{
+ return isofs_hashi_common(dentry, qstr, 1);
+}
+
+static int
+isofs_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
+{
+ return isofs_cmp_common(dentry, a, b, 1);
+}
+
+static int
+isofs_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b)
+{
+ return isofs_cmpi_common(dentry, a, b, 1);
+}
+#endif
+
static int parse_options(char *options, struct iso9660_options * popt)
{
char *this_char,*value;
@@ -95,7 +297,7 @@
popt->joliet = 'y';
popt->cruft = 'n';
popt->unhide = 'n';
- popt->check = 's'; /* default: strict */
+ popt->check = 'u'; /* unset */
popt->blocksize = 1024;
popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could
be shared with DOS machines so
@@ -274,6 +476,7 @@
unsigned int vol_desc_start;
struct inode * inode;
struct iso9660_options opt;
+ int table;

MOD_INC_USE_COUNT;
/* lock before any blocking operations */
@@ -374,7 +577,7 @@
} else if (sec->escape[2] == 0x45) {
joliet_level = 3;
}
- printk("ISO 9660 Extensions: Microsoft Joliet Level %d\n",
+ printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n",
joliet_level);
}
goto root_found;
@@ -532,7 +735,6 @@
s->s_op = &isofs_sops;
s->u.isofs_sb.s_mapping = opt.map;
s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 2 : 0);
- s->u.isofs_sb.s_name_check = opt.check;
s->u.isofs_sb.s_cruft = opt.cruft;
s->u.isofs_sb.s_unhide = opt.unhide;
s->u.isofs_sb.s_uid = opt.uid;
@@ -555,7 +757,10 @@
* CD with Unicode names. Until someone sees such a beast, it
* will not be supported.
*/
- if (joliet_level && opt.rock == 'y' && s->u.isofs_sb.s_rock != 1) {
+ if (opt.rock == 'y' && s->u.isofs_sb.s_rock == 1) {
+ joliet_level = 0;
+ }
+ if (joliet_level) {
iput(inode);
pri = (struct iso_primary_descriptor *) sec;
rootp = (struct iso_directory_record *)
@@ -566,11 +771,22 @@
<< s -> u.isofs_sb.s_log_zone_size);
inode = iget(s, s->u.isofs_sb.s_firstdatazone);
s->u.isofs_sb.s_rock = 0;
+ opt.rock = 'n';
+ }
+
+ if (opt.check == 'u') {
+ /* Only Joliet is case insensitive by default */
+ if (joliet_level) opt.check = 'r';
+ else opt.check = 's';
}

s->s_root = d_alloc_root(inode, NULL);
if (!(s->s_root))
goto out_no_root;
+ table = 0;
+ if (joliet_level) table += 2;
+ if (opt.check == 'r') table++;
+ s->s_root->d_op = &isofs_dentry_ops[table];

if(!check_disk_change(dev)) {
brelse(bh);
@@ -694,34 +910,36 @@
size = inode->u.isofs_i.i_section_size;
nextino = inode->u.isofs_i.i_next_section_ino;
#ifdef DEBUG
- printk("first inode: inode=%lu nextino=%lu firstext=%u size=%lu\n",
+ printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n",
inode->i_ino, nextino, firstext, size);
#endif
i = 0;
- while(b_off >= offset + size) {
- offset += size;
-
- if(nextino == 0) return 0;
- ino = iget(inode->i_sb, nextino);
- if(!ino) return 0;
- firstext = ino->u.isofs_i.i_first_extent;
- size = ino->u.isofs_i.i_section_size;
+ if (nextino) {
+ while(b_off >= offset + size) {
+ offset += size;
+
+ if(nextino == 0) return 0;
+ ino = iget(inode->i_sb, nextino);
+ if(!ino) return 0;
+ firstext = ino->u.isofs_i.i_first_extent;
+ size = ino->u.isofs_i.i_section_size;
#ifdef DEBUG
- printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
- inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
+ printk("read inode: inode=%lu ino=%lu nextino=%lu firstext=%u size=%lu\n",
+ inode->i_ino, nextino, ino->u.isofs_i.i_next_section_ino, firstext, size);
#endif
- nextino = ino->u.isofs_i.i_next_section_ino;
- iput(ino);
+ nextino = ino->u.isofs_i.i_next_section_ino;
+ iput(ino);

- if(++i > 100) {
- printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
- inode->i_ino, block, firstext, (unsigned)size, nextino);
- return 0;
+ if(++i > 100) {
+ printk("isofs_bmap: More than 100 file sections ?!?, aborting...\n");
+ printk("isofs_bmap: ino=%lu block=%d firstext=%u size=%u nextino=%lu\n",
+ inode->i_ino, block, firstext, (unsigned)size, nextino);
+ return 0;
+ }
}
}
#ifdef DEBUG
- printk("isofs_bmap: mapped inode:block %lu:%d to block %lu\n",
+ printk("isofs_bmap: mapped inode:block %x:%d to block %lu\n",
inode->i_ino, block, (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode));
#endif
return (b_off - offset + firstext) >> ISOFS_BUFFER_BITS(inode);
@@ -905,7 +1123,7 @@
#endif

#ifdef DEBUG
- printk("Get inode %d: %d %d: %d\n",inode->i_ino, block,
+ printk("Get inode %x: %d %d: %d\n",inode->i_ino, block,
((int)pnt) & 0x3ff, inode->i_size);
#endif

diff -ur linux-2.1.116-clean/fs/isofs/joliet.c linux/fs/isofs/joliet.c
--- linux-2.1.116-clean/fs/isofs/joliet.c Tue Jul 28 10:17:03 1998
+++ linux/fs/isofs/joliet.c Tue Aug 25 16:16:32 1998
@@ -79,8 +79,6 @@
unsigned char utf8;
struct nls_table *nls;
unsigned char len = 0;
- int i;
- char c;

utf8 = inode->i_sb->u.isofs_sb.s_utf8;
nls = inode->i_sb->u.isofs_sb.s_nls_iocharset;
@@ -96,14 +94,12 @@
len -= 2;
}

- if (inode->i_sb->u.isofs_sb.s_name_check == 'r') {
- for (i = 0; i < len; i++) {
- c = outname[i];
- /* lower case */
- if (c >= 'A' && c <= 'Z') c |= 0x20;
- if (c == ';') c = '.';
- outname[i] = c;
- }
+ /*
+ * Windows doesn't like periods at the end of a name,
+ * so neither do we
+ */
+ while (len >= 2 && (outname[len-1] == '.')) {
+ len--;
}

return len;
diff -ur linux-2.1.116-clean/fs/isofs/namei.c linux/fs/isofs/namei.c
--- linux-2.1.116-clean/fs/isofs/namei.c Tue Jul 28 10:17:03 1998
+++ linux/fs/isofs/namei.c Tue Aug 25 16:30:35 1998
@@ -22,33 +22,31 @@
* ok, we cannot use strncmp, as the name is not in our data space.
* Thus we'll have to use isofs_match. No big problem. Match also makes
* some sanity tests.
- *
- * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure.
*/
-static int isofs_match(int len,const char * name, const char * compare, int dlen)
+static int
+isofs_cmp(struct dentry * dentry, const char * compare, int dlen)
{
+ struct qstr qstr;
+
if (!compare)
- return 0;
+ return 1;

/* check special "." and ".." files */
if (dlen == 1) {
/* "." */
if (compare[0] == 0) {
- if (!len)
- return 1;
+ if (!dentry->d_name.len)
+ return 0;
compare = ".";
} else if (compare[0] == 1) {
compare = "..";
dlen = 2;
}
}
-#if 0
- if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen);
-#endif
-
- if (dlen != len)
- return 0;
- return !memcmp(name, compare, len);
+
+ qstr.name = compare;
+ qstr.len = dlen;
+ return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr);
}

/*
@@ -59,8 +57,8 @@
* itself (as an inode number). It does NOT read the inode of the
* entry - you'll have to do that yourself if you want to.
*/
-static struct buffer_head * isofs_find_entry(struct inode * dir,
- const char * name, int namelen, unsigned long * ino)
+static struct buffer_head *
+isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
@@ -195,7 +193,7 @@
}
/* This allows us to match with and without
* a trailing period. */
- if(dpnt[dlen-1] == '.' && namelen == dlen-1)
+ if(dpnt[dlen-1] == '.' && dentry->d_name.len == dlen-1)
dlen--;
}
/*
@@ -205,7 +203,7 @@
if( !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
|| dir->i_sb->u.isofs_sb.s_unhide == 'y' )
{
- match = isofs_match(namelen,name,dpnt,dlen);
+ match = (isofs_cmp(dentry,dpnt,dlen) == 0);
}
if (match) {
if(inode_number == -1) {
@@ -231,11 +229,10 @@
{
unsigned long ino;
struct buffer_head * bh;
- char *lcname;
struct inode *inode;

#ifdef DEBUG
- printk("lookup: %x %d\n",dir->i_ino, dentry->d_name.len);
+ printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
#endif
if (!dir)
return -ENOENT;
@@ -243,23 +240,9 @@
if (!S_ISDIR(dir->i_mode))
return -ENOENT;

- /* If mounted with check=relaxed (and most likely norock),
- * then first convert this name to lower case.
- */
- if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
- (lcname = kmalloc(dentry->d_name.len, GFP_KERNEL)) != NULL) {
- int i;
- char c;
-
- for (i=0; i<dentry->d_name.len; i++) {
- c = dentry->d_name.name[i];
- if (c >= 'A' && c <= 'Z') c |= 0x20;
- lcname[i] = c;
- }
- bh = isofs_find_entry(dir, lcname, dentry->d_name.len, &ino);
- kfree(lcname);
- } else
- bh = isofs_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &ino);
+ dentry->d_op = dir->i_sb->s_root->d_op;
+
+ bh = isofs_find_entry(dir, dentry, &ino);

inode = NULL;
if (bh) {
--- linux-2.1.116-clean/include/linux/iso_fs_sb.h Tue Jul 28 10:16:24 1998
+++ linux/include/linux/iso_fs_sb.h Tue Aug 25 19:25:03 1998
@@ -16,7 +16,6 @@
unsigned char s_rock;
unsigned char s_joliet_level;
unsigned char s_utf8;
- unsigned char s_name_check; /* r = relaxed, s = strict */
unsigned char s_cruft; /* Broken disks with high
byte of length containing
junk */
--- linux-2.1.116-clean/CREDITS Wed Aug 19 02:42:57 1998
+++ linux/CREDITS Tue Aug 25 20:09:55 1998
@@ -287,8 +287,8 @@
E: chaffee@cs.berkeley.edu
W: http://bmrc.berkeley.edu/people/chaffee/
D: vfat, fat32, joliet, native language support
-S: 3674 Oakwood Terrace #201
-S: Fremont, California 94536
+S: 3700 Warwick Road
+S: Fremont, California 94555
S: USA

N: Chih-Jen Chang
@@ -706,8 +706,8 @@
E: rth@cygnus.com
E: richard@gnu.org
D: Alpha/ELF, gcc, binutils, and glibc
-S: 50 E. Middlefield #10
-S: Mountain View, California 94043-3822
+S: 5450 Mayme #25
+S: San Jose, California 95129
S: USA

N: Sebastian Hetze

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html