Many files:
  Checked in e2fsprogs 1.05

diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog
index 1ea0a58..fcab1e6 100644
--- a/e2fsck/ChangeLog
+++ b/e2fsck/ChangeLog
@@ -1,3 +1,60 @@
+Fri Aug 30 20:24:30 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pass4.c (pass4): If the user refuses to connect an unattached
+		inode to lost+found, don't try to set i_links_count.  This
+		is bad, since if the user says yes, the inode will be
+		marked as unused, which is not necessarily the right
+		thing, especially since the rest of the cleanup doesn't
+		happen here.
+
+	* pass2.c (deallocate_inode): Set inode_link_info[ino] when
+		dellocating an inode.  (Not strictly necessary, but...)
+
+	* pass4.c (pass4): Add "bonehead" explanation to the "programming
+		error" message.
+
+Tue Aug 27 11:26:32 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* e2fsck.c (PRS,main): Added new options -s and -S.  -s will
+ 		byte-swap the filesystem so that it is normalized.  -S
+ 		will byte-swap the filesystem regardless of its current
+ 		byte-order.
+
+	* swapfs.c: New file, which will byte-swap a filesystem.
+
+Tue Aug 20 09:41:37 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pass1.c (pass1): Change handling on files with non-zero dtime
+		and non-zero i_link_count; before we treated them as
+		deleted file per botched ext2 0.3c kernel behavior.  We
+		now clear dtime instead.
+
+Mon Aug 19 23:33:57 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* e2fsck.c (main): If e2fsck sets the clean bit, even if
+		nothing else is changed, make sure FSCK_NONDESTRUCT is
+		set (since after all having the filesystem set to
+		invalid is an error.  :-)
+
+Fri Aug  9 10:25:13 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* pass1.c (process_block): Make sure that meta data doesn't get
+		accidentally set in the dir_blocks array (which could
+		happen in some error condtions).
+	
+	* pass1.c (pass1): 
+	* pass2.c (process_bad_inode): Check for fragments in a
+		OS-independent fashion.
+
+Thu Aug  8 15:20:54 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* e2fsck.c (check_if_skip): Close the filesystem when skipping the
+		cleanup for the filesystem.
+
+Mon Jul 22 22:03:28 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* e2fsck.c: Improve corrupt_msg, so that it's less confusing.
+
 Thu May 16 11:12:30 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
 	* Release of E2fsprogs version 1.04
diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in
index 8e2e51c..f4330c3 100644
--- a/e2fsck/Makefile.in
+++ b/e2fsck/Makefile.in
@@ -6,6 +6,7 @@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 top_builddir = ..
+my_dir = e2fsck
 INSTALL = @INSTALL@
 LDFLAG_STATIC = @LDFLAG_STATIC@
 
@@ -14,14 +15,14 @@
 PROGS=		e2fsck extend @EXTRA_PROGS@
 MANPAGES=	e2fsck.8
 
-LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) 
-DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR) 
+LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
+DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
 
-STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) 
-STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) 
+STATIC_LIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(STATIC_LIBUUID)
+STATIC_DEPLIBS= $(STATIC_LIBEXT2FS) $(STATIC_LIBCOM_ERR) $(STATIC_LIBUUID)
 
-PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) 
-PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) 
+PROFILED_LIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBUUID)
+PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) $(PROFILED_LIBUUID)
 
 .c.o:
 	$(CC) -c $(ALL_CFLAGS) $< -o $@
@@ -52,12 +53,12 @@
 #MCHECK= -DMCHECK
 
 OBJS= e2fsck.o pass1.o pass1b.o pass2.o pass3.o pass4.o pass5.o \
-	badblocks.o util.o dirinfo.o ehandler.o $(MTRACE_OBJ)
+	swapfs.o badblocks.o util.o dirinfo.o ehandler.o $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/e2fsck.o profiled/pass1.o profiled/pass1b.o \
 	profiled/pass2.o profiled/pass3.o profiled/pass4.o profiled/pass5.o \
 	profiled/badblocks.o profiled/util.o profiled/dirinfo.o \
-	profiled/ehandler.o
+	profiled/ehandler.o profiled/swapfs.o
 
 SRCS= $(srcdir)/e2fsck.c \
 	$(srcdir)/pass1.c \
@@ -72,7 +73,7 @@
 	$(srcdir)/ehandler.c \
 	$(MTRACE_SRC)
 
-all:: profiled $(PROGS) e2fsck.static e2fsck.shared
+all:: profiled $(PROGS) e2fsck.static e2fsck.shared $(MANPAGES)
 
 @PROFILE_CMT@all:: e2fsck.profiled
 
@@ -142,39 +143,35 @@
 # Makefile dependencies follow.  This must be the last section in
 # the Makefile.in file
 #
-e2fsck.o: $(srcdir)/e2fsck.c \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h \
- $(srcdir)/../version.h
+e2fsck.o: $(srcdir)/e2fsck.c $(top_srcdir)/lib/et/com_err.h \
+ $(top_srcdir)/lib/uuid/uuid.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h $(srcdir)/../version.h
 pass1.o: $(srcdir)/pass1.c $(top_srcdir)/lib/et/com_err.h \
  $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
-pass1b.o: $(srcdir)/pass1b.c \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
+pass1b.o: $(srcdir)/pass1b.c $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h
+pass2.o: $(srcdir)/pass2.c $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
-pass2.o: $(srcdir)/pass2.c $(top_srcdir)/lib/et/com_err.h \
- $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h
-pass3.o: $(srcdir)/pass3.c \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h \
- $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
- $(top_srcdir)/lib/ext2fs/bitops.h
+pass3.o: $(srcdir)/pass3.c $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h  $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 pass4.o: $(srcdir)/pass4.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
 pass5.o: $(srcdir)/pass5.c $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h
-badblocks.o: $(srcdir)/badblocks.c \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/bitops.h \
+ $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
+badblocks.o: $(srcdir)/badblocks.c $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
 util.o: $(srcdir)/util.c $(srcdir)/e2fsck.h \
@@ -182,13 +179,10 @@
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
 dirinfo.o: $(srcdir)/dirinfo.c $(top_srcdir)/lib/et/com_err.h \
- $(srcdir)/e2fsck.h \
- $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(top_srcdir)/lib/ext2fs/bitops.h
-ehandler.o: $(srcdir)/ehandler.c \
- $(srcdir)/e2fsck.h \
+ $(srcdir)/e2fsck.h $(top_srcdir)/lib/ext2fs/ext2fs.h \
+ $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
+ $(top_srcdir)/lib/ext2fs/bitops.h
+ehandler.o: $(srcdir)/ehandler.c $(srcdir)/e2fsck.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
- 
-
diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in
index bfd20f3..cb71505 100644
--- a/e2fsck/e2fsck.8.in
+++ b/e2fsck/e2fsck.8.in
@@ -8,7 +8,7 @@
 .SH SYNOPSIS
 .B e2fsck
 [
-.B \-pacnyrdfvtFV
+.B \-pacnyrdfvstFSV
 ]
 [
 .B \-b
@@ -104,6 +104,15 @@
 .I -r
 This option does nothing at all; it is provided only for backwards
 compatibility.
+.IP 
+.I -s
+This option will byte-swap the filesystem so that it is using the normalized, 
+standard byte-order (which is i386 or little endian).  If the filesystem is
+already in the standard byte-order, e2fsck will take no action.
+.TP
+.I -S
+This option will byte-swap the filesystem, regardless of its current 
+byte-order.
 .TP
 .I -t
 Print timing statistics for
diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c
index 6dbfa6f..9048298 100644
--- a/e2fsck/e2fsck.c
+++ b/e2fsck/e2fsck.c
@@ -17,6 +17,10 @@
  * enforced (but it's not much fun on a character device :-). 
  */
 
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
 #include <string.h>
 #include <fcntl.h>
 #include <ctype.h>
@@ -36,6 +40,7 @@
 #include <malloc.h>
 
 #include "et/com_err.h"
+#include "uuid/uuid.h"
 #include "e2fsck.h"
 #include "../version.h"
 
@@ -52,6 +57,8 @@
 int cflag = 0;			/* check disk */
 int preen = 0;
 int rwflag = 1;
+int swapfs = 0;
+int normalize_swapfs = 0;
 int inode_buffer_blocks = 0;
 blk_t superblock;
 int blocksize = 0;
@@ -80,7 +87,7 @@
 static void usage(NOARGS)
 {
 	fprintf(stderr,
-		"Usage: %s [-panyrcdfvtFV] [-b superblock] [-B blocksize]\n"
+		"Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
 		"\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
 		"\t\t[-l|-L bad_blocks_file] device\n", program_name);
 	exit(FSCK_USAGE);
@@ -206,11 +213,12 @@
 #define MIN_CHECK 1
 #define MAX_CHECK 2
 
-static const char *corrupt_msg = "\nThe filesystem superblock is corrupt.  "
-	"Try running e2fsck with an alternate\n"
-	"superblock using the -b option.  "
-	"(8193 is commonly an alternate superblock;\n"
-	"Hence, 'e2fsck -b 8193 <device>' may recover the filesystem.)\n\n";
+static const char *corrupt_msg =
+"\nThe superblock could not be read or does not describe a correct ext2\n"
+"filesystem.  If the device is valid and it really contains an ext2\n"
+"filesystem (and not swap or ufs or something else), then the superblock\n"
+"is corrupt, and you might try running e2fsck with an alternate superblock:\n"
+"    e2fsck -b 8193 <device>\n\n";
 
 static void check_super_value(const char *descr, unsigned long value,
 			      int flags, unsigned long min, unsigned long max)
@@ -224,7 +232,7 @@
 	}
 }
 
-static void relocate_hint()
+static void relocate_hint(void)
 {
 	static hint_issued = 0;
 
@@ -245,7 +253,7 @@
 static void check_super_block(ext2_filsys fs)
 {
 	blk_t	first_block, last_block;
-	struct ext2_super_block *s = fs->super;
+	struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super;
 	blk_t	blocks_per_group = fs->super->s_blocks_per_group;
 	int	i;
 	blk_t	should_be;
@@ -375,6 +383,20 @@
 		first_block += fs->super->s_blocks_per_group;
 		last_block += fs->super->s_blocks_per_group;
 	}
+
+	/*
+	 * If the UUID field isn't assigned, assign it.
+	 */
+	if (rwflag && uuid_is_null(s->s_uuid)) {
+		if (preen)
+			printf("%s: Adding UUID to filesystem.\n",
+			       device_name);
+		else
+			printf("Filesystem did not have a UUID; "
+			       "generating one.\n\n");
+		uuid_generate(s->s_uuid);
+		ext2fs_mark_super_dirty(fs);
+	}
 	return;
 }
 
@@ -387,7 +409,7 @@
 {
 	const char *reason = NULL;
 	
-	if (force || bad_blocks_file || cflag)
+	if (force || bad_blocks_file || cflag || swapfs)
 		return;
 	
 	if (fs->super->s_state & EXT2_ERROR_FS)
@@ -409,6 +431,7 @@
 		       fs->super->s_inodes_count,
 		       fs->super->s_blocks_count - fs->super->s_free_blocks_count,
 		       fs->super->s_blocks_count);
+		ext2fs_close(fs);
 		exit(FSCK_OK);
 	}
 }	
@@ -444,7 +467,7 @@
 	
 	if (argc && *argv)
 		program_name = *argv;
-	while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:")) != EOF)
+	while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
 		switch (c) {
 		case 'p':
 		case 'a':
@@ -515,6 +538,11 @@
 		case 'N':
 			device_name = optarg;
 			break;
+		case 's':
+			normalize_swapfs = 1;
+		case 'S':
+			swapfs = 1;
+			break;
 		default:
 			usage ();
 		}
@@ -522,7 +550,7 @@
 		return;
 	if (optind != argc - 1)
 		usage ();
-	if (nflag && !bad_blocks_file && !cflag)
+	if (nflag && !bad_blocks_file && !cflag && !swapfs)
 		rwflag = 0;
 	filesystem_name = argv[optind];
 	if (device_name == 0)
@@ -546,6 +574,13 @@
 		fatal_error ("BLKFLSBUF not supported");
 #endif /* BLKFLSBUF */
 	}
+	if (swapfs) {
+		if (cflag || bad_blocks_file) {
+			fprintf(stderr, "Incompatible options not "
+				"allowed when byte-swapping.\n");
+			fatal_error(0);
+		}
+	}
 }
 					
 int main (int argc, char *argv[])
@@ -604,25 +639,18 @@
 	if (retval) {
 		com_err(program_name, retval, "while trying to open %s",
 			filesystem_name);
-		switch (retval) {
-		case EXT2_ET_REV_TOO_HIGH:
+		if (retval == EXT2_ET_REV_TOO_HIGH)
 			printf ("Get a newer version of e2fsck!\n");
-			break;
-		case EXT2_ET_SHORT_READ:
+		else if (retval == EXT2_ET_SHORT_READ)
 			printf ("Could this be a zero-length partition?\n");
-			break;
-		case EPERM:
-		case EACCES:
+		else if ((retval == EPERM) || (retval == EACCES))
 			printf("You must have %s access to the "
 			       "filesystem or be root\n",
 			       rwflag ? "r/w" : "r/o");
-			break;
-		case ENXIO:
+		else if (retval == ENXIO)
 			printf("Possibly non-existent or swap device?\n");
-			break;
-		default:
+		else
 			printf(corrupt_msg);
-		}
 		fatal_error(0);
 	}
 
@@ -662,11 +690,21 @@
 	else if (cflag)
 		test_disk(fs);
 
+	if (normalize_swapfs) {
+		if ((fs->flags & EXT2_SWAP_BYTES) == ext2fs_native_flag()) {
+			fprintf(stderr, "%s: Filesystem byte order "
+				"already normalized.\n", device_name);
+			fatal_error(0);
+		}
+	}
+	if (swapfs)
+		swap_filesys(fs);
+
 	/*
 	 * Mark the system as valid, 'til proven otherwise
 	 */
 	ext2fs_mark_valid(fs);
-	
+
 	pass1(fs);
 	free(invalid_inode_bitmap);
 	free(invalid_block_bitmap);
@@ -698,9 +736,11 @@
 	if (!ext2fs_test_valid(fs))
 		exit_value = FSCK_UNCORRECTED;
 	if (rwflag) {
-		if (ext2fs_test_valid(fs))
+		if (ext2fs_test_valid(fs)) {
+			if (!(fs->super->s_state & EXT2_VALID_FS))
+				exit_value = FSCK_NONDESTRUCT;
 			fs->super->s_state = EXT2_VALID_FS;
-		else
+		} else
 			fs->super->s_state &= ~EXT2_VALID_FS;
 		fs->super->s_mnt_count = 0;
 		fs->super->s_lastcheck = time(NULL);
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index dea265d..2e0fa77 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -42,7 +42,7 @@
  * The last ext2fs revision level that this version of e2fsck is able to
  * support
  */
-#define E2FSCK_CURRENT_REV	0
+#define E2FSCK_CURRENT_REV	1
 
 /*
  * Inode count arrays
@@ -145,6 +145,12 @@
 extern int invalid_bitmaps;
 
 /*
+ * For pass1_check_directory and pass1_get_blocks
+ */
+extern ino_t stashed_ino;
+extern struct ext2_inode *stashed_inode;
+
+/*
  * Procedure declarations
  */
 
@@ -155,6 +161,14 @@
 extern void pass4(ext2_filsys fs);
 extern void pass5(ext2_filsys fs);
 
+/* pass1.c */
+extern errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino);
+extern errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks);
+extern errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino,
+				  struct ext2_inode *inode);
+extern errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
+				   struct ext2_inode *inode);
+
 /* badblock.c */
 extern void read_bad_blocks_file(ext2_filsys fs, const char *bad_blocks_file,
 				 int replace_bad_blocks);
@@ -171,6 +185,9 @@
 extern const char *ehandler_operation(const char *op);
 extern void ehandler_init(io_channel channel);
 
+/* swapfs.c */
+void swap_filesys(ext2_filsys fs);
+
 /* util.c */
 extern void *allocate_memory(int size, const char *description);
 extern int ask(const char * string, int def);
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 58f3c69..27ceecd 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -69,8 +69,6 @@
 ext2fs_block_bitmap block_dup_map = 0;
 ext2fs_block_bitmap block_illegal_map = 0;
 
-static int fix_link_count = -1;
-
 unsigned short * inode_link_info = NULL;
 
 static int process_block(ext2_filsys fs, blk_t	*blocknr,
@@ -80,8 +78,6 @@
 static void check_blocks(ext2_filsys fs, ino_t ino, struct ext2_inode *inode,
 			 char *block_buf);
 static void mark_table_blocks(ext2_filsys fs);
-static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino);
-static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks);
 static void alloc_bad_map(ext2_filsys fs);
 static void handle_fs_bad_blocks(ext2_filsys fs);
 static void process_inodes(ext2_filsys fs, char *block_buf);
@@ -170,6 +166,7 @@
 	char		*block_buf;
 	errcode_t	retval;
 	struct resource_track	rtrack;
+	unsigned char	frag, fsize;
 	
 	init_resource_track(&rtrack);
 	
@@ -229,6 +226,8 @@
 	block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer");
 	fs->get_blocks = pass1_get_blocks;
 	fs->check_directory = pass1_check_directory;
+	fs->read_inode = pass1_read_inode;
+	fs->write_inode = pass1_write_inode;
 	ehandler_operation("doing inode scan");
 	retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
 	if (retval) {
@@ -297,12 +296,6 @@
 					inode.i_dtime = 0;
 					e2fsck_write_inode(fs, ino, &inode,
 							   "pass1");
-					printf("Note: /lost+found will "
-					       "probably be deleted as well, "
-					       "due to the mke2fs bug.\n"
-					       "Be sure to run mklost+found "
-					       "to recreate it after e2fsck "
-					       "finishes.\n\n");
 				} else
 					ext2fs_unmark_valid(fs);
 			}
@@ -340,37 +333,44 @@
 			goto next;
 		}
 		/*
-		 * 0.3c ext2fs code didn't clear i_links_count for
+		 * n.b.  0.3c ext2fs code didn't clear i_links_count for
 		 * deleted files.  Oops.
+		 *
+		 * Since all new ext2 implementations get this right,
+		 * we now assume that the case of non-zero
+		 * i_links_count and non-zero dtime means that we
+		 * should keep the file, not delete it.
 		 * 
-		 * In the future, when the new ext2fs behavior is the
-		 * norm, we may want to handle the case of a non-zero
-		 * i_links_count and non-zero dtime by clearing dtime
-		 * and assuming the inode is in use, instead of
-		 * assuming the inode is not in use.
 		 */
 		if (inode.i_dtime) {
-			if (fix_link_count == -1) {
-				printf("\nDeleted inode detected with non-zero link count.\n");
-				printf("This is probably due to old ext2fs kernel code.  \n");
-				fix_link_count = ask("Fix inode(s)", 1);
-			}
-			printf("Inode %lu is deleted w/ non-zero link_count.  %s\n",
-			       ino, clear_msg[fix_link_count]);
-			if (fix_link_count) {
-				inode.i_links_count = 0;
-				inode_link_info[ino] = 0;
+			printf("Inode %lu is in use, but has dtime set\n",
+			       ino);
+			if (ask("Clear dtime", 1)) {
+				inode.i_dtime = 0;
 				e2fsck_write_inode(fs, ino, &inode, "pass1");
 			} else
 				ext2fs_unmark_valid(fs);
-			goto next;
 		}
 		
 		ext2fs_mark_inode_bitmap(inode_used_map, ino);
-		if (inode.i_faddr
-#if HAVE_EXT2_FRAGS
-		    || inode.i_frag || inode.i_fsize
-#endif
+		switch (fs->super->s_creator_os) {
+		    case EXT2_OS_LINUX:
+			frag = inode.osd2.linux2.l_i_frag;
+			fsize = inode.osd2.linux2.l_i_fsize;
+			break;
+		    case EXT2_OS_HURD:
+			frag = inode.osd2.hurd2.h_i_frag;
+			fsize = inode.osd2.hurd2.h_i_fsize;
+			break;
+		    case EXT2_OS_MASIX:
+			frag = inode.osd2.masix2.m_i_frag;
+			fsize = inode.osd2.masix2.m_i_fsize;
+			break;
+		    default:
+			frag = fsize = 0;
+		}
+		
+		if (inode.i_faddr || frag || fsize
 		    || inode.i_file_acl || inode.i_dir_acl) {
 			if (!inode_bad_map)
 				alloc_bad_map(fs);
@@ -448,10 +448,13 @@
 		}
 		pass1_dupblocks(fs, block_buf);
 	}
-	fs->get_blocks = 0;
-	fs->check_directory = 0;
 	free(inodes_to_process);
 endit:
+	fs->get_blocks = 0;
+	fs->check_directory = 0;
+	fs->read_inode = 0;
+	fs->write_inode = 0;
+	
 	free(block_buf);
 	ext2fs_free_block_bitmap(block_illegal_map);
 	block_illegal_map = 0;
@@ -747,6 +750,10 @@
 
 	if (blk == 0) {
 		if (p->is_dir == 0) {
+			/*
+			 * Should never happen, since only directories
+			 * get called with BLOCK_FLAG_HOLE
+			 */
 			printf("process_block() called with blk == 0, "
 			       "inode %lu???", p->ino);
 			return 0;
@@ -818,12 +825,10 @@
 
 	mark_block_used(fs, blk);
 	p->num_blocks++;
-	if (blockcnt < 0)
-		return 0;
-	
-	p->last_block = blockcnt;
+	if (blockcnt >= 0)
+		p->last_block = blockcnt;
 mark_dir:
-	if (p->is_dir) {
+	if (p->is_dir && (blockcnt >= 0)) {
 		if (dir_block_count >= dir_block_size) {
 			dir_block_size += 100;
 			dir_blocks = realloc(dir_blocks,
@@ -1208,7 +1213,7 @@
  * structure, so there's no point in letting the ext2fs library read
  * the inode again.
  */
-static errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
+errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
 {
 	int	i;
 	
@@ -1223,7 +1228,23 @@
 	exit(FSCK_ERROR);
 }
 
-static errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
+errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode)
+{
+	if (ino != stashed_ino)
+		return EXT2_ET_CALLBACK_NOTHANDLED;
+	*inode = *stashed_inode;
+	return 0;
+}
+
+errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
+			    struct ext2_inode *inode)
+{
+	if (ino == stashed_ino)
+		*stashed_inode = *inode;
+	return EXT2_ET_CALLBACK_NOTHANDLED;
+}
+
+errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
 {
 	if (ino == stashed_ino) {
 		if (!LINUX_S_ISDIR(stashed_inode->i_mode))
diff --git a/e2fsck/pass1b.c b/e2fsck/pass1b.c
index 287c24f..b3bc833 100644
--- a/e2fsck/pass1b.c
+++ b/e2fsck/pass1b.c
@@ -98,12 +98,6 @@
 static struct dup_inode *dup_ino = 0;
 static int dup_inode_count = 0;
 
-/*
- * For pass1_check_directory and pass1_get_blocks
- */
-extern ino_t stashed_ino;
-extern struct ext2_inode *stashed_inode;
-
 static ext2fs_inode_bitmap inode_dup_map;
 
 /*
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index f4a4d32..91bcc08 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -530,6 +530,7 @@
 	errcode_t		retval;
 	struct ext2_inode	inode;
 
+	inode_link_info[ino] = 0;
 	e2fsck_read_inode(fs, ino, &inode, "deallocate_inode");
 	inode.i_links_count = 0;
 	inode.i_dtime = time(0);
@@ -609,6 +610,7 @@
 	errcode_t		retval;
 	int			inode_modified = 0;
 	char			*pathname;
+	unsigned char		*frag, *fsize;
 
 	e2fsck_read_inode(fs, ino, &inode, "process_bad_inode");
 	retval = ext2fs_get_pathname(fs, dir, ino, &pathname);
@@ -634,23 +636,30 @@
 	}
 	check_for_zero_u32(fs, ino, pathname, "i_faddr", &inode.i_faddr,
 			    &inode_modified);
-#if HAVE_EXT2_FRAGS
-	check_for_zero_u8(fs, ino, pathname, "i_frag", &inode.i_frag,
-			    &inode_modified);
-	check_for_zero_u8(fs, ino, pathname, "i_fsize", &inode.i_fsize,
-			    &inode_modified);
-#else
-	/*
-	 * Even if the OS specific fields don't support i_frag and
-	 * i_fsize, make sure they are set to zero anyway.  This may
-	 * cause problems if on some other OS these fields are reused
-	 * for something else, but that's probably a bad idea....
-	 */
-	check_for_zero_u8(fs, ino, pathname, "i_frag",
-			  &inode.osd2.linux2.l_i_frag, &inode_modified);
-	check_for_zero_u8(fs, ino, pathname, "i_fsize",
-			  &inode.osd2.linux2.l_i_fsize, &inode_modified);
-#endif
+
+	switch (fs->super->s_creator_os) {
+	    case EXT2_OS_LINUX:
+		frag = &inode.osd2.linux2.l_i_frag;
+		fsize = &inode.osd2.linux2.l_i_fsize;
+		break;
+	    case EXT2_OS_HURD:
+		frag = &inode.osd2.hurd2.h_i_frag;
+		fsize = &inode.osd2.hurd2.h_i_fsize;
+		break;
+	    case EXT2_OS_MASIX:
+		frag = &inode.osd2.masix2.m_i_frag;
+		fsize = &inode.osd2.masix2.m_i_fsize;
+		break;
+	    default:
+		frag = fsize = 0;
+	}
+	if (frag)
+		check_for_zero_u8(fs, ino, pathname, "i_frag", frag,
+				  &inode_modified);
+	if (fsize)
+		check_for_zero_u8(fs, ino, pathname, "i_fsize", fsize,
+				  &inode_modified);
+
 	check_for_zero_u32(fs, ino, pathname, "i_file_acl", &inode.i_file_acl,
 			    &inode_modified);
 	check_for_zero_u32(fs, ino, pathname, "i_dir_acl", &inode.i_dir_acl,
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index dde578b..f167d15 100644
--- a/e2fsck/pass4.c
+++ b/e2fsck/pass4.c
@@ -38,13 +38,23 @@
 			if (ask("Connect to /lost+found", 1)) {
 				if (reconnect_file(fs, i))
 					ext2fs_unmark_valid(fs);
-			} else
+			} else {
+				/*
+				 * If we don't attach the inode, then
+				 * skip the i_links_test since there's
+				 * no point in trying to force
+				 * i_links_count to zero.
+				 */
 				ext2fs_unmark_valid(fs);
+				continue;
+			}
 		}
 		if (inode_count[i] != inode_link_info[i]) {
 			e2fsck_read_inode(fs, i, &inode, "pass4");
 			if (inode_link_info[i] != inode.i_links_count) {
 				printf("WARNING: PROGRAMMING BUG IN E2FSCK!\n");
+				printf("\tOR SOME BONEHEAD (YOU) IS CHECKING "
+				       "A MOUNTED (LIVE) FILESYSTEM.\n"); 
 				printf("inode_link_info[%ld] is %u, "
 				       "inode.i_links_count is %d.  "
 				       "They should be the same!\n",
diff --git a/e2fsck/swapfs.c b/e2fsck/swapfs.c
new file mode 100644
index 0000000..291fcb3
--- /dev/null
+++ b/e2fsck/swapfs.c
@@ -0,0 +1,199 @@
+/*
+ * swapfs.c --- byte-swap an ext2 filesystem
+ */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <et/com_err.h>
+#include "e2fsck.h"
+
+struct swap_block_struct {
+	ino_t		ino;
+	int		isdir;
+	errcode_t	errcode;
+	char		*dir_buf;
+	struct ext2_inode *inode;
+};
+
+/*
+ * This is a helper function for block_iterate.  We mark all of the
+ * indirect and direct blocks as changed, so that block_iterate will
+ * write them out.
+ */
+static int swap_block(ext2_filsys fs, blk_t *block_nr, int blockcnt,
+		      void *private)
+{
+	errcode_t	retval;
+	
+	struct swap_block_struct *sb = (struct swap_block_struct *) private;
+
+	if (sb->isdir && (blockcnt >= 0) && *block_nr) {
+		retval = ext2fs_read_dir_block(fs, *block_nr, sb->dir_buf);
+		if (retval) {
+			sb->errcode = retval;
+			return BLOCK_ABORT;
+		}
+		retval = ext2fs_write_dir_block(fs, *block_nr, sb->dir_buf);
+		if (retval) {
+			sb->errcode = retval;
+			return BLOCK_ABORT;
+		}
+	}
+	if (blockcnt >= 0) {
+		if (blockcnt < EXT2_NDIR_BLOCKS)
+			return 0;
+		return BLOCK_CHANGED;
+	}
+	if (blockcnt == BLOCK_COUNT_IND) {
+		if (*block_nr == sb->inode->i_block[EXT2_IND_BLOCK])
+			return 0;
+		return BLOCK_CHANGED;
+	}
+	if (blockcnt == BLOCK_COUNT_DIND) {
+		if (*block_nr == sb->inode->i_block[EXT2_DIND_BLOCK])
+			return 0;
+		return BLOCK_CHANGED;
+	}
+	if (blockcnt == BLOCK_COUNT_TIND) {
+		if (*block_nr == sb->inode->i_block[EXT2_TIND_BLOCK])
+			return 0;
+		return BLOCK_CHANGED;
+	}
+	return BLOCK_CHANGED;
+}
+
+/*
+ * This function is responsible for byte-swapping all of the indirect,
+ * block pointers.  It is also responsible for byte-swapping directories.
+ */
+static void swap_inode_blocks(ext2_filsys fs, ino_t ino, char *block_buf,
+			      struct ext2_inode *inode)
+{
+	errcode_t			retval;
+	struct swap_block_struct	sb;
+
+	sb.ino = ino;
+	sb.inode = inode;
+	sb.dir_buf = block_buf + fs->blocksize*3;
+	sb.errcode = 0;
+	sb.isdir = 0;
+	if (LINUX_S_ISDIR(inode->i_mode))
+		sb.isdir = 1;
+
+	retval = ext2fs_block_iterate(fs, ino, 0, block_buf, swap_block, &sb);
+	if (retval) {
+		com_err("swap_inode_blocks", retval,
+			"while calling ext2fs_block_iterate");
+		fatal_error(0);
+	}
+	if (sb.errcode) {
+		com_err("swap_inode_blocks", sb.errcode,
+			"while calling iterator function");
+		fatal_error(0);
+	}
+}
+
+static void swap_inodes(ext2_filsys fs)
+{
+	int			i, group;
+	ino_t			ino = 1;
+	char 			*buf, *block_buf;
+	errcode_t		retval;
+	struct ext2_inode *	inode;
+
+	fs->read_inode = pass1_read_inode;
+	fs->get_blocks = pass1_get_blocks;
+	
+
+	buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
+	if (!buf) {
+		com_err("swap_inodes", ENOMEM,
+			"while allocating inode buffer");
+		fatal_error(0);
+	}
+	block_buf = allocate_memory(fs->blocksize * 4,
+				    "block interate buffer");
+	for (group = 0; group < fs->group_desc_count; group++) {
+		retval = io_channel_read_blk(fs->io,
+		      fs->group_desc[group].bg_inode_table,
+		      fs->inode_blocks_per_group, buf);
+		if (retval) {
+			com_err("swap_inodes", retval,
+				"while reading inode table (group %d)",
+				group);
+			fatal_error(0);
+		}
+		inode = (struct ext2_inode *) buf;
+		for (i=0; i < fs->super->s_inodes_per_group; i++, ino++) {
+			if (fs->flags & EXT2_SWAP_BYTES_READ)
+				ext2fs_swap_inode(fs, inode, inode, 0);
+			stashed_ino = ino;
+			stashed_inode = inode;
+			
+			if (inode->i_block[EXT2_IND_BLOCK] ||
+			    inode->i_block[EXT2_DIND_BLOCK] ||
+			    inode->i_block[EXT2_TIND_BLOCK] ||
+			    LINUX_S_ISDIR(inode->i_mode))
+				swap_inode_blocks(fs, ino, block_buf, inode);
+			
+			if (fs->flags & EXT2_SWAP_BYTES_WRITE)
+				ext2fs_swap_inode(fs, inode, inode, 1);
+			inode++;
+		}
+		retval = io_channel_write_blk(fs->io,
+		      fs->group_desc[group].bg_inode_table,
+		      fs->inode_blocks_per_group, buf);
+		if (retval) {
+			com_err("swap_inodes", retval,
+				"while writing inode table (group %d)",
+				group);
+			fatal_error(0);
+		}
+	}
+	free(buf);
+	free(block_buf);
+	fs->read_inode = 0;
+	fs->get_blocks = 0;
+}
+
+void swap_filesys(ext2_filsys fs)
+{
+	struct resource_track	rtrack;
+
+	init_resource_track(&rtrack);
+
+	if (!preen)
+		printf("Pass 0: Doing byte-swap of filesystem\n");
+	
+#ifdef MTRACE
+	mtrace_print("Byte swap");
+#endif
+
+	if (fs->super->s_mnt_count) {
+		fprintf(stderr, "%s: the filesystem must be freshly "
+			"checked using fsck\n"
+			"and not mounted before trying to "
+			"byte-swap it.\n", device_name);
+		fatal_error(0);
+	}
+	if (fs->flags & EXT2_SWAP_BYTES) {
+		fs->flags &= ~(EXT2_SWAP_BYTES|EXT2_SWAP_BYTES_WRITE);
+		fs->flags |= EXT2_SWAP_BYTES_READ;
+	} else {
+		fs->flags &= ~EXT2_SWAP_BYTES_READ;
+		fs->flags |= EXT2_SWAP_BYTES_WRITE;
+	}
+	swap_inodes(fs);
+	if (fs->flags & EXT2_SWAP_BYTES_WRITE)
+		fs->flags |= EXT2_SWAP_BYTES;
+	fs->flags &= ~(EXT2_SWAP_BYTES_READ|EXT2_SWAP_BYTES_WRITE);
+	ext2fs_flush(fs);
+	
+	if (tflag > 1) {
+		printf("Byte swap: ");
+		print_resource_track(&rtrack);
+	}
+}
+
+