Many files:
  Checked in e2fsprogs 1.05

diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 90de2b5..41c9c54 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,3 +1,87 @@
+Sat Sep  7 07:36:03 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c: Override the kernel's idea of default
+		checkinterval from 0 (never) to 180 days.
+
+Wed Aug 28 03:20:03 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* namei.c (ext2fs_namei_follow): New function which follows
+		symbolic link (if any) at the target.
+
+Tue Aug 27 01:48:43 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_read_inode, ext2fs_write_inode): Add support
+		for shortcut function fs->read_inode() and fs->write_inode().
+		Added inode_cache to reduce CPU time spent in doing
+		byte swapping.
+
+	* swapfs.c (ext2fs_swap_super): Swap the new fields in a V2
+	 	superblock.
+
+	* namei.c (ext2fs_follow_link): New function.
+		(ext2fs_namei): Extended to have support for chasing
+ 		symbolic links.  ext2fs_namei() still returns an inode
+ 		which is a symbolic link.  Symbolic links are only chased
+ 		while resolving the containing directory.  To chase
+ 		symbolic links of the final result, use
+ 		ext2fs_follow_link().
+
+Mon Aug 26 23:46:07 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2_err.et.in: Added new error code EXT2_ET_SYMLINK_LOOP.
+
+	* bitops.h (ext2fs_set_bit, ext2fs_celar_bit): Use asm inlines
+		provided by Pete A. Zaitcev (zaitcev@lab.sun.mcst.ru).
+
+Thu Aug 22 00:40:18 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): On systems where the byte
+		order is not i386 compatible, set the swap_byte flag.
+
+	* inode.c (inocpy_with_swap): Check to see if inode contains a
+		fast symlink before swapping the inode block fields.  This
+		required adding a new argument to inocpy_with_swap to
+		determine whether the mode field is in host order or not.
+
+Wed Aug 21 00:45:42 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bitops.h (ext2fs_set_bit, ext2fs_clear_bit, ext2fs_test_bit): On
+		the sparc, if EXT2_STD_BITOPS set, use the standard
+		i386-compatible bitmask operations, instead on the
+		non-standard native bitmask operators.
+
+Fri Aug  9 11:11:35 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* block.c (ext2fs_block_iterate): Cause block iterator to return
+		the HURD translator block (along with everything else).
+		If the flag BLOCK_FLAG_DATA_ONLY is passed to the block
+		iterator, then don't return any meta data blocks
+		(including the HURD translator).
+
+Wed Jul 17 17:13:34 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* gen_uuid.c: New file, which generates DCE-compatible UUIDs.
+
+	* uuid.c: New file, containing UUID utility functions.
+
+Tue Jul 16 10:19:16 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Add a definition of the "real" ext2 superblock.
+
+Fri May 24 14:54:55 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Fix erroneous ino_t type used in block_bitmap type.
+
+Sun May 19 15:39:03 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* openfs.c (ext2fs_open): If the blocksize in the superblock is
+		zero, return the error EXT2_ET_CORRUPT_SUPERBLOCK, since
+		that's a basic value that must be correct for the rest of
+		the library to work.
+
+	* ext2_err.et.in (EXT2_ET_CORRUPT_SUPERBLOCK): Added new error
+	 	code.
+
 Thu May 16 11:12:30 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
 	* Release of E2fsprogs version 1.04
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 2666977..5319ce5 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -2,6 +2,7 @@
 top_srcdir = @top_srcdir@
 VPATH = @srcdir@
 top_builddir = ../..
+my_dir = lib/ext2fs
 INSTALL = @INSTALL@
 
 @MCONFIG@
@@ -29,6 +30,7 @@
 	llseek.o \
 	mkdir.o \
 	namei.o \
+	native.o \
 	newdir.o \
 	openfs.o \
 	read_bb.o \
@@ -60,6 +62,7 @@
 	$(srcdir)/llseek.c \
 	$(srcdir)/mkdir.c \
 	$(srcdir)/namei.c \
+	$(srcdir)/native.c \
 	$(srcdir)/newdir.c \
 	$(srcdir)/openfs.c \
 	$(srcdir)/read_bb.c \
@@ -83,7 +86,7 @@
 DLL_MYDIR = ext2fs
 DLL_INSTALL_DIR = $(libdir)
 
-ELF_VERSION = 2.0
+ELF_VERSION = 2.1
 ELF_SO_VERSION = 2
 ELF_IMAGE = libext2fs
 ELF_MYDIR = ext2fs
@@ -154,88 +157,90 @@
 # the Makefile.in file
 #
 ext2_err.o: ext2_err.c
-alloc.o: $(srcdir)/alloc.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+alloc.o: $(srcdir)/alloc.c $(srcdir)/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
 badblocks.o: $(srcdir)/badblocks.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
 bb_inode.o: $(srcdir)/bb_inode.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 bitmaps.o: $(srcdir)/bitmaps.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 bitops.o: $(srcdir)/bitops.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
 block.o: $(srcdir)/block.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 check_desc.o: $(srcdir)/check_desc.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 closefs.o: $(srcdir)/closefs.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 cmp_bitmaps.o: $(srcdir)/cmp_bitmaps.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 dirblock.o: $(srcdir)/dirblock.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 expanddir.o: $(srcdir)/expanddir.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 freefs.o: $(srcdir)/freefs.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 get_pathname.o: $(srcdir)/get_pathname.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 getsize.o: $(srcdir)/getsize.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 initialize.o: $(srcdir)/initialize.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 inline.o: $(srcdir)/inline.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 inode.o: $(srcdir)/inode.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 ismounted.o: $(srcdir)/ismounted.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 link.o: $(srcdir)/link.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
-llseek.o: $(srcdir)/llseek.c $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
+llseek.o: $(srcdir)/llseek.c $(top_srcdir)/lib/et/com_err.h \
+ $(srcdir)/io.h
 mkdir.o: $(srcdir)/mkdir.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 namei.o: $(srcdir)/namei.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
+native.o: $(srcdir)/native.c $(srcdir)/ext2fs.h \
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 newdir.o: $(srcdir)/newdir.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 openfs.o: $(srcdir)/openfs.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 read_bb.o: $(srcdir)/read_bb.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 read_bb_file.o: $(srcdir)/read_bb_file.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 rw_bitmaps.o: $(srcdir)/rw_bitmaps.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 swapfs.o: $(srcdir)/swapfs.c $(srcdir)/ext2fs.h \
- $(top_srcdir)/lib/et/com_err.h $(srcdir)/io.h \
- $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/bitops.h
+ $(top_srcdir)/lib/et/com_err.h  $(srcdir)/bitops.h \
+ $(srcdir)/io.h $(top_builddir)/lib/ext2fs/ext2_err.h
 unix_io.o: $(srcdir)/unix_io.c $(top_srcdir)/lib/et/com_err.h \
  $(top_builddir)/lib/ext2fs/ext2_err.h $(srcdir)/io.h
-
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index d5ef0ec..7aaf549 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -22,27 +22,25 @@
 
 #include "ext2fs.h"
 
-errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
-				       const char *descr,
-				       ext2fs_inode_bitmap *ret)
+errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+					 __u32 end,
+					 __u32 real_end,
+					 const char *descr,
+					 ext2fs_generic_bitmap *ret)
 {
 	ext2fs_inode_bitmap bitmap;
 	int	size;
 
-	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
-
-	fs->write_bitmaps = ext2fs_write_bitmaps;
-
-	bitmap = malloc(sizeof(struct ext2fs_struct_inode_bitmap));
+	bitmap = malloc(sizeof(struct ext2fs_struct_generic_bitmap));
 	if (!bitmap)
 		return ENOMEM;
 
-	bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
-	bitmap->fs = fs;
-	bitmap->start = 1;
-	bitmap->end = fs->super->s_inodes_count;
-	bitmap->real_end = (EXT2_INODES_PER_GROUP(fs->super)
-			    * fs->group_desc_count);
+	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	bitmap->fs = NULL;
+	bitmap->start = start;
+	bitmap->end = end;
+	bitmap->real_end = real_end;
+	bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
 	if (descr) {
 		bitmap->description = malloc(strlen(descr)+1);
 		if (!bitmap->description) {
@@ -66,46 +64,61 @@
 	return 0;
 }
 
-errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
+errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
 				       const char *descr,
-				       ext2fs_block_bitmap *ret)
+				       ext2fs_inode_bitmap *ret)
 {
-	ext2fs_block_bitmap bitmap;
-	int	size;
+	ext2fs_inode_bitmap bitmap;
+	errcode_t	retval;
+	__u32		start, end, real_end;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	fs->write_bitmaps = ext2fs_write_bitmaps;
 
-	bitmap = malloc(sizeof(struct ext2fs_struct_inode_bitmap));
-	if (!bitmap)
-		return ENOMEM;
+	start = 1;
+	end = fs->super->s_inodes_count;
+	real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count);
+
+	retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
+						descr, &bitmap);
+	if (retval)
+		return retval;
+	
+	bitmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
+	bitmap->fs = fs;
+	bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
+	
+	*ret = bitmap;
+	return 0;
+}
+
+errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
+				       const char *descr,
+				       ext2fs_block_bitmap *ret)
+{
+	ext2fs_block_bitmap bitmap;
+	errcode_t	retval;
+	__u32		start, end, real_end;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	fs->write_bitmaps = ext2fs_write_bitmaps;
+
+	start = fs->super->s_first_data_block;
+	end = fs->super->s_blocks_count-1;
+	real_end = (EXT2_BLOCKS_PER_GROUP(fs->super)  
+		    * fs->group_desc_count)-1 + start;
+	
+	retval = ext2fs_allocate_generic_bitmap(start, end, real_end,
+						descr, &bitmap);
+	if (retval)
+		return retval;
 
 	bitmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
 	bitmap->fs = fs;
-	bitmap->start = fs->super->s_first_data_block;
-	bitmap->end = fs->super->s_blocks_count-1;
-	bitmap->real_end = (EXT2_BLOCKS_PER_GROUP(fs->super) 
-			    * fs->group_desc_count)-1 + bitmap->start;
-	if (descr) {
-		bitmap->description = malloc(strlen(descr)+1);
-		if (!bitmap->description) {
-			free(bitmap);
-			return ENOMEM;
-		}
-		strcpy(bitmap->description, descr);
-	} else
-		bitmap->description = 0;
-
-	size = ((bitmap->real_end - bitmap->start) / 8) + 1;
-	bitmap->bitmap = malloc(size);
-	if (!bitmap->bitmap) {
-		free(bitmap->description);
-		free(bitmap);
-		return ENOMEM;
-	}
-
-	memset(bitmap->bitmap, 0, size);
+	bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
+	
 	*ret = bitmap;
 	return 0;
 }
diff --git a/lib/ext2fs/bitops.c b/lib/ext2fs/bitops.c
index da69e3b..6f256e5 100644
--- a/lib/ext2fs/bitops.c
+++ b/lib/ext2fs/bitops.c
@@ -72,3 +72,13 @@
 		com_err(0, errcode, "#%u", arg);
 }
 
+void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+			    int code, unsigned long arg)
+{
+	if (bitmap->description)
+		com_err(0, bitmap->base_error_code+code,
+			"#%u for %s", arg, bitmap->description);
+	else
+		com_err(0, bitmap->base_error_code + code, "#%u", arg);
+}
+
diff --git a/lib/ext2fs/bitops.h b/lib/ext2fs/bitops.h
index e98e2d2..e967c87 100644
--- a/lib/ext2fs/bitops.h
+++ b/lib/ext2fs/bitops.h
@@ -27,6 +27,8 @@
 extern const char *ext2fs_test_string;
 extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
 			       const char *description);
+extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+				int code, unsigned long arg);
 
 extern void ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
 extern void ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
@@ -172,6 +174,84 @@
 
 #define _EXT2_HAVE_ASM_BITOPS_
 
+#ifndef EXT2_OLD_BITOPS
+
+/*
+ * Do the bitops so that we are compatible with the standard i386
+ * convention.
+ */
+
+_INLINE_ int ext2fs_set_bit(int nr,void * addr)
+{
+#if 1
+	int		mask;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	__asm__ __volatile__("ldub	[%0], %%g6\n\t"
+			     "or	%%g6, %2, %%g5\n\t"
+			     "stb	%%g5, [%0]\n\t"
+			     "and	%%g6, %2, %0\n"
+	: "=&r" (ADDR)
+	: "0" (ADDR), "r" (mask)
+	: "g5", "g6");
+	return (int) ADDR;
+#else
+	int		mask, retval;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR |= mask;
+	return retval;
+#endif
+}
+
+_INLINE_ int ext2fs_clear_bit(int nr, void * addr)
+{
+#if 1
+	int		mask;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	__asm__ __volatile__("ldub	[%0], %%g6\n\t"
+			     "andn	%%g6, %2, %%g5\n\t"
+			     "stb	%%g5, [%0]\n\t"
+			     "and	%%g6, %2, %0\n"
+	: "=&r" (ADDR)
+	: "0" (ADDR), "r" (mask)
+	: "g5", "g6");
+	return (int) ADDR;
+	
+#else
+	int		mask, retval;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = (mask & *ADDR) != 0;
+	*ADDR &= ~mask;
+	return retval;
+#endif
+}
+
+_INLINE_ int ext2fs_test_bit(int nr, const void * addr)
+{
+	int			mask;
+	const unsigned char	*ADDR = (const unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	return ((mask & *ADDR) != 0);
+}
+
+#else
+
+/* Do things the old, unplesant way. */
+
 _INLINE_ int ext2fs_set_bit(int nr, void *addr)
 {
 	int		mask, retval;
@@ -205,6 +285,7 @@
 	mask = 1 << (nr & 31);
 	return ((mask & *ADDR) != 0);
 }
+#endif
 
 #endif /* __sparc__ */
 
@@ -223,70 +304,72 @@
 
 #endif /* !_EXT2_HAVE_ASM_SWAB */
 
+_INLINE_ void ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+				       __u32 bitno)
+{
+	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+		ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
+		return;
+	}
+	ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+					 blk_t bitno)
+{
+	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+		ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
+		return;
+	}
+	ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+				       blk_t bitno)
+{
+	if ((bitno < bitmap->start) || (bitno > bitmap->end)) {
+		ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
+		return 0;
+	}
+	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
 _INLINE_ void ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
 				       blk_t block)
 {
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
-				   bitmap->description);
-		return;
-	}
-	ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
+	ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
 }
 
 _INLINE_ void ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
 					 blk_t block)
 {
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
-				   block, bitmap->description);
-		return;
-	}
-	ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
+	ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block);
 }
 
 _INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
 				       blk_t block)
 {
-	if ((block < bitmap->start) || (block > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
-				   block, bitmap->description);
-		return 0;
-	}
-	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  block);
 }
 
 _INLINE_ void ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
 				       ino_t inode)
 {
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
-				   inode, bitmap->description);
-		return;
-	}
-	ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
+	ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
 }
 
 _INLINE_ void ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
 					 ino_t inode)
 {
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
-				   inode, bitmap->description);
-		return;
-	}
-	ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
+	ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode);
 }
 
 _INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
 				       ino_t inode)
 {
-	if ((inode < bitmap->start) || (inode > bitmap->end)) {
-		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
-				   inode, bitmap->description);
-		return 0;
-	}
-	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  inode);
 }
 
 _INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
index fe112b3..5138534 100644
--- a/lib/ext2fs/block.c
+++ b/lib/ext2fs/block.c
@@ -39,8 +39,10 @@
 	int	i, flags, limit;
 	blk_t	*block_nr;
 
-	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
-		ret = (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
+		ret = (*ctx->func)(ctx->fs, ind_block,
+				   BLOCK_COUNT_IND, ctx->private);
 	if (!*ind_block || (ret & BLOCK_ABORT))
 		return ret;
 	if (*ind_block >= ctx->fs->super->s_blocks_count ||
@@ -56,7 +58,8 @@
 		return ret;
 	}
 	limit = ctx->fs->blocksize >> 2;
-	if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+	if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+	    (ctx->fs->flags & EXT2_SWAP_BYTES_READ)) {
 		block_nr = (blk_t *) ctx->ind_buf;
 		for (i = 0; i < limit; i++, block_nr++)
 			*block_nr = ext2fs_swab32(*block_nr);
@@ -86,7 +89,8 @@
 		}
 	}
 	if (changed & BLOCK_CHANGED) {
-		if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+		if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+		    (ctx->fs->flags & EXT2_SWAP_BYTES_WRITE)) {
 			block_nr = (blk_t *) ctx->ind_buf;
 			for (i = 0; i < limit; i++, block_nr++)
 				*block_nr = ext2fs_swab32(*block_nr);
@@ -97,8 +101,10 @@
 			ret |= BLOCK_ERROR | BLOCK_ABORT;
 	}
 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
 	    !(ret & BLOCK_ABORT))
-		ret |= (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+		ret |= (*ctx->func)(ctx->fs, ind_block,
+				    BLOCK_COUNT_IND, ctx->private);
 	return ret;
 }
 	
@@ -108,8 +114,10 @@
 	int	i, flags, limit;
 	blk_t	*block_nr;
 
-	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
-		ret = (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
+		ret = (*ctx->func)(ctx->fs, dind_block,
+				   BLOCK_COUNT_DIND, ctx->private);
 	if (!*dind_block || (ret & BLOCK_ABORT))
 		return ret;
 	if (*dind_block >= ctx->fs->super->s_blocks_count ||
@@ -125,7 +133,8 @@
 		return ret;
 	}
 	limit = ctx->fs->blocksize >> 2;
-	if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+	if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+	    (ctx->fs->flags & EXT2_SWAP_BYTES_READ)) {
 		block_nr = (blk_t *) ctx->dind_buf;
 		for (i = 0; i < limit; i++, block_nr++)
 			*block_nr = ext2fs_swab32(*block_nr);
@@ -153,7 +162,8 @@
 		}
 	}
 	if (changed & BLOCK_CHANGED) {
-		if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+		if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+		    (ctx->fs->flags & EXT2_SWAP_BYTES_WRITE)) {
 			block_nr = (blk_t *) ctx->dind_buf;
 			for (i = 0; i < limit; i++, block_nr++)
 				*block_nr = ext2fs_swab32(*block_nr);
@@ -164,8 +174,10 @@
 			ret |= BLOCK_ERROR | BLOCK_ABORT;
 	}
 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
 	    !(ret & BLOCK_ABORT))
-		ret |= (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+		ret |= (*ctx->func)(ctx->fs, dind_block,
+				    BLOCK_COUNT_DIND, ctx->private);
 	return ret;
 }
 	
@@ -175,8 +187,10 @@
 	int	i, flags, limit;
 	blk_t	*block_nr;
 
-	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
-		ret = (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
+		ret = (*ctx->func)(ctx->fs, tind_block,
+				   BLOCK_COUNT_TIND, ctx->private);
 	if (!*tind_block || (ret & BLOCK_ABORT))
 		return ret;
 	if (*tind_block >= ctx->fs->super->s_blocks_count ||
@@ -192,7 +206,8 @@
 		return ret;
 	}
 	limit = ctx->fs->blocksize >> 2;
-	if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+	if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+	    (ctx->fs->flags & EXT2_SWAP_BYTES_READ)) {
 		block_nr = (blk_t *) ctx->tind_buf;
 		for (i = 0; i < limit; i++, block_nr++)
 			*block_nr = ext2fs_swab32(*block_nr);
@@ -220,7 +235,8 @@
 		}
 	}
 	if (changed & BLOCK_CHANGED) {
-		if (ctx->fs->flags & EXT2_SWAP_BYTES) {
+		if ((ctx->fs->flags & EXT2_SWAP_BYTES) ||
+		    (ctx->fs->flags & EXT2_SWAP_BYTES_WRITE)) {
 			block_nr = (blk_t *) ctx->tind_buf;
 			for (i = 0; i < limit; i++, block_nr++)
 				*block_nr = ext2fs_swab32(*block_nr);
@@ -231,8 +247,10 @@
 			ret |= BLOCK_ERROR | BLOCK_ABORT;
 	}
 	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
 	    !(ret & BLOCK_ABORT))
-		ret |= (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+		ret |= (*ctx->func)(ctx->fs, tind_block,
+				    BLOCK_COUNT_TIND, ctx->private);
 	
 	return ret;
 }
@@ -248,6 +266,7 @@
 			       void *private)
 {
 	int	i;
+	int	got_inode = 0;
 	int	ret = 0;
 	struct block_context ctx;
 	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */
@@ -274,7 +293,26 @@
 	}
 	ctx.dind_buf = ctx.ind_buf + fs->blocksize;
 	ctx.tind_buf = ctx.dind_buf + fs->blocksize;
+
+	/*
+	 * Iterate over the HURD translator block (if present)
+	 */
+	if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
+	    !(flags & BLOCK_FLAG_DATA_ONLY) &&
+	    inode.osd1.hurd1.h_i_translator) {
+		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+		if (ctx.errcode)
+			goto abort;
+		got_inode = 1;
+		ret |= (*func)(fs, &inode.osd1.hurd1.h_i_translator,
+			       BLOCK_COUNT_TRANSLATOR, private);
+		if (ret & BLOCK_ABORT)
+			goto abort;
+	}
 	
+	/*
+	 * Iterate over normal data blocks
+	 */
 	for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
 		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
 			ret |= (*func)(fs, &blocks[i], ctx.bcount, private);
@@ -292,14 +330,19 @@
 		if (ret & BLOCK_ABORT)
 			goto abort;
 	}
-	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND))
+	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
 		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort;
+	}
 
 abort:
 	if (ret & BLOCK_CHANGED) {
-		retval = ext2fs_read_inode(fs, ino, &inode);
-		if (retval)
-			return retval;
+		if (!got_inode) {
+			retval = ext2fs_read_inode(fs, ino, &inode);
+			if (retval)
+				return retval;
+		}
 		for (i=0; i < EXT2_N_BLOCKS; i++)
 			inode.i_block[i] = blocks[i];
 		retval = ext2fs_write_inode(fs, ino, &inode);
diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index bb2f717..3d5dbb2 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -27,7 +27,7 @@
  	retval = io_channel_read_blk(fs->io, block, 1, buf);
 	if (retval)
 		return retval;
-	if ((fs->flags & EXT2_SWAP_BYTES) == 0)
+	if ((fs->flags & (EXT2_SWAP_BYTES|EXT2_SWAP_BYTES_READ)) == 0)
 		return 0;
 	p = buf;
 	end = (char *) buf + fs->blocksize;
@@ -49,7 +49,8 @@
 	char		*buf = 0;
 	struct ext2_dir_entry *dirent;
 
-	if (fs->flags & EXT2_SWAP_BYTES) {
+	if ((fs->flags & EXT2_SWAP_BYTES) ||
+	    (fs->flags & EXT2_SWAP_BYTES_WRITE)) {
 		write_buf = buf = malloc(fs->blocksize);
 		if (!buf)
 			return ENOMEM;
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index 71153ce..81e0c1e 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -34,8 +34,8 @@
 ec	EXT2_ET_MAGIC_INODE_BITMAP,
 	"Wrong magic number for inode_bitmap structure"
 
-ec	EXT2_ET_MAGIC_RESERVED_1,
-	"Wrong magic number --- RESERVED_1"
+ec	EXT2_ET_MAGIC_GENERIC_BITMAP,
+	"Wrong magic number for generic_bitmap structure"
 
 ec	EXT2_ET_MAGIC_RESERVED_2,
 	"Wrong magic number --- RESERVED_2"
@@ -191,7 +191,24 @@
 	"Illegal or malformed device name"
 
 ec	EXT2_ET_MISSING_INODE_TABLE,
-	"A block group is missing an inode table."
+	"A block group is missing an inode table"
+
+ec	EXT2_ET_CORRUPT_SUPERBLOCK,
+	"The ext2 superblock is corrupt"
+
+ec	EXT2_ET_BAD_GENERIC_MARK,
+	"Illegal generic bit number passed to ext2fs_mark_generic_bitmap"
+
+ec	EXT2_ET_BAD_GENERIC_UNMARK,
+	"Illegal generic bit number passed to ext2fs_unmark_generic_bitmap"
+
+ec	EXT2_ET_BAD_GENERIC_TEST,
+	"Illegal generic bit number passed to ext2fs_test_generic_bitmap"
+
+ec	EXT2_ET_SYMLINK_LOOP,
+	"Too many symbolic links encountered."
+
+ec	EXT2_ET_CALLBACK_NOTHANDLED,
+	"The callback function will not handle this case"
 
 	end
-
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 73194c0..f385770 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -21,6 +21,7 @@
  */
 #define EXT2_LIB_CURRENT_REV	0
 
+#include <sys/types.h>
 #include <linux/types.h>
 
 typedef __u32		blk_t;
@@ -32,29 +33,26 @@
 
 typedef struct struct_ext2_filsys *ext2_filsys;
 
-struct ext2fs_struct_inode_bitmap {
-	int	magic;
-	ext2_filsys fs;
-	ino_t	start, end;
-	ino_t	real_end;
-	char	*description;
-	char	*bitmap;
-	int	reserved[8];
+struct ext2fs_struct_generic_bitmap {
+	int		magic;
+	ext2_filsys 	fs;
+	__u32		start, end;
+	__u32		real_end;
+	char	*	description;
+	char	*	bitmap;
+	errcode_t	base_error_code;
+	__u32		reserved[7];
 };
 
-typedef struct ext2fs_struct_inode_bitmap *ext2fs_inode_bitmap;
+#define EXT2FS_MARK_ERROR 	0
+#define EXT2FS_UNMARK_ERROR 	1
+#define EXT2FS_TEST_ERROR	2
 
-struct ext2fs_struct_block_bitmap {
-	int	magic;
-	ext2_filsys fs;
-	blk_t	start, end;
-	ino_t	real_end;
-	char	*description;
-	char	*bitmap;
-	int	reserved[8];
-};
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap;
 
-typedef struct ext2fs_struct_block_bitmap *ext2fs_block_bitmap;
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap;
+
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
 
 #ifdef EXT2_DYNAMIC_REV
 #define EXT2_FIRST_INODE(s)	EXT2_FIRST_INO(s)
@@ -74,6 +72,8 @@
 #define EXT2_FLAG_IB_DIRTY	0x10
 #define EXT2_FLAG_BB_DIRTY	0x20
 #define EXT2_SWAP_BYTES		0x40
+#define EXT2_SWAP_BYTES_READ	0x80
+#define EXT2_SWAP_BYTES_WRITE	0x100
 
 /*
  * Special flag in the ext2 inode i_flag field that means that this is
@@ -98,7 +98,11 @@
 	errcode_t (*get_blocks)(ext2_filsys fs, ino_t ino, blk_t *blocks);
 	errcode_t (*check_directory)(ext2_filsys fs, ino_t ino);
 	errcode_t (*write_bitmaps)(ext2_filsys fs);
-	int				reserved[16];
+	errcode_t (*read_inode)(ext2_filsys fs, ino_t ino,
+				struct ext2_inode *inode);
+	errcode_t (*write_inode)(ext2_filsys fs, ino_t ino,
+				struct ext2_inode *inode);
+	__u32				reserved[14];
 
 	/*
 	 * Not used by ext2fs library; reserved for the use of the
@@ -156,10 +160,22 @@
  * of the blocks containined in the indirect blocks are processed.
  * This is useful if you are going to be deallocating blocks from an
  * inode.
+ *
+ * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be
+ * called for data blocks only.
  */
 #define BLOCK_FLAG_APPEND	1
 #define BLOCK_FLAG_HOLE		1
 #define BLOCK_FLAG_DEPTH_TRAVERSE	2
+#define BLOCK_FLAG_DATA_ONLY	4
+
+/*
+ * Magic "block count" return values for the block iterator function.
+ */
+#define BLOCK_COUNT_IND		(-1)
+#define BLOCK_COUNT_DIND	(-2)
+#define BLOCK_COUNT_TIND	(-3)
+#define BLOCK_COUNT_TRANSLATOR	(-4)
 
 /*
  * Return flags for the directory iterator functions
@@ -224,6 +240,21 @@
 #define LINUX_S_ISGID  0002000
 #define LINUX_S_ISVTX  0001000
 
+#define LINUX_S_IRWXU 00700
+#define LINUX_S_IRUSR 00400
+#define LINUX_S_IWUSR 00200
+#define LINUX_S_IXUSR 00100
+
+#define LINUX_S_IRWXG 00070
+#define LINUX_S_IRGRP 00040
+#define LINUX_S_IWGRP 00020
+#define LINUX_S_IXGRP 00010
+
+#define LINUX_S_IRWXO 00007
+#define LINUX_S_IROTH 00004
+#define LINUX_S_IWOTH 00002
+#define LINUX_S_IXOTH 00001
+
 #define LINUX_S_ISLNK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
 #define LINUX_S_ISREG(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
 #define LINUX_S_ISDIR(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
@@ -238,6 +269,63 @@
 
 #define EXT2_CHECK_MAGIC(struct, code) \
 	  if ((struct)->magic != (code)) return (code)
+
+
+/*
+ * The ext2fs library private definition of the ext2 superblock, so we
+ * don't have to depend on the kernel's definition of the superblock,
+ * which might not have the latest features.
+ */
+struct ext2fs_sb {
+	__u32	s_inodes_count;		/* Inodes count */
+	__u32	s_blocks_count;		/* Blocks count */
+	__u32	s_r_blocks_count;	/* Reserved blocks count */
+	__u32	s_free_blocks_count;	/* Free blocks count */
+	__u32	s_free_inodes_count;	/* Free inodes count */
+	__u32	s_first_data_block;	/* First Data Block */
+	__u32	s_log_block_size;	/* Block size */
+	__s32	s_log_frag_size;	/* Fragment size */
+	__u32	s_blocks_per_group;	/* # Blocks per group */
+	__u32	s_frags_per_group;	/* # Fragments per group */
+	__u32	s_inodes_per_group;	/* # Inodes per group */
+	__u32	s_mtime;		/* Mount time */
+	__u32	s_wtime;		/* Write time */
+	__u16	s_mnt_count;		/* Mount count */
+	__s16	s_max_mnt_count;	/* Maximal mount count */
+	__u16	s_magic;		/* Magic signature */
+	__u16	s_state;		/* File system state */
+	__u16	s_errors;		/* Behaviour when detecting errors */
+	__u16	s_minor_rev_level; 	/* minor revision level */
+	__u32	s_lastcheck;		/* time of last check */
+	__u32	s_checkinterval;	/* max. time between checks */
+	__u32	s_creator_os;		/* OS */
+	__u32	s_rev_level;		/* Revision level */
+	__u16	s_def_resuid;		/* Default uid for reserved blocks */
+	__u16	s_def_resgid;		/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT2_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 * 
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__u32	s_first_ino; 		/* First non-reserved inode */
+	__u16   s_inode_size; 		/* size of inode structure */
+	__u16	s_block_group_nr; 	/* block group # of this superblock */
+	__u32	s_feature_compat; 	/* compatible feature set */
+	__u32	s_feature_incompat; 	/* incompatible feature set */
+	__u32	s_feature_ro_compat; 	/* readonly-compatible feature set */
+	__u8	s_uuid[16];		/* 128-bit uuid for volume */
+	char	s_volume_name[16]; 	/* volume name */
+	char	s_last_mounted[64]; 	/* directory where last mounted */
+	__u32	s_reserved[206];	/* Padding to the end of the block */
+};
   
 /*
  * function prototypes
@@ -272,6 +360,11 @@
 extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs);
 extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs);
 extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+						__u32 end,
+						__u32 real_end,
+						const char *descr,
+						ext2fs_generic_bitmap *ret);
 extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
 					      const char *descr,
 					      ext2fs_block_bitmap *ret);
@@ -323,6 +416,7 @@
 
 /* freefs.c */
 extern void ext2fs_free(ext2_filsys fs);
+extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
 extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
 extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
 
@@ -378,6 +472,13 @@
 			 int namelen, char *buf, ino_t *inode);
 extern errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd,
 			const char *name, ino_t *inode);
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ino_t root, ino_t cwd,
+			      const char *name, ino_t *inode);
+extern errcode_t ext2fs_follow_link(ext2_filsys fs, ino_t root, ino_t cwd,
+			ino_t inode, ino_t *res_inode);
+
+/* native.c */
+int ext2fs_native_flag(void);
 
 /* newdir.c */
 extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ino_t dir_ino,
@@ -414,6 +515,9 @@
 /* swapfs.c */
 extern void ext2fs_swap_super(struct ext2_super_block * super);
 extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp);
+extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
+			      struct ext2_inode *f, int hostorder);
+
 
 /* inline functions */
 extern void ext2fs_mark_super_dirty(ext2_filsys fs);
diff --git a/lib/ext2fs/freefs.c b/lib/ext2fs/freefs.c
index 63b5235..5c70983 100644
--- a/lib/ext2fs/freefs.c
+++ b/lib/ext2fs/freefs.c
@@ -33,9 +33,9 @@
 	free(fs);
 }
 
-void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
+void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
 {
-	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
+	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
 		return;
 
 	bitmap->magic = 0;
@@ -50,20 +50,21 @@
 	free(bitmap);
 }
 
+void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
+{
+	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
+		return;
+
+	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	ext2fs_free_generic_bitmap(bitmap);
+}
+
 void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
 {
 	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
 		return;
 
-	bitmap->magic = 0;
-	if (bitmap->description) {
-		free(bitmap->description);
-		bitmap->description = 0;
-	}
-	if (bitmap->bitmap) {
-		free(bitmap->bitmap);
-		bitmap->bitmap = 0;
-	}
-	free(bitmap);
+	bitmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	ext2fs_free_generic_bitmap(bitmap);
 }
 
diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
index cc7abd0..4108093 100644
--- a/lib/ext2fs/initialize.c
+++ b/lib/ext2fs/initialize.c
@@ -1,6 +1,11 @@
 /*
  * initialize.c --- initialize a filesystem handle given superblock
  * 	parameters.  Used by mke2fs when initializing a filesystem.
+ * 
+ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
+ * 
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
  */
 
 #include <stdio.h>
@@ -31,6 +36,19 @@
 #define CREATOR_OS EXT2_OS_LINUX /* by default */
 #endif
 
+/*
+ * Note we override the kernel include file's idea of what the default
+ * check interval (never) should be.  It's a good idea to check at
+ * least *occasionally*, specially since servers will never rarely get
+ * to reboot, since Linux is so robust these days.  :-)
+ * 
+ * 180 days (six months) seems like a good value.
+ */
+#ifdef EXT2_DFL_CHECKINTERVAL
+#undef EXT2_DFL_CHECKINTERVAL
+#endif
+#define EXT2_DFL_CHECKINTERVAL (86400 * 180)
+
 errcode_t ext2fs_initialize(const char *name, int flags,
 			    struct ext2_super_block *param,
 			    io_manager manager, ext2_filsys *ret_fs)
@@ -55,7 +73,7 @@
 	
 	memset(fs, 0, sizeof(struct struct_ext2_filsys));
 	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
-	fs->flags = flags | EXT2_FLAG_RW;
+	fs->flags = flags | EXT2_FLAG_RW | ext2fs_native_flag();
 	retval = manager->open(name, IO_FLAG_RW, &fs->io);
 	if (retval)
 		goto cleanup;
diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
index 04c5e4d..7d25ae1 100644
--- a/lib/ext2fs/inode.c
+++ b/lib/ext2fs/inode.c
@@ -19,8 +19,6 @@
 
 #include "ext2fs.h"
 
-static void inocpy_with_swap(struct ext2_inode *t, struct ext2_inode *f);
-
 errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
 				 ext2_inode_scan *ret_scan)
 {
@@ -151,15 +149,17 @@
 		scan->ptr += scan->inode_size - extra_bytes;
 		scan->bytes_left -= scan->inode_size - extra_bytes;
 
-		if (scan->fs->flags & EXT2_SWAP_BYTES)
-			inocpy_with_swap(inode, (struct ext2_inode *)
-					 scan->temp_buffer);
+		if ((scan->fs->flags & EXT2_SWAP_BYTES) ||
+		    (scan->fs->flags & EXT2_SWAP_BYTES_READ))
+			ext2fs_swap_inode(scan->fs, inode,
+				 (struct ext2_inode *) scan->temp_buffer, 0);
 		else
 			*inode = *((struct ext2_inode *) scan->temp_buffer);
 	} else {
-		if (scan->fs->flags & EXT2_SWAP_BYTES)
-			inocpy_with_swap(inode, (struct ext2_inode *)
-					 scan->ptr);
+		if ((scan->fs->flags & EXT2_SWAP_BYTES) ||
+		    (scan->fs->flags & EXT2_SWAP_BYTES_READ))
+			ext2fs_swap_inode(scan->fs, inode,
+				 (struct ext2_inode *) scan->ptr, 0);
 		else
 			*inode = *((struct ext2_inode *) scan->ptr);
 		scan->ptr += scan->inode_size;
@@ -178,6 +178,15 @@
 static char *inode_buffer = 0;
 static blk_t inode_buffer_block = 0;
 static int inode_buffer_size = 0;
+#define INODE_CACHE_SIZE 4
+#ifdef INODE_CACHE_SIZE
+static int cache_last = -1;
+static struct {
+	ino_t	inode;
+	struct ext2_inode value;
+} inode_cache[INODE_CACHE_SIZE];
+#endif
+
 
 errcode_t ext2fs_read_inode (ext2_filsys fs, unsigned long ino,
 			     struct ext2_inode * inode)
@@ -185,10 +194,29 @@
 	unsigned long 	group, block, block_nr, offset;
 	char 		*ptr;
 	errcode_t	retval;
-	int 		clen, length;
+	int 		clen, length, i;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+	/* Check to see if user has an override function */
+	if (fs->read_inode) {
+		retval = (fs->read_inode)(fs, ino, inode);
+		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+			return retval;
+	}
+	/* Check to see if it's in the inode cache */
+#ifdef INODE_CACHE_SIZE
+	if (cache_last == -1) {
+		for (i=0; i < INODE_CACHE_SIZE; i++)
+			inode_cache[i].inode = 0;
+		cache_last = INODE_CACHE_SIZE-1;
+	} else for (i=0; i < INODE_CACHE_SIZE; i++) {
+		if (inode_cache[i].inode == ino) {
+			*inode = inode_cache[i].value;
+			return 0;
+		}
+	}
+#endif
 	if (ino > fs->super->s_inodes_count)
 		return EXT2_ET_BAD_INODE_NUM;
 	if (inode_buffer_size != fs->blocksize) {
@@ -238,8 +266,16 @@
 	} else
 		memcpy((char *) inode, ptr, length);
 	
-	if (fs->flags & EXT2_SWAP_BYTES)
-		inocpy_with_swap(inode, inode);
+	if ((fs->flags & EXT2_SWAP_BYTES) ||
+	    (fs->flags & EXT2_SWAP_BYTES_READ))
+		ext2fs_swap_inode(fs, inode, inode, 0);
+
+	/* Update the inode cache */
+#ifdef INODE_CACHE_SIZE
+	cache_last = (cache_last + 1) % INODE_CACHE_SIZE;
+	inode_cache[cache_last].inode = ino;
+	inode_cache[cache_last].value = *inode;
+#endif
 
 	return 0;
 }
@@ -251,10 +287,25 @@
 	errcode_t	retval;
 	struct ext2_inode temp_inode;
 	char *ptr;
-	int i, clen, length;
+	int clen, length, i;
 
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
+	/* Check to see if user provided an override function */
+	if (fs->write_inode) {
+		retval = (fs->write_inode)(fs, ino, inode);
+		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+			return retval;
+	}
+	/* Check to see if the inode cache needs to be updated */
+#ifdef INODE_CACHE_SIZE
+	for (i=0; i < INODE_CACHE_SIZE; i++) {
+		if (inode_cache[i].inode == ino) {
+			inode_cache[i].value = *inode;
+			break;
+		}
+	}
+#endif
 	if (!(fs->flags & EXT2_FLAG_RW))
 		return EXT2_ET_RO_FILSYS;
 
@@ -271,8 +322,9 @@
 		inode_buffer_size = fs->blocksize;
 		inode_buffer_block = 0;
 	}
-	if (fs->flags & EXT2_SWAP_BYTES)
-		inocpy_with_swap(&temp_inode, inode);
+	if ((fs->flags & EXT2_SWAP_BYTES) ||
+	    (fs->flags & EXT2_SWAP_BYTES_WRITE))
+		ext2fs_swap_inode(fs, &temp_inode, inode, 1);
 	else
 		memcpy(&temp_inode, inode, sizeof(struct ext2_inode));
 	
@@ -367,32 +419,7 @@
 	if (retval)
 		return retval;
 	if (!LINUX_S_ISDIR(inode.i_mode))
-		return ENOTDIR;
+	return ENOTDIR;
 	return 0;
 }
 
-static void inocpy_with_swap(struct ext2_inode *t, struct ext2_inode *f)
-{
-	unsigned i;
-	
-	t->i_mode = ext2fs_swab16(f->i_mode);
-	t->i_uid = ext2fs_swab16(f->i_uid);
-	t->i_size = ext2fs_swab32(f->i_size);
-	t->i_atime = ext2fs_swab32(f->i_atime);
-	t->i_ctime = ext2fs_swab32(f->i_ctime);
-	t->i_mtime = ext2fs_swab32(f->i_mtime);
-	t->i_dtime = ext2fs_swab32(f->i_dtime);
-	t->i_gid = ext2fs_swab16(f->i_gid);
-	t->i_links_count = ext2fs_swab16(f->i_links_count);
-	t->i_blocks = ext2fs_swab32(f->i_blocks);
-	t->i_flags = ext2fs_swab32(f->i_flags);
-	for (i = 0; i < EXT2_N_BLOCKS; i++)
-		t->i_block[i] = ext2fs_swab32(f->i_block[i]);
-	t->i_version = ext2fs_swab32(f->i_version);
-	t->i_file_acl = ext2fs_swab32(f->i_file_acl);
-	t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
-	t->i_faddr = ext2fs_swab32(f->i_faddr);
-	t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
-	t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
-	t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
-}
diff --git a/lib/ext2fs/namei.c b/lib/ext2fs/namei.c
index 496c726..8fc71b0 100644
--- a/lib/ext2fs/namei.c
+++ b/lib/ext2fs/namei.c
@@ -13,6 +13,8 @@
 #include <errno.h>
 #endif
 
+/* #define NAMEI_DEBUG */
+
 #include <linux/ext2_fs.h>
 
 #include "ext2fs.h"
@@ -173,43 +175,186 @@
 	return (ls.found) ? 0 : ENOENT;
 }
 
-errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd, const char *name,
-		       ino_t *inode)
-{
-	ino_t		dir = cwd;
-	char		*buf;
-	const char	*p = name, *q;
-	int		len;
-	errcode_t	retval;
 
+static errcode_t open_namei(ext2_filsys fs, ino_t root, ino_t base,
+			    const char *pathname, int pathlen, int follow,
+			    int link_count, char *buf, ino_t *res_inode);
+
+static errcode_t follow_link(ext2_filsys fs, ino_t root, ino_t dir,
+			     ino_t inode, int link_count,
+			     char *buf, ino_t *res_inode)
+{
+	char *pathname;
+	char *buffer = 0;
+	errcode_t retval;
+	struct ext2_inode ei;
+
+#ifdef NAMEI_DEBUG
+	printf("follow_link: root=%lu, dir=%lu, inode=%lu, lc=%d\n",
+	       root, dir, inode, link_count);
+	
+#endif
+	retval = ext2fs_read_inode (fs, inode, &ei);
+	if (retval) return retval;
+	if (!LINUX_S_ISLNK (ei.i_mode)) {
+		*res_inode = inode;
+		return 0;
+	}
+	if (link_count++ > 5) {
+		return EXT2_ET_SYMLINK_LOOP;
+	}
+	if (ei.i_blocks) {
+		buffer = malloc (fs->blocksize);
+		if (!buffer)
+			return ENOMEM;
+		retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
+		if (retval) {
+			free(buffer);
+			return retval;
+		}
+		pathname = buffer;
+	} else
+		pathname = (char *)&(ei.i_block[0]);
+	retval = open_namei(fs, root, dir, pathname, ei.i_size, 1,
+			    link_count, buf, res_inode);
+	if (buffer)
+		free (buffer);
+	return retval;
+}
+
+/*
+ * This routine interprets a pathname in the context of the current
+ * directory and the root directory, and returns the inode of the
+ * containing directory, and a pointer to the filename of the file
+ * (pointing into the pathname) and the length of the filename.
+ */
+static errcode_t dir_namei(ext2_filsys fs, ino_t root, ino_t dir,
+			   const char *pathname, int pathlen,
+			   int link_count, char *buf,
+			   const char **name, int *namelen, ino_t *res_inode)
+{
+	char c;
+	const char *thisname;
+	int len;
+	ino_t inode;
+	errcode_t retval;
+
+	if ((c = *pathname) == '/') {
+        	dir = root;
+		pathname++;
+		pathlen--;
+	}
+	while (1) {
+        	thisname = pathname;
+		for (len=0; --pathlen >= 0;len++) {
+			c = *(pathname++);
+			if (c == '/')
+				break;
+		}
+		if (pathlen < 0)
+			break;
+		retval = ext2fs_lookup (fs, dir, thisname, len, buf, &inode);
+		if (retval) return retval;
+        	retval = follow_link (fs, root, dir, inode,
+				      link_count, buf, &dir);
+        	if (retval) return retval;
+    	}
+	*name = thisname;
+	*namelen = len;
+	*res_inode = dir;
+	return 0;
+}
+
+static errcode_t open_namei(ext2_filsys fs, ino_t root, ino_t base,
+			    const char *pathname, int pathlen, int follow,
+			    int link_count, char *buf, ino_t *res_inode)
+{
+	const char *basename;
+	int namelen;
+	ino_t dir, inode;
+	errcode_t retval;
+
+#ifdef NAMEI_DEBUG
+	printf("open_namei: root=%lu, dir=%lu, path=%*s, lc=%d\n",
+	       root, base, pathlen, pathname, link_count);
+#endif
+	retval = dir_namei(fs, root, base, pathname, pathlen,
+			   link_count, buf, &basename, &namelen, &dir);
+	if (retval) return retval;
+	if (!namelen) {                     /* special case: '/usr/' etc */
+		*res_inode=dir;
+		return 0;
+	}
+	retval = ext2fs_lookup (fs, dir, basename, namelen, buf, &inode);
+	if (retval)
+		return retval;
+	if (follow) {
+		retval = follow_link(fs, root, dir, inode, link_count,
+				     buf, &inode);
+		if (retval)
+			return retval;
+	}
+#ifdef NAMEI_DEBUG
+	printf("open_namei: (link_count=%d) returns %lu\n",
+	       link_count, inode);
+#endif
+	*res_inode = inode;
+	return 0;
+}
+
+errcode_t ext2fs_namei(ext2_filsys fs, ino_t root, ino_t cwd,
+		       const char *name, ino_t *inode)
+{
+	char *buf;
+	errcode_t retval;
+	
 	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
 
 	buf = malloc(fs->blocksize);
 	if (!buf)
 		return ENOMEM;
-	if (*p == '/') {
-		p++;
-		dir = root;
-	}
-	while (*p) {
-		q = strchr(p, '/');
-		if (q)
-			len = q - p;
-		else
-			len = strlen(p);
-		if (len) {
-			retval = ext2fs_lookup(fs, dir, p, len, buf, &dir);
-			if (retval) {
-				free(buf);
-				return retval;
-			}
-		}
-		if (q)
-			p = q+1;
-		else
-			break;
-	}
-	*inode = dir;
+	
+	retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
+			    buf, inode);
+
 	free(buf);
-	return 0;
+	return retval;
 }
+
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ino_t root, ino_t cwd,
+			      const char *name, ino_t *inode)
+{
+	char *buf;
+	errcode_t retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	buf = malloc(fs->blocksize);
+	if (!buf)
+		return ENOMEM;
+	
+	retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
+			    buf, inode);
+
+	free(buf);
+	return retval;
+}
+
+extern errcode_t ext2fs_follow_link(ext2_filsys fs, ino_t root, ino_t cwd,
+			ino_t inode, ino_t *res_inode)
+{
+	char *buf;
+	errcode_t retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	buf = malloc(fs->blocksize);
+	if (!buf)
+		return ENOMEM;
+	
+	retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
+
+	free(buf);
+	return retval;
+}
+
diff --git a/lib/ext2fs/native.c b/lib/ext2fs/native.c
new file mode 100644
index 0000000..aa371ce
--- /dev/null
+++ b/lib/ext2fs/native.c
@@ -0,0 +1,31 @@
+/*
+ * native.c --- returns the ext2_flag for a native byte order
+ * 
+ * Copyright (C) 1996 Theodore Ts'o.
+ * 
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+
+#include <stdio.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+static int i386_byteorder(void)
+{
+	int one = 1;
+	char *cp = (char *) &one;
+
+	return (*cp == 1);
+}
+
+int ext2fs_native_flag(void)
+{
+	if (i386_byteorder())
+		return 0;
+	return EXT2_SWAP_BYTES;
+}
+
+	
+	
diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c
index e8b01e2..74bf279 100644
--- a/lib/ext2fs/openfs.c
+++ b/lib/ext2fs/openfs.c
@@ -113,6 +113,10 @@
 #endif
 #endif
 	fs->blocksize = EXT2_BLOCK_SIZE(fs->super);
+	if (fs->blocksize == 0) {
+		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
+		goto cleanup;
+	}
 	fs->fragsize = EXT2_FRAG_SIZE(fs->super);
 	fs->inode_blocks_per_group = ((fs->super->s_inodes_per_group *
 				       EXT2_INODE_SIZE(fs->super) +
diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
index 371b8f9..968f41c 100644
--- a/lib/ext2fs/swapfs.c
+++ b/lib/ext2fs/swapfs.c
@@ -16,6 +16,8 @@
 
 void ext2fs_swap_super(struct ext2_super_block * super)
 {
+	struct ext2fs_sb *s = (struct ext2fs_sb *) super;
+	
 	super->s_inodes_count = ext2fs_swab32(super->s_inodes_count);
 	super->s_blocks_count = ext2fs_swab32(super->s_blocks_count);
 	super->s_r_blocks_count = ext2fs_swab32(super->s_r_blocks_count);
@@ -34,6 +36,7 @@
 	super->s_magic = ext2fs_swab16(super->s_magic);
 	super->s_state = ext2fs_swab16(super->s_state);
 	super->s_errors = ext2fs_swab16(super->s_errors);
+	s->s_minor_rev_level = ext2fs_swab16(s->s_minor_rev_level);
 	super->s_lastcheck = ext2fs_swab32(super->s_lastcheck);
 	super->s_checkinterval = ext2fs_swab32(super->s_checkinterval);
 	super->s_creator_os = ext2fs_swab32(super->s_creator_os);
@@ -42,6 +45,12 @@
 	super->s_def_resuid = ext2fs_swab16(super->s_def_resuid);
 	super->s_def_resgid = ext2fs_swab16(super->s_def_resgid);
 #endif
+	s->s_first_ino = ext2fs_swab32(s->s_first_ino);
+	s->s_inode_size = ext2fs_swab16(s->s_inode_size);
+	s->s_block_group_nr = ext2fs_swab16(s->s_block_group_nr);
+	s->s_feature_compat = ext2fs_swab32(s->s_feature_compat);
+	s->s_feature_incompat = ext2fs_swab32(s->s_feature_incompat);
+	s->s_feature_ro_compat = ext2fs_swab32(s->s_feature_ro_compat);
 }
 
 void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
@@ -54,5 +63,64 @@
 	gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
 }
 
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
+		       struct ext2_inode *f, int hostorder)
+{
+	unsigned i;
+	int islnk = 0;
 	
+	if (hostorder && LINUX_S_ISLNK(f->i_mode))
+		islnk = 1;
+	t->i_mode = ext2fs_swab16(f->i_mode);
+	if (!hostorder && LINUX_S_ISLNK(t->i_mode))
+		islnk = 1;
+	t->i_uid = ext2fs_swab16(f->i_uid);
+	t->i_size = ext2fs_swab32(f->i_size);
+	t->i_atime = ext2fs_swab32(f->i_atime);
+	t->i_ctime = ext2fs_swab32(f->i_ctime);
+	t->i_mtime = ext2fs_swab32(f->i_mtime);
+	t->i_dtime = ext2fs_swab32(f->i_dtime);
+	t->i_gid = ext2fs_swab16(f->i_gid);
+	t->i_links_count = ext2fs_swab16(f->i_links_count);
+	t->i_blocks = ext2fs_swab32(f->i_blocks);
+	t->i_flags = ext2fs_swab32(f->i_flags);
+	if (!islnk || f->i_blocks) {
+		for (i = 0; i < EXT2_N_BLOCKS; i++)
+			t->i_block[i] = ext2fs_swab32(f->i_block[i]);
+	} else if (t != f) {
+		for (i = 0; i < EXT2_N_BLOCKS; i++)
+			t->i_block[i] = f->i_block[i];
+	}
+	t->i_version = ext2fs_swab32(f->i_version);
+	t->i_file_acl = ext2fs_swab32(f->i_file_acl);
+	t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+	t->i_faddr = ext2fs_swab32(f->i_faddr);
 
+	switch (fs->super->s_creator_os) {
+	case EXT2_OS_LINUX:
+		t->osd2.linux2.l_i_frag = f->osd2.linux2.l_i_frag;
+		t->osd2.linux2.l_i_fsize = f->osd2.linux2.l_i_fsize;
+		t->osd2.linux2.i_pad1 = ext2fs_swab16(f->osd2.linux2.i_pad1);
+		break;
+	case EXT2_OS_HURD:
+		t->osd1.hurd1.h_i_translator =
+		  ext2fs_swab32 (f->osd1.hurd1.h_i_translator);
+		t->osd2.hurd2.h_i_frag = f->osd2.hurd2.h_i_frag;
+		t->osd2.hurd2.h_i_fsize = f->osd2.hurd2.h_i_fsize;
+		t->osd2.hurd2.h_i_mode_high =
+		  ext2fs_swab16 (f->osd2.hurd2.h_i_mode_high);
+		t->osd2.hurd2.h_i_uid_high =
+		  ext2fs_swab16 (f->osd2.hurd2.h_i_uid_high);
+		t->osd2.hurd2.h_i_gid_high =
+		  ext2fs_swab16 (f->osd2.hurd2.h_i_gid_high);
+		t->osd2.hurd2.h_i_author =
+		  ext2fs_swab32 (f->osd2.hurd2.h_i_author);
+		break;
+	case EXT2_OS_MASIX:
+		t->osd2.masix2.m_i_frag = f->osd2.masix2.m_i_frag;
+		t->osd2.masix2.m_i_fsize = f->osd2.masix2.m_i_fsize;
+		t->osd2.masix2.m_pad1 = ext2fs_swab16(f->osd2.masix2.m_pad1);
+		break;
+	}
+}
+