From 230e5ab6a084ed50470f101934782dbf54b0d06b Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sat, 6 Dec 1997 23:51:34 +0000 Subject: Merge with Linux 2.1.67. --- fs/isofs/inode.c | 199 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 156 insertions(+), 43 deletions(-) (limited to 'fs/isofs/inode.c') diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index a925159bf..b77e9facd 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,12 @@ static int check_bread = 0; void isofs_put_super(struct super_block *sb) { +#ifdef CONFIG_JOLIET + if (sb->u.isofs_sb.s_nls_iocharset) { + unload_nls(sb->u.isofs_sb.s_nls_iocharset); + sb->u.isofs_sb.s_nls_iocharset = NULL; + } +#endif lock_super(sb); #ifdef LEAK_CHECK @@ -67,6 +74,7 @@ static struct super_operations isofs_sops = { struct iso9660_options{ char map; char rock; + char joliet; char cruft; char unhide; unsigned char check; @@ -75,6 +83,8 @@ struct iso9660_options{ mode_t mode; gid_t gid; uid_t uid; + char *iocharset; + unsigned char utf8; }; static int parse_options(char *options, struct iso9660_options * popt) @@ -83,6 +93,7 @@ static int parse_options(char *options, struct iso9660_options * popt) popt->map = 'n'; popt->rock = 'y'; + popt->joliet = 'y'; popt->cruft = 'n'; popt->unhide = 'n'; popt->check = 's'; /* default: strict */ @@ -94,12 +105,18 @@ static int parse_options(char *options, struct iso9660_options * popt) a valid executable. */ popt->gid = 0; popt->uid = 0; + popt->iocharset = NULL; + popt->utf8 = 0; if (!options) return 1; for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { if (strncmp(this_char,"norock",6) == 0) { popt->rock = 'n'; continue; } + if (strncmp(this_char,"nojoliet",8) == 0) { + popt->joliet = 'n'; + continue; + } if (strncmp(this_char,"unhide",6) == 0) { popt->unhide = 'y'; continue; @@ -108,8 +125,31 @@ static int parse_options(char *options, struct iso9660_options * popt) popt->cruft = 'y'; continue; } + if (strncmp(this_char,"utf8",4) == 0) { + popt->utf8 = 1; + continue; + } if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; + +#ifdef CONFIG_JOLIET + if (!strcmp(this_char,"iocharset")) { + char *p; + int len; + + p = value; + while (*value && *value != ',') value++; + len = value - p; + if (len) { + popt->iocharset = kmalloc(len+1, GFP_KERNEL); + memcpy(popt->iocharset, p, len); + popt->iocharset[len] = 0; + } else { + popt->iocharset = NULL; + return 0; + } + } else +#endif if (!strcmp(this_char,"map") && value) { if (value[0] && !value[1] && strchr("on",*value)) popt->map = *value; @@ -234,10 +274,12 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, struct hs_primary_descriptor * h_pri = NULL; int high_sierra; int iso_blknum; + int joliet_level = 0; struct iso9660_options opt; int orig_zonesize; struct iso_primary_descriptor * pri = NULL; struct iso_directory_record * rootp; + struct iso_supplementary_descriptor *sec = NULL; struct iso_volume_descriptor * vdp; unsigned int vol_desc_start; @@ -254,6 +296,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, #if 0 printk("map = %c\n", opt.map); printk("rock = %c\n", opt.rock); + printk("joliet = %c\n", opt.joliet); printk("check = %c\n", opt.check); printk("cruft = %c\n", opt.cruft); printk("unhide = %c\n", opt.unhide); @@ -297,57 +340,93 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, vol_desc_start = isofs_get_last_session(dev); - for (iso_blknum = vol_desc_start+16; - iso_blknum < vol_desc_start+100; iso_blknum++) { - int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); - - if (!(bh = bread(dev,b,opt.blocksize))) { - s->s_dev = 0; - printk("isofs_read_super: bread failed, dev " - "%s iso_blknum %d block %d\n", - kdevname(dev), iso_blknum, b); - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; - } - - vdp = (struct iso_volume_descriptor *)bh->b_data; - hdp = (struct hs_volume_descriptor *)bh->b_data; + for (iso_blknum = vol_desc_start+16; + iso_blknum < vol_desc_start+100; iso_blknum++) + { + int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits); + if (!(bh = bread(dev,b,opt.blocksize))) { + s->s_dev = 0; + printk("isofs_read_super: bread failed, dev " + "%s iso_blknum %d block %d\n", + kdevname(dev), iso_blknum, b); + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; + } - if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { - if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) - goto out; - if (isonum_711 (hdp->type) == ISO_VD_END) - goto out; + vdp = (struct iso_volume_descriptor *)bh->b_data; + hdp = (struct hs_volume_descriptor *)bh->b_data; + + if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { + if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) + goto out; + if (isonum_711 (hdp->type) == ISO_VD_END) + goto out; + + s->u.isofs_sb.s_high_sierra = 1; + high_sierra = 1; + opt.rock = 'n'; + h_pri = (struct hs_primary_descriptor *)vdp; + break; + } - s->u.isofs_sb.s_high_sierra = 1; - high_sierra = 1; - opt.rock = 'n'; - h_pri = (struct hs_primary_descriptor *)vdp; + if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { + if (isonum_711 (vdp->type) == ISO_VD_END) + break; + if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) { + if (pri == NULL) { + pri = (struct iso_primary_descriptor *)vdp; + } +#ifdef CONFIG_JOLIET + } else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) { + sec = (struct iso_supplementary_descriptor *)vdp; + if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { + if (opt.joliet == 'y') { + opt.rock = 'n'; + if (sec->escape[2] == 0x40) { + joliet_level = 1; + } else if (sec->escape[2] == 0x43) { + joliet_level = 2; + } else if (sec->escape[2] == 0x45) { + joliet_level = 3; + } + printk("ISO9660 Extensions: Microsoft Joliet Level %d\n", + joliet_level); + } break; + } else { + /* Unknown supplementary volume descriptor */ + sec = NULL; + } +#endif } + /* Just skip any volume descriptors we don't recognize */ + } - if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { - if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) - goto out; - if (isonum_711 (vdp->type) == ISO_VD_END) - goto out; + brelse(bh); + } + if ((pri == NULL) && (sec == NULL) && (h_pri == NULL)) { + if (!silent) + printk("Unable to identify CD-ROM format.\n"); + s->s_dev = 0; + unlock_super(s); + MOD_DEC_USE_COUNT; + return NULL; + } - pri = (struct iso_primary_descriptor *)vdp; - break; - } + s->u.isofs_sb.s_joliet_level = joliet_level; - brelse(bh); - } - if(iso_blknum == vol_desc_start + 100) { - if (!silent) - printk("Unable to identify CD-ROM format.\n"); - s->s_dev = 0; - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; +#ifdef CONFIG_JOLIET + if (joliet_level) { + /* Note: In theory, it is possible to have Rock Ridge + * extensions mixed with Joliet. All character strings + * would just be saved as Unicode. Until someone sees such + * a disc, do not allow the two to be mixed + */ + pri = (struct iso_primary_descriptor *) sec; } +#endif if(high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; @@ -465,6 +544,28 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize); } +#ifdef CONFIG_JOLIET + s->u.isofs_sb.s_nls_iocharset = NULL; + if (joliet_level == 0) { + if (opt.iocharset) { + kfree(opt.iocharset); + opt.iocharset = NULL; + } + } else if (opt.utf8 == 0) { + char * p; + p = opt.iocharset ? opt.iocharset : "iso8859-1"; + s->u.isofs_sb.s_nls_iocharset = load_nls(p); + if (! s->u.isofs_sb.s_nls_iocharset) { + /* Fail only if explicit charset specified */ + if (opt.iocharset) { + kfree(opt.iocharset); + goto out; + } else { + s->u.isofs_sb.s_nls_iocharset = load_nls_default(); + } + } + } +#endif s->s_dev = dev; s->s_op = &isofs_sops; s->u.isofs_sb.s_mapping = opt.map; @@ -475,6 +576,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, s->u.isofs_sb.s_unhide = opt.unhide; s->u.isofs_sb.s_uid = opt.uid; s->u.isofs_sb.s_gid = opt.gid; + s->u.isofs_sb.s_utf8 = opt.utf8; /* * It would be incredibly stupid to allow people to mark every file on the disk * as suid, so we merely allow them to set the default permissions. @@ -490,13 +592,24 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, if (!(s->s_root)) { s->s_dev = 0; printk("get root inode failed\n"); +#ifdef CONFIG_JOLIET + if (s->u.isofs_sb.s_nls_iocharset) + unload_nls(s->u.isofs_sb.s_nls_iocharset); + if (opt.iocharset) kfree(opt.iocharset); +#endif MOD_DEC_USE_COUNT; return NULL; } if(!check_disk_change(s->s_dev)) { - return s; + return s; } +#ifdef CONFIG_JOLIET + if (s->u.isofs_sb.s_nls_iocharset) + unload_nls(s->u.isofs_sb.s_nls_iocharset); +#endif + if (opt.iocharset) kfree(opt.iocharset); + out: /* Kick out for various error conditions */ brelse(bh); s->s_dev = 0; -- cgit v1.2.3