patch-2.1.32 linux/fs/isofs/inode.c

Next file: linux/fs/isofs/rock.c
Previous file: linux/fs/isofs/dir.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.31/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
@@ -86,7 +86,10 @@
 	popt->check = 's';		/* default: strict */
 	popt->conversion = 'b';		/* default: no conversion */
 	popt->blocksize = 1024;
-	popt->mode = S_IRUGO;
+	popt->mode = S_IRUGO | S_IXUGO; /* r-x for all.  The disc could
+					   be shared with DOS machines so
+					   virtually anything could be
+					   a valid executable. */
 	popt->gid = 0;
 	popt->uid = 0;
 	if (!options) return 1;
@@ -227,23 +230,22 @@
 struct super_block *isofs_read_super(struct super_block *s,void *data,
 				     int silent)
 {
-	struct buffer_head *bh=NULL;
-	int iso_blknum;
-	unsigned int blocksize_bits;
-	int high_sierra;
-	kdev_t dev = s->s_dev;
-	unsigned int vol_desc_start;
-	int orig_zonesize;
-
-	struct iso_volume_descriptor *vdp;
-	struct hs_volume_descriptor *hdp;
-
-	struct iso_primary_descriptor *pri = NULL;
-	struct hs_primary_descriptor *h_pri = NULL;
+	struct buffer_head	      * bh = NULL;
+	unsigned int			blocksize;
+	unsigned int			blocksize_bits;
+	kdev_t				dev = s->s_dev;
+	struct hs_volume_descriptor   * hdp;
+	struct hs_primary_descriptor  * h_pri = NULL;
+	int				high_sierra;
+	int				iso_blknum;
+	struct iso9660_options		opt;
+	int				orig_zonesize;
+	struct iso_primary_descriptor * pri = NULL;
+	struct iso_directory_record   * rootp;
+	struct iso_volume_descriptor  * vdp;
+	unsigned int			vol_desc_start;
 
-	struct iso_directory_record *rootp;
 
-	struct iso9660_options opt;
 
 	MOD_INC_USE_COUNT;
 
@@ -265,6 +267,23 @@
 	printk("uid = %d\n", opt.uid);
 #endif
 
+ 	/*
+ 	 * First of all, get the hardware blocksize for this device.
+ 	 * If we don't know what it is, or the hardware blocksize is
+ 	 * larger than the blocksize the user specified, then use
+ 	 * that value.
+ 	 */
+ 	blocksize = get_hardblocksize(dev);
+ 	if(    (blocksize != 0)
+ 	    && (blocksize > opt.blocksize) )
+ 	  {
+ 	    /*
+ 	     * Force the blocksize we are going to use to be the
+ 	     * hardware blocksize.
+ 	     */
+ 	    opt.blocksize = blocksize;
+ 	  }
+ 
 	blocksize_bits = 0;
 	{
 	  int i = opt.blocksize;
@@ -273,6 +292,7 @@
 	    i >>=1;
 	  }
 	}
+
 	set_blocksize(dev, opt.blocksize);
 
 	lock_super(s);
@@ -362,6 +382,24 @@
 	/* RDE: convert log zone size to bit shift */
 
 	orig_zonesize = s -> u.isofs_sb.s_log_zone_size;
+
+	/*
+	 * If the zone size is smaller than the hardware sector size,
+	 * this is a fatal error.  This would occur if the
+	 * disc drive had sectors that were 2048 bytes, but the filesystem
+	 * had blocks that were 512 bytes (which should only very rarely
+	 * happen.
+	 */
+	if(    (blocksize != 0)
+	    && (orig_zonesize < blocksize) )
+	  {
+	      printk("Logical zone size(%ld) < hardware blocksize(%ld)\n", 
+		     orig_zonesize, blocksize);
+	      goto out;
+
+	  }
+
+
 	switch (s -> u.isofs_sb.s_log_zone_size)
 	  { case  512: s -> u.isofs_sb.s_log_zone_size =  9; break;
 	    case 1024: s -> u.isofs_sb.s_log_zone_size = 10; break;
@@ -403,8 +441,20 @@
 	 * Force the blocksize to 512 for 512 byte sectors.  The file
 	 * read primitives really get it wrong in a bad way if we don't
 	 * do this.
+	 *
+	 * Note - we should never be setting the blocksize to something
+	 * less than the hardware sector size for the device.  If we
+	 * do, we would end up having to read larger buffers and split
+	 * out portions to satisfy requests.
+	 *
+	 * Note2- the idea here is that we want to deal with the optimal
+	 * zonesize in the filesystem.  If we have it set to something less,
+	 * then we have horrible problems with trying to piece together
+	 * bits of adjacent blocks in order to properly read directory
+	 * entries.  By forcing the blocksize in this way, we ensure
+	 * that we will never be required to do this.
 	 */
-	if( orig_zonesize < opt.blocksize )
+	if( orig_zonesize != opt.blocksize )
 	  {
 	    opt.blocksize = orig_zonesize;
 	    blocksize_bits = 0;
@@ -482,6 +532,34 @@
 		printk("_isofs_bmap: block<0");
 		return 0;
 	}
+
+	/*
+	 * If we are beyond the end of this file, don't give out any
+	 * blocks.
+	 */
+	if( (block << ISOFS_BUFFER_BITS(inode)) >= inode->i_size )
+	  {
+	    off_t	max_legal_read_offset;
+
+	    /*
+	     * If we are *way* beyond the end of the file, print a message.
+	     * Access beyond the end of the file up to the next page boundary
+	     * is normal, however because of the way the page cache works.
+	     * In this case, we just return 0 so that we can properly fill
+	     * the page with useless information without generating any
+	     * I/O errors.
+	     */
+	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1) 
+	      & ~(PAGE_SIZE - 1);
+	    if( (block << ISOFS_BUFFER_BITS(inode)) >= max_legal_read_offset )
+	      {
+
+		printk("_isofs_bmap: block>= EOF(%d, %d)", block, 
+		       inode->i_size);
+	      }
+	    return 0;
+	  }
+
 	return (inode->u.isofs_i.i_first_extent >> ISOFS_BUFFER_BITS(inode)) + block;
 }
 
@@ -502,7 +580,6 @@
 	struct buffer_head * bh;
 	struct iso_directory_record * raw_inode;
 	unsigned char *pnt = NULL;
-	void *cpnt = NULL;
 	int high_sierra;
 	int block;
 	int volume_seq_no ;
@@ -519,30 +596,6 @@
 	raw_inode = ((struct iso_directory_record *) pnt);
 	high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
 
-	if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
-	        int frag1, offset;
-
-		offset = (inode->i_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);
-			goto fail;
-		}
-		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");
-			goto fail;
-		}
-		offset += *pnt - bufsize;
-		memcpy((char *)cpnt+frag1, bh->b_data, offset);
-		pnt = ((unsigned char *) cpnt);
-		raw_inode = ((struct iso_directory_record *) pnt);
-	}
-
 	if (raw_inode->flags[-high_sierra] & 2) {
 		inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR;
 		inode->i_nlink = 1; /* Set to 1.  We know there are 2, but
@@ -682,10 +735,6 @@
 	  else if (S_ISFIFO(inode->i_mode))
 	    init_fifo(inode);
 	}
-	if (cpnt) {
-		kfree (cpnt);
-		cpnt = NULL;
-	}
 	return;
       fail:
 	/* With a data error we return this information */
@@ -725,8 +774,6 @@
 	unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
 	unsigned int block,offset;
 	int parent_dir, inode_number;
-	int old_offset;
-	void * cpnt = NULL;
 	int result;
 	int directory_size;
 	struct buffer_head * bh;
@@ -786,7 +833,7 @@
 		   CDROM sector.  If we are at the end of the directory, we
 		   kick out of the while loop. */
 
-		if (*((unsigned char *) de) == 0)
+ 		if ((*((unsigned char *) de) == 0) || (offset == bufsize) )
 		{
 			brelse(bh);
 			offset = 0;
@@ -813,31 +860,12 @@
 		   bh block.  If not, we malloc a buffer, and put the two
 		   halves together, so that we can cleanly read the block.  */
 
-		old_offset = offset;
 		offset += *((unsigned char *) de);
 
-		if (offset >= bufsize)
+		if (offset > bufsize)
 		{
- 		        unsigned int frag1;
- 			frag1 = bufsize - old_offset;
- 			cpnt = kmalloc(*((unsigned char *) de),GFP_KERNEL);
-			if (!cpnt) return -1;
- 			memcpy(cpnt, bh->b_data + old_offset, frag1);
- 			de = (struct iso_directory_record *) ((char *)cpnt);
-			brelse(bh);
-			offset -= bufsize;
- 			directory_size -= bufsize;
-			if(directory_size < 0)
-			{
-				printk("Directory size < 0\n");
-				return -1;
-			}
-			block++;
-			if(!(bh = bread(parent->i_dev,block,bufsize))) {
- 			        kfree(cpnt);
-				return -1;
-			}
- 			memcpy((char *)cpnt+frag1, bh->b_data, offset);
+ 			printk("Directory overrun\n");
+ 			goto out;
 		}
 
 		if (find_rock_ridge_relocation(de, parent) == extent){
@@ -845,20 +873,12 @@
 			goto out;
 		}
 
-		if (cpnt) {
-			kfree(cpnt);
-			cpnt = NULL;
-		}
 	}
 
 	/* We go here for any condition we cannot handle.
 	   We also drop through to here at the end of the directory. */
 
  out:
-	if (cpnt) {
-	        kfree(cpnt);
-		cpnt = NULL;
-	}
 	brelse(bh);
 #ifdef DEBUG
 	printk("Resultant Inode %d\n",result);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov