patch-2.4.10 linux/fs/sysv/super.c

Next file: linux/fs/sysv/symlink.c
Previous file: linux/fs/sysv/inode.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.9/linux/fs/sysv/super.c linux/fs/sysv/super.c
@@ -26,11 +26,16 @@
 #include <linux/sysv_fs.h>
 #include <linux/init.h>
 
-/* The following functions try to recognize specific filesystems.
+/*
+ * The following functions try to recognize specific filesystems.
+ *
  * We recognize:
  * - Xenix FS by its magic number.
  * - SystemV FS by its magic number.
  * - Coherent FS by its funny fname/fpack field.
+ * - SCO AFS by s_nfree == 0xffff
+ * - V7 FS has no distinguishing features.
+ *
  * We discriminate among SystemV4 and SystemV2 FS by the assumption that
  * the time stamp is not < 01-01-1980.
  */
@@ -197,7 +202,19 @@
 		sb->sv_bytesex = BYTESEX_BE;
 	else
 		return 0;
-	if (sbd->s_time < JAN_1_1980) {
+ 
+ 	if (fs16_to_cpu(sb, sbd->s_nfree) == 0xffff) {
+ 		sb->sv_type = FSTYPE_AFS;
+ 		if (!(sb->s_flags & MS_RDONLY)) {
+ 			printk("SysV FS: SCO EAFS on %s detected, " 
+ 				"forcing read-only mode.\n", 
+ 				bdevname(sb->s_dev));
+ 			sb->s_flags |= MS_RDONLY;
+ 		}
+ 		return sbd->s_type;
+ 	}
+ 
+	if (fs32_to_cpu(sb, sbd->s_time) < JAN_1_1980) {
 		/* this is likely to happen on SystemV2 FS */
 		if (sbd->s_type > 3 || sbd->s_type < 1)
 			return 0;
@@ -261,6 +278,7 @@
 	[FSTYPE_SYSV2]	"SystemV Release 2",
 	[FSTYPE_COH]	"Coherent",
 	[FSTYPE_V7]	"V7",
+	[FSTYPE_AFS]	"AFS",
 };
 
 static void (*flavour_setup[])(struct super_block *) = {
@@ -269,6 +287,7 @@
 	[FSTYPE_SYSV2]	detected_sysv2,
 	[FSTYPE_COH]	detected_coherent,
 	[FSTYPE_V7]	detected_v7,
+	[FSTYPE_AFS]	detected_sysv4,
 };
 
 static int complete_read_super(struct super_block *sb, int silent, int size)
@@ -294,7 +313,8 @@
 	sb->sv_toobig_block = 10 + bsize_4 * (1 + bsize_4 * (1 + bsize_4));
 	sb->sv_ind_per_block_bits = n_bits-2;
 
-	sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits;
+	sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone)
+		<< sb->sv_inodes_per_block_bits;
 
 	sb->s_blocksize = bsize;
 	sb->s_blocksize_bits = n_bits;
@@ -346,13 +366,10 @@
 	sb->sv_block_base = 0;
 
 	for (i = 0; i < sizeof(flavours)/sizeof(flavours[0]) && !size; i++) {
-		struct buffer_head *next_bh;
-		next_bh = bread(dev, flavours[i].block, BLOCK_SIZE);
-		if (!next_bh)
-			continue;
 		brelse(bh);
-		bh = next_bh;
-
+		bh = bread(dev, flavours[i].block, BLOCK_SIZE);
+		if (!bh)
+			continue;
 		size = flavours[i].test(sb, bh);
 	}
 
@@ -411,8 +428,10 @@
 static struct super_block *v7_read_super(struct super_block *sb,void *data,
 				  int silent)
 {
-	struct buffer_head *bh;
+	struct buffer_head *bh, *bh2 = NULL;
 	kdev_t dev = sb->s_dev;
+	struct v7_super_block *v7sb;
+	struct sysv_inode *v7i;
 
 	if (440 != sizeof (struct v7_super_block))
 		panic("V7 FS: bad super-block size");
@@ -422,23 +441,41 @@
 	sb->sv_type = FSTYPE_V7;
 	sb->sv_bytesex = BYTESEX_PDP;
 
-	set_blocksize(dev,512);
+	set_blocksize(dev, 512);
 
 	if ((bh = bread(dev, 1, 512)) == NULL) {
 		if (!silent)
-			printk("VFS: unable to read V7 FS superblock on device "
-			       "%s.\n", bdevname(dev));
+			printk("VFS: unable to read V7 FS superblock on "
+			       "device %s.\n", bdevname(dev));
 		goto failed;
 	}
 
+	/* plausibility check on superblock */
+	v7sb = (struct v7_super_block *) bh->b_data;
+	if (fs16_to_cpu(sb,v7sb->s_nfree) > V7_NICFREE ||
+	    fs16_to_cpu(sb,v7sb->s_ninode) > V7_NICINOD ||
+	    fs32_to_cpu(sb,v7sb->s_time) == 0)
+		goto failed;
+
+	/* plausibility check on root inode: it is a directory,
+	   with a nonzero size that is a multiple of 16 */
+	if ((bh2 = bread(dev, 2, 512)) == NULL)
+		goto failed;
+	v7i = (struct sysv_inode *)(bh2->b_data + 64);
+	if ((fs16_to_cpu(sb,v7i->i_mode) & ~0777) != S_IFDIR ||
+	    (fs32_to_cpu(sb,v7i->i_size) == 0) ||
+	    (fs32_to_cpu(sb,v7i->i_size) & 017) != 0)
+		goto failed;
+	brelse(bh2);
 
 	sb->sv_bh1 = bh;
 	sb->sv_bh2 = bh;
 	if (complete_read_super(sb, silent, 1))
 		return sb;
 
-	brelse(bh);
 failed:
+	brelse(bh2);
+	brelse(bh);
 	return NULL;
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)