Many files:
  unix.c: Fix bug in check of feature set, to make sure we can really
  	fix this filesystem.
  problem.h: Make blkcount type to be of type blkcnt_t.  Make the num
  	field be a 64 bit type.  Add the problem code PR_1_FEATURE_LARGE_FILES
  problem.c: Add table entry for the problem code PR_1_FEATURE_LARGE_FILES.
  pass1.c (e2fsck_pass1): A non-zero i_dir_acl field is only a problem
  	for directory inodes.  (Since it is also i_size_high now.)  If there
  	are no large_files, then clear the LARGE_FLAG feature flag.  If there
  	are large_files, but the LARGE_FLAG feature flag is not set, complain
  	and offer to fix it.
  	(check_blocks): Add support to deal with non-directory inodes that
  	have i_size_high set (i.e., large_files).  Don't give an error if a
  	directory has preallocated blocks, to support the DIR_PREALLOC
  	feature.
  	(process_block, process_bad_block): The blockcnt variable is a type of
  	blkcnt_t, for conversion to the new block_iterate2.
  pass2.c (process_bad_inode): A non-zero i_dir_acl field is only a
  	problem for directory inodes.  (Since it is also i_size_high now.)
  message.c (expand_inode_expression): Print a 64-bits of the inode size
  	for non-directory inodes.  (Directory inodes can only use a 32-bit
  	directory acl size, since i_size_high is shared with i_dir_acl.)  Add
  	sanity check so that trying to print out the directory acl on a
  	non-directory inode will print zero.  (expand_percent_expression): %B
  	and %N, which print pctx->blkcount and pctx->num, can now be 64 bit
  	variables.  Print them using the "%lld" format if EXT2_NO_64_TYPE is
  	not defined.
  e2fsck.h: Add the large_flagsfield to the e2fsck context.
  e2fsck.c (e2fsck_reset_context): Clear the large_flags field.
ChangeLog, expect.1:
  f_messy_inode: Modify test to deal with changes to support 64-bit size
  	files.  (/MAKEDEV had i_dir_acl, now i_size_high, set.)

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 0d0ef86..4d7b72f 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,49 @@
+1998-03-23  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* unix.c: Fix bug in check of feature set, to make sure we can
+		really fix this filesystem.
+
+	* problem.h: Make blkcount type to be of type blkcnt_t.  Make the
+		num field be a 64 bit type.  Add the problem code
+		PR_1_FEATURE_LARGE_FILES
+
+	* problem.c: Add table entry for the problem code
+		PR_1_FEATURE_LARGE_FILES.
+
+	* pass1.c (e2fsck_pass1): A non-zero i_dir_acl field is only
+		a problem for directory inodes.  (Since it is also
+		i_size_high now.)   If there are no large_files, then
+		clear the LARGE_FLAG feature flag.  If there are
+		large_files, but the LARGE_FLAG feature flag is not set,
+		complain and offer to fix it.
+		(check_blocks): Add support to deal with non-directory
+		inodes that have i_size_high set (i.e., large_files).
+		Don't give an error if a directory has preallocated
+		blocks, to support the DIR_PREALLOC feature.
+		(process_block, process_bad_block): The blockcnt variable
+		is a type of blkcnt_t, for conversion to the new
+		block_iterate2.
+
+	* pass2.c (process_bad_inode): A non-zero i_dir_acl field is only
+		a problem for directory inodes.  (Since it is also
+		i_size_high now.)
+
+	* message.c (expand_inode_expression): Print a 64-bits of the
+		inode size for non-directory inodes.  (Directory inodes
+		can only use a 32-bit directory acl size, since
+		i_size_high is shared with i_dir_acl.)  Add sanity check
+		so that trying to print out the directory acl on a
+		non-directory inode will print zero.
+		(expand_percent_expression): %B and %N, which print 
+		pctx->blkcount and pctx->num, can now be 64 bit
+		variables.  Print them using the "%lld" format if
+		EXT2_NO_64_TYPE is not defined.
+
+	* e2fsck.h: Add the large_flagsfield to the e2fsck context.
+
+	* e2fsck.c (e2fsck_reset_context): Clear the large_flags
+		field.
+
 Sun Mar  8 23:08:08 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
 	* pass3.c (fix_dotdot_proc): 
diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c
index 56437d5..41195fe 100644
--- a/e2fsck/e2fsck.c
+++ b/e2fsck/e2fsck.c
@@ -108,6 +108,7 @@
 	ctx->fs_dind_count = 0;
 	ctx->fs_tind_count = 0;
 	ctx->fs_fragmented = 0;
+	ctx->large_files = 0;
 
 	/* Reset the superblock to the user's requested value */
 	ctx->superblock = ctx->use_superblock;
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index b8ac30c..e1c5944 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -205,6 +205,7 @@
 	int fs_dind_count;
 	int fs_tind_count;
 	int fs_fragmented;
+	int large_files;
 
 	/*
 	 * For the use of callers of the e2fsck functions; not used by
diff --git a/e2fsck/message.c b/e2fsck/message.c
index 82cb423..c839bbf 100644
--- a/e2fsck/message.c
+++ b/e2fsck/message.c
@@ -197,7 +197,20 @@
 	
 	switch (ch) {
 	case 's':
-		printf("%u", inode->i_size);
+		if (LINUX_S_ISDIR(inode->i_mode))
+			printf("%u", inode->i_size);
+		else {
+#ifdef EXT2_NO_64_TYPE
+			if (inode->i_size_high)
+				printf("0x%x%08x", inode->i_size_high,
+				       inode->i_size);
+			else
+				printf("%u", inode->i_size);
+#else
+			printf("%llu", (inode->i_size | 
+					((__u64) inode->i_size_high << 32)));
+#endif
+		}
 		break;
 	case 'b':
 		printf("%u", inode->i_blocks);
@@ -220,7 +233,8 @@
 		printf("%u", inode->i_file_acl);
 		break;
 	case 'd':
-		printf("%u", inode->i_dir_acl);
+		printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
+			      inode->i_dir_acl : 0));
 		break;
 	default:
 	no_inode:
@@ -282,7 +296,11 @@
 		printf("%u", ctx->blk);
 		break;
 	case 'B':
+#ifdef EXT2_NO_64_TYPE
 		printf("%d", ctx->blkcount);
+#else
+		printf("%lld", ctx->blkcount);
+#endif
 		break;
 	case 'c':
 		printf("%u", ctx->blk2);
@@ -303,7 +321,11 @@
 		printf("%s", error_message(ctx->errcode));
 		break;
 	case 'N':
+#ifdef EXT2_NO_64_TYPE
 		printf("%u", ctx->num);
+#else
+		printf("%llu", ctx->num);
+#endif
 		break;
 	case 'p':
 		print_pathname(fs, ctx->ino, 0);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index e2a35f0..7ba9c63 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -50,10 +50,10 @@
 #endif
 
 static int process_block(ext2_filsys fs, blk_t	*blocknr,
-			 int	blockcnt, blk_t ref_blk, 
+			 blkcnt_t blockcnt, blk_t ref_blk, 
 			 int ref_offset, void *priv_data);
 static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
-			     int blockcnt, blk_t ref_blk,
+			     blkcnt_t blockcnt, blk_t ref_blk,
 			     int ref_offset, void *priv_data);
 static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 			 char *block_buf);
@@ -68,12 +68,12 @@
 /* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
 
 struct process_block_struct {
-	ino_t	ino;
-	int	is_dir:1, clear:1, suppress:1, fragmented:1;
-	int	num_blocks;
-	int	last_block;
-	int	num_illegal_blocks;
-	blk_t	previous_block;
+	ino_t		ino;
+	int		is_dir:1, clear:1, suppress:1, fragmented:1;
+	blk_t		num_blocks;
+	blkcnt_t	last_block;
+	int		num_illegal_blocks;
+	blk_t		previous_block;
 	struct ext2_inode *inode;
 	struct problem_context *pctx;
 	e2fsck_t	ctx;
@@ -95,6 +95,20 @@
 static struct process_inode_block *inodes_to_process;
 static int process_inode_count;
 
+#define EXT2_BPP(bits) (1UL << ((bits) - 2))
+
+#define EXT2_MAX_SIZE(bits) \
+	(((EXT2_NDIR_BLOCKS + EXT2_BPP(bits) +	\
+	   EXT2_BPP(bits) * EXT2_BPP(bits) +	\
+	   EXT2_BPP(bits) * EXT2_BPP(bits) * EXT2_BPP(bits)) * \
+	  (1UL << bits)) - 1)
+
+static long long ext2_max_sizes[] = {
+EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
+};
+
+#undef EXT2_BPP
+
 /*
  * Free all memory allocated by pass1 in preparation for restarting
  * things.
@@ -382,7 +396,8 @@
 		}
 		
 		if (inode.i_faddr || frag || fsize
-		    || inode.i_file_acl || inode.i_dir_acl) {
+		    || inode.i_file_acl ||
+		    (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) {
 			if (!ctx->inode_bad_map)
 				alloc_bad_map(ctx);
 			ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
@@ -487,6 +502,24 @@
 	ext2fs_free_block_bitmap(ctx->block_illegal_map);
 	ctx->block_illegal_map = 0;
 
+	if (ctx->large_files && 
+	    !(fs->super->s_feature_ro_compat & 
+	      EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
+		if (fix_problem(ctx, PR_1_FEATURE_LARGE_FILES, &pctx)) {
+			fs->super->s_feature_ro_compat |= 
+				EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+			ext2fs_mark_super_dirty(fs);
+		}
+	} else if (!ctx->large_files &&
+	    (fs->super->s_feature_ro_compat &
+	      EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
+		if (fs->flags & EXT2_FLAG_RW) {
+			fs->super->s_feature_ro_compat &= 
+				~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+			ext2fs_mark_super_dirty(fs);
+		}
+	}
+	
 #ifdef RESOURCE_TRACK
 	if (ctx->options & E2F_OPT_TIME2)
 		print_resource_track("Pass 1", &rtrack);
@@ -654,6 +687,9 @@
 	struct process_block_struct pb;
 	ino_t		ino = pctx->ino;
 	struct ext2_inode *inode = pctx->inode;
+	int		bad_size = 0;
+	__u64		size;
+	struct ext2fs_sb	*sb;
 	
 	if (!ext2fs_inode_has_valid_blocks(pctx->inode))
 		return;
@@ -700,7 +736,7 @@
 
 	pb.num_blocks *= (fs->blocksize / 512);
 #if 0
-	printf("inode %u, i_size = %lu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n",
+	printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
 	       ino, inode->i_size, pb.last_block, inode->i_blocks,
 	       pb.num_blocks);
 #endif
@@ -716,16 +752,36 @@
 			pb.is_dir = 0;
 		}
 	}
-	if ((pb.is_dir && (inode->i_size !=
-			   (pb.last_block + 1) * fs->blocksize)) ||
-	    (inode->i_size < pb.last_block * fs->blocksize)) {
+	if (pb.is_dir) {
+		int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
+		if ((nblock > (pb.last_block + 1)) ||
+		    ((inode->i_size & (fs->blocksize-1)) != 0))
+			bad_size = 1;
+		else if (nblock < (pb.last_block + 1)) {
+			sb = (struct ext2fs_sb *) fs->super;
+			if (((pb.last_block + 1) - nblock) >
+			    sb->s_prealloc_dir_blocks)
+				bad_size = 1;
+		}
+	} else {
+		size = inode->i_size + ((__u64) inode->i_size_high << 32);
+		if ((size < pb.last_block * fs->blocksize))
+			bad_size = 1;
+		else if (size > ext2_max_sizes[fs->super->s_log_block_size])
+			bad_size = 1;
+	}
+	if (bad_size) {
 		pctx->num = (pb.last_block+1) * fs->blocksize;
 		if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
 			inode->i_size = pctx->num;
+			if (!pb.is_dir)
+				inode->i_size_high = pctx->num >> 32;
 			e2fsck_write_inode(ctx, ino, inode, "check_blocks");
 		}
 		pctx->num = 0;
 	}
+	if (!pb.is_dir && inode->i_size_high)
+		ctx->large_files++;
 	if (pb.num_blocks != inode->i_blocks) {
 		pctx->num = pb.num_blocks;
 		if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
@@ -793,7 +849,7 @@
  */
 int process_block(ext2_filsys fs,
 		  blk_t	*block_nr,
-		  int blockcnt,
+		  blkcnt_t blockcnt,
 		  blk_t ref_block,
 		  int ref_offset, 
 		  void *priv_data)
@@ -918,7 +974,7 @@
 
 int process_bad_block(ext2_filsys fs,
 		      blk_t *block_nr,
-		      int blockcnt,
+		      blkcnt_t blockcnt,
 		      blk_t ref_block,
 		      int ref_offset,
 		      void *priv_data)
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 52db68f..f52bc2e 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -667,6 +667,7 @@
 		inode_modified++;
 	}
 	if (inode.i_dir_acl &&
+	    LINUX_S_ISDIR(inode.i_mode) &&
 	    fix_problem(ctx, PR_2_DIR_ACL_ZERO, &pctx)) {
 		inode.i_dir_acl = 0;
 		inode_modified++;
@@ -778,4 +779,3 @@
 	}
 	return 0;
 }
-	
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 503e61e..f996b9b 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -400,6 +400,11 @@
 	/* Suppress messages prompt */
 	{ PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
 		  
+	/* Filesystem contains large files, but has no such flag in sb */
+	{ PR_1_FEATURE_LARGE_FILES,
+	  "@f contains large files, but lacks LARGE_FILE flag in @S.\n",
+	  PROMPT_FIX, 0 },
+	  
 	/* Pass 1b errors */
 
 	/* Pass 1B: Rescan for duplicate/bad blocks */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index 5788703..c4461a6 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -17,8 +17,9 @@
 	struct ext2_inode *inode;
 	struct ext2_dir_entry *dirent;
 	blk_t	blk, blk2;
-	int	blkcount, group;
-	__u32	num;
+	blkcnt_t	blkcount;
+	int		group;
+	__u64	num;
 	const char *str;
 };
 
@@ -229,6 +230,9 @@
 /* Suppress messages prompt */
 #define PR_1_SUPPRESS_MESSAGES		0x010002D
 
+/* Filesystem contains large files, but has no such flag in sb */
+#define PR_1_FEATURE_LARGE_FILES 	0x01002E
+
 /*
  * Pass 1b errors
  */
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 5d36a75..855ab74 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -536,7 +536,7 @@
 	 */
 	s = (struct ext2fs_sb *) fs->super;
 	if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
-	    (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
+	    (s->s_feature_incompat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
 		com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
 			"(%s)", ctx->filesystem_name);
 		goto get_newer;