patch-2.0.34 linux/fs/isofs/inode.c
Next file: linux/fs/isofs/joliet.c
Previous file: linux/fs/isofs/dir.c
Back to the patch index
Back to the overall index
- Lines: 549
- Date:
Wed Jun 3 15:17:49 1998
- Orig file:
v2.0.33/linux/fs/isofs/inode.c
- Orig date:
Fri Aug 15 11:11:45 1997
diff -u --recursive --new-file v2.0.33/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
@@ -21,6 +21,7 @@
#include <linux/malloc.h>
#include <linux/errno.h>
#include <linux/cdrom.h>
+#include <linux/nls.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -38,6 +39,10 @@
void isofs_put_super(struct super_block *sb)
{
+ 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;
+ }
lock_super(sb);
#ifdef LEAK_CHECK
@@ -64,6 +69,7 @@
struct iso9660_options{
char map;
char rock;
+ char joliet;
char cruft;
char unhide;
unsigned char check;
@@ -72,14 +78,18 @@
mode_t mode;
gid_t gid;
uid_t uid;
+ char *iocharset;
+ unsigned char utf8;
};
static int parse_options(char *options, struct iso9660_options * popt)
{
- char *this_char,*value;
+ char *this_char,*value,*p;
+ int len;
popt->map = 'n';
popt->rock = 'y';
+ popt->joliet = 'y';
popt->cruft = 'n';
popt->unhide = 'n';
popt->check = 's'; /* default: strict */
@@ -88,12 +98,18 @@
popt->mode = S_IRUGO;
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;
@@ -102,9 +118,27 @@
popt->cruft = 'y';
continue;
}
+ if (strncmp(this_char,"utf8",4) == 0) {
+ popt->utf8 = 1;
+ continue;
+ }
if ((value = strchr(this_char,'=')) != NULL)
*value++ = 0;
- if (!strcmp(this_char,"map") && value) {
+
+ if (!strcmp(this_char,"iocharset")) {
+ 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 if (!strcmp(this_char,"map") && value) {
if (value[0] && !value[1] && strchr("on",*value))
popt->map = *value;
else if (!strcmp(value,"off")) popt->map = 'o';
@@ -227,11 +261,14 @@
kdev_t dev = s->s_dev;
unsigned int vol_desc_start;
int orig_zonesize;
+ char *p;
+ int joliet_level = 0;
struct iso_volume_descriptor *vdp;
struct hs_volume_descriptor *hdp;
struct iso_primary_descriptor *pri = NULL;
+ struct iso_supplementary_descriptor *sec = NULL;
struct hs_primary_descriptor *h_pri = NULL;
struct iso_directory_record *rootp;
@@ -249,6 +286,7 @@
#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);
@@ -275,57 +313,84 @@
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;
- }
+ iso_blknum < vol_desc_start+100; iso_blknum++)
+ {
+ int b = iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits);
- vdp = (struct iso_volume_descriptor *)bh->b_data;
- hdp = (struct hs_volume_descriptor *)bh->b_data;
+ 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;
+
+ 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;
- 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;
+ s->u.isofs_sb.s_high_sierra = 1;
+ high_sierra = 1;
+ opt.rock = 'n';
+ h_pri = (struct hs_primary_descriptor *)vdp;
+ break;
+ }
+
+ 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;
+ }
+ } 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') {
+ 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;
+ }
}
-
- 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;
-
- pri = (struct iso_primary_descriptor *)vdp;
- break;
- }
+ /* Just skip any volume descriptors we don't recognize */
+ }
- 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;
+ 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;
+ }
+ s->u.isofs_sb.s_joliet_level = joliet_level;
+ if (joliet_level && opt.rock == 'n') {
+ /* This is the case of Joliet with the norock mount flag.
+ * A disc with both Joliet and Rock Ridge is handled later
+ */
+ pri = (struct iso_primary_descriptor *) sec;
+ }
+
if(high_sierra){
rootp = (struct iso_directory_record *) h_pri->root_directory_record;
#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS
@@ -365,11 +430,6 @@
goto out;
}
- /* RDE: data zone now byte offset! */
-
- s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
- isonum_711 (rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
s->s_magic = ISOFS_SUPER_MAGIC;
/* The CDROM is read-only, has no nodes (devices) on it, and since
@@ -381,13 +441,17 @@
brelse(bh);
+ /* RDE: data zone now byte offset! */
+
+ s->u.isofs_sb.s_firstdatazone = ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n",
s->u.isofs_sb.s_max_size,
1UL << s->u.isofs_sb.s_log_zone_size);
- printk(KERN_DEBUG "First datazone:%ld Root inode number %d\n",
+ printk(KERN_DEBUG "First datazone:%ld Root inode number %ld\n",
s->u.isofs_sb.s_firstdatazone >> s -> u.isofs_sb.s_log_zone_size,
- (isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ s->u.isofs_sb.s_firstdatazone);
if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n");
unlock_super(s);
/* set up enough so that it can read an inode */
@@ -412,16 +476,36 @@
printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize);
}
+ 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) {
+ 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();
+ }
+ }
+ }
s->s_dev = dev;
s->s_op = &isofs_sops;
s->u.isofs_sb.s_mapping = opt.map;
- s->u.isofs_sb.s_rock = (opt.rock == 'y' ? 1 : 0);
+ 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_conversion = opt.conversion;
s->u.isofs_sb.s_cruft = opt.cruft;
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.
@@ -429,21 +513,47 @@
s->u.isofs_sb.s_mode = opt.mode & 0777;
s->s_blocksize = opt.blocksize;
s->s_blocksize_bits = blocksize_bits;
- s->s_mounted = iget(s, (isonum_733(rootp->extent) +
- isonum_711(rootp->ext_attr_length))
- << s -> u.isofs_sb.s_log_zone_size);
+ s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
+
+ /*
+ * If this disk has both Rock Ridge and Joliet on it, then we
+ * want to use Rock Ridge by default. This can be overridden
+ * by using the norock mount option. There is still one other
+ * possibility that is not taken into account: a Rock Ridge
+ * 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) {
+ iput(s->s_mounted);
+ pri = (struct iso_primary_descriptor *) sec;
+ rootp = (struct iso_directory_record *)
+ pri->root_directory_record;
+ s->u.isofs_sb.s_firstdatazone =
+ ((isonum_733 (rootp->extent) +
+ isonum_711 (rootp->ext_attr_length))
+ << s -> u.isofs_sb.s_log_zone_size);
+ s->s_mounted = iget(s, s->u.isofs_sb.s_firstdatazone);
+ s->u.isofs_sb.s_rock = 0;
+ }
unlock_super(s);
if (!(s->s_mounted)) {
s->s_dev = 0;
printk("get root inode failed\n");
+ if (s->u.isofs_sb.s_nls_iocharset)
+ unload_nls(s->u.isofs_sb.s_nls_iocharset);
+ if (opt.iocharset) kfree(opt.iocharset);
MOD_DEC_USE_COUNT;
return NULL;
}
if(!check_disk_change(s->s_dev)) {
- return s;
+ return s;
}
+ if (s->u.isofs_sb.s_nls_iocharset)
+ unload_nls(s->u.isofs_sb.s_nls_iocharset);
+ if (opt.iocharset) kfree(opt.iocharset);
+
out: /* Kick out for various error conditions */
brelse(bh);
s->s_dev = 0;
@@ -470,17 +580,24 @@
int isofs_bmap(struct inode * inode,int block)
{
+ off_t b_off, offset, size;
+ struct inode *ino;
+ unsigned int firstext;
+ unsigned long nextino;
+ int i;
if (block<0) {
printk("_isofs_bmap: block<0");
return 0;
}
+ b_off = block << ISOFS_BUFFER_BITS(inode);
+
/*
* If we are beyond the end of this file, don't give out any
* blocks.
*/
- if( (block << ISOFS_BUFFER_BITS(inode)) > inode->i_size )
+ if( b_off > inode->i_size )
{
off_t max_legal_read_offset;
@@ -494,7 +611,7 @@
*/
max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
& ~(PAGE_SIZE - 1);
- if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset )
+ if( b_off >= max_legal_read_offset )
{
printk("_isofs_bmap: block>= EOF(%d, %ld)", block,
@@ -503,7 +620,44 @@
return 0;
}
- return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block;
+ offset = 0;
+ firstext = inode->u.isofs_i.i_first_extent;
+ 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",
+ inode->i_ino, nextino, firstext, size);
+#endif
+ i = 0;
+ 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);
+#endif
+ 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;
+ }
+ }
+ }
+#ifdef DEBUG
+ printk("isofs_bmap: mapped inode:block %lu:%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);
}
@@ -517,6 +671,82 @@
}
}
+static int isofs_read_level3_size(struct inode * inode)
+{
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
+ struct buffer_head * bh = NULL;
+ struct iso_directory_record * raw_inode = NULL; /* quiet gcc */
+ unsigned char *pnt = NULL;
+ void *cpnt = NULL;
+ int block = 0; /* Quiet GCC */
+ unsigned long ino;
+ int i;
+
+ inode->i_size = 0;
+ inode->u.isofs_i.i_next_section_ino = 0;
+ ino = inode->i_ino;
+ i = 0;
+ do {
+ if(i > 100) {
+ printk("isofs_read_level3_size: More than 100 file sections ?!?, aborting...\n"
+ "isofs_read_level3_size: inode=%lu ino=%lu\n", inode->i_ino, ino);
+ return 0;
+ }
+
+ if(bh == NULL || block != ino >> ISOFS_BUFFER_BITS(inode)) {
+ if(bh) brelse(bh);
+ block = ino >> ISOFS_BUFFER_BITS(inode);
+ if (!(bh=bread(inode->i_dev,block, bufsize))) {
+ printk("unable to read i-node block");
+ return 1;
+ }
+ }
+ pnt = ((unsigned char *) bh->b_data
+ + (ino & (bufsize - 1)));
+
+ if ((ino & (bufsize - 1)) + *pnt > bufsize){
+ int frag1, offset;
+
+ offset = (ino & (bufsize - 1));
+ frag1 = bufsize - offset;
+ cpnt = kmalloc(*pnt,GFP_KERNEL);
+ if (cpnt == NULL) {
+ printk(KERN_INFO "NoMem ISO inode %lu\n",inode->i_ino);
+ brelse(bh);
+ return 1;
+ }
+ memcpy(cpnt, bh->b_data + offset, frag1);
+ brelse(bh);
+ if (!(bh = bread(inode->i_dev,++block, bufsize))) {
+ kfree(cpnt);
+ printk("unable to read i-node block");
+ return 1;
+ }
+ offset += *pnt - bufsize;
+ memcpy((char *)cpnt+frag1, bh->b_data, offset);
+ pnt = ((unsigned char *) cpnt);
+ }
+
+ if(*pnt == 0) {
+ ino = (ino & ~(ISOFS_BLOCK_SIZE - 1)) + ISOFS_BLOCK_SIZE;
+ continue;
+ }
+ raw_inode = ((struct iso_directory_record *) pnt);
+
+ inode->i_size += isonum_733 (raw_inode->size);
+ if(i == 1) inode->u.isofs_i.i_next_section_ino = ino;
+
+ ino += *pnt;
+ if (cpnt) {
+ kfree (cpnt);
+ cpnt = NULL;
+ }
+ i++;
+ } while(raw_inode->flags[-inode->i_sb->u.isofs_sb.s_high_sierra] & 0x80);
+ brelse(bh);
+ return 0;
+}
+
void isofs_read_inode(struct inode * inode)
{
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
@@ -584,7 +814,13 @@
}
inode->i_uid = inode->i_sb->u.isofs_sb.s_uid;
inode->i_gid = inode->i_sb->u.isofs_sb.s_gid;
- inode->i_size = isonum_733 (raw_inode->size);
+
+ inode->u.isofs_i.i_section_size = isonum_733 (raw_inode->size);
+ if(raw_inode->flags[-high_sierra] & 0x80) {
+ if(isofs_read_level3_size(inode)) goto fail;
+ } else {
+ inode->i_size = isonum_733 (raw_inode->size);
+ }
/* There are defective discs out there - we do this to protect
ourselves. A cdrom will never contain more than 800Mb */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov