Submitted By: Joe Ciccone <joeciccone at crazyeyesoft dot com>
Date: 2006-02-09
Initial Package Version: 1.4.11
Upstream Status: Unknown
Origin: Rocklinux and Jim Gifford and Joe Ciccone
Description: Fixes cross-compilation issues and silo no longer links to
	libext2fs.so, it is integrated instead. Also allows silo to build
        and work properly on pure64 systems.

diff -Naur silo-1.4.11.orig/Makefile silo-1.4.11/Makefile
--- silo-1.4.11.orig/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/Makefile	2006-03-09 21:34:56 +0000
@@ -3,7 +3,7 @@
 
 # These only get built on Linux
 ifeq ($(OPSYS),Linux)
-  SUBDIRS  = common first second first-isofs tilo
+  SUBDIRS  = common first libext2fs second first-isofs tilo
   MANPAGES = maketilo.1 tilo.1
 endif
 
diff -Naur silo-1.4.11.orig/Rules.make silo-1.4.11/Rules.make
--- silo-1.4.11.orig/Rules.make	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/Rules.make	2006-03-09 21:48:42 +0000
@@ -1,12 +1,14 @@
 VERSION=1.4.11
 IMGVERSION=0.99
 RM=rm -f
-# We want to force 32-bit builds
-CC=gcc -m32
-LD=ld -m elf32_sparc
-AS=as
-STRIP=strip
-NM=nm
+CC=$(CROSS_COMPILE)gcc
+CC-SILO=$(CC) -m32 -Wa,-32 -I../include/emul_32
+BUILD_CC=gcc
+LD=$(CROSS_COMPILE)ld -m elf32_sparc
+AS=$(CROSS_COMPILE)as
+STRIP=$(CROSS_COMPILE)strip
+NM=$(CROSS_COMPILE)nm
+
 ELFTOAOUT=elftoaout
 BIN2H=../common/bin2h
 
diff -Naur silo-1.4.11.orig/common/Makefile silo-1.4.11/common/Makefile
--- silo-1.4.11.orig/common/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/common/Makefile	2006-03-09 21:34:56 +0000
@@ -5,19 +5,22 @@
 include ../Rules.make
 
 .c.o:
-	$(CC) $(CFLAGS) -c $*.c
+	$(CC-SILO) $(CFLAGS) -c $*.c
 
 .S.o:
-	$(CC) $(CFLAGS) -c $*.S
+	$(CC-SILO) $(CFLAGS) -c $*.S
 
 OBJS = sdiv.o rem.o udiv.o urem.o jmp.o printf.o console.o prom.o tree.o stringops2.o\
 	stringops1.o ffs.o divdi3.o udivdi3.o
-PROGRAMS = bin2h
 
-all: $(OBJS) $(PROGRAMS)
+bin2h:
+	$(BUILD_CC) $(CFLAGS) -o bin2h bin2h.c
+
+all: $(OBJS) bin2h
 
 prom.o: prom.c
-	$(CC) $(CFLAGS) -c -Wa,-Av9 -o prom.o prom.c
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 -o prom.o prom.c
 
 clean:
-	$(RM) $(PROGRAMS) *.o
+	$(RM) bin2h *.o
+
diff -Naur silo-1.4.11.orig/first/Makefile silo-1.4.11/first/Makefile
--- silo-1.4.11.orig/first/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/first/Makefile	2006-03-09 21:34:56 +0000
@@ -13,7 +13,7 @@
 LDFLAGS=-N -Ttext 0x4000
 
 .S.o:
-	$(CC) $(CFLAGS) -c $*.S
+	$(CC-SILO) $(CFLAGS) -c $*.S
 
 all: first.b first.h ultra.b ultra.h generic.b generic.h fd.b ieee32.b
 
@@ -33,7 +33,7 @@
 	sed -n 's/^\(000000000000\|0000\)4\([0-9a-f][0-9a-f][0-9a-f]\) .*letter_here.*$$/#define FD_LETTER_OFFSET_TMP 0x\2/p' < fd.map >> fd.h
 
 first.o: first.S
-	$(CC) $(CFLAGS) -c first.S -o first.o
+	$(CC-SILO) $(CFLAGS) -c first.S -o first.o
 
 first: first.o
 	$(LD) $(LDFLAGS) -o first first.o
@@ -46,7 +46,7 @@
 	$(DD) if=/dev/zero of=first.b bs=4 count=1 seek=127
 
 ultra.o: ultra.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9a ultra.S
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9a ultra.S
 
 ultra: ultra.o
 	$(LD) $(LDFLAGS) -o ultra ultra.o
@@ -60,7 +60,7 @@
 	$(DD) if=/dev/zero of=ultra.b bs=4 count=1 seek=127
 
 generic.o: generic.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9a generic.S
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9a generic.S
 
 generic: generic.o
 	$(LD) $(LDFLAGS) -o generic generic.o
@@ -74,7 +74,7 @@
 	$(DD) if=/dev/zero of=generic.b bs=4 count=1 seek=255
 
 fd.o: fd.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9a fd.S
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9a fd.S
 
 fd: fd.o
 	$(LD) $(LDFLAGS) -o fd fd.o
@@ -88,7 +88,7 @@
 	$(DD) if=/dev/zero of=fd.b bs=4 count=1 seek=255
 
 ieee32.o: ieee32.S ieee32.h
-	$(CC) $(CFLAGS) -DIMGVERSION='"SILO$(IMGVERSION)"' -c ieee32.S
+	$(CC-SILO) $(CFLAGS) -DIMGVERSION='"SILO$(IMGVERSION)"' -c ieee32.S
 
 ieee32.b: ieee32.o
 	$(LD) $(LDFLAGS) -o ieee32.b ieee32.o
diff -Naur silo-1.4.11.orig/first-isofs/Makefile silo-1.4.11/first-isofs/Makefile
--- silo-1.4.11.orig/first-isofs/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/first-isofs/Makefile	2006-03-09 21:34:56 +0000
@@ -11,10 +11,10 @@
 all: $(NAME).b
 
 .c.o:
-	$(CC) $(CFLAGS) -c $*.c
+	$(CC-SILO) $(CFLAGS) -c $*.c
 
 .S.o:
-	$(CC) $(CFLAGS) -c $*.S
+	$(CC-SILO) $(CFLAGS) -c $*.S
 
 OBJS_COMMON = ../common/prom.o ../common/console.o ../common/tree.o
 OBJS = crt0.o $(NAME).o $(OBJS_COMMON)
@@ -28,7 +28,7 @@
 	cat $<.aout >> $@
 
 crt0.o:	crt0.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9 -o $@ $<
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 -o $@ $<
 
 clean:
 	$(RM) *.o $(NAME) $(NAME).b $(NAME).aout
diff -Naur silo-1.4.11.orig/include/emul_32/asm/elf.h silo-1.4.11/include/emul_32/asm/elf.h
--- silo-1.4.11.orig/include/emul_32/asm/elf.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/include/emul_32/asm/elf.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,162 @@
+#ifndef __ASMSPARC_ELF_H
+#define __ASMSPARC_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+
+/*
+ * Sparc section types
+ */
+#define STT_REGISTER		13
+
+/*
+ * Sparc ELF relocation types
+ */
+#define	R_SPARC_NONE		0
+#define	R_SPARC_8		1
+#define	R_SPARC_16		2
+#define	R_SPARC_32		3
+#define	R_SPARC_DISP8		4
+#define	R_SPARC_DISP16		5
+#define	R_SPARC_DISP32		6
+#define	R_SPARC_WDISP30		7
+#define	R_SPARC_WDISP22		8
+#define	R_SPARC_HI22		9
+#define	R_SPARC_22		10
+#define	R_SPARC_13		11
+#define	R_SPARC_LO10		12
+#define	R_SPARC_GOT10		13
+#define	R_SPARC_GOT13		14
+#define	R_SPARC_GOT22		15
+#define	R_SPARC_PC10		16
+#define	R_SPARC_PC22		17
+#define	R_SPARC_WPLT30		18
+#define	R_SPARC_COPY		19
+#define	R_SPARC_GLOB_DAT	20
+#define	R_SPARC_JMP_SLOT	21
+#define	R_SPARC_RELATIVE	22
+#define	R_SPARC_UA32		23
+#define R_SPARC_PLT32		24
+#define R_SPARC_HIPLT22		25
+#define R_SPARC_LOPLT10		26
+#define R_SPARC_PCPLT32		27
+#define R_SPARC_PCPLT22		28
+#define R_SPARC_PCPLT10		29
+#define R_SPARC_10		30
+#define R_SPARC_11		31
+#define R_SPARC_64		32
+#define R_SPARC_OLO10		33
+#define R_SPARC_WDISP16		40
+#define R_SPARC_WDISP19		41
+#define R_SPARC_7		43
+#define R_SPARC_5		44
+#define R_SPARC_6		45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR       2
+#define HWCAP_SPARC_SWAP        4
+#define HWCAP_SPARC_MULDIV      8
+#define HWCAP_SPARC_V9		16
+#define HWCAP_SPARC_ULTRA3	32
+
+/* For the most part we present code dumps in the format
+ * Solaris does.
+ */
+typedef unsigned long elf_greg_t;
+#define ELF_NGREG 38
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/* Format is:
+ * 	G0 --> G7
+ *	O0 --> O7
+ *	L0 --> L7
+ *	I0 --> I7
+ *	PSR, PC, nPC, Y, WIM, TBR
+ */
+#define ELF_CORE_COPY_REGS(__elf_regs, __pt_regs)	\
+do {	unsigned long *dest = &(__elf_regs[0]);		\
+	struct pt_regs *src = (__pt_regs);		\
+	unsigned long *sp;				\
+	memcpy(&dest[0], &src->u_regs[0],		\
+	       sizeof(unsigned long) * 16);		\
+	/* Don't try this at home kids... */		\
+	sp = (unsigned long *) src->u_regs[14];		\
+	copy_from_user(&dest[16], sp,			\
+		       sizeof(unsigned long) * 16);	\
+	dest[32] = src->psr;				\
+	dest[33] = src->pc;				\
+	dest[34] = src->npc;				\
+	dest[35] = src->y;				\
+	dest[36] = dest[37] = 0; /* XXX */		\
+} while(0); /* Janitors: Don't touch this colon. */
+
+typedef struct {
+	union {
+		unsigned long	pr_regs[32];
+		double		pr_dregs[16];
+	} pr_fr;
+	unsigned long __unused;
+	unsigned long	pr_fsr;
+	unsigned char	pr_qcnt;
+	unsigned char	pr_q_entrysize;
+	unsigned char	pr_en;
+	unsigned int	pr_q[64];
+} elf_fpregset_t;
+
+#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs)	\
+	({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; })
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_SPARC)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_ARCH	EM_SPARC
+#define ELF_CLASS	ELFCLASS32
+#define ELF_DATA	ELFDATA2MSB
+
+#define USE_ELF_CORE_DUMP
+#ifndef CONFIG_SUN4
+#define ELF_EXEC_PAGESIZE	4096
+#else
+#define ELF_EXEC_PAGESIZE	8192
+#endif
+
+
+/* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
+   use of this is to invoke "./ld.so someprog" to test out a new version of
+   the loader.  We need to make sure that it is out of the way of the program
+   that it will "exec", and that there is sufficient room for the brk.  */
+
+#define ELF_ET_DYN_BASE         (TASK_UNMAPPED_BASE)
+
+/* This yields a mask that user programs can use to figure out what
+   instruction set this cpu supports.  This can NOT be done in userspace
+   on Sparc.  */
+
+/* Sun4c has none of the capabilities, most sun4m's have them all.
+ * XXX This is gross, set some global variable at boot time. -DaveM
+ */
+#define ELF_HWCAP	((ARCH_SUN4C_SUN4) ? 0 : \
+			 (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR | \
+			  HWCAP_SPARC_SWAP | \
+			  ((srmmu_modtype != Cypress && \
+			    srmmu_modtype != Cypress_vE && \
+			    srmmu_modtype != Cypress_vD) ? \
+			   HWCAP_SPARC_MULDIV : 0)))
+
+/* This yields a string that ld.so will use to load implementation
+   specific libraries for optimization.  This is more specific in
+   intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM	(NULL)
+
+
+#endif /* !(__ASMSPARC_ELF_H) */
diff -Naur silo-1.4.11.orig/include/emul_32/asm/posix_types.h silo-1.4.11/include/emul_32/asm/posix_types.h
--- silo-1.4.11.orig/include/emul_32/asm/posix_types.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/include/emul_32/asm/posix_types.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,122 @@
+#ifndef __ARCH_SPARC_POSIX_TYPES_H
+#define __ARCH_SPARC_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.  Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned int           __kernel_size_t;
+typedef int                    __kernel_ssize_t;
+typedef long int               __kernel_ptrdiff_t;
+typedef long                   __kernel_time_t;
+typedef long		       __kernel_suseconds_t;
+typedef long                   __kernel_clock_t;
+typedef int                    __kernel_pid_t;
+typedef unsigned short         __kernel_ipc_pid_t;
+typedef unsigned short         __kernel_uid_t;
+typedef unsigned short         __kernel_gid_t;
+typedef unsigned long          __kernel_ino_t;
+typedef unsigned short         __kernel_mode_t;
+typedef unsigned short         __kernel_umode_t;
+typedef short                  __kernel_nlink_t;
+typedef long                   __kernel_daddr_t;
+typedef long                   __kernel_off_t;
+typedef char *                 __kernel_caddr_t;
+typedef unsigned short	       __kernel_uid16_t;
+typedef unsigned short	       __kernel_gid16_t;
+typedef unsigned int	       __kernel_uid32_t;
+typedef unsigned int	       __kernel_gid32_t;
+typedef unsigned short	       __kernel_old_uid_t;
+typedef unsigned short	       __kernel_old_gid_t;
+typedef unsigned short	       __kernel_old_dev_t;
+typedef int                    __kernel_clockid_t;
+typedef int                    __kernel_timer_t;
+
+#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || (__STDC_VERSION__ >= 199901L)
+typedef long long	__kernel_loff_t;
+#endif
+
+typedef struct {
+#if defined(__KERNEL__) || defined(__USE_ALL)
+	int	val[2];
+#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+	int     __val[2];
+#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */
+} __kernel_fsid_t;
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __const__ __kernel_fd_set *p)
+{ 
+	unsigned long _tmp = fd / __NFDBITS;
+	unsigned long _rem = fd % __NFDBITS;
+	return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant cases (8 or 32 longs,
+ * for 256 and 1024-bit fd_sets respectively)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+	unsigned long *tmp = p->fds_bits;
+	int i;
+
+	if (__builtin_constant_p(__FDSET_LONGS)) {
+		switch (__FDSET_LONGS) {
+			case 32:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			  tmp[16] = 0; tmp[17] = 0; tmp[18] = 0; tmp[19] = 0;
+			  tmp[20] = 0; tmp[21] = 0; tmp[22] = 0; tmp[23] = 0;
+			  tmp[24] = 0; tmp[25] = 0; tmp[26] = 0; tmp[27] = 0;
+			  tmp[28] = 0; tmp[29] = 0; tmp[30] = 0; tmp[31] = 0;
+			  return;
+			case 16:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
+			  tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
+			  return;
+			case 8:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
+			  return;
+			case 4:
+			  tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
+			  return;
+		}
+	}
+	i = __FDSET_LONGS;
+	while (i) {
+		i--;
+		*tmp = 0;
+		tmp++;
+	}
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+
+#endif /* !(__ARCH_SPARC_POSIX_TYPES_H) */
diff -Naur silo-1.4.11.orig/include/emul_32/asm/types.h silo-1.4.11/include/emul_32/asm/types.h
--- silo-1.4.11.orig/include/emul_32/asm/types.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/include/emul_32/asm/types.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,41 @@
+#ifndef _SPARC_TYPES_H
+#define _SPARC_TYPES_H
+
+/*
+ * _xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space.
+ */
+
+/*
+ * This file is never included by application software unless
+ * explicitly requested (e.g., via linux/types.h) in which case the
+ * application is Linux specific so (user-) name space pollution is
+ * not a major issue.  However, for interoperability, libraries still
+ * need to be careful to avoid a name clashes.
+ */
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if (defined(__GNUC__) && !defined(__STRICT_ANSI__)) || (__STDC_VERSION__ >= 199901L)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+#if (defined(__STRICT_ANSI__) && !defined(inline))
+#define inline __inline__
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* defined(_SPARC_TYPES_H) */
diff -Naur silo-1.4.11.orig/include/ext2fs/ext2_err.h silo-1.4.11/include/ext2fs/ext2_err.h
--- silo-1.4.11.orig/include/ext2fs/ext2_err.h	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/include/ext2fs/ext2_err.h	2006-03-09 21:34:56 +0000
@@ -3,6 +3,8 @@
  * This file is automatically generated; please do not edit it.
  */
 
+#include <et/com_err.h>
+
 #define EXT2_ET_BASE                             (2133571328L)
 #define EXT2_ET_MAGIC_EXT2FS_FILSYS              (2133571329L)
 #define EXT2_ET_MAGIC_BADBLOCKS_LIST             (2133571330L)
@@ -19,8 +21,8 @@
 #define EXT2_ET_MAGIC_ICOUNT                     (2133571341L)
 #define EXT2_ET_MAGIC_PQ_IO_CHANNEL              (2133571342L)
 #define EXT2_ET_MAGIC_EXT2_FILE                  (2133571343L)
-#define EXT2_ET_MAGIC_RESERVED_7                 (2133571344L)
-#define EXT2_ET_MAGIC_RESERVED_8                 (2133571345L)
+#define EXT2_ET_MAGIC_E2IMAGE                    (2133571344L)
+#define EXT2_ET_MAGIC_INODE_IO_CHANNEL           (2133571345L)
 #define EXT2_ET_MAGIC_RESERVED_9                 (2133571346L)
 #define EXT2_ET_BAD_MAGIC                        (2133571347L)
 #define EXT2_ET_REV_TOO_HIGH                     (2133571348L)
@@ -86,7 +88,25 @@
 #define EXT2_ET_UNIMPLEMENTED                    (2133571408L)
 #define EXT2_ET_CANCEL_REQUESTED                 (2133571409L)
 #define EXT2_ET_FILE_TOO_BIG                     (2133571410L)
+#define EXT2_ET_JOURNAL_NOT_BLOCK                (2133571411L)
+#define EXT2_ET_NO_JOURNAL_SB                    (2133571412L)
+#define EXT2_ET_JOURNAL_TOO_SMALL                (2133571413L)
+#define EXT2_ET_JOURNAL_UNSUPP_VERSION           (2133571414L)
+#define EXT2_ET_LOAD_EXT_JOURNAL                 (2133571415L)
+#define EXT2_ET_NO_JOURNAL                       (2133571416L)
+#define EXT2_ET_DIRHASH_UNSUPP                   (2133571417L)
+#define EXT2_ET_BAD_EA_BLOCK_NUM                 (2133571418L)
+#define EXT2_ET_TOO_MANY_INODES                  (2133571419L)
+#define EXT2_ET_NOT_IMAGE_FILE                   (2133571420L)
+#define EXT2_ET_RES_GDT_BLOCKS                   (2133571421L)
+#define EXT2_ET_RESIZE_INODE_CORRUPT             (2133571422L)
+#define EXT2_ET_SET_BMAP_NO_IND                  (2133571423L)
+extern const struct error_table et_ext2_error_table;
 extern void initialize_ext2_error_table(void);
+
+/* For compatibility with Heimdal */
+extern void initialize_ext2_error_table_r(struct et_list **list);
+
 #define ERROR_TABLE_BASE_ext2 (2133571328L)
 
 /* for compatibility with older versions... */
diff -Naur silo-1.4.11.orig/include/ext2fs/ext2_io.h silo-1.4.11/include/ext2fs/ext2_io.h
--- silo-1.4.11.orig/include/ext2fs/ext2_io.h	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/include/ext2fs/ext2_io.h	2006-03-09 21:34:56 +0000
@@ -27,6 +27,8 @@
 typedef struct struct_io_manager *io_manager;
 typedef struct struct_io_channel *io_channel;
 
+#define CHANNEL_FLAGS_WRITETHROUGH	0x01
+
 struct struct_io_channel {
 	errcode_t	magic;
 	io_manager	manager;
@@ -47,7 +49,8 @@
 				       int actual_bytes_written,
 				       errcode_t error);
 	int		refcount;
-	int		reserved[15];
+	int		flags;
+	int		reserved[14];
 	void		*private_data;
 	void		*app_data;
 };
@@ -63,7 +66,11 @@
 	errcode_t (*write_blk)(io_channel channel, unsigned long block,
 			       int count, const void *data);
 	errcode_t (*flush)(io_channel channel);
-	int		reserved[16];
+	errcode_t (*write_byte)(io_channel channel, unsigned long offset,
+				int count, const void *data);
+	errcode_t (*set_option)(io_channel channel, const char *option, 
+				const char *arg);
+	int		reserved[14];
 };
 
 #define IO_FLAG_RW	1
@@ -78,6 +85,13 @@
 #define io_channel_flush(c) 		((c)->manager->flush((c)))
 #define io_channel_bumpcount(c)		((c)->refcount++)
 	
+/* io_manager.c */
+extern errcode_t io_channel_set_options(io_channel channel, 
+					const char *options);
+extern errcode_t io_channel_write_byte(io_channel channel, 
+				       unsigned long offset,
+				       int count, const void *data);
+
 /* unix_io.c */
 extern io_manager unix_io_manager;
 
diff -Naur silo-1.4.11.orig/libext2fs/ChangeLog silo-1.4.11/libext2fs/ChangeLog
--- silo-1.4.11.orig/libext2fs/ChangeLog	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ChangeLog	2006-03-09 21:34:56 +0000
@@ -0,0 +1,3311 @@
+2006-06-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.38
+
+2005-06-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* bitops.h, bitops.c (ext2fs_set_bit, ext2fs_clear_bit,
+		ext2fs_test_bit): Change these function prototypes to be
+		unsigned int's.  Negative bit numbers were never allowed
+		(and never made any sense), so this should be a safe
+		change.  This is needed to allow safe use of block numbers
+		greater than or equal to 2**31.
+
+2005-06-27  Stephen Tweedie  <sct@redhat.com>
+
+	* ext2fs.h (ext2fs_resize_mem): Fix C99 strict type aliasing
+		problems.  Addresses Red Hat Bugzilla #161183.
+
+2005-06-19  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsectsize.c (BLKSSZGET): Clean up test for when to manually
+		define the BLKSSZGET ioctl.
+
+2005-05-29  Theodore Ts'o  <tytso@mit.edu>
+
+	* ismounted.c (ext2fs_check_mount_point): Add test to see if the
+		device appears to be busy; this only works on Linux 2.6+
+		systems, but provides some additional bullet-proofing in
+		those cases.
+
+2005-05-08  Theodore Ts'o  <tytso@mit.edu>
+
+	* test_io.c (safe_getenv): Fix bug so it would fetch the right
+		environment variable.
+
+2005-04-09  Theodore Ts'o  <tytso@mit.edu>
+
+	* inode.c (ext2fs_write_new_inode), 
+		ind_block.c (ext2fs_read_ind_block): Add missing return
+		value in error return case.  (Otherwise we return garbage
+		instead of the error code.)
+
+2005-03-31  Theodore Ts'o  <tytso@mit.edu>
+
+	* test_io.c (test_open): If called by a setuid/setgid or an
+		otherwise privileged program, be paranoid and ignore the
+		TEST_IO_* environment variables.
+
+2005-03-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.37
+
+2005-03-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_ext_attr.h (EXT2_XATTR_LEN, EXT2_XATTR_SIZE): Add new
+		convenience cpp macros.
+
+2005-03-20  Theodore Ts'o  <tytso@mit.edu>
+
+	* mkdir.c (ext2fs_mkdir): Call ext2fs_write_new_inode() instead of
+		ext2fs_write_inode().
+
+	* inode.c (ext2fs_write_new_inode): New function which should be
+		used when the caller is writing an inode for the first
+		time.  It makes sure that the extra portion of the large
+		inode is initialized properly.
+
+2005-03-18  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Fix clean target to remove tst_getsectsize.
+
+	* getsize.c (ext2fs_get_device_size): Check to see if the number
+		of blocks is greater than 2**32 when we are doing a binary
+		search to determine the device size.  Thanks to Stephen
+		Tweedie for the patch.
+	
+2006-02-05  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.36
+
+2005-02-05  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Remove ext2fs.pc on a "make distclean"
+
+2005-02-04  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in (clean): Remove tst_getsize when doing a make clean
+
+2005-02-03  Theodore Ts'o  <tytso@mit.edu>
+
+	* bitops.c: Make the generic functions more efficient.
+
+	* bitops.h: Drop SPARC assembly code. It's less efficient than GCC
+		3.4 compiled code and also triggers nasty compiler
+		warnings on sparc64.  Thanks to Matthias Andree for his
+		analysis and suggestion.
+	
+2005-01-27  Theodore Ts'o  <tytso@mit.edu>
+
+	* res_gdt.c (ext2fs_create_resize_inode): Create the resize inode
+		even if s_reserved_gdt_blocks is zero.
+
+2005-01-26  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2fs.pc.in: Add pkg-config files.
+
+2005-01-25  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2fs.h: Add definition of struct ext2_inode_large
+
+	* ext2_fs.h: Add new function prototypes
+
+	* ext_attr.c (ext2fs_read_ext_attr, ext2fs_write_ext_attr): The
+		ext2fs_swap_ext_attr() has been moved to swapfs.c, and
+		given a new argument, has_header.
+
+	* swapfs.c (ext2fs_swap_ext_attr): Moved from ext_attr.c, and
+		takes an argument which controls whether or not there is
+		an EA header which needs to be byteswaped.
+		(ext2fs_swap_inode_full): New function which byte-swaps
+		the EA in inode.
+
+	* inode.c (ext2fs_get_next_inode_full, ext2fs_read_inode_full,
+		ext2fs_write_inode_full): New functions, originally from
+		Alex Tomas, but which needed to be substantially fixed so
+		that the tests wouldn't cause major stack overwrite bugs
+		in byte-swapping is enabled.
+	
+2005-01-18  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Fix the kernel compile-time echo commands to be
+		consistent and portable
+
+2005-01-07  Theodore Ts'o  <tytso@mit.edu>
+
+	* unlink.c (ext2fs_unlink): If both the name and the inode number
+		are unspecified, then return an error, so that we don't do
+		something surprising such as unconditionally deleting the
+		first directory entry.
+		(unlink_proc): Delete directory entries by coalescing it
+		with the previous entry, to avoid directory fragmentation.
+
+2005-01-06  Theodore Ts'o  <tytso@mit.edu>
+
+	* version.c (ext2fs_parse_version_string): Change parsing
+		algorithm so that version strings such as 1.36-rc1 returns
+		a non-surprising result (i.e., 136, and not 1361).
+
+2005-01-05  Theodore Ts'o  <tytso@mit.edu>
+
+	* block.c (block_iterate_ind, block_iterate_dind,
+		block_iterate_tind): Move the code which byte swaps and
+		read/writes indirect blocks to ext2fs_{read,write}_ind_block.
+		This saves 400 bytes, and we need them for the
+		resize_inode handling. 
+
+	* ind_block.c (ext2fs_read_ind_block, ext2fs_write_ind_block): New
+		functions.
+
+	* res_gdt.c (ext2fs_create_resize_inode): Use 
+		ext2fs_{read,write}_ind_block so that byte swapping is
+		handled on big-endian systems.
+
+	* dupfs.c (ext2fs_dup_handle): Make sure the new filesystem handle
+		has its own copy of the orig_super data structure.  (This
+		is a better way of fixing a double-free problem in
+		resize2fs which Fedora attempted to fix in 
+		e2fsprogs-1.35-double_free.patch.   Addresses Red Hat
+		Bugzilla #132707.)
+	
+2004-12-23  Theodore Ts'o  <tytso@mit.edu>
+
+	* inode.c (ext2fs_flush_icache): When flushing the icache, clear
+		the last-read block information as well.
+
+	* ext2fs.h (BMAP_SET), bmap.c (ext2fs_bmap): Add support for new
+		flag, BMAP_SET, which allows the caller to set a
+		particular logical->physical block mapping.
+
+	* ext2_err.et.in (EXT2_ET_SET_BMAP_NO_IND): New error code
+
+	* initialize.c (calc_reserved_gdt_blocks): #ifdef out all
+		debugging printf statements.
+	
+	* res_gdt.c (ext2fs_create_resize_inode): Return
+		EXT2_ET_RESIZE_INODE_CORRUPT if the resize inode is not
+		what we expect.  #ifdef out all debugging printf
+		statements.
+
+	* ext2_err.et.in (EXT2_ET_RESIZE_INODE_CORRUPT): Add new error code.
+
+2004-12-22  Theodore Ts'o  <tytso@mit.edu>
+
+	* swapfs.c (ext2fs_swap_super): Byteswap the reserved_gdt_blocks
+		superblocks field.
+
+2004-12-15  Theodore Ts'o  <tytso@mit.edu>
+
+	* sparse.c (ext2fs_list_backups, ext2fs_bg_has_super),
+		res_gdt.c (list_backups), closefs.c (ext2fs_bg_has_super),
+		ext2fs.h: Move ext2fs_list_backups() to res_gdt.c, and
+		ext2fs_bg_has_super() back to closefs.c.  There's no
+		reason for the new file, since list_backups() isn't being
+		used by any other functions, and can be made static, and
+		all users of the ext2fs filesystem will have to call
+		ext2fs_close() anyway.
+
+2004-12-15  Theodore Ts'o  <tytso@mit.edu>
+
+	* Applied resize inode patch from Andreas Dilger
+
+	* res_gdt.c (ext2fs_create_resize_inode): New function that
+		creates the resize inode.
+
+	* initialize.c (ext2fs_initialize): Reserve space for the resize
+		inode.
+
+	* ext2fs.h (EXT2_LIB_FEATURE_COMPAT_SUPP): Add
+		EXT2_FEATURE_COMPAT_RESIZE_INODE to the list of supported
+		capabilities.
+		Add function prototypes for res_gdt.c and sparse.c.
+
+	* closefs.c (ext2fs_super_and_bgd_loc): Take the reserved blocks
+		into account when calculating the number of overhead
+		blocks.
+
+	* closefs.c (ext2fs_bg_has_super, test_root), sparse.c: Move these
+		functions to the new file sparse.c
+
+	* alloc_sb.c (ext2fs_reserve_super_and_bgd): Reserve the blocks
+		saved in the resize inode as being in use.
+
+	* ext2_err.et.in (EXT2_ET_RES_GDT_BLOCKS): Add new error code.
+
+	* Makefile.in (srcdir): Add res_gdt.c and sparse.c to the ext2fs
+		library.
+
+2004-12-14  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Use Linux-kernel-style makefile output for "make
+		install"
+
+	* Makefile.in (installdirs): Use $(MKINSTALLDIRS) macro
+		Update dependencies.
+
+2004-11-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c (unix_set_option): Add support for the offset option.
+
+	* test_io.c (test_set_option): Add support for the set_option method.
+
+	* ext2_io.h: Add new io_channel method, set_option(), and change
+		io_channel_write_byte() from a macro to a library function.
+
+	* ext2fs.h, openfs.c(ext2fs_open2): New version of ext2fs_open
+		which adds a new parameter, io_options.
+		(ext2fs_open): If there is a question mark in the
+		filename, and no io_options are specified, assumed that
+		the text following the question mark are io_options.
+	
+	* io_manager.c, Makefile.in: New source file which contains
+		high-level functions for the io_channel layer.
+
+	* freefs.c (ext2fs_free): Make sure we don't free the io_channel
+		if image_io is NULL.
+
+	* Makefile.in: Use Linux-kernel-style makefile output to make it
+		easier to see errors/warnings.
+
+2004-11-29  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h (EXT2_EXTENTS_FL, EXT3_FEATURE_INCOMPAT_EXTENTS, 
+		EXT2_MAX_BLOCK_LOG_SIZE): Add definition for extent
+		feature and inode flag.  Change maximum allowable block
+		size to be 65536.
+
+2004-10-08  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Add support for Windows
+		9x/NT under Cygwin.  Thanks to Sam Robb
+		(samrobb@users.sourceforge.net) for pointing this and the
+		suggested code patch.
+
+2004-09-17  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c: Clean up header #include's.
+
+	* llseek.c (ext2fs_llseek): On non-linux systems, use lseek64() if
+		it is present.  (Addresses Debian bug #269044)
+
+2004-07-28  Theodore Ts'o  <tytso@mit.edu>
+
+	* rw_bitmaps.c (read_bitmaps), block.c (block_iterate_ind,
+		block_iterate_dind, block_iterate_tind), inode.c
+		(ext2fs_read_inode): If EXT2_FLAG_IMAGE_FILE is set, so
+		read the metadata from fs->image_io instead of fs->io.
+
+	* initialize.c (ext2fs_initialize), openfs.c (ext2fs_open):
+		Initialize fs->image_io to be the same as fs->io.
+	
+	* ext2_err.et.in (EXT2_ET_NOT_IMAGE_FILE): Add new error code. 
+
+	* openfs.c (ext2fs_get_data_io, ext2fs_set_data_io,
+		ext2fs_rewrite_to_io): New functions that allow
+		applications to manipulate fs->image_io and fs->io safely.
+
+	* freefs.c (ext2fs_free): If fs->image_io is different fs->io,
+		then call io_channel_close on fs->image_io.
+
+	* ext2fs.h: Add image_io element to the ext2_filsys data
+		structure.  Add ext2fs_get_data_io() ext2fs_set_data_io(),
+		and ext2fs_rewrite_to_io() prototypes.
+
+2004-05-26  Theodore Ts'o  <tytso@mit.edu>
+
+	* closefs.c (ext2fs_flush): Make sure the master superblock is
+		written last, and only after other I/O has been flushed to
+		disk.  Thanks to Junfeng Yang from the Stanford
+		Metacompilation group for pointing a potential ordering
+		constraint problem if we don't write things out in the
+		right order.
+
+	* test_io.c: Implement the ability to abort after n reads or
+		writes to a particular block.  The block is specified by
+		TEST_IO_BLOCK environment variable, and the read/write
+		count by the TEST_IO_READ_ABORT and TEST_IO_WRITE_ABORT
+		environment variables.  The block data is now only dumped
+		if the 0x10 bit is set in TEST_IO_FLAGS.
+
+2004-04-03  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_types.h.in: Remove check for _UUID_TYPES since uuid_types.h
+		is no longer used.
+
+2004-03-08  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Only use the BLKGETSIZE64
+		ioctl on Linux 2.6 since it is unreliable in Linux 2.4.
+		(Addresses Debian Bug #236528).  Fix typo in the ioctl
+		used for Mac OS X.
+
+2004-03-02  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Update getsize functions to
+		use Apple Darwin and Linux 64-bit ioctl's
+
+2004-02-29  Brian Bergstrand  <brian@bergstrand.org>
+
+	* Makefile.in: Use $(BSDLIB_PIC_FLAG) to determine whether to use
+		-fpic or -fPIC
+
+2004-02-28  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.35
+
+2004-02-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2fs.h (ext2fs_resize_mem): Fix C++ problem.  (Addresses Red
+		Hat Bugzilla #112448; thanks Thomas Woerner from Red Hat.)
+
+2004-02-14  Theodore Ts'o  <tytso@mit.edu>
+
+	* namei.c (follow_link): Correctly deal with symlinks that have
+		extended attribute information.  (Addresses Debian Bug
+		#232328)
+
+2004-01-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h: Reserve an extra 4 bytes for the journal backup,
+		which we're using due to a typo in the e2fsck code.  (Oops)
+
+	* swapfs.c (ext2fs_swap_inode): Fix byte swap bug which causes SE
+		Linux created symlinks with mandatory attributes to fail
+		to be properly handled on big endian systems.  (Addresses
+		Debian Bug #228723).
+		(ext2fs_swap_super): Byte swap some new fields in the
+		superblock, including the journal backup fields.
+
+2003-12-02  Theodore Ts'o  <tytso@mit.edu>
+
+	* alloc.c, bb_inode.c, bitops.c, block.c, check_desc.c, closefs.c,
+		dir_iterate.c, dirblock.c, expanddir.c, ext2fs.h,
+		get_pathname.c, icount.c, imager.c, initalize.c, inode.c,
+		lookup.c, openfs.c, read_bb.c, read_bb_file.c,
+		rw_bitmaps.c, unix_io.c, unlink.c, write_bb_file.c: Fix
+		gcc -Wall complaints.  Mainly marking variables as being
+		unsued, and catching signed vs. unsigned comparisons.
+
+2003-09-03  Theodore Ts'o  <tytso@mit.edu>
+
+	* closefs.c (ext2fs_super_and_bgd_loc): New function which
+		centralizes the calculation of the superblock and block
+		group descriptors.
+		(ext2fs_flush): Use ext2fs_super_and_bgd_lock to figure
+		out where to write the superblock and block group
+		descriptors.
+
+	* alloc_sb.c (ext2fs_reserve_super_and_bgd): New function which
+		reserves space in the block bitmap using
+		ext2fs_super_and_bgd_loc.
+
+	* initialize.c (ext2fs_initialize): Use
+		ext2fs_reserve_super_and_bgd to initialize the block bitmap.
+
+2003-08-20  Theodore Ts'o  <tytso@mit.edu>
+
+	* inode_io.c (ext2fs_inode_io_intern2), ext2fs.h: Add new function
+		allows the caller to pass in the inode data structure.
+
+	* fileio.c (ext2fs_file_open2), ext2fs.h: Add new function which
+		allows the caller to pass in the inode to be used in the
+		file I/O.
+
+	* ext2_fs.h: Add a backup of the location of the journal inode
+		blocks to the superblock.
+
+	* mkjournal.c (write_journal_inode): Save the location of the
+		journal inode to the backup location in the superblock.
+
+2003-08-01  Philipp Thomas <pthomas@suse.de>
+
+	* alloc.c, badblocks.c, bb_inode.c, bitmaps.c, block.c, bmap.c,
+		bmove.c, brel_ma.c, closefs.c, dblist.c, dblist_dir.c,
+		dir_iterate.c, dirblock.c, dupfs.c, expanddir.c, ext2fs.h,
+		ext_attr.c, fileio.c, freefs.c, get_pathname.c, icount.c,
+		initialize.c, inode.c, inode_io.c, irel_ma.c, mkdir.c,
+		mkjournal.c, namei.c, newdir.c, openfs.c, rs_bitmap.c,
+		rw_bitmaps.c, test_io.c, unix_io.c: ext2fs_getmem(),
+		ext2fs_free_mem(), and ext2fs_resize_mem() all now take a
+		'void *' instead of a 'void **' in order to avoid pointer
+		aliasing problems with GCC 3.x.
+
+2003-07-25  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.34
+
+2003-07-06  Theodore Ts'o  <tytso@mit.edu>
+
+	* kernel-jbd.h, flushb.c: Fix gcc -Wall nitpicks (indented cpp
+		directives)
+
+	* ext2_types.h.in, initialize.c: Fix gcc -Wall nitpicks 
+		(don't use #elsif)
+
+	* ismounted.c: Fix gcc -Wall nitpicks (Don't use exit as a goto label)
+
+	* llseek.c: Fix gcc -Wall nitpicks (don't use #elsif)
+
+	* lookup.c, read_bb.c: Fix gcc -Wall nitpicks (indent
+		non-traditional #pragma)
+
+	* test_io.c: Fix gcc -Wall nitpicks (const/unsigned type issues)
+
+2003-06-24    <tytso@snap.thunk.org>
+
+	* badblocks.c, ext2fs.h (ext2fs_u32_list_find,
+		ext2fs_u32_list_test, ext2fs_u32_list_del,
+		ext2fs_badblocks_list_del): Add functions to delete a
+		block from the badblocks list.
+	* tst_badblocks.c: Add test cases for ext2fs_badblocks_list_del().
+
+2003-05-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsectsize.c (ext2fs_get_device_sectsize): New function which
+		returns the hardware sector size (if it is available).
+
+2003-05-13  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c: Add #ifdef NO_IO_CACHE which disables all userspace
+		caching by the unix_io layer.  Not enabled, only for
+		debugging. 
+
+2003-05-05  Theodore Ts'o  <tytso@mit.edu>
+
+	* test_io.c: Pay attention to the environment variables
+		TEST_IO_LOGFILE, TEST_IO_FLAGS, and TEST_IO_BLOCK to
+		determine whether or not we should log io activity, and to
+		where.
+
+2003-05-03  Theodore Ts'o  <tytso@mit.edu>
+
+	* tst_badblocks.c (file_test): Use tmpfile() instead of mktemp().
+
+2003-04-29  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Allow windows code to get
+		the resize for filesystems that are in regular files.
+
+2003-04-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.33
+
+2003-04-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Use DYLD_LIBRAY_PATH so that "make check" works on
+		Darwin systems when building with shared libraries.
+
+2003-04-18  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c: Use __CYGWIN__ instead of CYGWIN.
+
+2003-04-17  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c: Add Cygwin/Windows version of ext2fs_get_device_size()
+
+2003-04-12  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c (raw_read_blk): Add Cygwin support (the Windows block
+		device only accepts sector aligned read requests.
+
+	* ismounted.c (check_mntent_file): Deal with OS's that don't
+		define MNTOPT_RO.
+
+	* imager.c: If the OS doesn't define ssize_t, typedef it to int.
+
+2003-04-11  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h (EXT2_FEATURE_RO_COMPAT_BTREE_DIR): Comment out unused
+		feature flag
+
+2003-03-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Use the compile_et --build-tree option.
+
+2003-03-14  Theodore Ts'o  <tytso@mit.edu>
+
+	* getsize.c: Add support for Apple Darwin's ioctl to get the hard
+		disk size.
+
+	* badblocks.c (ext2fs_u32_list_count), ext2fs.h: Add new function
+		which returns the number of entries in the list.
+
+2003-03-10  Theodore Ts'o  <tytso@mit.edu>
+
+	* fileio.c (ext2fs_file_lseek): Fix bug added when adding 64-bit
+		support; avoid null dereference when ret_pos is NULL.
+
+2003-03-06  Theodore Tso  <tytso@mit.edu>
+
+	* ext2_types.h.in: Don't redefine types if other e2fsprogs
+		*_types.h files have been included already.
+
+	* kernel-jbd.h: Use C99 variadic cpp macros if not using GCC.
+		(Older GCC's don't support the C99 variadic macros.)
+
+	* flushb.c (ext2fs_sync_device), 
+	ismounted.c (ext2fs_check_mount_point): Avoid GCC extension: 
+	#warning not supported by Solaris suncc
+
+	* ext2_ext_attr.h: Avoid GCC extension: 0 length arrays in
+		structure definition.  Not needed for now in 
+		ext2_ext_attr_entry.
+
+2003-01-25  Theodore Ts'o  <tytso@mit.edu>
+
+	* dirhash.c: Fix gcc -Wall nits.
+
+2003-01-22  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c (unix_write_blk): Fix up GCC -Wall nits.
+
+2003-01-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* fileio.c (ext2fs_file_read, ext2_file_lseek,
+		ext2_file_get_size): Add 64-bit support.
+
+	* ext2fs.h (EXT2_I_SIZE): Add macro which caluates a 64bit size
+		from i_size and i_size_high.
+
+2003-01-19  Theodore Ts'o  <tytso@mit.edu>
+
+	* initialize.c (ext2fs_initialize): If the user specifies a really
+		large number of inodes, then reduce the number of blocks
+		per group until we find a workable set of filesystem
+		parameters.
+
+	* ext2_err.et.in (EXT2_ET_TOO_MANY_INODES): Add new error code.
+
+2002-11-09  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.32
+
+2002-11-09  Theodore Ts'o  <tytso@mit.edu>
+
+	* unix_io.c (find_cached_block, reuse_cache, unix_read_blk, 
+		unix_write_blk): Optimize routines so that we don't end up
+		searching the cache twice when a block isn't in the
+		cache.  If reads are larger than READ_DIRECT_SIZE, don't
+		let them go through the cache.
+
+	* unix_io.c (find_cached_block): Fixed bug which caused some clean
+		blocks to be erroneously marked as dirty, so they would
+		get written back to the disk before they are evicted from
+		the cache.  Harmless, but it slows down e2fsck
+		significantly.
+
+2002-11-08  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.31
+
+2002-11-08    <tytso@snap.thunk.org>
+
+	* Makefile.in (check): Skip trying to compile test_byteswap
+		if --disable-byteswaap had been given to configure.
+
+2002-11-07    <tytso@snap.thunk.org>
+
+	* closefs.c (write_bgdesc, ext2fs_flush): Fix bug in meta_bg
+		support when the MASTER_SB_ONLY flag is set.  Some of
+		the descriptor blocks that should have been written out
+		were getting skipped.
+
+2002-10-31  Theodore Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.30
+
+2002-10-31  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h: Add support for a new inode flag, which is to be used
+		for indicating the top of directory hierarchies for the
+		Orlov block allocator.
+	
+	* ismounted.c (check_mntent, check_mntent_file): Add better
+		support for loopback-mounted filesystems.  Check /etc/mtab
+		if /proc/mounts doesn't turn up any mount flags, since
+		/etc/mtab has the loopback image filename, instead of
+		/dev/loop0.  Also, check based on st_dev and st_ino, so
+		that if a relative pathname or a pathnames using symbolic
+		links are used, we can detect the the filesystem correctly
+		in those cases.  (Addresses Sourceforge bug #619119)
+
+	* flushb.c (ext2fs_sync_device): If the BLKFLSBUF ioctl succeeds,
+		don't try the FDFLUSH ioctl that was required for floppies
+		with older kernels.  This avoids needless whining from the
+		MD device driver.  (Addresses Sourceforge bug #545832).
+
+	* openfs.c (ext2fs_open): Fix bug which caused us to pass the
+		wrong group_block to ext2fs_descriptor_block_loc if we're
+		using the backup superblock/block group descriptors.
+		(ext2fs_descriptor_block_loc): If we're using the backup
+		superblock descriptors, use the backup descriptor block in
+		the next block group.
+
+2002-10-30  Theodore Ts'o  <tytso@mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_group_table): Allocate the inode
+		table so that it buts up against the bitmap blocks, to
+		avoid block fragmentation.
+
+	* closefs.c (write_bgdesc), initalize.c (ext2fs_initialize): Fix
+		bug; only allocate group descriptor blocks up to
+		s_first_meta_bg.
+
+2002-10-25  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h: Add a new superblock field, s_mkfs_time, so that we
+		know when a filesystem was created.  (Sometimes this can
+		be useful...)
+
+	* initialize.c (ext2fs_initialize): Set the s_mkfs_time field.
+
+2002-10-20  Theodore Ts'o  <tytso@valinux.com>
+
+	* ext2_fs.h (EXT3_DEFM_JMODE): Add new default mount options for
+		the journal data mode.
+
+	* closefs.c (ext2fs_flush, write_bgdesc), ext2_fs.h, ext2fs.h,
+	openfs.c (ext2fs_descriptor_block_loc, ext2fs_open), initialize.c
+	(ext2fs_initialize), swapfs.c (ext2fs_swap_super): Add support for
+	the meta_blockgroup filesystem format.
+
+2002-10-15    <tytso@snap.thunk.org>
+
+	* ext2_fs.h: Add new field in superblock for default mount options.
+
+2002-10-13  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2fs.h: Add #include of header files necessary for ext2fs.h to
+		compile cleanly.
+
+2002-10-02  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* rw_bitmaps.c (ext2fs_write_block_bitmap,
+		ext2fs_read_block_bitmap): Don't set the CHANGED bit just
+		because the bitmap is getting written to disk.  Make
+		ext2fs_swap_bitmap be a static function, since it's not
+		intended to be exported.
+
+	* swapfs.c (ext2fs_swap_super): Byte-swap the hash seed
+
+2001-09-24  Theodore Tso  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.29
+
+2001-08-31  Theodore Tso  <tytso@thunk.org>
+
+	* Release of E2fsprogs 1.28
+
+2002-08-31  Theodore Ts'o  <tytso@valinux.com>
+
+	* dblist.c (ext2fs_dblist_sort): New function which allows the
+		caller to pass in a special sort comparison function.
+
+2002-08-20  Theodore Ts'o  <tytso@mit.edu>
+
+	* valid_blk.c (ext2fs_inode_has_valid_blocks): Fix bug which
+		failed to accurately characterize non-standard slow
+		symlinks.  (Which don't appear in practice on real-life
+		systems, fortunately.)
+
+2002-08-17  Theodore Ts'o  <tytso@mit.edu>
+
+	* Makefile.in: Remove inode_io.o from the standard object files,
+		and only build it if debugfs is enabled (it requires
+		fileio.o, which is only built if --disable-debugfs isn't
+		specified to configure).
+
+	* dirhash.c (ext2fs_dirhash): Change the MD4 hash in a backwards
+		incompatible way so that it is no longer
+		endian-dependent.  Add the TEA hash.  Allow the seed
+		parameter to be optional.
+
+	* ext2_fs.h: Remove the HALF_MD4_SEED and HALF_MD4_64 hashes.
+		These features are all now in the HALF_MD4 hash.  Add
+		definition for EXT2_HASH_TEA.
+
+	* ext2fs.h (ext2fs_dirhash): Change function prototype so it takes
+		a pointer instead of an array.
+
+2002-08-16  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_err.et.in (EXT2_ET_BAD_EA_BLOCK_NUM): New error code
+
+	* ext2fs.h (ext2fs_inode_data_blocks): New function which returns
+		the number of data blocks used by an inode exclusive of
+		the EA block.
+
+	* ext_attr.c (ext2fs_adjust_ea_refcount): New function which
+		adjusts the reference count in an extended attribute block.
+
+	* valid_blk.c (ext2fs_inode_has_valid_blocks): Add code to
+		correctly deal with extended attribute blocks in symbolic
+		links. 
+
+2002-08-13    <tytso@snap.thunk.org>
+
+	* Makefile.in: Move dupfs.o and test_io.o from the
+		needed-by-debugfs object list to the needed-by-resizer
+		object list.  Fixes compile problem if the system is built
+		with only --disable-debugfs.
+
+2002-07-29  Theodore Ts'o  <tytso@mit.edu>
+
+	* link.c (ext2fs_link): When adding a new link to a directory,
+		clear the HTREE bit.
+
+2002-07-23  Theodore Ts'o  <tytso@mit.edu>
+
+	* dirhash.c (ext2fs_dirhash): Fix bug which caused MD4
+		calculations for names > 32 characters to be completely
+		bogus.  Changed MD4 calculation to match what is currently
+		being used in the CVS gkernel tree.
+
+2002-07-19  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h: Add s_hash_seed and s_def_hash_version to the
+		superblock definition.
+
+	* badblocks.c, freefs.c, ext2fs.h: Use the badblocks functions to
+		create a set of u32_list functions.
+
+	* dirhash.c (halfMD4Transform): Shift the hash by one bit,
+		since that's required by the directory indexing code.
+
+2002-07-14  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2fs.h, read_bb_file.c: Change private to priv_data, to avoid
+		using a C++ reserved word.
+
+	* unix_io.c (unix_open): Only attempt the setrlimit workaround if
+		the kernel version is 2.4.10 -- 2.4.17, since otherwise an
+		old version of glibc (built against 2.2 headers) will
+		interact badly with the workaround to actually cause more
+		problems.  I hate it when the glibc folks think they're
+		being smarter than the kernel....
+
+2002-06-28  Andreas Dilger <adilger@clusterfs.com>
+
+	* ext2_fs.h: Add superblock field for reserved group descriptors.
+
+2002-06-28  Theodore Ts'o  <tytso@mit.edu>
+
+	* bitops.h: Add #define's for ext2fs_{l,b}e{32,16}_to_cpu and
+		ext2fs_cpu_to_{l,b}e{32,16}
+
+2002-06-27  Theodore Ts'o  <tytso@mit.edu>
+
+	* ismounted.c (check_mntent): In AIX 4.3, MOUNTED isn't defined.
+		Add appropriate fallbacks in this case.
+
+2002-06-26  Theodore Ts'o  <tytso@mit.edu>
+
+	* dirhash.c (ext2fs_dirhash): Change function signature to support
+		a hash seed, and to return the minor hash (for 64-bit hash
+		support).   Add support for the half MD4, half MD4 with
+		seed, and half MD4 with seed and 64 bits.
+
+2002-06-15  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_fs.h (EXT2_DIRSYNC_FL): Add new file.
+
+2002-06-09  Andreas Dilger <adilger@clusterfs.com>
+
+	* ext2_fs.h: Add macros for maximum block/inode counts:
+		EXT2_INODES_PER_BLOCK, EXT2_MAX_BLOCKS_PER_GROUP,
+		and EXT2_MAX_INODES_PER_GROUP.
+
+	* openfs.c (ext2fs_open): Check that the number of blocks in a group
+		is less than 2^16, otherwise we need an INCOMPAT flag (not
+		in existence yet, if ever) to open such a filesystem.
+
+	* initialize.c (ext2fs_initialize): Limit the number of blocks and
+		inodes in a group to less than 2^16.
+
+2002-06-09  Andreas Dilger <adilger@clusterfs.com>
+
+	* ext2_fs.h: Further minor cleanups of the header.  Consolidate
+		some checks for __KERNEL__ into one place.
+
+2002-05-22  Andreas Dilger <adilger@clusterfs.com>
+
+	* ext2_fs.h: Remove macros accessing u.ext2_sb field and use
+		the EXT2_SB() macro instead.  Remove kernel function
+		prototypes also.  This matches the 2.5 kernel, and
+		is also cleaner for other reasons.  Whitespace cleanup.
+
+2002-05-21  Theodore Ts'o  <tytso@mit.edu>
+
+	* ext2_ext_attr.h: Update to V2 version of the Bestbits format.
+
+2002-05-16  Andreas Dilger <adilger@clusterfs.com>
+
+	* ext2_fs.h: Change limits to support filesystems with 8k blocks.
+
+	* initialize.c (ext2fs_initialize): Remove assumption that
+		blocksizes are always <= 4k.
+
+2002-05-11  Theodore Ts'o  <tytso@mit.edu>
+
+	* bmap.c (ext2fs_bmap): Fix bug which caused ext2fs_bmap to fail
+		silently if inode pointer is NULL (and ext2fs_bmap is
+		expected to read the inode itself).
+
+2002-04-27  Theodore Ts'o  <tytso@mit.edu>
+
+	* ismounted.c (check_mntent_file, is_swap_device): Verify that the
+		file we are checking is a block device file before looking
+		at st_rdev, since it's not valid for normal files.
+		(is_swap_device): Move so that it is outside the
+		HAVE_MNTENT_H, so that it is always built.
+
+2002-03-11  Theodore Tso  <tytso@mit.edu>
+
+	* dirblock.c (ext2fs_read_dir_block2, ext2fs_write_dir_block): New
+		functions which take an extra flags argument.  The flag
+		EXT2_DIRBLOCK_V2_STRUCT will reverse when the name_len
+		field is byte swampped on big-endian machines, since in
+		the V2 structure, name_len is a char field which is
+		doesn't need to be byte swapped --- except if an
+		old-style kernel had byte-swapped the name_len field
+		as part of the V1 structure.
+
+	* ext2_err.et.in (EXT2_ET_DIRHASH_UNSUPP): New error code
+
+	* dirhash.c (ext2fs_dirhash): New function which calculates the
+		hash for a filename in an indexed directory.
+
+2002-03-08  Theodore Tso  <tytso@mit.edu>
+
+	* Release of E2fsprogs 1.27
+
+2002-03-07  Theodore Tso  <tytso@mit.edu>
+
+	* ext2fs.h (ext2fs_inode_io_intern): Add missing function prototype.
+
+	* bmap.c, fileio.c, inode_io.c, tst_badblocks.c, 
+		tst_byteswap.c: Fix gcc -Wall complaints
+
+	* Makefile.in (check): Use LD_LIBRARY_PATH to run test programs.
+		(From Philipp Thomas <pthomas@suse.de>)
+
+2002-02-25  Theodore Tso  <tytso@mit.edu>
+
+	* ext2_fs.h: Add structure definitions for the directory indexing
+		extension.
+
+2002-02-23  Theodore Tso  <tytso@mit.edu>
+
+	* unix_io.c (unix_open): Fix 2.4 resource limit workaround so that
+		it doesn't break things on mis32, sparc32, and alpha
+		platforms.
+
+2002-02-21  Theodore Tso  <tytso@mit.edu>
+
+	* ismounted.c (is_swap_device): Fix file descriptor/memory leak;
+		we were missing an fclose().
+
+2002-02-20  Theodore Tso  <tytso@mit.edu>
+
+	* Makefile.in, inode_io.c, ext2fs.h, ext2_err.et.in: Add new io
+		abstraction interface which exports an ext2 inode.
+
+	* ext2fs.h, fileio.c (ext2fs_file_flush): Export ext2fs_file_flush
+		as a public interface.  Change void * to const void * in
+		ext2fs_file_write's interface.
+
+	* test_io.c (test_close), unix_io.c (unix_close): Remove unneeded
+		conditional; save a few bytes.
+	
+2002-02-12  Theodore Tso  <tytso@mit.edu>
+
+	* Makefile.in (tst_badblocks): Add some extra .o files when
+		linking the debugging program tst_badblocks which are
+		needed if we aren't compiling with inline functions enable.
+
+	* kernel-list.h (__inline__): On non-gcc and non-Watcom compilers,
+		define away __inline__ since it may not be supported.
+
+	* kernel-jbd.h (jbd_debug): For systems that don't do STDC, use a
+		stripped down jbd_debug that doesn't use variadic
+		arguments.  This will cause warnings under AIX, but things
+		should still build.
+
+2002-02-03  Theodore Tso  <tytso@thunk.org>
+
+	* Release of E2fsprogs 1.26
+
+2002-02-03  Theodore Tso  <tytso@mit.edu>
+
+	* mkdir.c (ext2fs_mkdir): Change to use ext2fs_inode_alloc_stats2
+		so that the number of directories in use is adjusted
+		appropriately.
+
+	* alloc_stats.c (ext2fs_inode_alloc_stats2): Add new function
+		which optionally will modify the number of directories
+		count.
+
+2002-01-03  Theodore Tso  <tytso@mit.edu>
+
+	* dir_iterate.c (ext2fs_dir_iterate2, ext2fs_process_dir_block):
+		Add support for a new flag, DIRENT_FLAG_INCLUDE_REMOVED,
+		which will return deleted directory entries.
+		ext2fs_dir_iterate2 takes a new callback function which
+		is identical with the one used by
+		ext2fs_dblist_dir_iterate().  If the directory entry is
+		deleted, the callback function will be called with the
+		entry paraemter set to DIRENT_DELETED_FILE.
+
+	* Makefile.in, alloc_stats.c (ext2fs_inode_alloc_stats,
+		ext2fs_block_alloc_stats): New functions which update
+		block/inode allocation statistics in the bitmaps, block
+		group descriptors, and superblock.
+
+	* mkjournal.c (mkjournal_proc), mkdir.c (ext2fs_mkdir),
+		expanddir.c (expand_dir_proc), bb_inode.c
+		(clear_bad_block_proc, set_bad_block_proc,
+		ext2fs_update_bb_inode), alloc.c (ext2fs_alloc_block):
+		Update to use new block/inode allocation statistics.
+
+2001-12-24  Theodore Tso  <tytso@mit.edu>
+
+	* ismounted.c (is_swap_device): New function used by
+		ext2fs_check_if_mounted and ext2fs_check_mount_point which
+		determines whether or not the specified device is a swap
+		device by using /proc/swaps.  More bulletproofing for
+		idiotic/careless system administrators!
+
+	* ext2fs.h, openfs.c (ext2fs_open), initialize.c
+		(ext2fs_initialize), mkdir.c (ext2fs_mkdir): Add a new
+		field to struct_ext2_filsys, umask.  This field is
+		initialize to 022, and affects ext2fs_mkdir in the obvious
+		way.  (In the future umask should also affect new file
+		creation routines, but the fileio functions don't
+		currently support this yes.)
+
+	* ismounted.c (check_mntent_file): Stat all of the entries in
+		/etc/mtab and/or /proc/mounts in order to catch dim-witted
+		system administrators who might have created alias
+		devices.
+ 
+2001-12-23  Theodore Tso  <tytso@mit.edu>
+
+	* Makefile.in, jfs_user.h: Move linux/jbd.h to
+		ext2fs/kernel-jbd.h, to avoid using the system header
+		file version of hbd.h when using diet glibc (since it
+		forcibly adds /usr/include to the beginning of the
+		include search path.)
+
+	* kernel-jbd.h, kernel-list.h, jfs_compat.h: Move files from
+		include/linux directory.
+
+2001-12-16  Theodore Tso  <tytso@mit.edu>
+
+	* bitops.h (ext2fs_mark_generic_bitmap, ext2fs_unmark_generic_bitmap),
+		ext_attr.c (ext2fs_read_ext_attr, ext2fs_write_ext_attr),
+		fileio.c (ext2fs_file_write): Fix gcc -Wall nits
+
+	* Makefile.in, jfs_user.h: linux/jfs.h has been renamed to
+		linux/jbd.h
+
+2001-12-03  Theodore Tso  <tytso@mit.edu>
+
+	* unix_io.c (unix_open): Make sure the ulimit workaround works
+		regardless of the version of glibc which is used to
+		compild e2fsprogs.
+
+2001-11-26  Theodore Tso  <tytso@mit.edu>
+
+	* unix_io.c (unix_open): Work around a bug in 2.4.10+ kernels by
+		trying to unset the filesize limit if at all possible,
+		if a block device is getting opened.  (The filesize limit
+		shouldn't be applied against writes to a block device, but
+		starting in 2.4.10, the kernel is doing this.)
+	
+2001-11-05  Theodore Tso  <tytso@mit.edu>
+
+	* mkjournal.c (ext2fs_add_journal_inode): When creating a .journal
+		file on adding a journal to an already-mounted filesystem,
+		try to clear the ext2 file attributes on an already
+		existing .journal file so that we don't fail if on a
+		partially added journal to the filesystem.
+
+	* ext2_fs.h: Define a new ext2 file attribute, EXT2_NOTAIL_FL,
+		which signals that a particular inode should not have the
+		last bits of data (the "tail") be merged with another
+		file.  This is necessary to keep LILO happy.
+
+2001-09-20  Theodore Tso  <tytso@thunk.org>
+
+	* Release of E2fsprogs 1.25
+
+2001-09-16  Theodore Tso  <tytso@mit.edu>
+
+	* ext2_ext_attr.h: Remove unneeded #include of <linux/config.h>
+		which was breaking the build on the Hurd.  (Addresses
+		Debian bug #112414).
+
+2001-09-13  Theodore Ts'o  <tytso@mit.edu>
+
+	* ismounted.c (check_mntent_file): We now validate the entry in
+		/etc/mtab to make sure the filesystem is really mounted,
+		since some broken distributions (read: Slackware) have
+		buggy boot scripts that don't initialize /etc/mtab before
+		checking non-root filesystems.  (Slackware also doesn't
+		check the root filesystem separately, and reboot if the
+		root filesystem had changes applied to it, which is
+		dangerous and broken.)   
+
+2001-09-02  Theodore Tso  <tytso@thunk.org>
+
+	* Release of E2fsprogs 1.24a
+
+2001-08-30  Theodore Tso  <tytso@thunk.org>
+
+	* Release of E2fsprogs 1.24
+
+2001-08-30  Theodore Tso  <tytso@valinux.com>
+
+	* getsize.c (ext2fs_get_device_size): Back out BLKGETSIZE64
+		changes, since the ioctl number has been reused by another
+		unofficial patch.
+
+2001-08-15  Theodore Tso  <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.23
+
+2001-08-05  Theodore Tso  <tytso@valinux.com>
+
+	* alloc.c (ext2fs_new_inode, ext2fs_new_block): Use the fast
+		version of the bitmap test routines to speed up these
+		routines.  (At some point I may want to make these
+		routines use the find_first_bit functions, but that will
+		add a lot of complexity since it means that these
+		functions will have to break the bitmap abstraction
+		boundary.  It's not clear it's worth it.)
+
+	* mkjournal.c (mkjournal_proc): Remember the last block allocated
+		to speed up ext2fs_new_block().
+
+2001-07-29  Theodore Tso  <tytso@valinux.com>
+
+	* finddev.c (scan_dir): Fix memory leak; we weren't calling
+		closedir() when exiting the function in all cases.
+
+2001-07-27  Theodore Tso  <tytso@valinux.com>
+
+	* mkjournal.c (ext2fs_create_journal_superblock): Set the first
+		block usable in the journal for external journals to be 2
+		or 3, depending on the blocksize, so that the existing
+		kernel code does the right thing.
+
+	* getsize.c (ext2fs_get_device_size): Add support for the
+		BLKGETSIZE64 ioctl.  (Ioctl defined by unofficial patches
+		from Ben LaHaise, but it's likely this interface won't
+		change.)
+
+	* mkjournal.c (ext2fs_add_journal_device): Use the correct block
+		when writing the journal superblock, too.  (Oops! Needed
+		to make 1k filesystems with external journal to work.)
+
+2001-07-26  Theodore Tso  <tytso@valinux.com>
+
+	* mkjournal.c (ext2fs_add_journal_device): Use the correct block
+		to find the journal superblock if the blocksize is 1024.
+
+2001-07-21  Theodore Tso  <tytso@valinux.com>
+
+	* ext2_err.et.in (EXT2_ET_LOAD_EXT_JOURNAL): Add new error code
+
+2001-07-20  Theodore Tso  <tytso@valinux.com>
+
+	* ext_attr.c (ext2fs_write_ext_attr): When writing the extended
+		attribute block, set the filesystem changed bit.
+
+	* bitops.h (ext2fs_find_first_bit_set, ext2fs_find_next_bit_set):
+		Comment out these functions since we're not using them.
+
+2001-07-10  Theodore Tso  <tytso@valinux.com>
+
+	* closefs.c (write_primary_superblock): After writing changes to
+		the primary superblock, update the original superblock
+		copy so we don't have to re-write those changes in the
+		future.
+		(ext2fs_flush): Clear the superblock dirty flag after
+		we've flushed out changes to disk.
+
+2001-07-07  Theodore Tso  <tytso@valinux.com>
+
+	* bitops.h (ext2fs_find_first_bit_set): Use %esi instead of %ebx
+		to avoid register conflicts when compiling in PIC mode.
+
+2001-07-04  Theodore Tso  <tytso@valinux.com>
+
+	* bitops.h (ext2fs_find_first_bit_set, ext2fs_find_next_bit_set):
+		Add new functions (C and in i386 assembler) which quickly
+		find bits set in a bitmask.
+
+2001-06-23  Theodore Tso  <tytso@valinux.com>
+
+	* Makefile.in, ext_attr.c, ext2_attr.c, ext2fs.h: Add new files
+		ext2_ext_attr.h and ext_attr.c for extended attributes
+		support.
+
+	* Release of E2fsprogs 1.22
+
+2001-06-22  Theodore Tso  <tytso@valinux.com>
+
+	* mkjournal.c (ext2fs_add_journal_inode): Move close of file
+		descriptor so that adding a journal to a mounted
+		filesystem doesn't die.  (Fixes a bug accidentally
+		introduced in e2fsprogs 1.21.)
+
+	* mkjournal.c (ext2fs_add_journal_inode): Only use fchflags if
+		HAVE_CHFLAGS and UF_NODUMP are defined, since the Hurd has
+		fchflags without defining UF_NODUMP.  (Addresses Debian
+		bug #101361)
+
+	* flushb.c: Use platform independent method of defining the
+		BLKFLSBUF and FDFLUSH ioctl's.  Also include sys/mount.h
+		since on newer glibc's BLKFLSBUF is defined there.
+
+	* bitops.h: The C language versions of ext2fs_swab16/32 need to be
+		included if EXT2FS_ENABLE_SWAPFS is defined, since we need
+		to support byte swapping even if we don't support the
+		conversion functions.  (Fixes Debian bug #101686).
+
+	* dirblock.c (ext2fs_read_dir_block): Remove use of dir_entry_2
+		since the byte-swapping code all assumes the
+		ext2_dir_entry structure.  (It's a question of whether or
+		not name_len should be byte-swapped or not, and whether
+		it's a 16 bit or 8 bit field.)
+
+2001-06-15  Theodore Tso  <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.21
+
+2001-06-15  Theodore Tso  <tytso@valinux.com>
+
+	* Makefile.in: Fix bug in installation of ext2_types.h.  It is a
+		file which is generated and is therefore found in the
+		build directory, not source directory.
+
+	* ismounted.c (check_mntent_file): Use a test file in / to check
+		to see if the root filesystem is mounted read-only.  This
+		protects against the case where /etc might not be on /, as
+		well as the case where /etc/mtab doesn't exist.  (Both are
+		should-never happen scenarios, but you never know...)
+
+2001-06-14  Theodore Tso  <tytso@valinux.com>
+
+	* ismounted.c (ext2fs_check_if_mounted): Fix grammer in comment.
+		Remove unneeded #pragma argsused, since the arguments are
+		always used.
+
+2001-06-13  Theodore Tso  <tytso@valinux.com>
+
+	* ext2_types.h.in: If linux/types.h has been defined, then don't
+		try to redefine the typedefs.
+
+	* Makefile.in (HFILES): Add ext2_types.h to the list of files
+		which should be installed.
+
+	* ismounted.c (check_mntent_file): Work around GNU hurd brain
+		damage.  Addresses Debian bug #100304.
+
+	* Makefile.in: Limit some .o files from being included into the
+		library if --disable-debugfs, --disable-swapfs,
+		--disable-imager, or --disable-resizer are used.
+
+2001-06-12  Theodore Tso  <tytso@valinux.com>
+
+	* inode.c, tst_iscan.c: Stop using the compatibility badblocks
+		function, and use the ext2fs_badblocks_* functions
+		instead.
+
+2001-06-11  Theodore Tso  <tytso@valinux.com>
+
+	* Makefile.in, gen_bitmap.c, bitops.h: Move inline functions
+		ext2fs_mark_generic_bitmap and
+		ext2fs_unmark_generic_bitmap to gen_bitmap.c as normal
+		functions.  (This saves space and doesn't significantly
+		change the speed of e2fsck on a P-III.)
+
+	* ext2fs.h, bitops.h, block.c, bmap.c, closefs.c, dirblock.c,
+		inode.c, native.c, openfs.c, rw_bitmaps.c, swapfs.c: Only
+		include the byte-swapping logic if ENABLE_SWAPFS is turned
+		on or if we're on a big-endian machine.
+	
+	* initialize.c (ext2fs_initialize):Use WORDS_BIGENDIAN directly to
+		set EXT2_FLAG_SWAP_BYTES, instead of using
+		ext2fs_native_flag.
+	
+	* native.c (ext2fs_native_flag): Use WORDS_BIGENDIAN provided by
+		autoconf to determine whether or not return
+		EXT2_FLAG_SWAP_BYTES.
+
+2001-06-10  Theodore Tso  <tytso@valinux.com>
+
+	* Makefile.in: Remove the dependence on the libe2p library.
+
+	* mkjournal.c (ext2fs_add_journal_inode): Replace use of fsetflags
+		with direct usage of the ioctl/fchflags so that we don't
+		have to depend on the libe2p library.
+
+2001-06-08  Theodore Tso  <tytso@valinux.com>
+
+	* ext2_types.h.in: Use unsigned ints in favor of unsigned longs
+		when trying to find a 32-bit wide type.
+
+	* icount.c (insert_icount_el): Fix the code used to estimate the
+		size of the new icount array to be more intelligent, to
+		avoid reallocating the array too many times.  Thanks to
+		Enrique Perez-Terron for pointing this out.
+
+2001-06-02  Theodore Tso  <tytso@valinux.com>
+
+	* valid_blk.c (ext2fs_inode_has_valid_blocks): Only check i_blocks
+		for a symlink to determine whether it is a fast symlink.
+
+2001-06-01  Theodore Tso  <tytso@valinux.com>
+
+	* Makefile.in, dosio.c, ext2_fs.h, ext2_types.h.in, ext2fs.h:
+		Move include/asm/types.h.in to lib/ext2fs/ext2_types.h.in.
+
+2001-05-25  Theodore Tso  <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.20
+
+2001-05-25  Theodore Tso  <tytso@valinux.com>
+
+	* ismounted.c: More cleanups for ismounted.c, some from Andreas,
+		some to clean up Andreas's patches.  Use strncpy instead
+		of strcpy to save the root's mountpoint.  Clean up #ifdef
+		structure.  Remove uneeded variable in testing/debug driver.
+
+2001-05-24  Andreas Dilger  <adilger@turbolinux.com>
+
+	* ismounted.c: Add check for root device which doesn't depend on
+		/etc/fstab or /proc/mounts to be correct.  Don't call
+		endmntent() before we are done with mnt struct.
+
+2001-05-23  Theodore Tso  <tytso@valinux.com>
+
+	* ext2_err.et.in (EXT2_ET_JOURNAL_UNSUPP_VERSION): Added new error
+		code.
+
+2001-05-21  Theodore Tso  <tytso@valinux.com>
+
+	* ext2_fs.h: Change assignment of EXT2_FEATURE_COMPAT_DIR_INDEX to
+		make room for pre-existing usage of
+		EXT2_FEATURE_COMPAT_EXT_ATTR.  Add flag EXT2_INDEX_FL with
+		the same codepoint as EXT2_BTREE_FL.
+
+2001-05-20  Theodore Tso  <tytso@valinux.com>
+
+	* ext2fs.h: #include <> instead of "" for ext2fs and et header
+		files, since they will be installed in /usr/include
+
+2001-05-14  Theodore Tso  <tytso@valinux.com>
+
+	* alloc.c, alloc_tables.c, badblocks.c, bb_compat.c, bb_inode.c,
+		bitmaps.c, bitops.c, block.c, bmap.c, bmove.c, brel_ma.c,
+		check_desc.c, closefs.c, cmp_bitmaps.c, dblist.c,
+		dblist_dir.c, dir_iterate.c, dirblock.c, dupfs.c,
+		expanddir.c, ext2_fs.h, fileio.c, finddev.c, flushb.c,
+		freefs.c, get_pathname.c, getsize.c, icount.c, imager.c,
+		initialize.c, inline.c, inode.c, irel_ma.c, ismounted.c,
+		link.c, lookup.c, mkdir.c, mkjournal.c, namei.c, native.c,
+		newdir.c, nt_io.c, openfs.c, read_bb.c, read_bb_file.c,
+		rs_bitmap.c, rw_bitmaps.c, swapfs.c, test_io.c,
+		tst_badblocks.c, tst_byteswap.c, tst_getsize.c,
+		tst_iscan.c, unix_io.c, unlink.c, valid_blk.c, version.c,
+		write_bb_file.c, ext2_fs.h: Moved file from include/linux.
+		Adjust all files in this directroy to include this file.
+
+	* mkjournal.c (ext2fs_create_journal_superblock): Remove redundant
+		code.
+
+2001-05-05  Theodore Tso  <tytso@valinux.com>
+
+	* fileio.c (ext2fs_file_read): Factored out common code and
+		cleaned up function.  Fixed a bug where if there was an
+		error reading from the disk, the number of bytes read
+		wasn't reliably set.  (Fixes Debian bug #79163)
+		(ext2fs_file_write): Factored out common code and made
+		function more efficient; if writing a full block, don't
+		bother to do a read-modify-write cycle.
+
+2001-05-04  Theodore Tso  <tytso@valinux.com>
+
+	* dirblock.c (ext2fs_read_dir_block): Check for an directory
+		record length which isn't a multiple four, and treat that
+		as an invalid.  Scan the directory and return an error
+		(EXT2_ET_DIR_CORRUPTED) if the directory records are
+		corrupted.
+		(ext2fs_write_dir_block): If while byte-swapping the
+		directory block, if there's an error, abort and return
+		EXT2_ET_DIR_CORRUPTED.
+
+2001-05-02  Theodore Tso  <tytso@valinux.com>
+
+	* ext2fs.h (EXT2_FLAG_IMAGE_FILE): Add new flag, and add
+		image_header field in the ext2_filsys structure
+
+	* block.c (block_iterate_ind, block_iterate_dind, block_iterate_tind): 
+	* inode.c (ext2fs_read_inode): 
+	* rw_bitmaps.c (read_bitmaps): 
+	* openfs.c (ext2fs_open): Add support for EXT2_FLAG_IMAGE_FILE
+
+	* imager.c (ext2fs_image_bitmap_read): Fix bug in imager to make
+		sure the full bitmap is saved.
+
+2001-05-01  Theodore Tso  <tytso@valinux.com>
+
+	* e2image.h (struct ext2_image_hdr): Add space for the device name
+		in the image header.
+
+	* dir_iterate.c (ext2fs_process_dir_block): Add a double-check to
+		make sure the rec_len is a multiple of 4, to prevent
+		bus-errors on architectures which care about mis-aligned
+		pointer references.
+
+2001-04-25  Theodore Tso  <tytso@valinux.com>
+
+	* getsize.c (ext2fs_get_device_size): Use an unsigned long to
+		query the device sizes using the BLKGETSIZE ioctl.
+
+2001-04-16  Theodore Tso  <tytso@valinux.com>
+
+	* ismounted.c (check_mntent): Check /proc/mounts on Linux systems
+		before checking /etc/mtab.  The EXT2_MF_READONLY flag is
+		now set from the /etc/mtab options field for all
+		filesystems, not just the root filesystem.  Add debugging
+		code to make it easier to test ext2fs_check_if_mounted().
+
+	* mkjournal.c (ext2fs_create_journal_superblock): Add safety
+		check; return an error if there's an attempt to create a
+		journal less than 1024 filesystem blocks.
+
+	* ext2_err.et.in, mkjournal.c: Change EXT2_JOURNAL_NOT_BLOCK and
+		EXT2_NO_JOURNAL_SB to be EXT2_ET_*.
+
+2001-02-20  Theodore Tso  <tytso@valinux.com>
+
+	* bitops.h (ext2fs_swab16, ext2fs_swab32): Add i386 assembly
+		inline functions.
+
+	* tst_byteswap.c: New function to test the byteswap functions.
+		Add to regression test suite.
+
+2001-02-08  Theodore Tso  <tytso@valinux.com>
+
+	* e2image.h (struct ext2_image_hdr): Fix type for fs_hostname
+
+2001-02-07  Theodore Tso  <tytso@valinux.com>
+
+	* mkjournal.c (ext2fs_create_journal_superblock): Fix the setting
+		of s_first for external devices to always be 1, since
+		jsb->s_first is always relative to the start of the
+		journal superblock.  Use htonl(1) when setting s_nr_users.
+
+2001-01-17  Theodore Ts'o  <tytso@valinux.com>
+
+	* mkjournal.c (ext2fs_add_journal_device): Fix bug where the
+		device number of the filesystem (instead of the journal)
+		was being dropped into s_journal_dev.
+
+2001-01-15  Theodore Ts'o  <tytso@valinux.com>
+
+	* initialize.c (ext2fs_initialize): Add support for initializing
+		the ext2 superblock for external journal devices.  This
+		basically means we don't bother to allocate any block
+		group descriptors.
+
+	* openfs.c (ext2fs_open): Only open external journal devices if
+		the new flag EXT2_FLAG_JOURNAL_DEV_OK is passed to
+		ext2fs_open.  When opening such devices, don't try to read
+		the block group descriptors, since they're not there.
+
+	* ext2_err.et.in (EXT2_NO_JOURNAL_SB): Add new error code 
+	
+	* mkjournal.c: Export a new function,
+		ext2fs_create_journal_superblock(), which allocates and
+		returns a buffer containing a journal superblock.  This is
+		needed by mke2fs to create an external journal.  Rewrote
+		ext2fs_add_journal_device() so that it no longer creates
+		the external journal, but rather adds a filesystem to an
+		existing external journal.  It handles all of the UUID
+		manipulation.
+
+	* ext2fs.h: List the EXT3_FEATURE_JOURNAL_DEV as a flag supported
+		by the library.  Define the EXT2_FLAG_JOURNAL_DEV_OK.
+		Changed function prototype for ext2fs_add_journal_device().
+		
+2001-01-14  Theodore Ts'o  <tytso@valinux.com>
+
+	* closefs.c (ext2fs_flush): Don't write out anything beyond the
+		 primary superblock if EXT2_INCOMPAT_JOURNAL_DEV is
+		 listed.
+
+2001-01-12  Theodore Ts'o  <tytso@valinux.com>
+
+	* imager.c: Fix gcc -Wall complaints and a series of bugs where
+		retval wasn't set correctly.  (Thanks to Andreas Dilger
+		for pointing this out.)
+
+2001-01-11    <tytso@snap.thunk.org>
+
+	* flushb.c (ext2fs_sync_device): New function which centralizes
+		all of the places which might try to use the BLKFLSBUF
+		or FDFLUSH ioctls (and usually failing to define them
+		since the system header files don't usually do this for
+		us, and we're trying to avoid usage of kernel include
+		files now).
+
+2001-01-10    <tytso@snap.thunk.org>
+
+	* alloc.c, bb_inode.c, bitmaps.c, bitops.h, block.c, bmap.c, 
+		bmove.c, brel.h, cmp_bitmaps.c, dblist.c, dblist_dir.c, 
+		dir_iterate.c, expanddir.c, ext2fs.h, ext2fsP.h, fileio.c,
+		finddev.c, get_pathname.c, icount.c, inode.c, irel.h, 
+		irel_ma.c, ismounted.c, link.c, lookup.c, mkdir.c, 
+		mkjournal.c, namei.c, newdir.c, read_bb_file.c, test_io.c,
+		tst_iscan.c, unix_io.c, unlink.c: Change use of ino_t to
+		ext2_ino_t, to protect applications that attempt to
+		compile -D_FILE_OFFSET_BITS=64, since this inexplicably
+		changes ino_t(!?).  So we use ext2_ino_t  to avoid an
+		unexpected ABI change.
+
+2001-01-05    <tytso@snap.thunk.org>
+
+	* dirblock.c (ext2fs_read_dir_block): Fix a potential case where
+		we may overrun allocated memory in case of a corrupted
+		filesystem (or an e2fsck test case :-) when byte-swapping
+		the directory block.
+
+	* ext2fs.h: Indent the #warning to fix gcc -Wall complaint.
+
+	* mkjournal.c (ext2fs_add_journal_device): Fix various gcc -Wall
+		complaints including a missing return 0 at the end of
+		ext2fs_add_journal_device.
+
+2001-01-03    <tytso@snap.thunk.org>
+
+	* Makefile.in: Link in libe2p when creating libext2fs as a shared
+		library, since mkjournal.c now references fsetflags().
+
+	* mkjournal.c (ext2fs_add_journal_inode): Folded in Andreas
+		Dilger's changes (with fixups) to allow on-line creation
+		of a journal file.
+
+	* ext2fs.h, closefs.c (ext2fs_flush): Add new flag,
+		EXT2_FLAG_SUPER_ONLY, which the close routines to only
+		update the superblock, and not the group descriptors.
+
+2000-12-30  Andreas Dilger  <adilger@turbolinux.com>
+
+	* ismounted.c: add ext2fs_check_mount_point() function, which will
+		optionally return the mount point of a device if mounted
+
+2000-12-14  Andreas Dilger  <adilger@turbolinux.com>
+
+	* mkjournal.c: rename ext2fs_add_journal_fs() to the more descriptive
+		ext2fs_add_journal_inode()
+
+2001-01-01    <tytso@snap.thunk.org>
+
+	* ext2fs.h: Remove definition of ext2fs_sb.  Note: this may break
+		source (but not binary) compatibility of some users of the
+		ext2 library.  They should just simply do a global search
+		and replace of struct ext2fs_sb with struct
+		ext2_super_block, and use their own private copy of
+		ext2_fs.h if they aren't already.
+
+	* closefs.c, initialize.c, link.c, newdir.c, openfs.c, swapfs.c:
+		Replace use of ext2fs_sb with ext2_super_block.
+
+2000-12-31    <tytso@snap.thunk.org>
+
+	* ext2fs.h: Cleaned up header file by removing definitions of
+		feature flags that might not have been defined in older
+		ext2 header files.  Now that we're using our own
+		include/linux/ext2fs.h header file, this can never happen.
+
+	* jfs_dat.h: Removed old header file which is no longer needed.
+
+2000-12-13  Theodore Ts'o  <tytso@valinux.com>
+
+	* closefs.c (ext2fs_update_dynamic_rev): New function suggested
+		by Andreas Dilger to update the filesystem revision to
+		EXT2_DYNAMIC_REV.
+
+	* swapfs.c (ext2fs_swap_super): Add byte swapping for the journal
+		fields.
+
+2000-12-09    <tytso@snap.thunk.org>
+
+	* ext2fs.h, mkjournal.c (ext2fs_add_journal_inode,
+		ext2fs_add_journal_device): Add a new argument to the APIs
+		of these function, which is a flags word.  This is used to
+		allow the creation of a V1 superblock for those folks who
+		are using ext3 0.3b in production.  Note, the user-land
+		interface for getting at this flag won't be documented, as
+		the V1 superblock is deprecated.
+
+	* mkjournal.c (init_journal_superblock): Sync Stephen's changes
+		which creates a V2 superblock instead of a V1 superblock.
+
+2000-11-21    <tytso@snap.thunk.org>
+
+	* test_io.c (test_write_blk, test_write_byte): Fix typos pointed
+		out by Andreas Dilger.
+
+2000-11-05    <tytso@snap.thunk.org>
+
+	* imager.c (ext2fs_image_{inode,super,bitmap}_{read,write},
+		ext2_fs.h, Makefile.in: New file that has routines that
+		save ext2fs metadata to a file.
+
+	* ext2_err.et.in (EXT2_ET_MAGIC_E2IMAGE): New error code assigned.
+
+	* e2image.h: New file which defines the file format for the ext2
+		image file.  (Saved copy of ext2 metadata to a file as a
+		saving throw against worst-case damage.)
+
+2000-11-01    <tytso@snap.thunk.org>
+
+	* inode.c (ext2fs_flush_icache): Add new function
+		ext2fs_flush_icache() which flushes the internal inode
+		cache.  Applications which modify the inode table blocks
+		directly must call this function.
+
+2000-10-26    <tytso@snap.thunk.org>
+
+	* mkjournal.c: Add #include of netinet/in.h, since Solaris
+		requires it for ntohl().
+
+	* ext2_io.h (io_channel_write_byte): Add new interface to allow
+		callers to write specific byte ranges.  This is an
+		optional interface, which not all IO channels may
+		implement.
+
+	* unix_io.c (unix_write_byte):
+	* test_io.c (test_write_byte): Add implementation of the
+		write_byte function.
+
+	* closefs.c (write_primary_superblock, ext2fs_flush): Add a new
+		function which writes the primary superblock.  If the IO
+		channel supports writing raw bytes directly, only fields
+		which were modified are written to the disk.  This makes
+		it safe(r) to use utilities like tune2fs on a mounted
+		filesystem. 
+
+	* freefs.c (ext2fs_free): Free the original superblock if it is
+		available. 
+
+	* openfs.c (ext2fs_open): Store a copy of the original superblock
+		when opening it.
+
+	* ext2fs.h: Add a field to store the original superblock in the
+		ext2 context structure.
+
+2000-10-24    <tytso@snap.thunk.org>
+
+	* llseek.c: Add #ifdef's for IA64 (it's a 64-bit platform, so we
+		don't need to use llseek).
+
+2000-10-24    <tytso@valinux.com>
+
+	* Makefile.in, ext2fs.h, jfs_dat.h, mkjournal.c: Add functions for
+		creating an ext3 journal on a filesystem.
+
+2000-08-21    <tytso@valinux.com>
+
+	* ext2_err.et.in (EXT2_JOURNAL_NOT_BLOCK): Add new error code.
+
+2000-08-22    <tytso@valinux.com>
+
+	* unix_io.c: Make massive changes to support a multiple block
+		writethrough cacheing.
+
+	* ext2_io.h: Added flags field to the io_channel structure.
+
+2000-08-19    <tytso@valinux.com>
+
+	* finddev.c, ext2fs.h, Makefile.in: Add new file, finddev.c, which
+		provides the function ext2fs_find_block_device().  This
+		function returns the pathname to a block device, given its
+		device number.
+
+2000-07-13    <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.19
+
+2000-07-07  Theodore Ts'o  <tytso@valinux.com>
+
+	* ext2fs.h (EXT2_LIB_FEATURE_INCOMPAT_SUPP): Add
+		EXT3_FEATURE_INCOMPAT_RECOVER (aka needs_recovery) to the
+		list of filesystem flags supported by the library.
+
+2000-07-04  Theodore Ts'o  <tytso@valinux.com>
+
+	* ext2fs.h: Update to include latest journalling additions to the
+		superblock.
+
+	* dll/jump.funcs: Add new jumptable entries for
+		ext2fs_write_bb_FILE, ext2fs_read_bb_FILE2, and
+		ext2fs_badblocks_equal.
+
+	* tst_badblocks.c: Update test program to test
+		ext2fs_read_bb_FILE2 and ext2fs_write_FILE.
+
+	* write_bb_file.c (ext2fs_write_bb_FILE): New function which
+		writes out bad blocks list to a file.
+
+	* read_bb_file.c (ext2fs_read_bb_FILE2): Add new function which
+		changes the callback function to take two additional
+		arguments; a private blind pointer supplied by the caller,
+		and pointer to a char * containing a pointer to the
+		invalid string.
+
+	* badblocks.c (ext2fs_badblocks_equal): Add new function which
+		returns true if two badblocks list are equal.
+
+	* Makefile.in: Remove explicit link of -lc in the shared library.
+		(It shouldn't be necessary, and is harmful in some cases).
+
+2000-06-10  Theodore Ts'o  <tytso@valinux.com>
+
+	* getsize.c (main): Add debugging code under #ifdef DEBUG
+
+2000-05-27  Theodore Ts'o  <tytso@valinux.com>
+
+	* mkdir.c (ext2fs_mkdir): Read the parent directory's inode
+		earlier, so that if there's an error reading it, we can
+		more cleanly back out of the operation.
+
+2000-05-25    <tytso@snap.thunk.org>
+
+	* getsize.c (ext2fs_get_device_size): Use open64() instead of
+		open() if it exists.  Under linux, manually define the
+		ioctl for BLKGETSIZE if it isn't already defined and it's
+		safe to do so.
+
+	* unix_io.c (unix_open): Use open64() instead of open() if it
+		exists. 
+
+	* llseek.c: Simplify header includes of unistd.h.  If lseek64 is
+		available (and prototypes are defined) use it in
+		preference to llseek.
+
+	* Makefile: Add hack dependency rule so that parallel makes work
+		correctly. 
+
+2000-05-18  Theodore Ts'o  <tytso@valinux.com>
+
+	* ext2fs.h: Add appropriate ifdef's to support C++ compilation.
+
+2000-04-03  Theodore Ts'o  <tytso@valinux.com>
+
+	* block.c: Readibility tweak in conditionals involving
+		ctx->fs->flags.
+
+	* ext2fs.h: Use AUTOCONF SIZEOF_* macros if available to determine
+		how to define __s64 and __u64.  Turn off "compression is
+		experimental" warning if the cpp macro
+		I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL is defined.
+
+2000-02-11    <tytso@snap.thunk.org>
+
+	* ext2fs.h: Define EXT2FS_COMPRESSED_BLKADDR and HOLE_BLKADDR.
+		Conditionally include Compression as a supported type if
+		ENABLE_COMPRESSION (via --enable-compression) is turned on.
+
+	* swapfs.c (ext2fs_swap_super): Swap the compression usage bitmap.
+
+2000-02-08    <tytso@snap.thunk.org>
+
+	* bitops.h (ext2fs_mark_generic_bitmap, ext2fs_unmark_generic_bitmap,
+		ext2fs_mark_block_bitmap, ext2fs_unmark_block_bitmap,
+		ext2fs_mark_inode_bitmap, ext2fs_unmark_inode_bitmap):
+		Change to return the previous state of the bit that is
+		being marked or unmarked.  For speed optimization.
+	
+2000-02-02  Theodore Ts'o  <tytso@valinux.com>
+
+	* getsize.c, ismounted.c: Remove unneeded include of linux/fs.h
+
+	* swapfs.c: Remove #ifdef HAVE_EXT2_INODE_VERSION since it's not
+		needed any more; we know it will always be i_generation.
+		Add support for swapping the high bits of the uid and gid.
+
+1999-11-19    <tytso@valinux.com>
+
+	* mkdir.c (ext2fs_mkdir): Only update the parent's inode link
+		counts if the link was successful.  Patch suggested by
+		jeremy@goop.org.
+
+	* Makefile.in (distclean): Remove TAGS and Makefile.in.old from
+		the source directory.
+
+1999-11-10    <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.18
+
+1999-11-08    <tytso@valinux.com>
+
+	* Makefile.in (tst_badblocks): Add freefs.o to the object list,
+		since ext2fs_badblocks_list_free was moved to freefs.c.
+
+	* tst_badblocks.c: Use the newer badblocks API names.  Add
+		duplicate blocks to the test inputs to test dealing with
+		adding blocks which are already in the badblocks list.
+
+	* badblocks.c (ext2fs_badblocks_list_add): If appending to the end
+		of the list, use a shortcut O(1) operations instead of an
+		O(n) operation.  (Idea suggested by David Beattie.)
+
+	* freefs.c (ext2fs_free): Use ext2fs_badblocks_list_free() instead
+		of badblocks_list_free(), to save a procedure call.
+
+1999-10-26    <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.17
+
+1999-10-26    <tytso@valinux.com>
+
+	* ext2fs.h: Add kludge to deal with the fact that egcs cpp doesn't
+		seem to handle ~0UL the same way as they used to.
+
+1999-10-25    <tytso@valinux.com>
+
+	* nt_io.c (_OpenNtName): Open the device using
+		FILE_SYNCHRONOUS_IO_NONALERT instead of
+		FILE_SYNCHRONOUS_IO_ALERT
+		(nt_open): At the end of the device open routine, unlock 
+		the drive but do not dismount it.
+
+	* initialize.c (CREATOR_OS): Use __GNU__ instead of __gnu__ to
+		detect the Hurd OS.
+
+1999-10-22    <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.16
+
+1999-10-22    <tytso@valinux.com>
+
+	* mkdir.c (ext2fs_mkdir): Pass EXT2_FT_DIR flag to ext2fs_link().
+
+	* link.c (ext2fs_link): This call now uses the low three bits of
+		the flags parameter to pass the directory filetype
+		information; it will set the directory entry FILETYPE
+		information if the filesystem supports it.
+
+	* newdir.c (ext2fs_new_dir_block): If the FILETYPE superblock
+		option is set, then create the '.' and '..' entries with
+		the filetype set to EXT2_FT_DIR.
+
+1999-09-24    <tytso@valinux.com>
+
+	* nt_io.c: New file which supports I/O under Windows NT.
+
+1999-09-07    <tytso@valinux.com>
+
+	* ext2fs.h: Add new fields for journalling and define new
+		feature bits used by newer filesystems: IMAGIC_INODES,
+		HAS_JOURNAL, RECOVER.
+
+	* expanddir.c (ext2fs_expand_dir, expand_dir_proc): Change where
+		we update the inode block count and size files so that the
+		block count field is updated correctly when we create an
+		indirect block.
+
+1999-07-18  Theodore Ts'o  <tytso@valinux.com>
+
+	* Release of E2fsprogs 1.15
+
+1999-06-23    <tytso@valinux.com>
+
+	* swapfs.c (ext2fs_swap_inode): Add compatibility for Linux 2.3
+		kernels that use i_generation instead of i_version.  Patch
+		supplied by Jon Bright <sircus@sircus.demon.co.uk>.
+
+1999-06-21    <tytso@valinux.com>
+
+	* dir_iterate.c (ext2fs_process_dir_block): Check for corrupted
+		directory entry before calling the callback function.
+		This should prevent some core dumps of insufficiently
+		paranoid callback functions.
+
+1999-05-29    <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Add feature definition for AFS IMAGIC inodes.
+
+	* fileio.c (ext2fs_file_open): Remove obsolete comment stating
+		that we don't handle writing yet (we do).  Fixed bug where
+		we weren't allocating a big enough buffer for ext2_bmap.
+
+1999-05-03    <tytso@rsts-11.mit.edu>
+
+	* openfs.c (ext2fs_open): Check to make sure that the number of
+		blocks per group is not zero --- if so, it must be a bad
+		superblock!
+
+1999-01-09  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs 1.14
+
+1999-01-07  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_read_inode, ext2fs_write_inode): Check to see if
+		the inode number is zero; if it's zero, return
+		EXT2_ET_BAD_INODE_NUM.
+
+1998-12-30  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Use EXT2_FIRST_INODE instead
+		of EXT2_FIRST_INO to ensure compatibility with Linux 1.2
+		header files.
+
+Mon Jan  4 02:32:09 1999  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* llseek.c (ext2fs_llseek): Change ext2fs_llseek() in the
+ 		non-Linux case to use EINVAL by default, unless it isn't
+ 		defined, in which case we use EXT2_ET_INVALID_ARGUMENT
+ 		instead.
+
+1998-12-15  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs 1.13
+
+1998-12-03  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Updated dependencies.
+
+1998-09-22  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Make sure that we allocate
+		enough inodes so that we can make a valid filesystem.
+
+1998-09-02  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* rw_bitmaps.c: Fixed signed/unsigned warnings.
+
+	* fileio.c (ext2fs_file_set_size): Remove unneeded extern from the
+		function declaration.
+
+	* dblist.c (make_dblist): Add safety check in case the dblist
+		pointer passed in is null (in which case, assign it to
+		fs->dblist).  Fixed some signed/unsigned warnings.
+
+	* bmap.c: Make addr_per_block be of type blk_t to avoid
+		signed/unsigned warnings.
+
+	* namei.c (ext2fs_follow_link): Remove uneeded extern from the
+		function declaration.
+
+	* get_pathname.c (get_pathname_proc): Use return value from
+		ext2fs_get_mem, instead of checking if &gp->name is
+		NULL.
+
+	* dir_iterate.c (ext2fs_process_dir_block): 
+	* dblist_dir.c (ext2fs_dblist_dir_iterate): Remove uneeded extern
+		from the function declaration.
+
+	* block.c (ext2fs_block_iterate2): If the read_inode call fails,
+		return the error directly instead of jumping to the
+		cleanup routine, since we don't need to do any cleanup.
+
+	* alloc_table.c (ext2fs_allocate_group_table): Make this
+		function take a dgrp_t for its group argument.
+
+	* ext2fs.h: Make dgrp_t an __u32 type, and make
+		fs->desc_group_count be of type dgrp_t.
+
+1998-07-27  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* badblocks.c (ext2fs_badblocks_list_add): Use a bigger increment
+		than 10 blocks when we need to expand the size of the
+		badblocks list.
+
+1998-07-09  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs 1.12
+
+1998-06-30  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* closefs.c (ext2fs_flush): Update the s_block_group_nr field as
+		appropriate for all of the block group copies, so that
+		it's clear where the beginning of the filesystem is on the
+		disk.  (For when the partition table gets scrod.)
+
+	* ext2fs.h: Change the name of the feature from
+		EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE to
+		EXT2_FEATURE_INCOMPAT_FILESIZE (to match with the kernel).
+
+1998-06-18  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (get_next_blockgroup): Fix bug where if
+		get_next_blockgroup() is called early because of a missing
+		inode table in a block group, the current_inode counter
+		wasn't incremented correctly.
+
+1998-06-16  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* read_bb.c (ext2fs_read_bb_inode): Make function more robust
+		against a completely trashed bad block inode.
+
+1998-06-10  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_group_table): Fix bug so that if
+		the stride length hits a bad value, we retry the block
+		allocation starting at the beginning of the block group.
+
+	* ext2fs.h, bb_inode.c, block.c, bmove.c, dir_iterate.c,
+		expanddir.c, ext2fsP.h, read_bb.c: Change blkcnt_t to be
+		e2_blkcnt_t to avoid collision with LFS API.
+
+1998-05-01  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Initialize s_inodes_count in a
+		way that avoids overflows on disk sizes greater than 4GB.
+
+1998-04-28  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Define EXT2_QSORT_TYPE appropriately for the
+		return type for comparison functions for qsort.
+
+	* dblist.c (dir_block_cmp): Use EXT2_QSORT_TYPE in function
+		declaration.
+
+1998-04-26  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h, bitops.h: Add support for the Watcom C compiler to do
+		inline functions.
+
+	* ext2fs.h, dosio.c: Use asm/types.h instead of linux/types.h to
+		evade a potential problem with glibc's header files trying
+		to spike out linux/types.h.
+
+	* ext2fs.h (ext2fs_resize_mem): Change the function prototype to
+		include the old size of the memory, which is needed for
+		some braindamaged memory allocation systems that don't
+		support realloc().
+
+	* badblocks.c (ext2fs_badblocks_list_add):
+	  bb_inode.c (clear_bad_block_proc):
+	  dblist.c (ext2fs_add_dir_block):
+	  icount.c (insert_icount_el):
+	  irel_ma.c (ima_put):
+	  rs_bitmap.c (ext2fs_resize_generic_bitmap): Update functions to
+		  pass the old size of the memory to be resized to
+		  ext2fs_resize_mem(). 
+
+1998-03-30  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in: Change to use new installation directory variables
+		convention.  Fix uninstall rules to take $(DESTDIR) into
+		account.
+
+1998-03-29  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: If __STRICT_ANSI__ is defined and we're on a platform
+		with 32 bit longs, then we need to manually define __s64
+		and __u64, since the current kernel header files don't
+		define these if __STRICT_ANSI__ is defined.  This is a
+		problem if we are compiling with full GCC warnings, since
+		we do need 64 bit support.
+	
+	* Makefile.in (OBJS): Remove bmove.o from files to be built,
+		since we're not using ext2fs_move_blocks() and there
+		is some question as to its usefulness in its current
+		form.
+
+	* bmap.c (block_bmap): Remove unused function.
+
+	* bmove.c (process_block): Fix -Wall warning.
+
+1998-03-23  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* block.c (ext2fs_block_iterate3): Make the ref_offset field
+		contain the offset into the inode.i_blocks array when
+		ref_block is zero.  Since we haven't done a formal
+		release of e2fsprogs since block_iterate2 was first
+		introduced, I removed block_iterate2, and renamed
+		block_iterate3 to be block_iterate2.
+
+	* bb_inode.c, bmove.c, dblist_dir.c, dir_iterate.c,
+		expanddir.c, ext2fs.h, ext2fsP.h, read_bb.c: Change
+		use of block_iterate and block_iterate2 to
+		block_iterate2 with the new prototype for the
+		interator function.  (using blkcnt_t forr blockcount)
+
+1998-03-21  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Add new superblock fields (s_algorithm_usage_bitmap, 
+		s_prealloc_blocks, s_prealloc_dir_blocks).  Added
+		conditional defines of new features COMPAT_DIR_PREALLOC,
+		RO_COMPAT_LARGE_FILE RO_COMPAT_BTREE_DIR,
+		INCOMPAT_COMPRESSION, INCOMPAT_DIRNAME_SIZE.  Changed
+		the library to declare that we support COMPAT_DIR_PREALLOC, 
+		INCOMPAT_DIRNAME_SIZE, RO_COMPAT_LARGE_FILE.
+
+	* fileio.c: Rename function ext2fs_file_llseek to be
+		ext2fs_file_lseek, which is more accurate.
+
+	* block.c: Add new function ext2fs_block_iterate3 which calls
+		the iterator function with the blockcount argument of
+		type blkcnt_t.  This version of the function is
+		allowed to handle large files; the other fucntions are
+		not.
+
+	* ext2fs.h: Add new type blkcnt_t
+
+	* ext2_err.et.in: Add error code EXT2_ET_FILE_TOO_BIG
+
+	* block.c (ext2fs_block_iterate2): Fix bug where the block count
+		field wasn't getting correctly incremented for sparse
+		files when the indirect or doubly-indirect block
+		specified in the inode was zero.
+
+Sun Mar  8 22:42:47 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* unlink.c (unlink_proc): 
+	* lookup.c (lookup_proc): 
+	* link.c (link_proc): 
+	* get_pathname.c (get_pathname_proc): 
+	* dir_iterate.c (ext2fs_process_dir_block): Mask off high 8 bits
+		from dirent->name_len, so it can be used for other
+		purposes.
+
+	* ext2fs.h: Add definition of EXT2_FEATURE_INCOMPAT_DIRNAME_SIZE,
+		and indicate that we have support for this incompatible
+		option.
+
+Mon Feb 23 08:46:33 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2_err.et.in: Added new error code, EXT2_ET_CANCEL_REQUESTED.
+
+Fri Feb 20 23:58:01 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_get_num_dirs): Improve the estimation of the
+ 		number of directories when the block group information is
+ 		unreliable.
+
+1998-02-20  Theodore Y. Ts'o  <tytso@edt.mit.edu>
+
+	* inode.c (ext2fs_get_next_inode): Always do the check to see if the
+		inode table is missing so that we catch the case where the
+		first block group is missing.
+
+	* getsize.c, ismounted.c, unix_io.c: #include errno.h since it's
+		needed.
+
+Mon Feb 16 16:16:00 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2_io.h, ext2fs.h: Protect against being included multiple times.
+
+	* bmove.c: #include ext2fsP.h instead of "ext2fs/ext2fs.h"
+
+	* test_io.c (test_flush): Add a debugging printf when the flush
+		method is called.
+
+	* rw_bitmaps.c (ext2fs_read_bitmaps): If the bitmaps are already
+		read in, return right away.
+
+Sun Feb  1 08:20:24 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bitops.h: Don't try to do i386 inline asm functions if the
+ 		compiler isn't GCC.
+
+	* ext2fs.h: If EXT2_FLAT_INCLUDES is defined, #include e2_types.h,
+ 		instead of linux/types.h, and e2_bitops.h instead of
+ 		ext2fs/bitops.h.
+
+	* icount.c, version.c: Don't #include <et/com_err.h>, as it isn't
+		necessary. 
+
+Sat Jan 17 13:13:31 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_open_inode_scan): Initialize the group variables
+		so that we don't need to call get_next_blockgroup() the
+		first time around.  Saves a bit of time, and prevents us
+		from needing to assign -1 to current_group (which is an
+		unsigned value).
+
+	* icount.c (insert_icount_el): Cast the estimated number of inodes
+		from a float to an ino_t.
+
+	* alloc.c, alloc_tables.c, badlbocks.c, bb_compat.c, bb_inode.c,
+ 		bitmaps.c, bitops.c, block.c, bmap.c, bmove.c, brel_ma.c,
+ 		check_desc.c, closefs.c, cmp_bitmaps.c, dblist.c,
+ 		dblist_dir.c, dir_iterate.c, dirblock.c, dupfs.c,
+		expanddir.c, ext2fs.h, fileio.c, freefs.c,
+		get_pathname.c, getsize.c, icount.c, initialize.c,
+		inline.c, inode.c, irel_ma.c, ismounted.c, link.c,
+		lookup.c, mkdir.c, namei.c, native.c, newdir.c,
+		openfs.c, read_bb.c, read_bb_file.c, rs_bitmap.c,
+		rw_bitmaps.c, swapfs.c, test_io.c, tst_badblocks.c,
+		tst_getsize.c, tst_iscan.c, unix_io.c, unlink.c,
+		valid_blk.c, version.c: If EXT2_FLAT_INCLUDES is
+		defined, then assume all of the
+ 		ext2-specific header files are in a flat directory.
+
+	* block.c, bmove.c, dirblock.c, fileio.c: Explicitly cast
+		all assignments from void * to be compatible with C++.
+
+Tue Jan  6 11:28:15 1998  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* closefs.c (ext2fs_flush): Add a call to io_channel_flush() to
+		make sure the contents of the disk are flushed to disk.
+
+Mon Dec 29 14:39:13 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_add_dir_block): Change new to be new_entry to
+		avoid C++ namespace clash.
+
+	* bitmaps.c (ext2fs_copy_bitmap): Change new to be new_map to
+		avoid C++ namespace clash.
+
+	* ext2fs.h, bb_inode.c, block.c, bmove.c, brel.h, brel_ma.c,
+ 	 	irel.h, irel_ma.c, dblist.c, dblist_dir.c, dir_iterate.c,
+ 	 	ext2fsP.h, expanddir.c, get_pathname.c, inode.c, link.c,
+ 	 	unlink.c: Change private to be priv_data (to avoid C++
+ 	 	namespace clash)
+
+Fri Nov 28 09:26:31 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_get_num_dirs): Make ext2fs_get_num_dirs more
+		paranoid about validating the directory counts from the
+		block group information.
+
+	* all files: Don't include stdlib.h anymore; include it in
+		ext2_fs.h, since that file requires stdlib.h
+
+Thu Nov 20 16:07:38 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* expanddir.c (ext2fs_expand_dir): Check to make sure the block
+		bitmap is loaded, and return an error if it is not.
+		(expand_dir_proc): Only use ext2fs_write_dir_block when
+		writing a directory block, not when writing out a fresh
+		indirect block.
+
+Tue Nov 11 22:46:45 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in, tst_getsize.c: Added new file which is used to test
+		the ext2fs_get_device_size function.
+
+	* ext2_err.et.in (EXT2_ET_UNIMPLEMENTED): Added new error code.
+
+Sun Nov  2 20:36:13 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h: Make ext2fs_get_mem take an unsigned argument.
+
+	* fileio.c (ext2fs_file_get_size, ext2fs_file_set_size,
+		ext2fs_file_get_fs): New functions added.
+
+
+Fri Oct 31 12:16:52 1997    <tytso@EDT.MIT.EDU>
+
+	* bitops.c (ext2fs_warn_bitmap, ext2fs_warn_bitmap2): Don't call
+	 	com_err if OMIT_COM_ERR is defined.
+
+Thu Oct 30 11:33:57 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Rename new error codes to _ET_ in them for consistency.
+
+Sat Oct 25 00:06:58 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* [all files, basically]: Added definition of ext2fs_get_mem, 
+		ext2fs_free_mem, and ext2fs_resize_mem in ext2fs.h, and
+		changed all library routines to use these wrapper functions.
+
+	* dblist.c, mkdir.c: use EXT2_DIR_EXISTS and EXT2_DB_NOT_FOUND
+		instead of the system error messages.
+	
+	* ext2_err.et.in: Added new error messages EXT2_DIR_EXISTS and
+	 	EXT2_DB_NOT_FOUND
+
+	* ext2fs.h: Added function declarations and constants for bmap.c
+	 	and fileio.c.
+
+	* ext2_err.et.in: Added new error messages EXT2_FILE_RO and
+	 	EXT2_ET_MAGIC_EXT2_FILE
+
+	* Makefile.in: Added files bmap.c and fileio.c, and temporarily
+		commented out brel_ma.c and irel_ma.c
+
+	* bmap.c: New file which maps a file's logical block number to its
+		physical block number.
+
+	* fileio.c: New file which implements simple file reading and
+		writing primitives.
+
+	* alloc.c (ext2fs_alloc_block): New function which allocates a
+ 		block, zeros it, and updates the filesystem accounting
+ 		records appropriately.
+
+Wed Oct 22 16:47:27 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2_err.et.in: Added new error codes: EXT2_NO_MEMORY,
+		EXT2_INVALID_ARGUMENT, EXT2_BLOCK_ALLOC_FAIL,
+		EXT2_INODE_ALLOC_FAIL, EXT2_NOT_DIRECTORY
+
+	* Change various library files to use these functions instead of
+		EINVAL, ENOENT, etc.
+
+Mon Oct 20 19:32:40 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* llseek.c: Check HAVE_LLSEEK_PROTOTYPE to see whether or not we
+		need to declare llseek().
+
+Sun Oct 19 18:56:22 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Rename io.h to be ext2_io.h (avoid namespace collisions)
+
+	* Add #ifdef's for HAVE_SYS_STAT_H and HAVE_SYS_TYPES_H
+
+Fri Oct  3 13:35:59 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* llseek.c (ext2fs_llseek): Fix type error for ext2fs_llseek()
+
+	* icount.c (ext2fs_icount_validate): 
+	* bmove.c (process_block): Fix lint error in type for fprintf().
+
+Mon Sep 15 11:45:09 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_check_directory): Add support for the callback
+		to return the error code EXT2_ET_CALLBACK_NOTHANDLED.
+
+Thu Sep  4 12:28:22 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bitmaps.c (ext2fs_set_bitmap_padding): New function which sets the
+		padding of the bitmap to be all one's.
+
+Wed Sep  3 14:27:30 1997  Theodore Y. Ts'o  <tytso@edt.mit.edu>
+
+	* llseek.c: Added missing semicolon to glibc fixup declaration of
+ 	llseek().
+
+	* bmove.c: Add #include of errno.h
+
+Sat Aug 23 22:47:46 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (ELF_SO_VERSION): Bump version to be 2.4 since we've
+		added a new field to the io_channel (app_data).
+
+	* io.h: Add a new element to the io_channel structure, app_data.
+
+	* initialize.c, openfs.c: Set io->app_data to point at the
+	 	filesystem handle.
+
+Thu Aug 14 08:14:17 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* io.h: Change the prototype of ext2fs_llseek() to use int's
+		instead of unsigned int's.
+
+	* llseek.c: Change to allow PIC and !HAVE_LLSEEK.  Add a prototype
+		to make life easer for GNU Libc 2.
+
+	* rw_bitmaps.c: On the PowerPC, the big-endian variant of the ext2
+ 		filesystem has its bitmaps stored as 32-bit words with bit
+ 		0 as the LSB of each word.  Thus a bitmap with only bit 0
+ 		set would be, as a string of bytes, 00 00 00 01 00 ...  To
+ 		cope with this, we byte-reverse each word of a bitmap if
+ 		we have a big-endian filesystem, that is, if we are *not*
+ 		byte-swapping other word-sized numbers.
+
+Mon Aug 11 03:30:48 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dosio.c: New file to do DOS/BIOS disk accesses.
+
+	* namei.c (open_namei): Make pathlen be of type size_t.
+
+	* llseek.c: Always #include stdlib.h since it's need to define
+		size_t.  
+
+	* io.h: Use errcode_t for magic numbers.
+
+	* icount.c (get_icount_el): Use size_t where appropriate
+	
+	* dupfs.c (ext2fs_dup_handle): 
+	* dblist.c (dir_block_cmp): Use size_t where appropriate.
+
+	* read_bb.c (ext2fs_read_bb_inode): 
+	* cmp_bitmaps.c (ext2fs_compare_inode_bitmap): Use blk_t, ino_t
+		and size_t where appropriate.
+
+	* closefs.c (ext2fs_flush): Use dgrp_t instead of int where
+		appropriate.
+
+	* openfs.c (ext2fs_open): 
+	* check_desc.c (ext2fs_check_desc): Use blk_t instead of int where
+		appropriate.
+
+	* rw_bitmaps.c (read_bitmaps): 
+	* irel_ma.c: 
+	* inode.c (ext2fs_write_inode): 
+	* initialize.c (ext2fs_initialize):
+	* brel_ma.c: Fix to make be 16-bit safe.
+
+	* link.c (ext2fs_link): 
+	* unlink.c (ext2fs_unlink):
+	* lookup.c (lookup_proc): 
+	* ismounted.c (ext2fs_check_if_mounted): 
+	* block.c (xlate_func): Add #pragma argsused for Turbo C.
+
+Sun Aug 10 10:05:22 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* block.c (ext2fs_block_iterate2): Use retval which is a errcode_t
+		type.
+
+	* bitmaps.c (make_bitmap): Use size_t instead of int where
+		appropriate.
+
+	* bb_inode.c (set_bad_block_proc): Add #pragma argsused for Turbo C.
+
+	* alloc.c (ext2fs_new_inode): Use ino_t instead of int for the
+		group number.
+
+	* get_pathname.c: Use ino_t instead of int where appropriate.
+
+	* ext2fs.h: Make the magic structure element be errcode_t instead
+		of int.
+
+	* alloc.c alloc_tables.c badblocks.c bb_compat.c bb_inode.c
+ 	 	bitmaps.c block.c bmove.c brel_ma.c check_desc.c closefs.c
+ 	 	cmp_bitmaps.c dblist.c dblist_dir.c dir_iterate.c
+ 	 	dirblock.c dupfs.c expanddir.c freefs.c get_pathname.c
+ 	 	icount.c initialize.c inline.c inode.c irel_ma.c link.c
+ 	 	llseek.c lookup.c mkdir.c namei.c newdir.c read_bb.c
+ 	 	read_bb_file.c rs_bitmap.c rw_bitmaps.c swapfs.c 
+ 	 	test_io.c tst_badblocks.c tst_iscan.c unix_io.c unlink.c
+ 	 	valid_blk.c version.c: Add an #ifdef for HAVE_UNISTD_H
+
+Tue Jun 17 01:33:20 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* unix_io.c (unix_read_blk): If ext2fs_llseek() fails, but errno
+		is zero, then return EXT2_IO_LLSEEK_FAILED.
+
+	* ext2_err.et.in: Add a new error code, EXT2_IO_LLSEEK_FAILED.
+
+	* Release of E2fsprogs 1.11
+
+Mon Jun 16 23:53:06 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_dblist_count): Added new function which returns
+		the number of directory blocks in dblist.
+
+Sat Jun 14 01:39:13 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* unix_io.c (unix_flush): Make the io_channel flush function do a
+		fsync to flush the kernel buffers to disk.
+
+Wed Jun 11 18:25:31 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_inode_scan_goto_blockgroup): Fix bug; the
+		current inode number wasn't being set by the
+		goto_blockgroup function.
+
+Mon Jun  9 10:45:48 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bmove.c (ext2fs_move_blocks): New function which takes a bitmap
+		of blocks which need to be moved, and moves those blocks
+		to another location in the filesystem.
+
+	* rs_bitmap.c (ext2fs_resize_generic_bitmap): When expanding a
+		bitmap, make sure all of the new parts of the bitmap are
+		zero. 
+
+Sun Jun  8 16:24:39 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bitmaps.c (ext2fs_copy_bitmap): Fix bug; the destination bitmap
+		wasn't being returned to the caller.
+
+	* alloc_tables.c (ext2fs_allocate_group_table): Add new function
+		ext2fs_allocate_group_table() which sets the group tables
+		for a particular block group.  The relevant code was
+		factored out of ext2fs_allocate_tables().
+
+	* dblist.c (make_dblist): Adjust the initial size of the directory
+ 		block list to be a bit more realistic (ten plus twice the
+ 		number of directories in the filesystem).
+
+Thu May  8 22:19:09 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* badblocks.c (ext2fs_badblocks_list_test): Fix bug where
+ 		ext2fs_badblocks_list_test would test the list (and exceed
+ 		array boundaries) if there were no bad blocks on the bad
+ 		blocks list.  (Showed up when user tried: mke2fs -c -b 4096).
+
+Thu Apr 24 12:16:42 1997  Theodre Ts'o  <tytso@localhost.mit.edu>
+
+	* Release of E2fsprogs version 1.10
+
+Thu Apr 24 10:13:42 1997  Theodre Ts'o  <tytso@localhost.mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_tables): Correctly place the
+		inode and block bitmaps based on the RAID 0 stride
+		parameter (which is passed by mke2fs).
+
+	* ext2fs.h: Add "stride" parameter to ext2_filsys, to be used by
+ 		mke2fs to communicate the stride length to
+ 		ext2fs_allocate_tables()
+
+Wed Apr 23 21:50:42 1997  Theodre Ts'o  <tytso@localhost.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Fix to compile under Linux 1.2
+		systems.  (We can't assume that the new filesystem types
+		are supported.)
+
+Wed Apr 23 18:40:53 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_tables): Make sure that we
+		allocate the inode and block bitmaps inside block group at
+		all times.
+
+Mon Apr 21 00:06:28 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc.c (ext2fs_new_block): Fix bug where if goal==0 and the
+		filesystem has no free blocks, ext2fs_new_block would loop
+		forever.
+
+	* dupfs.c (ext2fs_dup_handle): Duplicate an ext2 filesystem handle
+
+	* freefs.c (ext2fs_free_inode_cache): Decrement refcount and only
+		free if refcount goes to zero.
+
+	* inode.c (create_icache): Initialize refcount to 1.
+
+	* ext2fsP.h: Added refcount to ext2_inode_cache
+
+	* dblist.c (ext2fs_copy_dblist): New function to copy a directory
+		block list.
+
+	* badblocks.c (ext2fs_badblocks_copy): New function to copy a
+		badblocks structure.
+
+Sun Apr 20 23:19:51 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* bitmaps.c (ext2fs_copy_bitmap): New function to copy a bitmap.
+
+	* unix_io.c, test_io.c (unix_open, test_open): Initialize the
+ 	 	refcount to 1.
+		(unix_close, test_close): Decrement the refcount and only
+ 		close the io_channel if the refcount goes to 0.
+
+	* io.h: Add refcount to the io_channel structure.  Add new macro
+		interface io_channel_bumpcount() to bump the refcount.
+
+Thu Apr 17 20:25:03 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_read_inode, ext2fs_write_inode): Use the inode
+		cache in the filesystem handle, instead of the inode cache
+		in a static variable.
+
+	* freefs.c: Added static function to free the inode cache (called by
+		ext2fs_free). 
+
+	* ext2fsP.h: Added definition of the ext2_inode_cache structures.
+
+	* ext2fs.h: Added pointer to the inode_cache structure.
+
+	* block.c (block_iterate_ind, block_iterate_dind, 
+		block_iterate_tind): If there are holes in the indirect,
+		doubly indirect, or triply indirect blocks, increment the
+		block count field automatically.
+
+Thu Apr 17 12:23:38 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.09
+
+Mon Apr 14 20:38:56 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* version.c (ext2fs_parse_version_string): Check the passed in
+		version string (instead of the hard-coded one).
+
+	* alloc_tables.c (ext2fs_allocate_tables): If the last block is
+		greater filesystem size, clamp it to prevent allocating a
+		block or inode bitmap beyond the filesystem.
+
+	* initialize.c (ext2fs_initialize): Fix bug where the metatdata
+	 	overhead calculation was accidentally removed.
+
+Fri Apr 11 18:56:26 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.08
+
+Thu Apr 10 13:15:15 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_set_dir_block): New function which sets the
+ 		block of a dblist entry, given the directory inode and
+ 		blockcnt.
+
+Sat Apr  5 12:42:42 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc_tables.c (ext2fs_allocate_tables): Allocate the bitmap and
+		inode bitmaps at staggered locations across the block
+		groups, to avoid concentrating the bitmaps on a small
+		number of disks when using striped RAID arrays.
+
+	* initialize.c (ext2fs_initialize): By default, choose the maximum
+		possible number of blocks per group (based on the size of
+		the bitmaps in the blocksize).
+
+Fri Apr  4 11:28:16 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Add support for
+		EXT2_COMPAT_SPARSE_SUPER feature.
+
+	* closefs.c (ext2fs_bg_has_super): New function to determine
+		whether or a particular block group should have a
+		superblock and block group descriptor.  Used for the
+		EXT2_COMPAT_SPARSE_SUPER feature is turned on.
+		(ext2fs_flush):  Check ext2fs_bg_has_super to see whether
+		or not the superblock should be written out for the block
+		group. 
+
+	* ext2fs.h (EXT2_COMPAT_SPARSE_SUPER): Define compatibility flag
+		for sparse duplicate superblocks.
+
+	* version.c (ext2fs_get_library_version): New function which
+		returns the library version.
+
+	* version.c (ext2fs_parse_version_string): New function which
+		parses a version string and returns a version number,
+		so application programs can compare version numbers as
+		integers.
+
+Wed Mar 26 00:43:52 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* icount.c (ext2fs_create_icount): Change function so that it also
+		takes a new argument which contains a "hint" icount
+		structure.  This "hint" icount allows the create function
+		to set up the sorted list in advance.  This reduces
+		significantly the amount of data moving needed to insert
+		these inodes into the list later.
+	
+	* icount.c (ext2fs_icount_validate): New function which validates
+		that the icount structure's rep invariant.
+
+	* icount.c (get_icount_el): Completely revamped implementation
+		to subsume put_icount_el().  Put_icount_el() used to
+		use an O(N) implementation to insert in the middle
+		of the icount list.  It now uses a O(ln N) to search
+		for where the icount should be inserted, and then uses
+		a memcpy to move the list down (instead of a for loop).
+	
+	* icount.c (ext2fs_icount_fetch, ext2fs_icount_store,
+ 		ext2fs_icount_increment, ext2fs_icount_decrement): Check
+ 		to see if the inode is within bounds; if it isn't, return
+ 		EINVAL.
+
+	* bitops.h (ext2fs_test_generic_bitmap): Fix error message given
+ 		when a bad inode number is passed to test_generic_bitmap
+ 		to be EXT2FS_TEST_ERROR instead of the wrong
+ 		EXT2FS_UNMARK_ERROR.
+
+Wed Mar 12 13:32:05 1997  Theodore Y. Ts'o  <tytso@mit.edu>
+
+	* Release of E2fsprogs version 1.07
+
+Sun Mar  2 16:46:18 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Makefile.in (ELF_VERSION): Change version to be 2.2
+
+Tue Feb 11 14:54:02 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc.c (ext2fs_get_free_blocks): Change routine to use
+	 	ext2fs_fast_test_block_bitmap_range().
+
+	* bitops.h (ext2fs_fast_test_block_bitmap_range,
+ 		ext2fs_test_block_bitmap_range: New inline functions which
+ 		test to see whether a contiguous range of blocks is
+ 		available.
+
+Thu Feb  6 10:00:13 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* badblocks.c (ext2fs_badblocks_list_create): Rename sybmols to use
+ 		use ext2fs_badblocks_* instead of badblocks_*
+
+	* bb_compat.c: New file which translates between old badblocks_*()
+		names to ext2fs_badblocks_*()
+
+	* unlink.c (ext2fs_unlink): New file, moved ext2fs_unlink() from
+	 	link.c (since e2fsck doesn't use ext2fs_unlink()).
+
+	* rs_bitmap.c (ext2fs_resize_generic_bitmap): New file, contains
+ 		bitmap resizing routine moved from bitmaps.c, since e2fsck
+ 		doesn't need to use this function.
+
+	* lookup.c (ext2fs_lookup): Moved ext2fs_lookup to its own file,
+		since e2fsck only needs ext2fs_lookup.
+
+Mon Feb  3 10:11:40 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_open_inode_scan): Set fs->badblocks if it is not
+		already set; this is needed so that programs like dump
+		which use the inode scan functions will deal with
+		filesystems that have bad blocks in the inode table.
+
+Sun Feb  2 00:17:36 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h (struct_badblocks_list, struct_badblocks_iterate): 
+		Moved to ext2fsP.h, since it doesn't need to be part of
+		the public interface.
+
+	* dir_iterate.c: Move ext2_dir_iterate out of namei.c.
+
+Sat Feb  1 10:14:55 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dblist.c (ext2fs_get_num_dirs): New file, which implements a
+ 		directory block list abstraction.  (Code moved from
+ 		e2fsck).
+
+	* ext2fs.h, inode.c: Moved definition of ext2_struct_inode_scan to
+		to inode.c (since no one else should be peeking inside it!)
+
+	* valid_blk.c (ext2_inode_has_valid_blocks): New function.
+
+	* openfs.c (ext2fs_open): Check the feature set in the ext2
+		superblock, and refuse to open filesystems if they contain
+		incompatible features.  (Can be overriden with the
+		EXT2_FLAG_FORCE 
+
+Sun Jan 12 11:31:46 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* block.c (ext2fs_block_iterate2): Added new function
+	 	ext2fs_block_iterate2 which changes the function
+	 	signature of the callback function to include the
+	 	referencing block and offset.
+
+	* inode.c (ext2fs_inode_scan_goto_blockgroup): Added new function
+	 	ext2fs_inode_scan_goto_blockgroup which allows an
+	 	application to jump to a particular block group while
+	 	doing an inode scan.
+
+Wed Jan  1 23:50:12 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* dirblock.c: Include string.h, since we use memcpy().
+
+Tue Dec  3 12:27:29 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): The ioctl BLKGETSIZE returns
+		a long not an int; this doesn't matter on i386 machines,
+		but it does on Alpha's.
+	
+Fri Nov 29 20:57:37 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_write_inode, ext2fs_read_inode): If the inode
+ 		table pointer is NULL, then return an error indicating
+ 		that the inode table is missing.
+		(get_next_blockgroup, get_next_blocks,
+ 		ext2fs_get_next_inode): Don't treat a missing inode table
+ 		as permanent error.  Return MISSING_INODE_TABLE, but as an
+ 		advisory error code, much like BAD_BLOCK_IN_INODE_TABLE.
+
+	* rw_bitmaps.c (ext2fs_write_block_bitmap,
+ 	 	ext2fs_write_inode_bitmap): If the inode or block bitmap
+ 	 	block is zero, then don't write out the inode or block
+ 	 	bitmap.  The idea here is to avoid stomping on the
+ 	 	superblock.
+		(read_bitmaps): If the inode or block bitmap block is
+	 	zero, then fill in that portion of the inode or block
+	 	bitmap with all zeros.
+
+	* inode.c (ext2fs_get_next_inode): Fix bug in handling of bad
+ 		blocks in inode table when the inode table size is
+ 		non-standard (and can therefore span blocks).
+
+Tue Oct 29 20:13:14 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* alloc.c (ext2fs_new_block): Fix fencepost error in
+		ext2fs_new_block; make sure we don't try to allocate the
+		first block beyond the end of the filesystem.
+
+Mon Oct 14 11:00:48 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (check_for_inode_bad_blocks): New function called by
+		get_next_blocks() to avoid reading in bad blocks marked in
+		fs->badblocks.  Inodes located in bad blocks are returned
+		by ext2fs_get_next_inode() returns the error code 
+		EXT2_ET_BAD_BLOCK_IN_INODE_TABLE.
+	
+	* alloc_tables.c (ext2fs_allocate_tables): New function which
+		performs the part of mke2fs's job of allocating the 
+		filesystem tables.
+
+	* test_io.c (test_close): IO manager which is used for testing
+	 	purposes.
+
+Sun Oct 13 04:31:57 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_get_next_inode): Separate out the function of
+ 		setting up for a new block group to get_next_blockgroup().
+		Separate out the function of reading in blocks of the
+		inode table to get_next_blocks().
+
+	* ext2fs.h: Add the badblocks list to the ext2_filsys entry
+
+	* badblocks.c (badblocks_list_add, badblocks_list_test): Add
+ 		blocks to the badblock list in sorted order.  This allows
+ 		badblocks_list_test to be coded using a binary search for
+ 		speed.
+
+Tue Oct  8 02:02:03 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.06
+
+Mon Oct  7 00:44:17 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* ext2fs.h, block.c, closefs.c, dirblock.c, inode.c, native.c,
+	 	open.c: Change EXT2_SWAP to EXT2_FLAG_SWAP for
+	 	consistency's sake.
+	
+	* closefs.c (ext2fs_flush): If the flag EXT2_MASTER_SB_ONLY is
+		set, then only write out the master superblock.
+
+Sun Oct  6 21:45:26 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* block.c (ext2fs_block_iterate): Fixed bug which caused
+ 		block_iterate to fail to handle HURD created filesystems;
+ 		it tested the inode translator field before the inode was
+ 		loaded.
+
+Tue Sep 17 14:08:24 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Make sure the description for
+		the inode bitmap is set correctly.
+
+	* bitmaps.c (ext2fs_allocate_generic_bitmap): Fix minor type typo.
+
+Thu Sep 12 15:23:07 1996  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.05
+
+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
+
+Wed Mar 27 00:33:40 1996    <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.03
+
+Tue Mar 26 12:06:32 1996    <tytso@rsts-11.mit.edu>
+
+	* bitops.h (ext2fs_set_bit, ext2fs_clear_bit, ext2fs_test_bit):
+		Change the m68k bit numbering for bitmasks to match with
+		the bit numbering used by all other ext2 implementations.
+
+Thu Mar  7 03:37:00 1996    <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_get_next_inode, ext2fs_close_inode_scan, 
+	ext2fs_open_inode_scan): Support dynamically-sized inodes.
+
+Wed Mar  6 12:26:29 1996    <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_read_inode, ext2fs_write_inode): Support
+		dynamically-sized inodes.
+
+	* openfs.c (ext2fs_open): Allow dynamic revision filesystem to be
+	        loaded.
+
+Tue Mar  5 03:49:37 1996    <tytso@rsts-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Catch an error condition where
+		the passed in size is *really* too small.
+
+	* alloc.c (ext2fs_new_inode): 
+	* ext2fs.h (EXT2_FIRST_INODE): Add support for dynamic revision to
+		get first inode.
+
+Wed Feb 21 15:56:17 1996    <tytso@rsts-11.mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Open the device read-only
+		when trying to determine its size.
+
+Wed Jan 31 11:06:08 1996    <tytso@rsts-11.mit.edu>
+
+	* Release of E2fsprogs version 1.02
+
+Sat Dec  9 09:57:50 1995    <tytso@rsts-11.mit.edu>
+
+	* rw_bitops.c (ext2fs_write_block_bitmap):
+	* bitops.c (ext2fs_test_bit, ext2fs_clear_bit, ext2fs_set_bit):
+	* bitops.h (ext2fs_test_bit, ext2fs_clear_bit, ext2fs_set_bit):
+		Rename {test,set,clear}_bit to ext2fs_{test,set,clear}_bit, 
+		to avoid conflicts with with kernel include files.  Also
+		rename ADDR and CONST_ADDR to EXT2FS_ADDR and
+		EXT2FS_CONST_ADDR. 
+
+Thu Oct 26 12:09:16 1995    <tytso@rsts-11.mit.edu>
+
+	* ext2_err.et: Updated message in EXT2_ET_BASE to say version 0.5c
+
+	* swapfs.c (ext2fs_swap_super): Put an #ifdef check around
+		s_def_resuid and s_def_resgid for backwards compatibility.
+
+Fri Oct 20 23:33:31 1995    <tytso@rsts-11.mit.edu>
+
+	* bitops.h: Added #ifdef's for Sparc.
+
+Wed Sep  6 22:14:46 1995    <tytso@rsts-11.mit.edu>
+
+	* getsize.c: #include <sys/ioctl.h> under Linux to pick up ioctl()
+	        declaration
+
+	* closefs.c: #include <string.h> to pick up memset() declaration
+
+Mon Sep  4 21:45:29 1995  Remy Card  <card@bbj>
+
+	* Makefile.in: Added support for BSD shared libraries.
+
+	* initialize.c (ext2fs_initialize): Correctly set the s_creator_os
+		flag.
+
+Mon Sep  4 09:55:30 1995    <tytso@rsts-11.mit.edu>
+
+	* unix_io.c (unix_open): Add a double check; if the passed in name
+		is NULL, return EXT2_ET_BAD_DEVICE_NAME.
+
+	* ext2_err.et (EXT2_ET_BAD_DEVICE_NAME): Added new error code
+
+Wed Aug 16 15:44:10 1995    <tytso@rsts-11.mit.edu>
+
+	* inode.c (ext2fs_check_directory): Use LINUX_S_ISDIR instead of
+		S_ISDIR.
+
+Tue Aug 15 13:08:36 1995    <tytso@rsts-11.mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): Add support for reading the
+		partition size from a BSD disk label.
+
+Thu Aug 10 09:33:26 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* getsize.c (ext2fs_get_device_size): New function that determins
+		the size of a device.  Used by mke2fs and e2fsck.
+
+Sat Aug 12 03:09:54 1995  Remy Card  <card@bbj>
+
+	* Makefile.in (install): Install static libraries in $(ulibdir)
+		(/usr/lib on Linux) instead of $(libdir) (/lib on Linux).
+
+Wed Aug  9 17:04:23 1995  Theodore Y. Ts'o  <tytso@dcl>
+
+	* bitmaps.c (ext2fs_free_inode_bitmap, ext2fs_free_block_bitmap):
+		Move these functions to freefs.c.
+
+	* closefs.c (ext2fs_flush): If swapping blocks, clear the group
+		descriptors shadow memory to keep purify quiet.  (This
+		also has the nice benefit that the unused portion of the
+		shadow descriptors are zeroed out.)
+
+	* dirblock.c (ext2fs_write_dir_block): We need to use
+		dirent->rec_len *before* it's byteswapped to find the
+		location of the next directory structure!
+
+	* alloc.c (ext2fs_new_inode): Fix bug which could potentially
+		cause ext2fs_new_inode to loop infinitely if we're trying
+		to allocate an inode in group #0 and there are no free
+		inodes at all in the system.
+
+	* closefs.c: #include <errno.h> if it exists.
+
+Sun Aug  6 13:27:50 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* ext2fs.h (BLOCK_FLAG_HOLE): Added new definition for
+		BLOCK_FLAG_APPEND.  Added documentation for the block
+		interator flags.
+
+Sat Aug  5 11:44:05 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* Makefile.in (DLL_INSTALL_DIR, ELF_INSTALL_DIR): Set the
+		installation directories correctly.
+
+Tue Jul 18 09:27:38 1995    <tytso@rsx-11.mit.edu>
+
+	* namei.c (process_dir_block): 
+	* mkdir.c (ext2fs_mkdir): 
+	* expanddir.c (expand_dir_proc): Use ext2fs_{read,write}_dir_block
+		to read/write the directory block.
+
+	* dirblock.c (ext2fs_read_dir_block), ext2fs_write_dir_block): New
+		file containing functions for reading and writing
+		directory blocks (byte swapping if necesssary)
+
+	* block.c (block_iterate_ind, block_iterate_dind, 
+		block_iterate_tind): Byte swap the block addresses if
+		EXT2_SWAP_BYTES is set (and swap them back before writing
+		them out.)
+
+	* inode.c (inocpy_with_swap): New function.
+	(ext2fs_get_next_inode, ext2fs_read_inode, ext2fs_write_inode):
+		Call inocpy_with_swap if EXT2_SWAP_BYTES if set.
+
+	* closefs.c (ext2fs_flush): If EXT2_SWAP_BYTES is set, then swap
+		the superblock and group descriptors before writing it out.
+
+	* openfs.c (ext2fs_open): If the magic number is byte-swapped,
+		then set the EXT2_SWAP_BYTES and byte-swap the superblock
+		and group descriptors.
+
+	* swapfs.c (ext2fs_swap_super, ext2fs_swap_group_desc): New functions
+		to desp ext2 filesystem structures.
+
+	* bitops.c (set_bit, clear_bit, test_bit): Use modifications
+		supplied by Pete A. Zaitcev so that the C language
+		versions of these functions are more portable.  They will
+		now work on both little and big endian systems, and the
+		assumption that 32-bit integers are used is gone.
+
+	* bitops.h (ext2_swab16, ext2_swab32): Added new functions for
+		doing byte swapping.
+
+	* ext2fs.h (EXT2_SWAP_BYTES): Add new flag which indicates that
+		byte swapping should take place.
+
+Sun Jul 16 06:21:43 1995    <tytso@rsx-11.mit.edu>
+
+	* Makefile.in, cmp_bitmaps.c (ext2fs_compare_block_bitmap_end,
+	        ext2fs_compare_inode_bitmap_end): Added new file
+		containing routines to compare bitmaps.
+
+	* ext2_err.et (EXT2_ET_NEQ_BLOCK_BITMAP, EXT2_ET_NEQ_INODE_BITMAP): 
+		Added new error codes.
+
+Sat Jul 15 04:23:37 1995    <tytso@rsx-11.mit.edu>
+
+	* inode.c (ext2fs_get_next_inode): Don't check scan->inode_buffer;
+		if the magic number is correct, it will be allocated.
+
+Fri Jul 14 19:02:59 1995    <tytso@rsx-11.mit.edu>
+
+	* block.c (block_iterate_ind, block_iterate_dind, 
+		block_iterate_tind): Don't recompute block_nr each loop;
+		just increment it!  Factor check of BLOCK_FLAG_APPEND out
+		of the loop.  Factor mask of BLOCK_CHANGED into changed
+		variable out of the loop.  (block_iterate_ind, in
+		particular, gets called a lot, so every little
+		optimization helps.)
+
+Thu Jul 13 08:02:45 1995    <tytso@rsx-11.mit.edu>
+
+	* block.c (block_iterate_ind, block_iterate_dind, 
+		block_iterate_tind): Precompute limit of loop to speed up
+		block_iterate_ind and company.
+
+	* bitops.h (ext2fs_fast_mark_block_bitmap, 
+		ext2fs_fast_unmark_block_bitmap, ext2fs_fast_test_block_bitmap,
+		ext2fs_fast_mark_inode_bitmap, ext2fs_fast_unmark_inode_bitmap,
+		ext2fs_fast_test_inode_bitmap): Add fast version of these
+		functions, which don't do range checking.
+
+	* bitops.h (ext2fs_get_block_bitmap_start, 
+		ext2fs_get_inode_bitmap_start, ext2fs_get_block_bitmap_end,
+		ext2fs_get_inode_bitmap_end): Add new accessor functions
+		which return the start and end points of the bitmaps.
+
+Tue Jul 11 18:59:41 1995    <tytso@rsx-11.mit.edu>
+
+	* llseek.c (ext2_llseek): If the offset is small enough, use lseek
+		instead of llseek.  The errno if the offset is too large
+		and lseek is not supported should be EINVAL, not -EINVAL.
+
+Thu Jun 15 23:43:02 1995  Remy Card  <card@bbj>
+
+	* Makefile.in: Added support for ELF shared libraries.
+		Fixed typos in the compilation rules.
+		(distclean): Added Makefile.
+
+	* llseek.c (llseek): New function, if llseek() does not exist in the
+	C library.
+	(ext2_llseek): Changed to call llseek().
+
+Mon Jun 12 08:29:07 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* ext2fs.h: Use __u32 to define blk_t, instead of unsigned long.
+
+Sun Jun 11 15:02:54 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* mkdir.c (ext2fs_mkdir): Use LINUX_S_IFDIR instead of S_IFDIR.
+
+	* ext2fs.h (LINUX_S_IFDIR): Define a linux specific versions of
+		the S_*, which are normally defined in <sys/stat.h>.  This
+		allows us to compile e2fsprogs on a non-Linux system,
+		which may have a different value for S_IFDIR.
+
+Sat Jun 10 23:47:05 1995  Theodore Y. Ts'o  <tytso@lurch.mit.edu>
+
+	* bitops.c (clear_bit, set_bit): Remove calls to cli() and sti();
+		this is a user-mode application!
+
+Thu Jun  8 13:13:22 1995  Miles Bader  <miles@churchy.gnu.ai.mit.edu>
+
+	* llseek.c: Put the include of <linux/unistd.h> inside the #ifdef
+	__linux__ so that non-linux systems won't see it.
+
+	* alloc.c: Include <errno.h> if possible.
+	* badblocks.c: Ditto.
+	* bb_inode.c: Ditto.
+	* bitmaps.c: Ditto.
+	* block.c: Ditto.
+	* expanddir.c: Ditto.
+	* get_pathname.c: Ditto.
+	* initialize.c: Ditto.
+	* inode.c: Ditto.
+	* llseek.c: Ditto.
+	* mkdir.c: Ditto.
+	* namei.c: Ditto.
+	* newdir.c: Ditto.
+	* openfs.c: Ditto.
+	* rw_bitmaps.c: Ditto.
+	* unix_io.c: Ditto.
+
+	* Makefile.in: Rewritten to conform to GNU coding standards and
+	support separate compilation directories.
+
+Thu May 11 04:13:12 1995    <tytso@rsx-11.mit.edu>
+
+	* initialize.c (ext2fs_initialize): Don't allow more than one
+		bitmaps's worth of inodes in a group.
+
+Sat Mar 11 14:07:11 1995  Theodore Y. Ts'o  <tytso@localhost>
+
+	* llseek.c (ext2_llseek): Added error checking to the llseek()
+		compat code to protect against overflow.  This only
+		applies to 1.0 and early 1.1 kernels, which don't support
+		the llseek() system call.
+
+Thu Nov 24 16:29:00 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* unix_io.c (unix_open): Initialize the read_error and write_error
+		io_channel pointers to be null.
+
+	* bb_inode.c (clear_bad_block_proc): If an illegal block number is
+		found, clear it but don't try to update the filesystem
+		accounting information, since that's hopeless anyway.
+
+	* block.c (bloblock_iterate_ind, bloblock_iterate_dind,
+	bloblock_iterate_tind): Check to see if the indirect blocks are
+		valid before trying to read them.
+
+	* ext2_err.et (EXT2_ET_BAD_IND_BLOCK, EX2_ET_BAD_DIND_BLOCK,
+	EXT2_ET_BAD_TIND_BLOCK): Add new error codes.
+
+	* bitops.h (ext2fs_mark_block_bitmap, ext2fs_unmark_block_bitmap,
+	ext2fs_test_block_bitmap, ext2fs_mark_inode_bitmap,
+	ext2fs_unmark_inode_bitmap, ext2fs_test_inode_bitmap):  If an
+		illegal block or inode number is passed in, return instead
+		of trying to test, set, or clear the bit.
+
+Mon Nov  7 21:32:33 1994  Remy Card  <card@bbj>
+
+	* Makefile: Added a dummy install target in case shared libraries
+		are not built.
+
+Mon Oct 24 14:11:44 1994    (tytso@rsx-11)
+
+	* bitmaps.c (ext2fs_allocate_block_bitmap): Fix calculation of how
+		the real last block of the bitmap should be calculated.
+
+Wed Sep  7 10:05:36 1994    (tytso@rsx-11)
+
+	* bitmaps.c (ext2fs_fudge_inode_bitmap_end, 
+		ext2fs_fudge_block_bitmap_end, ext2fs_clear_inode_bitmap,
+		ext2fs_clear_block_bitmap, ext2fs_free_inode_bitmap,
+		ext2fs_free_block_bitmap): Add magic number checking for
+		the inode and block bitmaps.
+
+	* bitmaps.c (ext2fs_allocate_block_bitmap): Fix to set the correct
+		magic number for a block bitmap instead of an inode bitmap.
+
+	* inode.c (ext2fs_close_inode_scan, ext2fs_get_next_inode):  Add
+		magic number checking for the inode_scan structure.
+
+	* badblocks.c (badblocks_list_free, badblocks_list_add, 
+		badblocks_list_test, badblocks_list_iterate_begin,
+		badblocks_list_iterate, badblocks_list_iterate_end): Add
+		magic number checking for the badblocks_list and
+		badblocks_iterate structures.
+
+	* ext2_err.et (EXT2_ET_MAGIC_UNIX_IO_CHANNEL): 
+	* unix_io.c (unix_open, unix_close, unix_set_blksize, unix_read_blk,
+		unix_write_blk, unix_flush): Add magic number checking
+		both for io_channel structure and unix_private_data
+		structure.
+
+	* openfs.c (ext2fs_open): Add check for io_manager structure's
+		magic number.
+
+	* rw_bitmaps.c (ext2fs_write_inode_bitmap, ext2fs_write_block_bitmap,
+		ext2fs_read_inode_bitmap, ext2fs_read_block_bitmap,
+		ext2fs_read_bitmaps, ext2fs_write_bitmaps): 
+	* read_bb.c (ext2fs_read_bb_inode): 
+	* read_bb_file.c (ext2fs_read_bb_FILE): 
+	* newdir.c (ext2fs_new_dir_block): 
+	* namei.c (ext2fs_dir_iterate, ext2fs_lookup, ext2fs_namei): 
+	* link.c (ext2fs_link, ext2fs_unlink): 
+	* inode.c (ext2fs_open_inode_scan, ext2fs_read_inode,
+		ext2fs_write_inode, ext2fs_get_blocks, 
+		ext2fs_check_directory): 
+	* get_pathname.c (ext2fs_get_pathname): 
+	* expanddir.c (ext2fs_expand_dir): 
+	* block.c (ext2fs_block_iterate): 
+	* bitmaps.c (ext2fs_allocate_inode_bitmap, 
+		ext2fs_allocate_block_bitmap): 
+	* bb_inode.c (ext2fs_update_bb_inode): 
+	* alloc.c (ext2fs_new_inode,ext2fs_new_block,ext2fs_get_free_blocks): 
+	* check_desc.c (ext2fs_check_desc): 
+	* closefs.c (ext2fs_close, ext2fs_flush): 
+	* freefs.c (ext2fs_free): Add check for ext2_filsys magic number.
+
+	* Makefile:
+	* ext2fs.h:
+	* openfs.c:
+	* check_desc.c (ext2fs_check_desc): Move ext2fs_check_desc from
+	openfs.c into its own file.
+
+	* ext2fs.h (EXT2_CHECK_MAGIC): Added macro for checking for
+	structure magic numbers.
+
+	* closefs.c (ext2fs_flush): Folded in Remy Card's changes to clear
+	the EXT2_VALID_FS flag in the backup superblock blocks, so that if
+	someone uses the -b option to specify the use of the backup
+	superblock --- this usually means that the main superblock is
+	toast.  :-)
+
+	* ext2fs.h: 
+	* ext2_err.et (EXT2_ET_REV_TOO_HIGH): 
+	* openfs.c (ext2fs_open): Folded in Remy Card's changes to add a
+	revision level to the superblock.
+
+Sun Aug 21 00:50:08 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* ext2fs.h:
+	* bitmaps.c:
+	* bitops.c
+	* bitops.h:
+	* openfs.c:
+	* initialize.c: Completely revamped the inode and block bitmap
+	structures, so that they can be better chance of being extensible
+	in a shared library.  They are now their own type, instead of
+	being a char *.  Also, the function signatures of
+	ext2fs_test_block_bitmap, ext2fs_mark_block_bitmap,
+	ext2fs_unmark_block_bitmap, ext2fs_test_inode_bitmap,
+	ext2fs_mark_inode_bitmap, and ext2fs_unmark_inode_bitmap were
+	changed to eliminate the ext2_filsys argument, since it is no
+	longer necessary.
+
+Wed Aug 17 21:46:44 1994  Remy Card  (card@bbj)
+
+	* unix_io.c (unix_read_blk and unix_write_blk): use the llseek
+	system call if available.
+
+	* llseek.c: new file.  This is the stub calling the llseek system
+	call which allows supports for 2GB+ file systems.
+
+	* initialize.c (ext2fs_initialize): Ext2fs_initialize now stores
+	the creator operating system.
+
+Wed Aug 17 10:03:24 1994  Theodore Y. Ts'o  (tytso@rt-11)
+
+	* initialize.c (ext2fs_initialize): Ext2fs_initialize now sets up
+	the group descriptor statistics in addition to everything else.
+	This relieves mke2fs of the responsibility of doing it.
+
+	* bitops.c, bitops.h: Add assembly inline functions for the 68000.
+	Added a new #define, _EXT2_HAVE_ASM_BITOPS_ to control whether or
+	not the generic C function equivalents should be included or not.
+
+	* openfs.c (ext2fs_open): If a superblock is specified, then use
+	the backup group descriptors that go along with this superblock,
+	instead of using the primary group descriptors.  This allows
+	e2fsck to recover filesystems where the primary group descriptors
+	have been trashed.
+
+
diff -Naur silo-1.4.11.orig/libext2fs/Makefile silo-1.4.11/libext2fs/Makefile
--- silo-1.4.11.orig/libext2fs/Makefile	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/Makefile	2006-03-09 21:34:56 +0000
@@ -0,0 +1,21 @@
+
+include ../Rules.make
+
+DEFS = -DLOCALEDIR=\"$(localedir)\" -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DENABLE_HTREE=1 -DENABLE_SWAPFS=1 -DPACKAGE=\"e2fsprogs\" -DVERSION=\"0.14.1\" -DHAVE_LONG_LONG=1 -DHAVE_LONG_DOUBLE=1 -DHAVE_WCHAR_T=1 -DHAVE_WINT_T=1 -DHAVE_INTTYPES_H_WITH_UINTMAX=1 -DHAVE_STDINT_H_WITH_UINTMAX=1 -DHAVE_INTMAX_T=1 -DHAVE_POSIX_PRINTF=1 -DHAVE_ALLOCA_H=1 -DHAVE_ALLOCA=1 -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETPAGESIZE=1 -DHAVE_MMAP=1 -DINTDIV0_RAISES_SIGFPE=1 -DHAVE_UNSIGNED_LONG_LONG=1 -DHAVE_UINTMAX_T=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_STDINT_H=1 -DHAVE_ARGZ_H=1 -DHAVE_LIMITS_H=1 -DHAVE_LOCALE_H=1 -DHAVE_NL_TYPES_H=1 -DHAVE_MALLOC_H=1 -DHAVE_STDDEF_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_PARAM_H=1 -DHAVE_ASPRINTF=1 -DHAVE_FWPRINTF=1 -DHAVE_GETCWD=1 -DHAVE_GETEGID=1 -DHAVE_GETEUID=1 -DHAVE_GETGID=1 -DHAVE_GETUID=1 -DHAVE_MEMPCPY=1 -DHAVE_MUNMAP=1 -DHAVE_PUTENV=1 -DHAVE_SETENV=1 -DHAVE_SETLOCALE=1 -DHAVE_SNPRINTF=1 -DHAVE_STPCPY=1 -DHAVE_STRCASECMP=1 -DHAVE_STRDUP=1 -DHAVE_STRTOUL=1 -DHAVE_TSEARCH=1 -DHAVE_WCSLEN=1 -DHAVE___ARGZ_COUNT=1 -DHAVE___ARGZ_STRINGIFY=1 -DHAVE___ARGZ_NEXT=1 -DHAVE___FSETLOCKING=1 -DHAVE_DECL__SNPRINTF=0 -DHAVE_DECL__SNWPRINTF=0 -DHAVE_DECL_FEOF_UNLOCKED=1 -DHAVE_DECL_FGETS_UNLOCKED=0 -DHAVE_DECL_GETC_UNLOCKED=1 -DHAVE_ICONV=1 -DICONV_CONST= -DHAVE_LANGINFO_CODESET=1 -DHAVE_LC_MESSAGES=1 -DENABLE_NLS=1 -DHAVE_GETTEXT=1 -DHAVE_DCGETTEXT=1 -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDARG_H=1 -DHAVE_STDINT_H=1 -DHAVE_ERRNO_H=1 -DHAVE_MALLOC_H=1 -DHAVE_MNTENT_H=1 -DHAVE_PATHS_H=1 -DHAVE_DIRENT_H=1 -DHAVE_GETOPT_H=1 -DHAVE_SETJMP_H=1 -DHAVE_SIGNAL_H=1 -DHAVE_TERMIOS_H=1 -DHAVE_LINUX_FD_H=1 -DHAVE_LINUX_MAJOR_H=1 -DHAVE_SYS_IOCTL_H=1 -DHAVE_SYS_PRCTL_H=1 -DHAVE_SYS_QUEUE_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_SYS_SYSMACROS_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_WAIT_H=1 -DHAVE_SYS_RESOURCE_H=1 -DHAVE_NETINET_IN_H=1 -DHAVE_SYS_MOUNT_H=1 -DHAVE_NET_IF_H=1 -DHAVE_VPRINTF=1 -DHAVE_RECLEN_DIRENT=1 -DHAVE_TYPE_SSIZE_T=1 -DHAVE_LSEEK64_PROTOTYPE=1 -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8 -DHAVE_INTTYPES_H=1 -DHAVE_INTPTR_T=1 -DHAVE_GETRUSAGE=1 -DHAVE_LLSEEK=1 -DHAVE_LSEEK64=1 -DHAVE_OPEN64=1 -DHAVE_STRTOULL=1 -DHAVE_STRCASECMP=1 -DHAVE_SRANDOM=1 -DHAVE_FCHOWN=1 -DHAVE_MALLINFO=1 -DHAVE_FDATASYNC=1 -DHAVE_STRNLEN=1 -DHAVE_STRPTIME=1 -DHAVE_SYSCONF=1 -DHAVE_PATHCONF=1 -DHAVE_POSIX_MEMALIGN=1 -DHAVE_MEMALIGN=1 -DHAVE_VALLOC=1 -DHAVE___SECURE_GETENV=1 -DHAVE_PRCTL=1 -DHAVE_DLOPEN=1 -DHAVE_EXT2_IOCTLS=1
+
+DEBUGFS_LIB_OBJS = inode_io.o namei.o write_bb_file.o 
+RESIZE_LIB_OBJS = rs_bitmap.o dupfs.o test_io.o 
+E2IMAGE_LIB_OBJS = imager.o
+OBJS= $(DEBUGFS_LIB_OBJS) $(RESIZE_LIB_OBJS) $(E2IMAGE_LIB_OBJS) ext2_err.o alloc.o alloc_sb.o alloc_stats.o alloc_tables.o badblocks.o bb_inode.o bitmaps.o bitops.o block.o bmap.o check_desc.o closefs.o dblist.o dblist_dir.o dirblock.o dirhash.o dir_iterate.o expanddir.o ext_attr.o finddev.o flushb.o freefs.o gen_bitmap.o get_pathname.o getsize.o getsectsize.o icount.o ind_block.o initialize.o inline.o inode.o io_manager.o ismounted.o link.o llseek.o lookup.o mkdir.o mkjournal.o native.o newdir.o openfs.o read_bb.o read_bb_file.o res_gdt.o rw_bitmaps.o swapfs.o unix_io.o unlink.o valid_blk.o version.o
+
+all: libext2fs.a
+
+libext2fs.a: $(OBJS)
+	$(RM) libext2fs.a
+	$(AR) rc libext2fs.a $(OBJS)
+
+clean:
+	$(RM) -f libext2fs.a $(OBJS)
+
+.c.o:
+	$(CC-SILO) $(CFLAGS) $(DEFS) -c $< -o $@
diff -Naur silo-1.4.11.orig/libext2fs/alloc.c silo-1.4.11/libext2fs/alloc.c
--- silo-1.4.11.orig/libext2fs/alloc.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/alloc.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,173 @@
+/*
+ * alloc.c --- allocate new inodes, blocks for ext2fs
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Right now, just search forward from the parent directory's block
+ * group to find the next free inode.
+ *
+ * Should have a special policy for directories.
+ */
+errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, 
+			   int mode EXT2FS_ATTR((unused)),
+			   ext2fs_inode_bitmap map, ext2_ino_t *ret)
+{
+	ext2_ino_t	dir_group = 0;
+	ext2_ino_t	i;
+	ext2_ino_t	start_inode;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	
+	if (!map)
+		map = fs->inode_map;
+	if (!map)
+		return EXT2_ET_NO_INODE_BITMAP;
+	
+	if (dir > 0) 
+		dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
+
+	start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
+	if (start_inode < EXT2_FIRST_INODE(fs->super))
+		start_inode = EXT2_FIRST_INODE(fs->super);
+	i = start_inode;
+
+	do {
+		if (!ext2fs_fast_test_inode_bitmap(map, i))
+			break;
+		i++;
+		if (i > fs->super->s_inodes_count)
+			i = EXT2_FIRST_INODE(fs->super);
+	} while (i != start_inode);
+	
+	if (ext2fs_test_inode_bitmap(map, i))
+		return EXT2_ET_INODE_ALLOC_FAIL;
+	*ret = i;
+	return 0;
+}
+
+/*
+ * Stupid algorithm --- we now just search forward starting from the
+ * goal.  Should put in a smarter one someday....
+ */
+errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
+			   ext2fs_block_bitmap map, blk_t *ret)
+{
+	blk_t	i;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!map)
+		map = fs->block_map;
+	if (!map)
+		return EXT2_ET_NO_BLOCK_BITMAP;
+	if (!goal || (goal >= fs->super->s_blocks_count))
+		goal = fs->super->s_first_data_block;
+	i = goal;
+	do {
+		if (!ext2fs_fast_test_block_bitmap(map, i)) {
+			*ret = i;
+			return 0;
+		}
+		i++;
+		if (i >= fs->super->s_blocks_count)
+			i = fs->super->s_first_data_block;
+	} while (i != goal);
+	return EXT2_ET_BLOCK_ALLOC_FAIL;
+}
+
+/*
+ * This function zeros out the allocated block, and updates all of the
+ * appropriate filesystem records.
+ */
+errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+			     char *block_buf, blk_t *ret)
+{
+	errcode_t	retval;
+	blk_t		block;
+	char		*buf = 0;
+
+	if (!block_buf) {
+		retval = ext2fs_get_mem(fs->blocksize, &buf);
+		if (retval)
+			return retval;
+		block_buf = buf;
+	}
+	memset(block_buf, 0, fs->blocksize);
+
+	if (!fs->block_map) {
+		retval = ext2fs_read_block_bitmap(fs);
+		if (retval)
+			goto fail;
+	}
+
+	retval = ext2fs_new_block(fs, goal, 0, &block);
+	if (retval)
+		goto fail;
+
+	retval = io_channel_write_blk(fs->io, block, 1, block_buf);
+	if (retval)
+		goto fail;
+	
+	ext2fs_block_alloc_stats(fs, block, +1);
+	*ret = block;
+	return 0;
+
+fail:
+	if (buf)
+		ext2fs_free_mem(&buf);
+	return retval;
+}
+
+errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
+				 int num, ext2fs_block_bitmap map, blk_t *ret)
+{
+	blk_t	b = start;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!map)
+		map = fs->block_map;
+	if (!map)
+		return EXT2_ET_NO_BLOCK_BITMAP;
+	if (!b)
+		b = fs->super->s_first_data_block;
+	if (!finish)
+		finish = start;
+	if (!num)
+		num = 1;
+	do {
+		if (b+num-1 > fs->super->s_blocks_count)
+			b = fs->super->s_first_data_block;
+		if (ext2fs_fast_test_block_bitmap_range(map, b, num)) {
+			*ret = b;
+			return 0;
+		}
+		b++;
+	} while (b != finish);
+	return EXT2_ET_BLOCK_ALLOC_FAIL;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/alloc_sb.c silo-1.4.11/libext2fs/alloc_sb.c
--- silo-1.4.11.orig/libext2fs/alloc_sb.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/alloc_sb.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,57 @@
+/*
+ * alloc_sb.c --- Allocate the superblock and block group descriptors for a 
+ * newly initialized filesystem.  Used by mke2fs when initializing a filesystem
+ *
+ * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
+				 dgrp_t group,
+				 ext2fs_block_bitmap bmap)
+{
+	blk_t	super_blk, old_desc_blk, new_desc_blk;
+	int	j, old_desc_blocks, num_blocks;
+
+	num_blocks = ext2fs_super_and_bgd_loc(fs, group, &super_blk, 
+					      &old_desc_blk, &new_desc_blk, 0);
+
+	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+		old_desc_blocks = fs->super->s_first_meta_bg;
+	else
+		old_desc_blocks = 
+			fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
+
+	if (super_blk || (group == 0))
+		ext2fs_mark_block_bitmap(bmap, super_blk);
+
+	if (old_desc_blk) {
+		for (j=0; j < old_desc_blocks; j++)
+			ext2fs_mark_block_bitmap(bmap, old_desc_blk + j);
+	}
+	if (new_desc_blk)
+		ext2fs_mark_block_bitmap(bmap, new_desc_blk);
+
+	return num_blocks;
+}
diff -Naur silo-1.4.11.orig/libext2fs/alloc_stats.c silo-1.4.11/libext2fs/alloc_stats.c
--- silo-1.4.11.orig/libext2fs/alloc_stats.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/alloc_stats.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,52 @@
+/*
+ * alloc_stats.c --- Update allocation statistics for ext2fs
+ *
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
+			       int inuse, int isdir)
+{
+	int	group = ext2fs_group_of_ino(fs, ino);
+
+	if (inuse > 0)
+		ext2fs_mark_inode_bitmap(fs->inode_map, ino);
+	else
+		ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
+	fs->group_desc[group].bg_free_inodes_count -= inuse;
+	if (isdir)
+		fs->group_desc[group].bg_used_dirs_count += inuse;
+	fs->super->s_free_inodes_count -= inuse;
+	ext2fs_mark_super_dirty(fs);
+	ext2fs_mark_ib_dirty(fs);
+}
+
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
+{
+	ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
+}
+
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
+{
+	int	group = ext2fs_group_of_blk(fs, blk);
+
+	if (inuse > 0)
+		ext2fs_mark_block_bitmap(fs->block_map, blk);
+	else
+		ext2fs_unmark_block_bitmap(fs->block_map, blk);
+	fs->group_desc[group].bg_free_blocks_count -= inuse;
+	fs->super->s_free_blocks_count -= inuse;
+	ext2fs_mark_super_dirty(fs);
+	ext2fs_mark_bb_dirty(fs);
+}
diff -Naur silo-1.4.11.orig/libext2fs/alloc_tables.c silo-1.4.11/libext2fs/alloc_tables.c
--- silo-1.4.11.orig/libext2fs/alloc_tables.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/alloc_tables.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,117 @@
+/*
+ * alloc_tables.c --- Allocate tables for a newly initialized
+ * filesystem.  Used by mke2fs when initializing a filesystem
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
+				      ext2fs_block_bitmap bmap)
+{
+	errcode_t	retval;
+	blk_t		group_blk, start_blk, last_blk, new_blk, blk;
+	int		j;
+
+	group_blk = fs->super->s_first_data_block +
+		(group * fs->super->s_blocks_per_group);
+	
+	last_blk = group_blk + fs->super->s_blocks_per_group;
+	if (last_blk >= fs->super->s_blocks_count)
+		last_blk = fs->super->s_blocks_count - 1;
+
+	if (!bmap)
+		bmap = fs->block_map;
+	
+	/*
+	 * Allocate the block and inode bitmaps, if necessary
+	 */
+	if (fs->stride) {
+		start_blk = group_blk + fs->inode_blocks_per_group;
+		start_blk += ((fs->stride * group) %
+			      (last_blk - start_blk));
+		if (start_blk > last_blk)
+			start_blk = group_blk;
+	} else
+		start_blk = group_blk;
+
+	if (!fs->group_desc[group].bg_block_bitmap) {
+		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+						1, bmap, &new_blk);
+		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) 
+			retval = ext2fs_get_free_blocks(fs, group_blk,
+					last_blk, 1, bmap, &new_blk);
+		if (retval)
+			return retval;
+		ext2fs_mark_block_bitmap(bmap, new_blk);
+		fs->group_desc[group].bg_block_bitmap = new_blk;
+	}
+
+	if (!fs->group_desc[group].bg_inode_bitmap) {
+		retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
+						1, bmap, &new_blk);
+		if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) 
+			retval = ext2fs_get_free_blocks(fs, group_blk,
+					last_blk, 1, bmap, &new_blk);
+		if (retval)
+			return retval;
+		ext2fs_mark_block_bitmap(bmap, new_blk);
+		fs->group_desc[group].bg_inode_bitmap = new_blk;
+	}
+
+	/*
+	 * Allocate the inode table
+	 */
+	if (!fs->group_desc[group].bg_inode_table) {
+		retval = ext2fs_get_free_blocks(fs, group_blk, last_blk,
+						fs->inode_blocks_per_group,
+						bmap, &new_blk);
+		if (retval)
+			return retval;
+		for (j=0, blk = new_blk;
+		     j < fs->inode_blocks_per_group;
+		     j++, blk++)
+			ext2fs_mark_block_bitmap(bmap, blk);
+		fs->group_desc[group].bg_inode_table = new_blk;
+	}
+
+	
+	return 0;
+}
+
+	
+
+errcode_t ext2fs_allocate_tables(ext2_filsys fs)
+{
+	errcode_t	retval;
+	dgrp_t		i;
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+		retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/badblocks.c silo-1.4.11/libext2fs/badblocks.c
--- silo-1.4.11.orig/libext2fs/badblocks.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/badblocks.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,327 @@
+/*
+ * badblocks.c --- routines to manipulate the bad block structure
+ * 
+ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * Helper function for making a badblocks list
+ */
+static errcode_t make_u32_list(int size, int num, __u32 *list,
+			       ext2_u32_list *ret)
+{
+	ext2_u32_list	bb;
+	errcode_t	retval;
+	
+	retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
+	if (retval)
+		return retval;
+	memset(bb, 0, sizeof(struct ext2_struct_u32_list));
+	bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
+	bb->size = size ? size : 10;
+	bb->num = num;
+	retval = ext2fs_get_mem(bb->size * sizeof(blk_t), &bb->list);
+	if (!bb->list) {
+		ext2fs_free_mem(&bb);
+		return retval;
+	}
+	if (list)
+		memcpy(bb->list, list, bb->size * sizeof(blk_t));
+	else
+		memset(bb->list, 0, bb->size * sizeof(blk_t));
+	*ret = bb;
+	return 0;
+}
+	
+
+/*
+ * This procedure creates an empty u32 list.
+ */
+errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
+{
+	return make_u32_list(size, 0, 0, ret);
+}
+
+/*
+ * This procedure creates an empty badblocks list.
+ */
+errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
+{
+	return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
+}
+
+
+/*
+ * This procedure copies a badblocks list
+ */
+errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
+{
+	errcode_t	retval;
+	
+	retval = make_u32_list(src->size, src->num, src->list, dest);
+	if (retval)
+		return retval;
+	(*dest)->badblocks_flags = src->badblocks_flags;
+	return 0;
+}
+
+errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
+				ext2_badblocks_list *dest)
+{
+	return ext2fs_u32_copy((ext2_u32_list) src,
+			       (ext2_u32_list *) dest);
+}
+
+/*
+ * This procedure frees a badblocks list.
+ *
+ * (note: moved to closefs.c)
+ */
+
+
+/*
+ * This procedure adds a block to a badblocks list.
+ */
+errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
+{
+	errcode_t	retval;
+	int		i, j;
+	unsigned long	old_size;
+
+	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+	if (bb->num >= bb->size) {
+		old_size = bb->size * sizeof(__u32);
+		bb->size += 100;
+		retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
+					   &bb->list);
+		if (retval) {
+			bb->size -= 100;
+			return retval;
+		}
+	}
+
+	/*
+	 * Add special case code for appending to the end of the list
+	 */
+	i = bb->num-1;
+	if ((bb->num != 0) && (bb->list[i] == blk))
+		return 0;
+	if ((bb->num == 0) || (bb->list[i] < blk)) {
+		bb->list[bb->num++] = blk;
+		return 0;
+	}
+
+	j = bb->num;
+	for (i=0; i < bb->num; i++) {
+		if (bb->list[i] == blk)
+			return 0;
+		if (bb->list[i] > blk) {
+			j = i;
+			break;
+		}
+	}
+	for (i=bb->num; i > j; i--)
+		bb->list[i] = bb->list[i-1];
+	bb->list[j] = blk;
+	bb->num++;
+	return 0;
+}
+
+errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
+{
+	return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
+}
+
+/*
+ * This procedure finds a particular block is on a badblocks
+ * list.
+ */
+int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
+{
+	int	low, high, mid;
+
+	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+		return -1;
+
+	if (bb->num == 0)
+		return -1;
+
+	low = 0;
+	high = bb->num-1;
+	if (blk == bb->list[low])
+		return low;
+	if (blk == bb->list[high])
+		return high;
+
+	while (low < high) {
+		mid = (low+high)/2;
+		if (mid == low || mid == high)
+			break;
+		if (blk == bb->list[mid])
+			return mid;
+		if (blk < bb->list[mid])
+			high = mid;
+		else
+			low = mid;
+	}
+	return -1;
+}
+
+/*
+ * This procedure tests to see if a particular block is on a badblocks
+ * list.
+ */
+int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
+{
+	if (ext2fs_u32_list_find(bb, blk) < 0)
+		return 0;
+	else
+		return 1;
+}
+
+int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
+{
+	return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
+}
+
+
+/*
+ * Remove a block from the badblock list
+ */
+int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
+{
+	int	remloc, i;
+
+	if (bb->num == 0)
+		return -1;
+
+	remloc = ext2fs_u32_list_find(bb, blk);
+	if (remloc < 0)
+		return -1;
+
+	for (i = remloc ; i < bb->num-1; i++)
+		bb->list[i] = bb->list[i+1];
+	bb->num--;
+	return 0;
+}
+
+void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
+{
+	ext2fs_u32_list_del(bb, blk);
+}
+
+errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+					ext2_u32_iterate *ret)
+{
+	ext2_u32_iterate iter;
+	errcode_t		retval;
+
+	EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
+	if (retval)
+		return retval;
+
+	iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
+	iter->bb = bb;
+	iter->ptr = 0;
+	*ret = iter;
+	return 0;
+}
+
+errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+					      ext2_badblocks_iterate *ret)
+{
+	return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
+					      (ext2_u32_iterate *) ret);
+}
+
+
+int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
+{
+	ext2_u32_list	bb;
+
+	if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
+		return 0;
+
+	bb = iter->bb;
+
+	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+		return 0;
+	
+	if (iter->ptr < bb->num) {
+		*blk = bb->list[iter->ptr++];
+		return 1;
+	} 
+	*blk = 0;
+	return 0;
+}
+
+int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
+{
+	return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
+				       (__u32 *) blk);
+}
+
+
+void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
+{
+	if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
+		return;
+
+	iter->bb = 0;
+	ext2fs_free_mem(&iter);
+}
+
+void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
+{
+	ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
+}
+
+
+int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
+{
+	EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+	EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
+
+	if (bb1->num != bb2->num)
+		return 0;
+
+	if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
+		return 0;
+	return 1;
+}
+
+int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
+{
+	return ext2fs_u32_list_equal((ext2_u32_list) bb1,
+				     (ext2_u32_list) bb2);
+}
+
+int ext2fs_u32_list_count(ext2_u32_list bb)
+{
+	return bb->num;
+}
diff -Naur silo-1.4.11.orig/libext2fs/bb_compat.c silo-1.4.11/libext2fs/bb_compat.c
--- silo-1.4.11.orig/libext2fs/bb_compat.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bb_compat.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,63 @@
+/*
+ * bb_compat.c --- compatibility badblocks routines
+ * 
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+errcode_t badblocks_list_create(badblocks_list *ret, int size)
+{
+	return ext2fs_badblocks_list_create(ret, size);
+}
+
+void badblocks_list_free(badblocks_list bb)
+{
+	ext2fs_badblocks_list_free(bb);
+}
+
+errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
+{
+	return ext2fs_badblocks_list_add(bb, blk);
+}
+
+int badblocks_list_test(badblocks_list bb, blk_t blk)
+{
+	return ext2fs_badblocks_list_test(bb, blk);
+}
+
+errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+				       badblocks_iterate *ret)
+{
+	return ext2fs_badblocks_list_iterate_begin(bb, ret);
+}
+
+int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
+{
+	return ext2fs_badblocks_list_iterate(iter, blk);
+}
+
+void badblocks_list_iterate_end(badblocks_iterate iter)
+{
+	ext2fs_badblocks_list_iterate_end(iter);
+}
diff -Naur silo-1.4.11.orig/libext2fs/bb_inode.c silo-1.4.11/libext2fs/bb_inode.c
--- silo-1.4.11.orig/libext2fs/bb_inode.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bb_inode.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,267 @@
+/*
+ * bb_inode.c --- routines to update the bad block inode.
+ * 
+ * WARNING: This routine modifies a lot of state in the filesystem; if
+ * this routine returns an error, the bad block inode may be in an
+ * inconsistent state.
+ * 
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct set_badblock_record {
+	ext2_badblocks_iterate	bb_iter;
+	int		bad_block_count;
+	blk_t		*ind_blocks;
+	int		max_ind_blocks;
+	int		ind_blocks_size;
+	int		ind_blocks_ptr;
+	char		*block_buf;
+	errcode_t	err;
+};
+
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+			      e2_blkcnt_t blockcnt,
+			      blk_t ref_block, int ref_offset,
+			      void *priv_data);
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+				e2_blkcnt_t blockcnt,
+				blk_t ref_block, int ref_offset,
+				void *priv_data);
+	
+/*
+ * Given a bad blocks bitmap, update the bad blocks inode to reflect
+ * the map.
+ */
+errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
+{
+	errcode_t			retval;
+	struct set_badblock_record 	rec;
+	struct ext2_inode		inode;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!fs->block_map)
+		return EXT2_ET_NO_BLOCK_BITMAP;
+	
+	rec.bad_block_count = 0;
+	rec.ind_blocks_size = rec.ind_blocks_ptr = 0;
+	rec.max_ind_blocks = 10;
+	retval = ext2fs_get_mem(rec.max_ind_blocks * sizeof(blk_t),
+				&rec.ind_blocks);
+	if (retval)
+		return retval;
+	memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
+	retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
+	if (retval)
+		goto cleanup;
+	memset(rec.block_buf, 0, fs->blocksize);
+	rec.err = 0;
+	
+	/*
+	 * First clear the old bad blocks (while saving the indirect blocks) 
+	 */
+	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
+				       BLOCK_FLAG_DEPTH_TRAVERSE, 0,
+				       clear_bad_block_proc, &rec);
+	if (retval)
+		goto cleanup;
+	if (rec.err) {
+		retval = rec.err;
+		goto cleanup;
+	}
+	
+	/*
+	 * Now set the bad blocks!
+	 *
+	 * First, mark the bad blocks as used.  This prevents a bad
+	 * block from being used as an indirecto block for the bad
+	 * block inode (!).
+	 */
+	if (bb_list) {
+		retval = ext2fs_badblocks_list_iterate_begin(bb_list,
+							     &rec.bb_iter);
+		if (retval)
+			goto cleanup;
+		retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
+					       BLOCK_FLAG_APPEND, 0,
+					       set_bad_block_proc, &rec);
+		ext2fs_badblocks_list_iterate_end(rec.bb_iter);
+		if (retval) 
+			goto cleanup;
+		if (rec.err) {
+			retval = rec.err;
+			goto cleanup;
+		}
+	}
+	
+	/*
+	 * Update the bad block inode's mod time and block count
+	 * field.  
+	 */
+	retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+	if (retval)
+		goto cleanup;
+	
+	inode.i_atime = inode.i_mtime = time(0);
+	if (!inode.i_ctime)
+		inode.i_ctime = time(0);
+	inode.i_blocks = rec.bad_block_count * (fs->blocksize / 512);
+	inode.i_size = rec.bad_block_count * fs->blocksize;
+
+	retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
+	if (retval)
+		goto cleanup;
+	
+cleanup:
+	ext2fs_free_mem(&rec.ind_blocks);
+	ext2fs_free_mem(&rec.block_buf);
+	return retval;
+}
+
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Clear the bad blocks in the bad block inode, while saving the
+ * indirect blocks.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+				e2_blkcnt_t blockcnt,
+				blk_t ref_block EXT2FS_ATTR((unused)),
+				int ref_offset EXT2FS_ATTR((unused)),
+				void *priv_data)
+{
+	struct set_badblock_record *rec = (struct set_badblock_record *)
+		priv_data;
+	errcode_t	retval;
+	unsigned long 	old_size;
+
+	if (!*block_nr)
+		return 0;
+
+	/*
+	 * If the block number is outrageous, clear it and ignore it.
+	 */
+	if (*block_nr >= fs->super->s_blocks_count ||
+	    *block_nr < fs->super->s_first_data_block) {
+		*block_nr = 0;
+		return BLOCK_CHANGED;
+	}
+
+	if (blockcnt < 0) {
+		if (rec->ind_blocks_size >= rec->max_ind_blocks) {
+			old_size = rec->max_ind_blocks * sizeof(blk_t);
+			rec->max_ind_blocks += 10;
+			retval = ext2fs_resize_mem(old_size, 
+				   rec->max_ind_blocks * sizeof(blk_t),
+				   &rec->ind_blocks);
+			if (retval) {
+				rec->max_ind_blocks -= 10;
+				rec->err = retval;
+				return BLOCK_ABORT;
+			}
+		}
+		rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
+	}
+
+	/*
+	 * Mark the block as unused, and update accounting information
+	 */
+	ext2fs_block_alloc_stats(fs, *block_nr, -1);
+	
+	*block_nr = 0;
+	return BLOCK_CHANGED;
+}
+
+	
+/*
+ * Helper function for update_bb_inode()
+ *
+ * Set the block list in the bad block inode, using the supplied bitmap.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
+			      e2_blkcnt_t blockcnt,
+			      blk_t ref_block EXT2FS_ATTR((unused)),
+			      int ref_offset EXT2FS_ATTR((unused)),
+			      void *priv_data)
+{
+	struct set_badblock_record *rec = (struct set_badblock_record *)
+		priv_data;
+	errcode_t	retval;
+	blk_t		blk;
+
+	if (blockcnt >= 0) {
+		/*
+		 * Get the next bad block.
+		 */
+		if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
+			return BLOCK_ABORT;
+		rec->bad_block_count++;
+	} else {
+		/*
+		 * An indirect block; fetch a block from the
+		 * previously used indirect block list.  The block
+		 * most be not marked as used; if so, get another one.
+		 * If we run out of reserved indirect blocks, allocate
+		 * a new one.
+		 */
+	retry:
+		if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
+			blk = rec->ind_blocks[rec->ind_blocks_ptr++];
+			if (ext2fs_test_block_bitmap(fs->block_map, blk))
+				goto retry;
+		} else {
+			retval = ext2fs_new_block(fs, 0, 0, &blk);
+			if (retval) {
+				rec->err = retval;
+				return BLOCK_ABORT;
+			}
+		}
+		retval = io_channel_write_blk(fs->io, blk, 1, rec->block_buf);
+		if (retval) {
+			rec->err = retval;
+			return BLOCK_ABORT;
+		}
+	}
+	
+	/*
+	 * Update block counts
+	 */
+	ext2fs_block_alloc_stats(fs, blk, +1);
+	
+	*block_nr = blk;
+	return BLOCK_CHANGED;
+}
+
+
+
+
+
+
diff -Naur silo-1.4.11.orig/libext2fs/bitmaps.c silo-1.4.11/libext2fs/bitmaps.c
--- silo-1.4.11.orig/libext2fs/bitmaps.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bitmaps.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,212 @@
+/*
+ * bitmaps.c --- routines to read, write, and manipulate the inode and
+ * block bitmaps.
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+static errcode_t make_bitmap(__u32 start, __u32 end, __u32 real_end,
+			     const char *descr, char *init_map,
+			     ext2fs_generic_bitmap *ret)
+{
+	ext2fs_generic_bitmap	bitmap;
+	errcode_t		retval;
+	size_t			size;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 
+				&bitmap);
+	if (retval)
+		return retval;
+
+	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) {
+		retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
+		if (retval) {
+			ext2fs_free_mem(&bitmap);
+			return retval;
+		}
+		strcpy(bitmap->description, descr);
+	} else
+		bitmap->description = 0;
+
+	size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
+	retval = ext2fs_get_mem(size, &bitmap->bitmap);
+	if (retval) {
+		ext2fs_free_mem(&bitmap->description);
+		ext2fs_free_mem(&bitmap);
+		return retval;
+	}
+
+	if (init_map)
+		memcpy(bitmap->bitmap, init_map, size);
+	else
+		memset(bitmap->bitmap, 0, size);
+	*ret = bitmap;
+	return 0;
+}
+
+errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
+					 __u32 end,
+					 __u32 real_end,
+					 const char *descr,
+					 ext2fs_generic_bitmap *ret)
+{
+	return make_bitmap(start, end, real_end, descr, 0, ret);
+}
+
+errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+			     ext2fs_generic_bitmap *dest)
+{
+	errcode_t		retval;
+	ext2fs_generic_bitmap	new_map;
+
+	retval = make_bitmap(src->start, src->end, src->real_end,
+			     src->description, src->bitmap, &new_map);
+	if (retval)
+		return retval;
+	new_map->magic = src->magic;
+	new_map->fs = src->fs;
+	new_map->base_error_code = src->base_error_code;
+	*dest = new_map;
+	return 0;
+}
+
+void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
+{
+	__u32	i, j;
+
+	for (i=map->end+1, j = i - map->start; i <= map->real_end; i++, j++)
+		ext2fs_set_bit(j, map->bitmap);
+
+	return;
+}	
+
+errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
+				       const char *descr,
+				       ext2fs_inode_bitmap *ret)
+{
+	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;
+
+	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->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
+	
+	*ret = bitmap;
+	return 0;
+}
+
+errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
+					ext2_ino_t end, ext2_ino_t *oend)
+{
+	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
+	
+	if (end > bitmap->real_end)
+		return EXT2_ET_FUDGE_INODE_BITMAP_END;
+	if (oend)
+		*oend = bitmap->end;
+	bitmap->end = end;
+	return 0;
+}
+
+errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
+					blk_t end, blk_t *oend)
+{
+	EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
+	
+	if (end > bitmap->real_end)
+		return EXT2_ET_FUDGE_BLOCK_BITMAP_END;
+	if (oend)
+		*oend = bitmap->end;
+	bitmap->end = end;
+	return 0;
+}
+
+void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
+{
+	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_INODE_BITMAP))
+		return;
+
+	memset(bitmap->bitmap, 0,
+	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+}
+
+void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
+{
+	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_BLOCK_BITMAP))
+		return;
+
+	memset(bitmap->bitmap, 0,
+	       (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
+}
diff -Naur silo-1.4.11.orig/libext2fs/bitops.c silo-1.4.11/libext2fs/bitops.c
--- silo-1.4.11.orig/libext2fs/bitops.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bitops.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,91 @@
+/*
+ * bitops.c --- Bitmap frobbing code.  See bitops.h for the inlined
+ * 	routines.
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef _EXT2_HAVE_ASM_BITOPS_
+
+/*
+ * For the benefit of those who are trying to port Linux to another
+ * architecture, here are some C-language equivalents.  You should
+ * recode these in the native assmebly language, if at all possible.
+ *
+ * C language equivalents written by Theodore Ts'o, 9/26/92.
+ * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
+ * systems, as well as non-32 bit systems.
+ */
+
+int ext2fs_set_bit(unsigned int nr,void * addr)
+{
+	int		mask, retval;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = mask & *ADDR;
+	*ADDR |= mask;
+	return retval;
+}
+
+int ext2fs_clear_bit(unsigned int nr, void * addr)
+{
+	int		mask, retval;
+	unsigned char	*ADDR = (unsigned char *) addr;
+
+	ADDR += nr >> 3;
+	mask = 1 << (nr & 0x07);
+	retval = mask & *ADDR;
+	*ADDR &= ~mask;
+	return retval;
+}
+
+int ext2fs_test_bit(unsigned 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);
+}
+
+#endif	/* !_EXT2_HAVE_ASM_BITOPS_ */
+
+void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
+			const char *description)
+{
+#ifndef OMIT_COM_ERR
+	if (description)
+		com_err(0, errcode, "#%lu for %s", arg, description);
+	else
+		com_err(0, errcode, "#%lu", arg);
+#endif
+}
+
+void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap,
+			    int code, unsigned long arg)
+{
+#ifndef OMIT_COM_ERR
+	if (bitmap->description)
+		com_err(0, bitmap->base_error_code+code,
+			"#%lu for %s", arg, bitmap->description);
+	else
+		com_err(0, bitmap->base_error_code + code, "#%lu", arg);
+#endif
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/bitops.h silo-1.4.11/libext2fs/bitops.h
--- silo-1.4.11.orig/libext2fs/bitops.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bitops.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,617 @@
+/*
+ * bitops.h --- Bitmap frobbing code.  The byte swapping routines are
+ * 	also included here.
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ * i386 bitops operations taken from <asm/bitops.h>, Copyright 1992,
+ * Linus Torvalds.
+ */
+
+
+extern int ext2fs_set_bit(unsigned int nr,void * addr);
+extern int ext2fs_clear_bit(unsigned int nr, void * addr);
+extern int ext2fs_test_bit(unsigned int nr, const void * addr);
+extern __u16 ext2fs_swab16(__u16 val);
+extern __u32 ext2fs_swab32(__u32 val);
+
+#ifdef WORDS_BIGENDIAN
+#define ext2fs_cpu_to_le32(x) ext2fs_swab32((x))
+#define ext2fs_le32_to_cpu(x) ext2fs_swab32((x))
+#define ext2fs_cpu_to_le16(x) ext2fs_swab16((x))
+#define ext2fs_le16_to_cpu(x) ext2fs_swab16((x))
+#define ext2fs_cpu_to_be32(x) ((__u32)(x))
+#define ext2fs_be32_to_cpu(x) ((__u32)(x))
+#define ext2fs_cpu_to_be16(x) ((__u16)(x))
+#define ext2fs_be16_to_cpu(x) ((__u16)(x))
+#else
+#define ext2fs_cpu_to_le32(x) ((__u32)(x))
+#define ext2fs_le32_to_cpu(x) ((__u32)(x))
+#define ext2fs_cpu_to_le16(x) ((__u16)(x))
+#define ext2fs_le16_to_cpu(x) ((__u16)(x))
+#define ext2fs_cpu_to_be32(x) ext2fs_swab32((x))
+#define ext2fs_be32_to_cpu(x) ext2fs_swab32((x))
+#define ext2fs_cpu_to_be16(x) ext2fs_swab16((x))
+#define ext2fs_be16_to_cpu(x) ext2fs_swab16((x))
+#endif
+
+/*
+ * EXT2FS bitmap manipulation routines.
+ */
+
+/* Support for sending warning messages from the inline subroutines */
+extern const char *ext2fs_block_string;
+extern const char *ext2fs_inode_string;
+extern const char *ext2fs_mark_string;
+extern const char *ext2fs_unmark_string;
+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 int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
+extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+				       blk_t block);
+extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block);
+
+extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
+extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+				       ext2_ino_t inode);
+extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode);
+
+extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+					  blk_t block);
+extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+					    blk_t block);
+extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
+					 blk_t block);
+
+extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					  ext2_ino_t inode);
+extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					    ext2_ino_t inode);
+extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					 ext2_ino_t inode);
+extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap);
+extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap);
+extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap);
+extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap);
+
+extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					   blk_t block, int num);
+extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					     blk_t block, int num);
+extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					  blk_t block, int num);
+extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+						blk_t block, int num);
+extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+						  blk_t block, int num);
+extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					       blk_t block, int num);
+extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map);
+
+/* These two routines moved to gen_bitmap.c */
+extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+					 __u32 bitno);
+extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
+					   blk_t bitno);
+/*
+ * The inline routines themselves...
+ * 
+ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
+ * functions at all; they will be included as normal functions in
+ * inline.c
+ */
+#ifdef NO_INLINE_FUNCS
+#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \
+			   defined(__i586__) || defined(__mc68000__) || \
+			   defined(__sparc__)))
+	/* This prevents bitops.c from trying to include the C */
+	/* function version of these functions */
+#define _EXT2_HAVE_ASM_BITOPS_
+#endif
+#endif /* NO_INLINE_FUNCS */
+
+#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#ifdef __GNUC__
+#define _INLINE_ extern __inline__
+#else				/* For Watcom C */
+#define _INLINE_ extern inline
+#endif
+#endif
+
+#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \
+     (defined(__i386__) || defined(__i486__) || defined(__i586__)))
+
+#define _EXT2_HAVE_ASM_BITOPS_
+#define _EXT2_HAVE_ASM_SWAB_
+#define _EXT2_HAVE_ASM_FINDBIT_
+
+/*
+ * These are done by inline assembly for speed reasons.....
+ *
+ * All bitoperations return 0 if the bit was cleared before the
+ * operation and != 0 if it was not.  Bit 0 is the LSB of addr; bit 32
+ * is the LSB of (addr+1).
+ */
+
+/*
+ * Some hacks to defeat gcc over-optimizations..
+ */
+struct __dummy_h { unsigned long a[100]; };
+#define EXT2FS_ADDR (*(struct __dummy_h *) addr)
+#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr)	
+
+_INLINE_ int ext2fs_set_bit(unsigned int nr, void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit),"=m" (EXT2FS_ADDR)
+		:"r" (nr));
+	return oldbit;
+}
+
+_INLINE_ int ext2fs_clear_bit(unsigned int nr, void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit),"=m" (EXT2FS_ADDR)
+		:"r" (nr));
+	return oldbit;
+}
+
+_INLINE_ int ext2fs_test_bit(unsigned int nr, const void * addr)
+{
+	int oldbit;
+
+	__asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0"
+		:"=r" (oldbit)
+		:"m" (EXT2FS_CONST_ADDR),"r" (nr));
+	return oldbit;
+}
+
+#if 0
+_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
+{
+	int d0, d1, d2;
+	int res;
+
+	if (!size)
+		return 0;
+	/* This looks at memory. Mark it volatile to tell gcc not to move it around */
+	__asm__ __volatile__(
+		"cld\n\t"			     
+		"xorl %%eax,%%eax\n\t"
+		"xorl %%edx,%%edx\n\t"
+		"repe; scasl\n\t"
+		"je 1f\n\t"
+		"movl -4(%%edi),%%eax\n\t"
+		"subl $4,%%edi\n\t"
+		"bsfl %%eax,%%edx\n"
+		"1:\tsubl %%esi,%%edi\n\t"
+		"shll $3,%%edi\n\t"
+		"addl %%edi,%%edx"
+		:"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+		:"1" ((size + 31) >> 5), "2" (addr), "S" (addr));
+	return res;
+}
+
+_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
+{
+	unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+	int set = 0, bit = offset & 31, res;
+	
+	if (bit) {
+		/*
+		 * Look for zero in first byte
+		 */
+		__asm__("bsfl %1,%0\n\t"
+			"jne 1f\n\t"
+			"movl $32, %0\n"
+			"1:"
+			: "=r" (set)
+			: "r" (*p >> bit));
+		if (set < (32 - bit))
+			return set + offset;
+		set = 32 - bit;
+		p++;
+	}
+	/*
+	 * No bit found yet, search remaining full bytes for a bit
+	 */
+	res = ext2fs_find_first_bit_set(p, size - 32 * (p - (unsigned long *) addr));
+	return (offset + set + res);
+}
+#endif
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+_INLINE_ __u32 ext2fs_swab32(__u32 val)
+{
+#ifdef EXT2FS_REQUIRE_486
+	__asm__("bswap %0" : "=r" (val) : "0" (val));
+#else
+	__asm__("xchgb %b0,%h0\n\t"	/* swap lower bytes	*/
+		"rorl $16,%0\n\t"	/* swap words		*/
+		"xchgb %b0,%h0"		/* swap higher bytes	*/
+		:"=q" (val)
+		: "0" (val));
+#endif
+	return val;
+}
+
+_INLINE_ __u16 ext2fs_swab16(__u16 val)
+{
+	__asm__("xchgb %b0,%h0"		/* swap bytes		*/ \
+		: "=q" (val) \
+		:  "0" (val)); \
+		return val;
+}
+#endif
+
+#undef EXT2FS_ADDR
+
+#endif	/* i386 */
+
+#ifdef __mc68000__
+
+#define _EXT2_HAVE_ASM_BITOPS_
+
+_INLINE_ int ext2fs_set_bit(unsigned int nr,void * addr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfset %2@{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+
+	return retval;
+}
+
+_INLINE_ int ext2fs_clear_bit(unsigned int nr, void * addr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bfclr %2@{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+
+	return retval;
+}
+
+_INLINE_ int ext2fs_test_bit(unsigned int nr, const void * addr)
+{
+	char retval;
+
+	__asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0"
+	     : "=d" (retval) : "d" (nr^7), "a" (addr));
+
+	return retval;
+}
+
+#endif /* __mc68000__ */
+
+
+#if !defined(_EXT2_HAVE_ASM_SWAB_) && defined(EXT2FS_ENABLE_SWAPFS)
+
+_INLINE_ __u16 ext2fs_swab16(__u16 val)
+{
+	return (val >> 8) | (val << 8);
+}
+
+_INLINE_ __u32 ext2fs_swab32(__u32 val)
+{
+	return ((val>>24) | ((val>>8)&0xFF00) |
+		((val<<8)&0xFF0000) | (val<<24));
+}
+
+#endif /* !_EXT2_HAVE_ASM_SWAB */
+
+#if !defined(_EXT2_HAVE_ASM_FINDBIT_)
+_INLINE_ int ext2fs_find_first_bit_set(void * addr, unsigned size)
+{
+	char	*cp = (unsigned char *) addr;
+	int 	res = 0, d0;
+
+	if (!size)
+		return 0;
+
+	while ((size > res) && (*cp == 0)) {
+		cp++;
+		res += 8;
+	}
+	d0 = ffs(*cp);
+	if (d0 == 0)
+		return size;
+	
+	return res + d0 - 1;
+}
+
+_INLINE_ int ext2fs_find_next_bit_set (void * addr, int size, int offset)
+{
+	unsigned char * p;
+	int set = 0, bit = offset & 7, res = 0, d0;
+	
+	res = offset >> 3;
+	p = ((unsigned char *) addr) + res;
+	
+	if (bit) {
+		set = ffs(*p & ~((1 << bit) - 1));
+		if (set)
+			return (offset & ~7) + set - 1;
+		p++;
+		res += 8;
+	}
+	while ((size > res) && (*p == 0)) {
+		p++;
+		res += 8;
+	}
+	d0 = ffs(*p);
+	if (d0 == 0)
+		return size;
+
+	return (res + d0 - 1);
+}
+#endif	
+
+_INLINE_ int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
+					blk_t bitno);
+
+_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_TEST_ERROR, bitno);
+		return 0;
+	}
+	return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+				       blk_t block)
+{
+	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap)
+				       bitmap,
+					  block);
+}
+
+_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+					 blk_t block)
+{
+	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					    block);
+}
+
+_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap,
+				       blk_t block)
+{
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  block);
+}
+
+_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+				       ext2_ino_t inode)
+{
+	return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  inode);
+}
+
+_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					 ext2_ino_t inode)
+{
+	return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+				     inode);
+}
+
+_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+				       ext2_ino_t inode)
+{
+	return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, 
+					  inode);
+}
+
+_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap,
+					    blk_t block)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
+				   bitmap->description);
+		return;
+	}
+#endif	
+	ext2fs_set_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap,
+					      blk_t block)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK,
+				   block, bitmap->description);
+		return;
+	}
+#endif
+	ext2fs_clear_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap,
+					    blk_t block)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
+				   block, bitmap->description);
+		return 0;
+	}
+#endif
+	return ext2fs_test_bit(block - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					    ext2_ino_t inode)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((inode < bitmap->start) || (inode > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_MARK,
+				   inode, bitmap->description);
+		return;
+	}
+#endif
+	ext2fs_set_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					      ext2_ino_t inode)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((inode < bitmap->start) || (inode > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_UNMARK,
+				   inode, bitmap->description);
+		return;
+	}
+#endif
+	ext2fs_clear_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap,
+					   ext2_ino_t inode)
+{
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((inode < bitmap->start) || (inode > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
+				   inode, bitmap->description);
+		return 0;
+	}
+#endif
+	return ext2fs_test_bit(inode - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap)
+{
+	return bitmap->start;
+}
+
+_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap)
+{
+	return bitmap->start;
+}
+
+_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap)
+{
+	return bitmap->end;
+}
+
+_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap)
+{
+	return bitmap->end;
+}
+
+_INLINE_ int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					    blk_t block, int num)
+{
+	int	i;
+
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
+				   block, bitmap->description);
+		return 0;
+	}
+	for (i=0; i < num; i++) {
+		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
+			return 0;
+	}
+	return 1;
+}
+
+_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap,
+						 blk_t block, int num)
+{
+	int	i;
+
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
+				   block, bitmap->description);
+		return 0;
+	}
+#endif
+	for (i=0; i < num; i++) {
+		if (ext2fs_fast_test_block_bitmap(bitmap, block+i))
+			return 0;
+	}
+	return 1;
+}
+
+_INLINE_ void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					     blk_t block, int num)
+{
+	int	i;
+	
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
+				   bitmap->description);
+		return;
+	}
+	for (i=0; i < num; i++)
+		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+						  blk_t block, int num)
+{
+	int	i;
+	
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
+				   bitmap->description);
+		return;
+	}
+#endif	
+	for (i=0; i < num; i++)
+		ext2fs_set_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+					       blk_t block, int num)
+{
+	int	i;
+	
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
+				   bitmap->description);
+		return;
+	}
+	for (i=0; i < num; i++)
+		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+
+_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap,
+						    blk_t block, int num)
+{
+	int	i;
+	
+#ifdef EXT2FS_DEBUG_FAST_OPS
+	if ((block < bitmap->start) || (block+num-1 > bitmap->end)) {
+		ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
+				   bitmap->description);
+		return;
+	}
+#endif	
+	for (i=0; i < num; i++)
+		ext2fs_clear_bit(block + i - bitmap->start, bitmap->bitmap);
+}
+#undef _INLINE_
+#endif
+
diff -Naur silo-1.4.11.orig/libext2fs/block.c silo-1.4.11/libext2fs/block.c
--- silo-1.4.11.orig/libext2fs/block.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/block.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,437 @@
+/*
+ * block.c --- iterate over all blocks in an inode
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct block_context {
+	ext2_filsys	fs;
+	int (*func)(ext2_filsys	fs,
+		    blk_t	*blocknr,
+		    e2_blkcnt_t	bcount,
+		    blk_t	ref_blk,
+		    int		ref_offset,
+		    void	*priv_data);
+	e2_blkcnt_t	bcount;
+	int		bsize;
+	int		flags;
+	errcode_t	errcode;
+	char	*ind_buf;
+	char	*dind_buf;
+	char	*tind_buf;
+	void	*priv_data;
+};
+
+static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
+			     int ref_offset, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags, limit, offset;
+	blk_t	*block_nr;
+
+	limit = ctx->fs->blocksize >> 2;
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ctx->flags & BLOCK_FLAG_DATA_ONLY))
+		ret = (*ctx->func)(ctx->fs, ind_block,
+				   BLOCK_COUNT_IND, ref_block,
+				   ref_offset, ctx->priv_data);
+	if (!*ind_block || (ret & BLOCK_ABORT)) {
+		ctx->bcount += limit;
+		return ret;
+	}
+	if (*ind_block >= ctx->fs->super->s_blocks_count ||
+	    *ind_block < ctx->fs->super->s_first_data_block) {
+		ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, 
+					     ctx->ind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+
+	block_nr = (blk_t *) ctx->ind_buf;
+	offset = 0;
+	if (ctx->flags & BLOCK_FLAG_APPEND) {
+		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
+			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+					     *ind_block, offset, 
+					     ctx->priv_data);
+			changed	|= flags;
+			if (flags & BLOCK_ABORT) {
+				ret |= BLOCK_ABORT;
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	} else {
+		for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
+			if (*block_nr == 0)
+				continue;
+			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+					     *ind_block, offset, 
+					     ctx->priv_data);
+			changed	|= flags;
+			if (flags & BLOCK_ABORT) {
+				ret |= BLOCK_ABORT;
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	}
+	if (changed & BLOCK_CHANGED) {
+		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
+						      ctx->ind_buf);
+		if (ctx->errcode)
+			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,
+				    BLOCK_COUNT_IND, ref_block,
+				    ref_offset, ctx->priv_data);
+	return ret;
+}
+	
+static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
+			      int ref_offset, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags, limit, offset;
+	blk_t	*block_nr;
+
+	limit = ctx->fs->blocksize >> 2;
+	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
+			    BLOCK_FLAG_DATA_ONLY)))
+		ret = (*ctx->func)(ctx->fs, dind_block,
+				   BLOCK_COUNT_DIND, ref_block,
+				   ref_offset, ctx->priv_data);
+	if (!*dind_block || (ret & BLOCK_ABORT)) {
+		ctx->bcount += limit*limit;
+		return ret;
+	}
+	if (*dind_block >= ctx->fs->super->s_blocks_count ||
+	    *dind_block < ctx->fs->super->s_first_data_block) {
+		ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, 
+					     ctx->dind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+
+	block_nr = (blk_t *) ctx->dind_buf;
+	offset = 0;
+	if (ctx->flags & BLOCK_FLAG_APPEND) {
+		for (i = 0; i < limit; i++, block_nr++) {
+			flags = block_iterate_ind(block_nr,
+						  *dind_block, offset,
+						  ctx);
+			changed |= flags;
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	} else {
+		for (i = 0; i < limit; i++, block_nr++) {
+			if (*block_nr == 0) {
+				ctx->bcount += limit;
+				continue;
+			}
+			flags = block_iterate_ind(block_nr,
+						  *dind_block, offset,
+						  ctx);
+			changed |= flags;
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	}
+	if (changed & BLOCK_CHANGED) {
+		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
+						      ctx->dind_buf);
+		if (ctx->errcode)
+			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,
+				    BLOCK_COUNT_DIND, ref_block,
+				    ref_offset, ctx->priv_data);
+	return ret;
+}
+	
+static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
+			      int ref_offset, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags, limit, offset;
+	blk_t	*block_nr;
+
+	limit = ctx->fs->blocksize >> 2;
+	if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
+			    BLOCK_FLAG_DATA_ONLY)))
+		ret = (*ctx->func)(ctx->fs, tind_block,
+				   BLOCK_COUNT_TIND, ref_block,
+				   ref_offset, ctx->priv_data);
+	if (!*tind_block || (ret & BLOCK_ABORT)) {
+		ctx->bcount += limit*limit*limit;
+		return ret;
+	}
+	if (*tind_block >= ctx->fs->super->s_blocks_count ||
+	    *tind_block < ctx->fs->super->s_first_data_block) {
+		ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, 
+					     ctx->tind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+
+	block_nr = (blk_t *) ctx->tind_buf;
+	offset = 0;
+	if (ctx->flags & BLOCK_FLAG_APPEND) {
+		for (i = 0; i < limit; i++, block_nr++) {
+			flags = block_iterate_dind(block_nr,
+						   *tind_block,
+						   offset, ctx);
+			changed |= flags;
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	} else {
+		for (i = 0; i < limit; i++, block_nr++) {
+			if (*block_nr == 0) {
+				ctx->bcount += limit*limit;
+				continue;
+			}
+			flags = block_iterate_dind(block_nr,
+						   *tind_block,
+						   offset, ctx);
+			changed |= flags;
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+			offset += sizeof(blk_t);
+		}
+	}
+	if (changed & BLOCK_CHANGED) {
+		ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
+						      ctx->tind_buf);
+		if (ctx->errcode)
+			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,
+				    BLOCK_COUNT_TIND, ref_block,
+				    ref_offset, ctx->priv_data);
+	
+	return ret;
+}
+	
+errcode_t ext2fs_block_iterate2(ext2_filsys fs,
+				ext2_ino_t ino,
+				int	flags,
+				char *block_buf,
+				int (*func)(ext2_filsys fs,
+					    blk_t	*blocknr,
+					    e2_blkcnt_t	blockcnt,
+					    blk_t	ref_blk,
+					    int		ref_offset,
+					    void	*priv_data),
+				void *priv_data)
+{
+	int	i;
+	int	got_inode = 0;
+	int	ret = 0;
+	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */
+	struct ext2_inode inode;
+	errcode_t	retval;
+	struct block_context ctx;
+	int	limit;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	/*
+	 * Check to see if we need to limit large files
+	 */
+	if (flags & BLOCK_FLAG_NO_LARGE) {
+		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+		if (ctx.errcode)
+			return ctx.errcode;
+		got_inode = 1;
+		if (!LINUX_S_ISDIR(inode.i_mode) &&
+		    (inode.i_size_high != 0))
+			return EXT2_ET_FILE_TOO_BIG;
+	}
+
+	retval = ext2fs_get_blocks(fs, ino, blocks);
+	if (retval)
+		return retval;
+
+	limit = fs->blocksize >> 2;
+
+	ctx.fs = fs;
+	ctx.func = func;
+	ctx.priv_data = priv_data;
+	ctx.flags = flags;
+	ctx.bcount = 0;
+	if (block_buf) {
+		ctx.ind_buf = block_buf;
+	} else {
+		retval = ext2fs_get_mem(fs->blocksize * 3, &ctx.ind_buf);
+		if (retval)
+			return retval;
+	}
+	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)) {
+		ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
+		if (ctx.errcode)
+			goto abort_exit;
+		got_inode = 1;
+		if (inode.osd1.hurd1.h_i_translator) {
+			ret |= (*ctx.func)(fs,
+					   &inode.osd1.hurd1.h_i_translator,
+					   BLOCK_COUNT_TRANSLATOR,
+					   0, 0, priv_data);
+			if (ret & BLOCK_ABORT)
+				goto abort_exit;
+		}
+	}
+	
+	/*
+	 * Iterate over normal data blocks
+	 */
+	for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
+		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
+			ret |= (*ctx.func)(fs, &blocks[i],
+					    ctx.bcount, 0, i, priv_data);
+			if (ret & BLOCK_ABORT)
+				goto abort_exit;
+		}
+	}
+	if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK,
+					 0, EXT2_IND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort_exit;
+	} else
+		ctx.bcount += limit;
+	if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK,
+					  0, EXT2_DIND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort_exit;
+	} else
+		ctx.bcount += limit * limit;
+	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK,
+					  0, EXT2_TIND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort_exit;
+	}
+
+abort_exit:
+	if (ret & BLOCK_CHANGED) {
+		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);
+		if (retval)
+			return retval;
+	}
+
+	if (!block_buf)
+		ext2fs_free_mem(&ctx.ind_buf);
+
+	return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
+}
+
+/*
+ * Emulate the old ext2fs_block_iterate function!
+ */
+
+struct xlate {
+	int (*func)(ext2_filsys	fs,
+		    blk_t	*blocknr,
+		    int		bcount,
+		    void	*priv_data);
+	void *real_private;
+};
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
+		      blk_t ref_block EXT2FS_ATTR((unused)),
+		      int ref_offset EXT2FS_ATTR((unused)),
+		      void *priv_data)
+{
+	struct xlate *xl = (struct xlate *) priv_data;
+
+	return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
+}
+
+errcode_t ext2fs_block_iterate(ext2_filsys fs,
+			       ext2_ino_t ino,
+			       int	flags,
+			       char *block_buf,
+			       int (*func)(ext2_filsys fs,
+					   blk_t	*blocknr,
+					   int	blockcnt,
+					   void	*priv_data),
+			       void *priv_data)
+{
+	struct xlate xl;
+	
+	xl.real_private = priv_data;
+	xl.func = func;
+
+	return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
+				     block_buf, xlate_func, &xl);
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/bmap.c silo-1.4.11/libext2fs/bmap.c
--- silo-1.4.11.orig/libext2fs/bmap.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bmap.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,270 @@
+/*
+ * bmap.c --- logical to physical block mapping
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
+#define _BMAP_INLINE_	__inline__
+#else
+#define _BMAP_INLINE_
+#endif
+
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
+			     struct ext2_inode *inode, 
+			     char *block_buf, int bmap_flags,
+			     blk_t block, blk_t *phys_blk);
+
+#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
+
+static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, 
+					      blk_t ind, char *block_buf, 
+					      int *blocks_alloc,
+					      blk_t nr, blk_t *ret_blk)
+{
+	errcode_t	retval;
+	blk_t		b;
+
+	if (!ind) {
+		if (flags & BMAP_SET)
+			return EXT2_ET_SET_BMAP_NO_IND;
+		*ret_blk = 0;
+		return 0;
+	}
+	retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
+	if (retval)
+		return retval;
+
+	if (flags & BMAP_SET) {
+		b = *ret_blk;
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+			b = ext2fs_swab32(b);
+#endif
+		((blk_t *) block_buf)[nr] = b;
+		return io_channel_write_blk(fs->io, ind, 1, block_buf);
+	}
+
+	b = ((blk_t *) block_buf)[nr];
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+		b = ext2fs_swab32(b);
+#endif
+
+	if (!b && (flags & BMAP_ALLOC)) {
+		b = nr ? ((blk_t *) block_buf)[nr-1] : 0;
+		retval = ext2fs_alloc_block(fs, b,
+					    block_buf + fs->blocksize, &b);
+		if (retval)
+			return retval;
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+			((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
+		else
+#endif
+			((blk_t *) block_buf)[nr] = b;
+
+		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
+		if (retval)
+			return retval;
+
+		(*blocks_alloc)++;
+	}
+
+	*ret_blk = b;
+	return 0;
+}
+
+static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
+					       blk_t dind, char *block_buf, 
+					       int *blocks_alloc,
+					       blk_t nr, blk_t *ret_blk)
+{
+	blk_t		b;
+	errcode_t	retval;
+	blk_t		addr_per_block;
+	
+	addr_per_block = (blk_t) fs->blocksize >> 2;
+
+	retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf, 
+				blocks_alloc, nr / addr_per_block, &b);
+	if (retval)
+		return retval;
+	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
+				nr % addr_per_block, ret_blk);
+	return retval;
+}
+
+static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
+					       blk_t tind, char *block_buf, 
+					       int *blocks_alloc,
+					       blk_t nr, blk_t *ret_blk)
+{
+	blk_t		b;
+	errcode_t	retval;
+	blk_t		addr_per_block;
+	
+	addr_per_block = (blk_t) fs->blocksize >> 2;
+
+	retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf, 
+				 blocks_alloc, nr / addr_per_block, &b);
+	if (retval)
+		return retval;
+	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
+				nr % addr_per_block, ret_blk);
+	return retval;
+}
+
+errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
+		      char *block_buf, int bmap_flags, blk_t block,
+		      blk_t *phys_blk)
+{
+	struct ext2_inode inode_buf;
+	blk_t addr_per_block;
+	blk_t	b;
+	char	*buf = 0;
+	errcode_t	retval = 0;
+	int		blocks_alloc = 0, inode_dirty = 0;
+
+	if (!(bmap_flags & BMAP_SET))
+		*phys_blk = 0;
+
+	/* Read inode structure if necessary */
+	if (!inode) {
+		retval = ext2fs_read_inode(fs, ino, &inode_buf);
+		if (retval)
+			return retval;
+		inode = &inode_buf;
+	}
+	addr_per_block = (blk_t) fs->blocksize >> 2;
+
+	if (!block_buf) {
+		retval = ext2fs_get_mem(fs->blocksize * 2, &buf);
+		if (retval)
+			return retval;
+		block_buf = buf;
+	}
+
+	if (block < EXT2_NDIR_BLOCKS) {
+		if (bmap_flags & BMAP_SET) {
+			b = *phys_blk;
+#ifdef EXT2FS_ENABLE_SWAPFS
+			if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+			    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+				b = ext2fs_swab32(b);
+#endif
+			inode_bmap(inode, block) = b;
+			inode_dirty++;
+			goto done;
+		}
+
+		*phys_blk = inode_bmap(inode, block);
+		b = block ? inode_bmap(inode, block-1) : 0;
+		
+		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
+			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			if (retval)
+				goto done;
+			inode_bmap(inode, block) = b;
+			blocks_alloc++;
+			*phys_blk = b;
+		}
+		goto done;
+	}
+	
+	/* Indirect block */
+	block -= EXT2_NDIR_BLOCKS;
+	if (block < addr_per_block) {
+		b = inode_bmap(inode, EXT2_IND_BLOCK);
+		if (!b) {
+			if (!(bmap_flags & BMAP_ALLOC)) {
+				if (bmap_flags & BMAP_SET)
+					retval = EXT2_ET_SET_BMAP_NO_IND;
+				goto done;
+			}
+
+			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
+ 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			if (retval)
+				goto done;
+			inode_bmap(inode, EXT2_IND_BLOCK) = b;
+			blocks_alloc++;
+		}
+		retval = block_ind_bmap(fs, bmap_flags, b, block_buf, 
+					&blocks_alloc, block, phys_blk);
+		goto done;
+	}
+	
+	/* Doubly indirect block  */
+	block -= addr_per_block;
+	if (block < addr_per_block * addr_per_block) {
+		b = inode_bmap(inode, EXT2_DIND_BLOCK);
+		if (!b) {
+			if (!(bmap_flags & BMAP_ALLOC)) {
+				if (bmap_flags & BMAP_SET)
+					retval = EXT2_ET_SET_BMAP_NO_IND;
+				goto done;
+			}
+
+			b = inode_bmap(inode, EXT2_IND_BLOCK);
+ 			retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+			if (retval)
+				goto done;
+			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
+			blocks_alloc++;
+		}
+		retval = block_dind_bmap(fs, bmap_flags, b, block_buf, 
+					 &blocks_alloc, block, phys_blk);
+		goto done;
+	}
+
+	/* Triply indirect block */
+	block -= addr_per_block * addr_per_block;
+	b = inode_bmap(inode, EXT2_TIND_BLOCK);
+	if (!b) {
+		if (!(bmap_flags & BMAP_ALLOC)) {
+			if (bmap_flags & BMAP_SET)
+				retval = EXT2_ET_SET_BMAP_NO_IND;
+			goto done;
+		}
+
+		b = inode_bmap(inode, EXT2_DIND_BLOCK);
+		retval = ext2fs_alloc_block(fs, b, block_buf, &b);
+		if (retval)
+			goto done;
+		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
+		blocks_alloc++;
+	}
+	retval = block_tind_bmap(fs, bmap_flags, b, block_buf, 
+				 &blocks_alloc, block, phys_blk);
+done:
+	if (buf)
+		ext2fs_free_mem(&buf);
+	if ((retval == 0) && (blocks_alloc || inode_dirty)) {
+		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
+		retval = ext2fs_write_inode(fs, ino, inode);
+	}
+	return retval;
+}
+
+
+
diff -Naur silo-1.4.11.orig/libext2fs/bmove.c silo-1.4.11/libext2fs/bmove.c
--- silo-1.4.11.orig/libext2fs/bmove.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/bmove.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,160 @@
+/*
+ * bmove.c --- Move blocks around to make way for a particular
+ * 	filesystem structure.
+ *
+ * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+struct process_block_struct {
+	ext2_ino_t		ino;
+	struct ext2_inode *	inode;
+	ext2fs_block_bitmap	reserve;
+	ext2fs_block_bitmap	alloc_map;
+	errcode_t		error;
+	char			*buf;
+	int			add_dir;
+	int			flags;
+};
+
+static int process_block(ext2_filsys fs, blk_t	*block_nr,
+			 e2_blkcnt_t blockcnt, blk_t ref_block,
+			 int ref_offset, void *priv_data)
+{
+	struct process_block_struct *pb;
+	errcode_t	retval;
+	int		ret;
+	blk_t		block, orig;
+
+	pb = (struct process_block_struct *) priv_data;
+	block = orig = *block_nr;
+	ret = 0;
+	
+	/*
+	 * Let's see if this is one which we need to relocate
+	 */
+	if (ext2fs_test_block_bitmap(pb->reserve, block)) {
+		do {
+			if (++block >= fs->super->s_blocks_count)
+				block = fs->super->s_first_data_block;
+			if (block == orig) {
+				pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
+				return BLOCK_ABORT;
+			}
+		} while (ext2fs_test_block_bitmap(pb->reserve, block) ||
+			 ext2fs_test_block_bitmap(pb->alloc_map, block));
+
+		retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
+		if (retval) {
+			pb->error = retval;
+			return BLOCK_ABORT;
+		}
+		retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
+		if (retval) {
+			pb->error = retval;
+			return BLOCK_ABORT;
+		}
+		*block_nr = block;
+		ext2fs_mark_block_bitmap(pb->alloc_map, block);
+		ret = BLOCK_CHANGED;
+		if (pb->flags & EXT2_BMOVE_DEBUG)
+			printf("ino=%ld, blockcnt=%lld, %d->%d\n", pb->ino,
+			       blockcnt, orig, block);
+	}
+	if (pb->add_dir) {
+		retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
+					      block, (int) blockcnt);
+		if (retval) {
+			pb->error = retval;
+			ret |= BLOCK_ABORT;
+		}
+	}
+	return ret;
+}
+
+errcode_t ext2fs_move_blocks(ext2_filsys fs,
+			     ext2fs_block_bitmap reserve,
+			     ext2fs_block_bitmap alloc_map,
+			     int flags)
+{
+	ext2_ino_t	ino;
+	struct ext2_inode inode;
+	errcode_t	retval;
+	struct process_block_struct pb;
+	ext2_inode_scan	scan;
+	char		*block_buf;
+	
+	retval = ext2fs_open_inode_scan(fs, 0, &scan);
+	if (retval)
+		return retval;
+
+	pb.reserve = reserve;
+	pb.error = 0;
+	pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
+	pb.flags = flags;
+	
+	retval = ext2fs_get_mem(fs->blocksize * 4, &block_buf);
+	if (retval)
+		return retval;
+	pb.buf = block_buf + fs->blocksize * 3;
+
+	/*
+	 * If GET_DBLIST is set in the flags field, then we should
+	 * gather directory block information while we're doing the
+	 * block move.
+	 */
+	if (flags & EXT2_BMOVE_GET_DBLIST) {
+		if (fs->dblist) {
+			ext2fs_free_dblist(fs->dblist);
+			fs->dblist = NULL;
+		}
+		retval = ext2fs_init_dblist(fs, 0);
+		if (retval)
+			return retval;
+	}
+
+	retval = ext2fs_get_next_inode(scan, &ino, &inode);
+	if (retval)
+		return retval;
+	
+	while (ino) {
+		if ((inode.i_links_count == 0) ||
+		    !ext2fs_inode_has_valid_blocks(&inode))
+			goto next;
+		
+		pb.ino = ino;
+		pb.inode = &inode;
+
+		pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
+			      flags & EXT2_BMOVE_GET_DBLIST);
+
+		retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+					      process_block, &pb);
+		if (retval)
+			return retval;
+		if (pb.error)
+			return pb.error;
+
+	next:
+		retval = ext2fs_get_next_inode(scan, &ino, &inode);
+		if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+			goto next;
+	}
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/brel.h silo-1.4.11/libext2fs/brel.h
--- silo-1.4.11.orig/libext2fs/brel.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/brel.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,86 @@
+/*
+ * brel.h
+ * 
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct ext2_block_relocate_entry {
+	blk_t	new;
+	__s16	offset;
+	__u16	flags;
+	union {
+		blk_t		block_ref;
+		ext2_ino_t	inode_ref;
+	} owner;
+};
+
+#define RELOCATE_TYPE_REF  0x0007
+#define RELOCATE_BLOCK_REF 0x0001
+#define RELOCATE_INODE_REF 0x0002
+
+typedef struct ext2_block_relocation_table *ext2_brel;
+
+struct ext2_block_relocation_table {
+	__u32	magic;
+	char	*name;
+	blk_t	current;
+	void	*priv_data;
+
+	/*
+	 * Add a block relocation entry.
+	 */
+	errcode_t (*put)(ext2_brel brel, blk_t old,
+			      struct ext2_block_relocate_entry *ent);
+
+	/*
+	 * Get a block relocation entry.
+	 */
+	errcode_t (*get)(ext2_brel brel, blk_t old,
+			      struct ext2_block_relocate_entry *ent);
+
+	/*
+	 * Initialize for iterating over the block relocation entries.
+	 */
+	errcode_t (*start_iter)(ext2_brel brel);
+	
+	/*
+	 * The iterator function for the inode relocation entries.
+	 * Returns an inode number of 0 when out of entries.
+	 */
+	errcode_t (*next)(ext2_brel brel, blk_t *old,
+			  struct ext2_block_relocate_entry *ent);
+
+	/*
+	 * Move the inode relocation table from one block number to
+	 * another.
+	 */
+	errcode_t (*move)(ext2_brel brel, blk_t old, blk_t new);
+
+	/*
+	 * Remove a block relocation entry.
+	 */
+	errcode_t (*delete)(ext2_brel brel, blk_t old);
+
+
+	/*
+	 * Free the block relocation table.
+	 */
+	errcode_t (*free)(ext2_brel brel);
+};
+
+errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+				    ext2_brel *brel);
+
+#define ext2fs_brel_put(brel, old, ent) ((brel)->put((brel), old, ent))
+#define ext2fs_brel_get(brel, old, ent) ((brel)->get((brel), old, ent))
+#define ext2fs_brel_start_iter(brel) ((brel)->start_iter((brel)))
+#define ext2fs_brel_next(brel, old, ent) ((brel)->next((brel), old, ent))
+#define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new))
+#define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old))
+#define ext2fs_brel_free(brel) ((brel)->free((brel)))
+
diff -Naur silo-1.4.11.orig/libext2fs/brel_ma.c silo-1.4.11/libext2fs/brel_ma.c
--- silo-1.4.11.orig/libext2fs/brel_ma.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/brel_ma.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,197 @@
+/*
+ * brel_ma.c
+ * 
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * TODO: rewrite to not use a direct array!!!  (Fortunately this
+ * module isn't really used yet.)
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "brel.h"
+
+static errcode_t bma_put(ext2_brel brel, blk_t old,
+			struct ext2_block_relocate_entry *ent);
+static errcode_t bma_get(ext2_brel brel, blk_t old,
+			struct ext2_block_relocate_entry *ent);
+static errcode_t bma_start_iter(ext2_brel brel);
+static errcode_t bma_next(ext2_brel brel, blk_t *old,
+			 struct ext2_block_relocate_entry *ent);
+static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new);
+static errcode_t bma_delete(ext2_brel brel, blk_t old);
+static errcode_t bma_free(ext2_brel brel);
+
+struct brel_ma {
+	__u32 magic;
+	blk_t max_block;
+	struct ext2_block_relocate_entry *entries;
+};
+
+errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block,
+				      ext2_brel *new_brel)
+{
+	ext2_brel		brel = 0;
+	errcode_t	retval;
+	struct brel_ma 	*ma = 0;
+	size_t		size;
+
+	*new_brel = 0;
+
+	/*
+	 * Allocate memory structures
+	 */
+	retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
+				&brel);
+	if (retval)
+		goto errout;
+	memset(brel, 0, sizeof(struct ext2_block_relocation_table));
+	
+	retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
+	if (retval)
+		goto errout;
+	strcpy(brel->name, name);
+	
+	retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
+	if (retval)
+		goto errout;
+	memset(ma, 0, sizeof(struct brel_ma));
+	brel->priv_data = ma;
+	
+	size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
+			 (max_block+1));
+	retval = ext2fs_get_mem(size, &ma->entries);
+	if (retval)
+		goto errout;
+	memset(ma->entries, 0, size);
+	ma->max_block = max_block;
+
+	/*
+	 * Fill in the brel data structure
+	 */
+	brel->put = bma_put;
+	brel->get = bma_get;
+	brel->start_iter = bma_start_iter;
+	brel->next = bma_next;
+	brel->move = bma_move;
+	brel->delete = bma_delete;
+	brel->free = bma_free;
+	
+	*new_brel = brel;
+	return 0;
+
+errout:
+	bma_free(brel);
+	return retval;
+}
+
+static errcode_t bma_put(ext2_brel brel, blk_t old,
+			struct ext2_block_relocate_entry *ent)
+{
+	struct brel_ma 	*ma;
+
+	ma = brel->priv_data;
+	if (old > ma->max_block)
+		return EXT2_ET_INVALID_ARGUMENT;
+	ma->entries[(unsigned)old] = *ent;
+	return 0;
+}
+
+static errcode_t bma_get(ext2_brel brel, blk_t old,
+			struct ext2_block_relocate_entry *ent)
+{
+	struct brel_ma 	*ma;
+
+	ma = brel->priv_data;
+	if (old > ma->max_block)
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned)old].new == 0)
+		return ENOENT;
+	*ent = ma->entries[old];
+	return 0;
+}
+
+static errcode_t bma_start_iter(ext2_brel brel)
+{
+	brel->current = 0;
+	return 0;
+}
+
+static errcode_t bma_next(ext2_brel brel, blk_t *old,
+			  struct ext2_block_relocate_entry *ent)
+{
+	struct brel_ma 	*ma;
+
+	ma = brel->priv_data;
+	while (++brel->current < ma->max_block) {
+		if (ma->entries[(unsigned)brel->current].new == 0)
+			continue;
+		*old = brel->current;
+		*ent = ma->entries[(unsigned)brel->current];
+		return 0;
+	}
+	*old = 0;
+	return 0;
+}
+
+static errcode_t bma_move(ext2_brel brel, blk_t old, blk_t new)
+{
+	struct brel_ma 	*ma;
+
+	ma = brel->priv_data;
+	if ((old > ma->max_block) || (new > ma->max_block))
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned)old].new == 0)
+		return ENOENT;
+	ma->entries[(unsigned)new] = ma->entries[old];
+	ma->entries[(unsigned)old].new = 0;
+	return 0;
+}
+
+static errcode_t bma_delete(ext2_brel brel, blk_t old)
+{
+	struct brel_ma 	*ma;
+
+	ma = brel->priv_data;
+	if (old > ma->max_block)
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned)old].new == 0)
+		return ENOENT;
+	ma->entries[(unsigned)old].new = 0;
+	return 0;
+}
+
+static errcode_t bma_free(ext2_brel brel)
+{
+	struct brel_ma 	*ma;
+
+	if (!brel)
+		return 0;
+
+	ma = brel->priv_data;
+
+	if (ma) {
+		if (ma->entries)
+			ext2fs_free_mem(&ma->entries);
+		ext2fs_free_mem(&ma);
+	}
+	if (brel->name)
+		ext2fs_free_mem(&brel->name);
+	ext2fs_free_mem(&brel);
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/check_desc.c silo-1.4.11/libext2fs/check_desc.c
--- silo-1.4.11.orig/libext2fs/check_desc.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/check_desc.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,68 @@
+/*
+ * check_desc.c --- Check the group descriptors of an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * This routine sanity checks the group descriptors
+ */
+errcode_t ext2fs_check_desc(ext2_filsys fs)
+{
+	dgrp_t i;
+	blk_t block = fs->super->s_first_data_block;
+	blk_t next;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+		next = block + fs->super->s_blocks_per_group;
+		/*
+		 * Check to make sure block bitmap for group is
+		 * located within the group.
+		 */
+		if (fs->group_desc[i].bg_block_bitmap < block ||
+		    fs->group_desc[i].bg_block_bitmap >= next)
+			return EXT2_ET_GDESC_BAD_BLOCK_MAP;
+		/*
+		 * Check to make sure inode bitmap for group is
+		 * located within the group
+		 */
+		if (fs->group_desc[i].bg_inode_bitmap < block ||
+		    fs->group_desc[i].bg_inode_bitmap >= next)
+			return EXT2_ET_GDESC_BAD_INODE_MAP;
+		/*
+		 * Check to make sure inode table for group is located
+		 * within the group
+		 */
+		if (fs->group_desc[i].bg_inode_table < block ||
+		    ((fs->group_desc[i].bg_inode_table +
+		      fs->inode_blocks_per_group) >= next))
+			return EXT2_ET_GDESC_BAD_INODE_TABLE;
+		
+		block = next;
+	}
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/closefs.c silo-1.4.11/libext2fs/closefs.c
--- silo-1.4.11.orig/libext2fs/closefs.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/closefs.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,381 @@
+/*
+ * closefs.c --- close an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int test_root(int a, int b)
+{
+	if (a == 0)
+		return 1;
+	while (1) {
+		if (a == 1)
+			return 1;
+		if (a % b)
+			return 0;
+		a = a / b;
+	}
+}
+
+int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+{
+	if (!(fs->super->s_feature_ro_compat &
+	      EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+		return 1;
+
+	if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
+	    test_root(group_block, 7))
+		return 1;
+
+	return 0;
+}
+
+int ext2fs_super_and_bgd_loc(ext2_filsys fs, 
+			     dgrp_t group,
+			     blk_t *ret_super_blk,
+			     blk_t *ret_old_desc_blk,
+			     blk_t *ret_new_desc_blk,
+			     int *ret_meta_bg)
+{
+	blk_t	group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
+	unsigned int meta_bg, meta_bg_size;
+	int	numblocks, has_super;
+	int	old_desc_blocks;
+
+	group_block = fs->super->s_first_data_block +
+		(group * fs->super->s_blocks_per_group);
+
+	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+		old_desc_blocks = fs->super->s_first_meta_bg;
+	else
+		old_desc_blocks = 
+			fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
+
+	if (group == fs->group_desc_count-1) {
+		numblocks = (fs->super->s_blocks_count -
+			     fs->super->s_first_data_block) %
+			fs->super->s_blocks_per_group;
+		if (!numblocks)
+			numblocks = fs->super->s_blocks_per_group;
+	} else
+		numblocks = fs->super->s_blocks_per_group;
+
+	has_super = ext2fs_bg_has_super(fs, group);
+
+	if (has_super) {
+		super_blk = group_block;
+		numblocks--;
+	}
+	meta_bg_size = (fs->blocksize / sizeof (struct ext2_group_desc));
+	meta_bg = group / meta_bg_size;
+
+	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
+	    (meta_bg < fs->super->s_first_meta_bg)) {
+		if (has_super) {
+			old_desc_blk = group_block + 1;
+			numblocks -= old_desc_blocks;
+		}
+	} else {
+		if (((group % meta_bg_size) == 0) ||
+		    ((group % meta_bg_size) == 1) ||
+		    ((group % meta_bg_size) == (meta_bg_size-1))) {
+			if (has_super)
+				has_super = 1;
+			new_desc_blk = group_block + has_super;
+			numblocks--;
+		}
+	}
+		
+	numblocks -= 2 + fs->inode_blocks_per_group;
+
+	if (ret_super_blk)
+		*ret_super_blk = super_blk;
+	if (ret_old_desc_blk)
+		*ret_old_desc_blk = old_desc_blk;
+	if (ret_new_desc_blk)
+		*ret_new_desc_blk = new_desc_blk;
+	if (ret_meta_bg)
+		*ret_meta_bg = meta_bg;
+	return (numblocks);
+}
+
+
+/*
+ * This function forces out the primary superblock.  We need to only
+ * write out those fields which we have changed, since if the
+ * filesystem is mounted, it may have changed some of the other
+ * fields.
+ *
+ * It takes as input a superblock which has already been byte swapped
+ * (if necessary).
+ *
+ */
+static errcode_t write_primary_superblock(ext2_filsys fs,
+					  struct ext2_super_block *super)
+{
+	__u16		*old_super, *new_super;
+	int		check_idx, write_idx, size;
+	errcode_t	retval;
+
+	if (!fs->io->manager->write_byte || !fs->orig_super) {
+		io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+		retval = io_channel_write_blk(fs->io, 1, -SUPERBLOCK_SIZE,
+					      super);
+		io_channel_set_blksize(fs->io, fs->blocksize);
+		return retval;
+	}
+
+	old_super = (__u16 *) fs->orig_super;
+	new_super = (__u16 *) super;
+
+	for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
+		if (old_super[check_idx] == new_super[check_idx])
+			continue;
+		write_idx = check_idx;
+		for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
+			if (old_super[check_idx] == new_super[check_idx])
+				break;
+		size = 2 * (check_idx - write_idx);
+#if 0
+		printf("Writing %d bytes starting at %d\n",
+		       size, write_idx*2);
+#endif
+		retval = io_channel_write_byte(fs->io,
+			       SUPERBLOCK_OFFSET + (2 * write_idx), size,
+					       new_super + write_idx);
+		if (retval)
+			return retval;
+	}
+	memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
+	return 0;
+}
+
+
+/*
+ * Updates the revision to EXT2_DYNAMIC_REV
+ */
+void ext2fs_update_dynamic_rev(ext2_filsys fs)
+{
+	struct ext2_super_block *sb = fs->super;
+
+	if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
+		return;
+
+	sb->s_rev_level = EXT2_DYNAMIC_REV;
+	sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
+	sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
+	/* s_uuid is handled by e2fsck already */
+	/* other fields should be left alone */
+}
+
+static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
+				    blk_t group_block,
+				    struct ext2_super_block *super_shadow)
+{
+	dgrp_t	sgrp = group;
+	
+	if (sgrp > ((1 << 16) - 1))
+		sgrp = (1 << 16) - 1;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES)
+		super_shadow->s_block_group_nr = ext2fs_swab16(sgrp);
+	else
+#endif
+		fs->super->s_block_group_nr = sgrp;
+
+	return io_channel_write_blk(fs->io, group_block, -SUPERBLOCK_SIZE, 
+				    super_shadow);
+}
+
+
+errcode_t ext2fs_flush(ext2_filsys fs)
+{
+	dgrp_t		i,j;
+	blk_t		group_block;
+	errcode_t	retval;
+	unsigned long	fs_state;
+	struct ext2_super_block *super_shadow = 0;
+	struct ext2_group_desc *group_shadow = 0;
+	struct ext2_group_desc *s, *t;
+	char	*group_ptr;
+	int	old_desc_blocks;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	fs_state = fs->super->s_state;
+
+	fs->super->s_wtime = time(NULL);
+	fs->super->s_block_group_nr = 0;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+		retval = EXT2_ET_NO_MEMORY;
+		retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
+		if (retval)
+			goto errout;
+		retval = ext2fs_get_mem((size_t)(fs->blocksize *
+						 fs->desc_blocks),
+					&group_shadow);
+		if (retval)
+			goto errout;
+		memset(group_shadow, 0, (size_t) fs->blocksize *
+		       fs->desc_blocks);
+
+		/* swap the group descriptors */
+		for (j=0, s=fs->group_desc, t=group_shadow;
+		     j < fs->group_desc_count; j++, t++, s++) {
+			*t = *s;
+			ext2fs_swap_group_desc(t);
+		}
+	} else {
+		super_shadow = fs->super;
+		group_shadow = fs->group_desc;
+	}
+#else
+	super_shadow = fs->super;
+	group_shadow = fs->group_desc;
+#endif
+	
+	/*
+	 * If this is an external journal device, don't write out the
+	 * block group descriptors or any of the backup superblocks
+	 */
+	if (fs->super->s_feature_incompat &
+	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
+		goto write_primary_superblock_only;
+
+	/*
+	 * Set the state of the FS to be non-valid.  (The state has
+	 * already been backed up earlier, and will be restored after
+	 * we write out the backup superblocks.)
+	 */
+	fs->super->s_state &= ~EXT2_VALID_FS;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+		*super_shadow = *fs->super;
+		ext2fs_swap_super(super_shadow);
+	}
+#endif
+
+	/*
+	 * Write out the master group descriptors, and the backup
+	 * superblocks and group descriptors.
+	 */
+	group_block = fs->super->s_first_data_block;
+	group_ptr = (char *) group_shadow;
+	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
+		old_desc_blocks = fs->super->s_first_meta_bg;
+	else
+		old_desc_blocks = fs->desc_blocks;
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+		blk_t	super_blk, old_desc_blk, new_desc_blk;
+		int	meta_bg;
+
+		ext2fs_super_and_bgd_loc(fs, i, &super_blk, &old_desc_blk, 
+					 &new_desc_blk, &meta_bg);
+
+		if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
+			retval = write_backup_super(fs, i, super_blk,
+						    super_shadow);
+			if (retval)
+				goto errout;
+		}
+		if (fs->flags & EXT2_FLAG_SUPER_ONLY)
+			continue;
+		if ((old_desc_blk) && 
+		    (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
+			retval = io_channel_write_blk(fs->io,
+			      old_desc_blk, old_desc_blocks, group_ptr);
+			if (retval)
+				goto errout;
+		}
+		if (new_desc_blk) {
+			retval = io_channel_write_blk(fs->io, new_desc_blk,
+				1, group_ptr + (meta_bg*fs->blocksize));
+			if (retval)
+				goto errout;
+		}
+	}
+	fs->super->s_block_group_nr = 0;
+	fs->super->s_state = fs_state;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+		*super_shadow = *fs->super;
+		ext2fs_swap_super(super_shadow);
+	}
+#endif
+
+	/*
+	 * If the write_bitmaps() function is present, call it to
+	 * flush the bitmaps.  This is done this way so that a simple
+	 * program that doesn't mess with the bitmaps doesn't need to
+	 * drag in the bitmaps.c code.
+	 */
+	if (fs->write_bitmaps) {
+		retval = fs->write_bitmaps(fs);
+		if (retval)
+			goto errout;
+	}
+
+write_primary_superblock_only:
+	/*
+	 * Write out master superblock.  This has to be done
+	 * separately, since it is located at a fixed location
+	 * (SUPERBLOCK_OFFSET).  We flush all other pending changes
+	 * out to disk first, just to avoid a race condition with an
+	 * insy-tinsy window....
+	 */
+	retval = io_channel_flush(fs->io);
+	retval = write_primary_superblock(fs, super_shadow);
+	if (retval)
+		goto errout;
+
+	fs->flags &= ~EXT2_FLAG_DIRTY;
+
+	retval = io_channel_flush(fs->io);
+errout:
+	fs->super->s_state = fs_state;
+	if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+		if (super_shadow)
+			ext2fs_free_mem(&super_shadow);
+		if (group_shadow)
+			ext2fs_free_mem(&group_shadow);
+	}
+	return retval;
+}
+
+errcode_t ext2fs_close(ext2_filsys fs)
+{
+	errcode_t	retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (fs->flags & EXT2_FLAG_DIRTY) {
+		retval = ext2fs_flush(fs);
+		if (retval)
+			return retval;
+	}
+	if (fs->write_bitmaps) {
+		retval = fs->write_bitmaps(fs);
+		if (retval)
+			return retval;
+	}
+	ext2fs_free(fs);
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/cmp_bitmaps.c silo-1.4.11/libext2fs/cmp_bitmaps.c
--- silo-1.4.11.orig/libext2fs/cmp_bitmaps.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/cmp_bitmaps.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,72 @@
+/*
+ * cmp_bitmaps.c --- routines to compare inode and block bitmaps.
+ *
+ * Copyright (C) 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+				      ext2fs_block_bitmap bm2)
+{
+	blk_t	i;
+	
+	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_BLOCK_BITMAP);
+	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_BLOCK_BITMAP);
+
+	if ((bm1->start != bm2->start) ||
+	    (bm1->end != bm2->end) ||
+	    (memcmp(bm1->bitmap, bm2->bitmap,
+		    (size_t) (bm1->end - bm1->start)/8)))
+		return EXT2_ET_NEQ_BLOCK_BITMAP;
+
+	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
+		if (ext2fs_fast_test_block_bitmap(bm1, i) !=
+		    ext2fs_fast_test_block_bitmap(bm2, i))
+			return EXT2_ET_NEQ_BLOCK_BITMAP;
+
+	return 0;
+}
+
+errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+				      ext2fs_inode_bitmap bm2)
+{
+	ext2_ino_t	i;
+	
+	EXT2_CHECK_MAGIC(bm1, EXT2_ET_MAGIC_INODE_BITMAP);
+	EXT2_CHECK_MAGIC(bm2, EXT2_ET_MAGIC_INODE_BITMAP);
+
+	if ((bm1->start != bm2->start) ||
+	    (bm1->end != bm2->end) ||
+	    (memcmp(bm1->bitmap, bm2->bitmap,
+		    (size_t) (bm1->end - bm1->start)/8)))
+		return EXT2_ET_NEQ_INODE_BITMAP;
+
+	for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
+		if (ext2fs_fast_test_inode_bitmap(bm1, i) !=
+		    ext2fs_fast_test_inode_bitmap(bm2, i))
+			return EXT2_ET_NEQ_INODE_BITMAP;
+
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/dblist.c silo-1.4.11/libext2fs/dblist.c
--- silo-1.4.11.orig/libext2fs/dblist.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dblist.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,260 @@
+/*
+ * dblist.c -- directory block list functions
+ * 
+ * Copyright 1997 by Theodore Ts'o
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
+
+/*
+ * Returns the number of directories in the filesystem as reported by
+ * the group descriptors.  Of course, the group descriptors could be
+ * wrong!
+ */
+errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
+{
+	dgrp_t	i;
+	ext2_ino_t	num_dirs, max_dirs;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	
+	num_dirs = 0;
+	max_dirs = fs->super->s_inodes_per_group;
+	for (i = 0; i < fs->group_desc_count; i++) {
+		if (fs->group_desc[i].bg_used_dirs_count > max_dirs)
+			num_dirs += max_dirs / 8;
+		else
+			num_dirs += fs->group_desc[i].bg_used_dirs_count;
+	}
+	if (num_dirs > fs->super->s_inodes_count)
+		num_dirs = fs->super->s_inodes_count;
+
+	*ret_num_dirs = num_dirs;
+
+	return 0;
+}
+
+/*
+ * helper function for making a new directory block list (for
+ * initialize and copy).
+ */
+static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size, ext2_ino_t count,
+			     struct ext2_db_entry *list,
+			     ext2_dblist *ret_dblist)
+{
+	ext2_dblist	dblist;
+	errcode_t	retval;
+	size_t		len;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if ((ret_dblist == 0) && fs->dblist &&
+	    (fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
+		return 0;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
+	if (retval)
+		return retval;
+	memset(dblist, 0, sizeof(struct ext2_struct_dblist));
+
+	dblist->magic = EXT2_ET_MAGIC_DBLIST;
+	dblist->fs = fs;
+	if (size)
+		dblist->size = size;
+	else {
+		retval = ext2fs_get_num_dirs(fs, &dblist->size);
+		if (retval)
+			goto cleanup;
+		dblist->size = (dblist->size * 2) + 12;
+	}
+	len = (size_t) sizeof(struct ext2_db_entry) * dblist->size;
+	dblist->count = count;
+	retval = ext2fs_get_mem(len, &dblist->list);
+	if (retval)
+		goto cleanup;
+	
+	if (list)
+		memcpy(dblist->list, list, len);
+	else
+		memset(dblist->list, 0, len);
+	if (ret_dblist)
+		*ret_dblist = dblist;
+	else
+		fs->dblist = dblist;
+	return 0;
+cleanup:
+	if (dblist)
+		ext2fs_free_mem(&dblist);
+	return retval;
+}
+
+/*
+ * Initialize a directory block list
+ */
+errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
+{
+	ext2_dblist	dblist;
+	errcode_t	retval;
+
+	retval = make_dblist(fs, 0, 0, 0, &dblist);
+	if (retval)
+		return retval;
+
+	dblist->sorted = 1;
+	if (ret_dblist)
+		*ret_dblist = dblist;
+	else
+		fs->dblist = dblist;
+
+	return 0;
+}
+
+/*
+ * Copy a directory block list
+ */
+errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
+{
+	ext2_dblist	dblist;
+	errcode_t	retval;
+
+	retval = make_dblist(src->fs, src->size, src->count, src->list,
+			     &dblist);
+	if (retval)
+		return retval;
+	dblist->sorted = src->sorted;
+	*dest = dblist;
+	return 0;
+}
+
+/*
+ * Close a directory block list
+ *
+ * (moved to closefs.c)
+ */
+
+
+/*
+ * Add a directory block to the directory block list
+ */
+errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
+			       int blockcnt)
+{
+	struct ext2_db_entry 	*new_entry;
+	errcode_t		retval;
+	unsigned long		old_size;
+	
+	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+	if (dblist->count >= dblist->size) {
+		old_size = dblist->size * sizeof(struct ext2_db_entry);
+		dblist->size += 100;
+		retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
+					   sizeof(struct ext2_db_entry),
+					   &dblist->list);
+		if (retval) {
+			dblist->size -= 100;
+			return retval;
+		}
+	}
+	new_entry = dblist->list + ( (int) dblist->count++);
+	new_entry->blk = blk;
+	new_entry->ino = ino;
+	new_entry->blockcnt = blockcnt;
+
+	dblist->sorted = 0;
+
+	return 0;
+}
+
+/*
+ * Change the directory block to the directory block list
+ */
+errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
+			       int blockcnt)
+{
+	dgrp_t			i;
+	
+	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+	for (i=0; i < dblist->count; i++) {
+		if ((dblist->list[i].ino != ino) ||
+		    (dblist->list[i].blockcnt != blockcnt))
+			continue;
+		dblist->list[i].blk = blk;
+		dblist->sorted = 0;
+		return 0;
+	}
+	return EXT2_ET_DB_NOT_FOUND;
+}
+
+void ext2fs_dblist_sort(ext2_dblist dblist,
+			EXT2_QSORT_TYPE (*sortfunc)(const void *,
+						    const void *))
+{
+	if (!sortfunc)
+		sortfunc = dir_block_cmp;
+	qsort(dblist->list, (size_t) dblist->count,
+	      sizeof(struct ext2_db_entry), sortfunc);
+	dblist->sorted = 1;
+}
+
+/*
+ * This function iterates over the directory block list
+ */
+errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
+				int (*func)(ext2_filsys fs,
+					    struct ext2_db_entry *db_info,
+					    void	*priv_data),
+				void *priv_data)
+{
+	ext2_ino_t	i;
+	int		ret;
+	
+	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+	if (!dblist->sorted)
+		ext2fs_dblist_sort(dblist, 0);
+	for (i=0; i < dblist->count; i++) {
+		ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
+		if (ret & DBLIST_ABORT)
+			return 0;
+	}
+	return 0;
+}
+
+static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
+{
+	const struct ext2_db_entry *db_a =
+		(const struct ext2_db_entry *) a;
+	const struct ext2_db_entry *db_b =
+		(const struct ext2_db_entry *) b;
+
+	if (db_a->blk != db_b->blk)
+		return (int) (db_a->blk - db_b->blk);
+	
+	if (db_a->ino != db_b->ino)
+		return (int) (db_a->ino - db_b->ino);
+
+	return (int) (db_a->blockcnt - db_b->blockcnt);
+}
+
+int ext2fs_dblist_count(ext2_dblist dblist)
+{
+	return (int) dblist->count;
+}
diff -Naur silo-1.4.11.orig/libext2fs/dblist_dir.c silo-1.4.11/libext2fs/dblist_dir.c
--- silo-1.4.11.orig/libext2fs/dblist_dir.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dblist_dir.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,75 @@
+/*
+ * dblist_dir.c --- iterate by directory entry
+ *
+ * Copyright 1997 by Theodore Ts'o
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
+		       void *priv_data);
+
+errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
+				    int	flags,
+				    char	*block_buf,
+				    int (*func)(ext2_ino_t dir,
+						int	entry,
+						struct ext2_dir_entry *dirent,
+						int	offset,
+						int	blocksize,
+						char	*buf,
+						void	*priv_data),
+				    void *priv_data)
+{
+	errcode_t		retval;
+	struct dir_context	ctx;
+
+	EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
+
+	ctx.dir = 0;
+	ctx.flags = flags;
+	if (block_buf)
+		ctx.buf = block_buf;
+	else {
+		retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
+		if (retval)
+			return retval;
+	}
+	ctx.func = func;
+	ctx.priv_data = priv_data;
+	ctx.errcode = 0;
+
+	retval = ext2fs_dblist_iterate(dblist, db_dir_proc, &ctx);
+	
+	if (!block_buf)
+		ext2fs_free_mem(&ctx.buf);
+	if (retval)
+		return retval;
+	return ctx.errcode;
+}
+
+static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry *db_info,
+		       void *priv_data)
+{
+	struct dir_context	*ctx;
+
+	ctx = (struct dir_context *) priv_data;
+	ctx->dir = db_info->ino;
+	
+	return ext2fs_process_dir_block(fs, &db_info->blk,
+					db_info->blockcnt, 0, 0, priv_data);
+}
diff -Naur silo-1.4.11.orig/libext2fs/dir_iterate.c silo-1.4.11/libext2fs/dir_iterate.c
--- silo-1.4.11.orig/libext2fs/dir_iterate.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dir_iterate.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,219 @@
+/*
+ * dir_iterate.c --- ext2fs directory iteration operations
+ * 
+ * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+/*
+ * This function checks to see whether or not a potential deleted
+ * directory entry looks valid.  What we do is check the deleted entry
+ * and each successive entry to make sure that they all look valid and
+ * that the last deleted entry ends at the beginning of the next
+ * undeleted entry.  Returns 1 if the deleted entry looks valid, zero
+ * if not valid.
+ */
+static int ext2fs_validate_entry(char *buf, int offset, int final_offset)
+{
+	struct ext2_dir_entry *dirent;
+	
+	while (offset < final_offset) {
+		dirent = (struct ext2_dir_entry *)(buf + offset);
+		offset += dirent->rec_len;
+		if ((dirent->rec_len < 8) ||
+		    ((dirent->rec_len % 4) != 0) ||
+		    (((dirent->name_len & 0xFF)+8) > dirent->rec_len))
+			return 0;
+	}
+	return (offset == final_offset);
+}
+
+errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
+			      ext2_ino_t dir,
+			      int flags,
+			      char *block_buf,
+			      int (*func)(ext2_ino_t	dir,
+					  int		entry,
+					  struct ext2_dir_entry *dirent,
+					  int	offset,
+					  int	blocksize,
+					  char	*buf,
+					  void	*priv_data),
+			      void *priv_data)
+{
+	struct		dir_context	ctx;
+	errcode_t	retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_check_directory(fs, dir);
+	if (retval)
+		return retval;
+	
+	ctx.dir = dir;
+	ctx.flags = flags;
+	if (block_buf)
+		ctx.buf = block_buf;
+	else {
+		retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
+		if (retval)
+			return retval;
+	}
+	ctx.func = func;
+	ctx.priv_data = priv_data;
+	ctx.errcode = 0;
+	retval = ext2fs_block_iterate2(fs, dir, 0, 0,
+				       ext2fs_process_dir_block, &ctx);
+	if (!block_buf)
+		ext2fs_free_mem(&ctx.buf);
+	if (retval)
+		return retval;
+	return ctx.errcode;
+}
+
+struct xlate {
+	int (*func)(struct ext2_dir_entry *dirent,
+		    int		offset,
+		    int		blocksize,
+		    char	*buf,
+		    void	*priv_data);
+	void *real_private;
+};
+
+static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
+		      int entry EXT2FS_ATTR((unused)),
+		      struct ext2_dir_entry *dirent, int offset,
+		      int blocksize, char *buf, void *priv_data)
+{
+	struct xlate *xl = (struct xlate *) priv_data;
+
+	return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
+}
+
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, 
+			      ext2_ino_t dir,
+			      int flags,
+			      char *block_buf,
+			      int (*func)(struct ext2_dir_entry *dirent,
+					  int	offset,
+					  int	blocksize,
+					  char	*buf,
+					  void	*priv_data),
+			      void *priv_data)
+{
+	struct xlate xl;
+	
+	xl.real_private = priv_data;
+	xl.func = func;
+
+	return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
+				   xlate_func, &xl);
+}
+
+
+/*
+ * Helper function which is private to this module.  Used by
+ * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
+ */
+int ext2fs_process_dir_block(ext2_filsys fs,
+			     blk_t	*blocknr,
+			     e2_blkcnt_t blockcnt,
+			     blk_t	ref_block EXT2FS_ATTR((unused)),
+			     int	ref_offset EXT2FS_ATTR((unused)),
+			     void	*priv_data)
+{
+	struct dir_context *ctx = (struct dir_context *) priv_data;
+	unsigned int	offset = 0;
+	unsigned int	next_real_entry = 0;
+	int		ret = 0;
+	int		changed = 0;
+	int		do_abort = 0;
+	int		entry, size;
+	struct ext2_dir_entry *dirent;
+
+	if (blockcnt < 0)
+		return 0;
+
+	entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
+	
+	ctx->errcode = ext2fs_read_dir_block(fs, *blocknr, ctx->buf);
+	if (ctx->errcode)
+		return BLOCK_ABORT;
+
+	while (offset < fs->blocksize) {
+		dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
+		if (((offset + dirent->rec_len) > fs->blocksize) ||
+		    (dirent->rec_len < 8) ||
+		    ((dirent->rec_len % 4) != 0) ||
+		    (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
+			ctx->errcode = EXT2_ET_DIR_CORRUPTED;
+			return BLOCK_ABORT;
+		}
+		if (!dirent->inode &&
+		    !(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
+			goto next;
+
+		ret = (ctx->func)(ctx->dir,
+				  (next_real_entry > offset) ?
+				  DIRENT_DELETED_FILE : entry,
+				  dirent, offset,
+				  fs->blocksize, ctx->buf,
+				  ctx->priv_data);
+		if (entry < DIRENT_OTHER_FILE)
+			entry++;
+			
+		if (ret & DIRENT_CHANGED)
+			changed++;
+		if (ret & DIRENT_ABORT) {
+			do_abort++;
+			break;
+		}
+next:		
+ 		if (next_real_entry == offset)
+			next_real_entry += dirent->rec_len;
+ 
+ 		if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
+			size = ((dirent->name_len & 0xFF) + 11) & ~3;
+
+			if (dirent->rec_len != size)  {
+				unsigned int final_offset;
+
+				final_offset = offset + dirent->rec_len;
+				offset += size;
+				while (offset < final_offset &&
+				       !ext2fs_validate_entry(ctx->buf,
+							      offset,
+							      final_offset))
+					offset += 4;
+				continue;
+			}
+		}
+		offset += dirent->rec_len;
+	}
+
+	if (changed) {
+		ctx->errcode = ext2fs_write_dir_block(fs, *blocknr, ctx->buf);
+		if (ctx->errcode)
+			return BLOCK_ABORT;
+	}
+	if (do_abort)
+		return BLOCK_ABORT;
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/dirblock.c silo-1.4.11/libext2fs/dirblock.c
--- silo-1.4.11.orig/libext2fs/dirblock.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dirblock.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,130 @@
+/*
+ * dirblock.c --- directory block routines.
+ * 
+ * Copyright (C) 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
+				 void *buf, int flags EXT2FS_ATTR((unused)))
+{
+	errcode_t	retval;
+	char		*p, *end;
+	struct ext2_dir_entry *dirent;
+	unsigned int	name_len, rec_len, do_swap;
+	
+
+ 	retval = io_channel_read_blk(fs->io, block, 1, buf);
+	if (retval)
+		return retval;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	do_swap = (fs->flags & (EXT2_FLAG_SWAP_BYTES|
+				EXT2_FLAG_SWAP_BYTES_READ)) != 0;
+#endif
+	p = (char *) buf;
+	end = (char *) buf + fs->blocksize;
+	while (p < end-8) {
+		dirent = (struct ext2_dir_entry *) p;
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if (do_swap) {
+			dirent->inode = ext2fs_swab32(dirent->inode);
+			dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+		}
+#endif
+		name_len = dirent->name_len;
+#ifdef WORDS_BIGENDIAN
+		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+#endif
+		rec_len = dirent->rec_len;
+		if ((rec_len < 8) || (rec_len % 4)) {
+			rec_len = 8;
+			retval = EXT2_ET_DIR_CORRUPTED;
+		}
+		if (((name_len & 0xFF) + 8) > dirent->rec_len)
+			retval = EXT2_ET_DIR_CORRUPTED;
+		p += rec_len;
+	}
+	return retval;
+}
+
+errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
+				 void *buf)
+{
+	return ext2fs_read_dir_block2(fs, block, buf, 0);
+}
+
+
+errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
+				  void *inbuf, int flags EXT2FS_ATTR((unused)))
+{
+#ifdef EXT2FS_ENABLE_SWAPFS
+	int		do_swap = 0;
+	errcode_t	retval;
+	char		*p, *end;
+	char		*buf = 0;
+	struct ext2_dir_entry *dirent;
+
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+		do_swap = 1;
+
+#ifndef WORDS_BIGENDIAN
+	if (!do_swap)
+		return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
+#endif
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	memcpy(buf, inbuf, fs->blocksize);
+	p = buf;
+	end = buf + fs->blocksize;
+	while (p < end) {
+		dirent = (struct ext2_dir_entry *) p;
+		if ((dirent->rec_len < 8) ||
+		    (dirent->rec_len % 4)) {
+			ext2fs_free_mem(&buf);
+			return (EXT2_ET_DIR_CORRUPTED);
+		}
+		p += dirent->rec_len;
+		if (do_swap) {
+			dirent->inode = ext2fs_swab32(dirent->inode);
+			dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+		}
+#ifdef WORDS_BIGENDIAN 
+		if (flags & EXT2_DIRBLOCK_V2_STRUCT)
+			dirent->name_len = ext2fs_swab16(dirent->name_len);
+#endif
+	}
+ 	retval = io_channel_write_blk(fs->io, block, 1, buf);
+	ext2fs_free_mem(&buf);
+	return retval;
+#else
+ 	return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
+#endif
+}
+
+
+errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
+				 void *inbuf)
+{
+	return ext2fs_write_dir_block2(fs, block, inbuf, 0);
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/dirhash.c silo-1.4.11/libext2fs/dirhash.c
--- silo-1.4.11.orig/libext2fs/dirhash.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dirhash.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,233 @@
+/*
+ * dirhash.c -- Calculate the hash of a directory entry
+ *
+ * Copyright (c) 2001  Daniel Phillips
+ * 
+ * Copyright (c) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Keyed 32-bit hash function using TEA in a Davis-Meyer function
+ *   H0 = Key
+ *   Hi = E Mi(Hi-1) + Hi-1
+ *
+ * (see Applied Cryptography, 2nd edition, p448).
+ *
+ * Jeremy Fitzhardinge <jeremy@zip.com.au> 1998
+ * 
+ * This code is made available under the terms of the GPL
+ */
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(__u32 buf[4], __u32 const in[])
+{
+	__u32	sum = 0;
+	__u32	b0 = buf[0], b1 = buf[1];
+	__u32	a = in[0], b = in[1], c = in[2], d = in[3];
+	int	n = 16;
+
+	do {							
+		sum += DELTA;					
+		b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);	
+		b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);	
+	} while(--n);
+
+	buf[0] += b0;
+	buf[1] += b1;
+}
+
+/* F, G and H are basic MD4 functions: selection, majority, parity */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The generic round function.  The application is so specific that
+ * we don't bother protecting all the arguments with parens, as is generally
+ * good macro practice, in favor of extra legibility.
+ * Rotation is separate from addition to prevent recomputation
+ */
+#define ROUND(f, a, b, c, d, x, s)	\
+	(a += f(b, c, d) + x, a = (a << s) | (a >> (32-s)))
+#define K1 0
+#define K2 013240474631UL
+#define K3 015666365641UL
+
+/*
+ * Basic cut-down MD4 transform.  Returns only 32 bits of result.
+ */
+static void halfMD4Transform (__u32 buf[4], __u32 const in[])
+{
+	__u32	a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[0] + K1,  3);
+	ROUND(F, d, a, b, c, in[1] + K1,  7);
+	ROUND(F, c, d, a, b, in[2] + K1, 11);
+	ROUND(F, b, c, d, a, in[3] + K1, 19);
+	ROUND(F, a, b, c, d, in[4] + K1,  3);
+	ROUND(F, d, a, b, c, in[5] + K1,  7);
+	ROUND(F, c, d, a, b, in[6] + K1, 11);
+	ROUND(F, b, c, d, a, in[7] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[1] + K2,  3);
+	ROUND(G, d, a, b, c, in[3] + K2,  5);
+	ROUND(G, c, d, a, b, in[5] + K2,  9);
+	ROUND(G, b, c, d, a, in[7] + K2, 13);
+	ROUND(G, a, b, c, d, in[0] + K2,  3);
+	ROUND(G, d, a, b, c, in[2] + K2,  5);
+	ROUND(G, c, d, a, b, in[4] + K2,  9);
+	ROUND(G, b, c, d, a, in[6] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[3] + K3,  3);
+	ROUND(H, d, a, b, c, in[7] + K3,  9);
+	ROUND(H, c, d, a, b, in[2] + K3, 11);
+	ROUND(H, b, c, d, a, in[6] + K3, 15);
+	ROUND(H, a, b, c, d, in[1] + K3,  3);
+	ROUND(H, d, a, b, c, in[5] + K3,  9);
+	ROUND(H, c, d, a, b, in[0] + K3, 11);
+	ROUND(H, b, c, d, a, in[4] + K3, 15);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#undef ROUND
+#undef F
+#undef G
+#undef H
+#undef K1
+#undef K2
+#undef K3
+
+/* The old legacy hash */
+static ext2_dirhash_t dx_hack_hash (const char *name, int len)
+{
+	__u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+	while (len--) {
+		__u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
+		
+		if (hash & 0x80000000) hash -= 0x7fffffff;
+		hash1 = hash0;
+		hash0 = hash;
+	}
+	return (hash0 << 1);
+}
+
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+{
+	__u32	pad, val;
+	int	i;
+
+	pad = (__u32)len | ((__u32)len << 8);
+	pad |= pad << 16;
+
+	val = pad;
+	if (len > num*4)
+		len = num * 4;
+	for (i=0; i < len; i++) {
+		if ((i % 4) == 0)
+			val = pad;
+		val = msg[i] + (val << 8);
+		if ((i % 4) == 3) {
+			*buf++ = val;
+			val = pad;
+			num--;
+		}
+	}
+	if (--num >= 0)
+		*buf++ = val;
+	while (--num >= 0)
+		*buf++ = pad;
+}
+
+/*
+ * Returns the hash of a filename.  If len is 0 and name is NULL, then
+ * this function can be used to test whether or not a hash version is
+ * supported.
+ * 
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash.  If the seed is all zero's, then some default seed
+ * may be used.
+ * 
+ * A particular hash version specifies whether or not the seed is
+ * represented, and whether or not the returned hash is 32 bits or 64
+ * bits.  32 bit hashes will return 0 for the minor hash.
+ */
+errcode_t ext2fs_dirhash(int version, const char *name, int len,
+			 const __u32 *seed,
+			 ext2_dirhash_t *ret_hash,
+			 ext2_dirhash_t *ret_minor_hash)
+{
+	__u32	hash;
+	__u32	minor_hash = 0;
+	const char	*p;
+	int		i;
+	__u32 		in[8], buf[4];
+
+	/* Initialize the default seed for the hash checksum functions */
+	buf[0] = 0x67452301;
+	buf[1] = 0xefcdab89;
+	buf[2] = 0x98badcfe;
+	buf[3] = 0x10325476;
+
+	/* Check to see if the seed is all zero's */
+	if (seed) {
+		for (i=0; i < 4; i++) {
+			if (seed[i])
+				break;
+		}
+		if (i < 4)
+			memcpy(buf, seed, sizeof(buf));
+	}
+		
+	switch (version) {
+	case EXT2_HASH_LEGACY:
+		hash = dx_hack_hash(name, len);
+		break;
+	case EXT2_HASH_HALF_MD4:
+		p = name;
+		while (len > 0) {
+			str2hashbuf(p, len, in, 8);
+			halfMD4Transform(buf, in);
+			len -= 32;
+			p += 32;
+		}
+		minor_hash = buf[2];
+		hash = buf[1];
+		break;
+	case EXT2_HASH_TEA:
+		p = name;
+		while (len > 0) {
+			str2hashbuf(p, len, in, 4);
+			TEA_transform(buf, in);
+			len -= 16;
+			p += 16;
+		}
+		hash = buf[0];
+		minor_hash = buf[1];
+		break;
+	default:
+		*ret_hash = 0;
+		return EXT2_ET_DIRHASH_UNSUPP;
+	}
+	*ret_hash = hash & ~1;
+	if (ret_minor_hash)
+		*ret_minor_hash = minor_hash;
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/dosio.c silo-1.4.11/libext2fs/dosio.c
--- silo-1.4.11.orig/libext2fs/dosio.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dosio.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,456 @@
+/*
+ * dosio.c -- Disk I/O module for the ext2fs/DOS library.
+ *
+ * Copyright (c) 1997 by Theodore Ts'o.
+ * 
+ * Copyright (c) 1997 Mark Habersack
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ */
+
+#include <stdio.h>
+#include <bios.h>
+#include <string.h>
+#include <ctype.h>
+#include <io.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include <ext2fs/ext2_types.h>
+#include "utils.h"
+#include "dosio.h"
+#include "et/com_err.h"
+#include "ext2_err.h"
+#include "ext2fs/io.h"
+
+/*
+ * Some helper macros
+ */
+#define LINUX_EXT2FS       0x83
+#define LINUX_SWAP         0x82
+#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
+#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
+
+/*
+ * Exported variables
+ */
+unsigned long        _dio_error;
+unsigned long        _dio_hw_error;
+
+/*
+ * Array of all opened partitions
+ */
+static PARTITION        **partitions = NULL;
+static unsigned short   npart = 0; /* Number of mapped partitions */
+static PARTITION        *active = NULL;
+
+/*
+ * I/O Manager routine prototypes
+ */
+static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
+static errcode_t dos_close(io_channel channel);
+static errcode_t dos_set_blksize(io_channel channel, int blksize);
+static errcode_t dos_read_blk(io_channel channel, unsigned long block,
+                                             int count, void *buf);
+static errcode_t dos_write_blk(io_channel channel, unsigned long block,
+                               int count, const void *buf);
+static errcode_t dos_flush(io_channel channel);
+
+static struct struct_io_manager struct_dos_manager = {
+        EXT2_ET_MAGIC_IO_MANAGER,
+        "DOS I/O Manager",
+        dos_open,
+        dos_close,
+        dos_set_blksize,
+        dos_read_blk,
+        dos_write_blk,
+        dos_flush
+};
+io_manager dos_io_manager = &struct_dos_manager;
+
+/*
+ * Macro taken from unix_io.c
+ */
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+          if ((struct)->magic != (code)) return (code)
+
+/*
+ * Calculates a CHS address of a sector from its LBA
+ * offset for the given partition.
+ */
+static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
+{
+  unsigned long      abss;
+
+  chs->offset = lba_addr & 0x000001FF;
+  abss = (lba_addr >> 9) + part->start;
+  chs->cyl    = abss / (part->sects * part->heads);
+  chs->head   = (abss / part->sects) % part->heads;
+  chs->sector = (abss % part->sects) + 1;
+}
+
+#ifdef __TURBOC__
+#pragma argsused
+#endif
+/*
+ * Scans the passed partition table looking for *pno partition
+ * that has LINUX_EXT2FS type.
+ *
+ * TODO:
+ * For partition numbers >5 Linux uses DOS extended partitions -
+ * dive into them an return an appropriate entry. Also dive into
+ * extended partitions when scanning for a first Linux/ext2fs.
+ */
+static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
+                                          unsigned short phys,
+                                          unsigned char *pno)
+{
+  unsigned        i;
+
+  if(*pno != 0xFF && *pno >= 5)
+     return NULL; /* We don't support extended partitions for now */
+
+  if(*pno != 0xFF)
+  {
+    if(pentry[*pno].type == LINUX_EXT2FS)
+      return &pentry[*pno];
+    else
+    {
+      if(!pentry[*pno].type)
+        *pno = 0xFE;
+      else if(pentry[*pno].type == LINUX_SWAP)
+        *pno = 0xFD;
+      return NULL;
+    }
+  }
+
+  for(i = 0; i < 4; i++)
+    if(pentry[i].type == LINUX_EXT2FS)
+    {
+      *pno = i;
+      return &pentry[i];
+    }
+
+  return NULL;
+}
+
+/*
+ * Allocate libext2fs structures associated with I/O manager
+ */
+static io_channel alloc_io_channel(PARTITION *part)
+{
+  io_channel     ioch;
+
+  ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
+  if (!ioch)
+	  return NULL;
+  memset(ioch, 0, sizeof(struct struct_io_channel));
+  ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+  ioch->manager = dos_io_manager;
+  ioch->name = (char *)malloc(strlen(part->dev)+1);
+  if (!ioch->name) {
+	  free(ioch);
+	  return NULL;
+  }
+  strcpy(ioch->name, part->dev);
+  ioch->private_data = part;
+  ioch->block_size = 1024; /* The smallest ext2fs block size */
+  ioch->read_error = 0;
+  ioch->write_error = 0;
+
+  return ioch;
+}
+
+#ifdef __TURBOC__
+#pragma argsused
+#endif
+/*
+ * Open the 'name' partition, initialize all information structures
+ * we need to keep and create libext2fs I/O manager.
+ */
+static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
+{
+  unsigned char  *tmp, sec[512];
+  PARTITION      *part;
+  PTABLE_ENTRY   *pent;
+  PARTITION        **newparts;
+  
+  if(!dev)
+  {
+    _dio_error = ERR_BADDEV;
+    return EXT2_ET_BAD_DEVICE_NAME;
+  }
+
+  /*
+   * First check whether the dev name is OK
+   */
+  tmp = (unsigned char*)strrchr(dev, '/');
+  if(!tmp)
+  {
+    _dio_error = ERR_BADDEV;
+    return EXT2_ET_BAD_DEVICE_NAME;
+  }
+  *tmp = 0;
+  if(strcmp(dev, "/dev"))
+  {
+    _dio_error = ERR_BADDEV;
+    return EXT2_ET_BAD_DEVICE_NAME;
+  }
+  *tmp++ = '/';
+
+  /*
+   * Check whether the partition data is already in cache
+   */
+
+  part = (PARTITION*)malloc(sizeof(PARTITION));
+  if (!part)
+	  return ENOMEM;
+  {
+    int   i = 0;
+
+    for(;i < npart; i++)
+      if(!strcmp(partitions[i]->dev, dev))
+      {
+        /* Found it! Make it the active one */
+        active = partitions[i];
+        *channel = alloc_io_channel(active);
+	if (!*channel)
+		return ENOMEM;
+        return 0;
+      }
+  }
+
+  /*
+   * Drive number & optionally partn number
+   */
+  switch(tmp[0])
+  {
+    case 'h':
+    case 's':
+      part->phys = 0x80;
+      part->phys += toupper(tmp[2]) - 'A';
+      /*
+       * Do we have the partition number?
+       */
+      if(tmp[3])
+        part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
+      else
+        part->pno = 0xFF;
+      break;
+
+    case 'f':
+      if(tmp[2])
+        part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
+      else
+        part->phys = 0x00; /* We'll assume /dev/fd0 */
+      break;
+
+    default:
+      _dio_error = ERR_BADDEV;
+      return ENODEV;
+  }
+
+  if(part->phys < 0x80)
+  {
+     /* We don't support floppies for now */
+     _dio_error = ERR_NOTSUPP;
+     return EINVAL;
+  }
+
+  part->dev = strdup(dev);
+
+  /*
+   * Get drive's geometry
+   */
+  _dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
+                           part->phys,
+                           0, /* head */
+                           0, /* cylinder */
+                           1, /* sector */
+                           1, /* just one sector */
+                           sec);
+
+  if(!HW_OK())
+  {
+    _dio_error = ERR_HARDWARE;
+    if (part)
+	    free(part);
+    return EFAULT;
+  }
+
+  /*
+   * Calculate the geometry
+   */
+  part->cyls  = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
+  part->heads = sec[3] + 1;
+  part->sects = sec[0] & 0x3F;
+
+  /*
+   * Now that we know all we need, let's look for the partition
+   */
+  _dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
+
+  if(!HW_OK())
+  {
+    _dio_error = ERR_HARDWARE;
+    if (part)
+	    free(part);
+    return EFAULT;
+  }
+
+  pent = (PTABLE_ENTRY*)&sec[0x1BE];
+  pent = scan_partition_table(pent, part->phys, &part->pno);
+
+  if(!pent)
+  {
+    _dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
+                 part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
+    if (part)
+	    free(part);
+    return ENODEV;
+  }
+
+  /*
+   * Calculate the remaining figures
+   */
+  {
+    unsigned long    fsec, fhead, fcyl;
+
+    fsec = (unsigned long)(pent->start_sec & 0x3F);
+    fhead = (unsigned long)pent->start_head;
+    fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
+    part->start = fsec + fhead * part->sects + fcyl *
+                  (part->heads * part->sects) - 1;
+    part->len = pent->size;
+  }
+
+  /*
+   * Add the partition to the table
+   */
+  newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
+  if (!newparts) {
+	  free(part);
+	  return ENOMEM;
+  }
+  partitions = newparts;
+  partitions[npart++] = active = part;
+
+  /*
+   * Now alloc all libe2fs structures
+   */
+  *channel = alloc_io_channel(active);
+  if (!*channel)
+	  return ENOMEM;
+
+  return 0;
+}
+
+static errcode_t dos_close(io_channel channel)
+{
+	if (channel->name)
+		free(channel->name);
+	if (channel)
+		free(channel);
+
+	return 0;
+}
+
+static errcode_t dos_set_blksize(io_channel channel, int blksize)
+{
+  channel->block_size = blksize;
+
+  return 0;
+}
+
+static errcode_t dos_read_blk(io_channel channel, unsigned long block,
+                                             int count, void *buf)
+{
+  PARTITION     *part;
+  size_t        size;
+  ext2_loff_t   loc;
+  CHS           chs;
+
+  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+  part = (PARTITION*)channel->private_data;
+
+  size = (size_t)((count < 0) ? -count : count * channel->block_size);
+  loc = (ext2_loff_t) block * channel->block_size;
+
+  lba2chs(loc, &chs, part);
+  /*
+   * Potential bug here:
+   *   If DJGPP is used then reads of >18 sectors will fail!
+   *   Have to rewrite biosdisk.
+   */
+  _dio_hw_error = biosdisk(DISK_READ,
+                           part->phys,
+                           chs.head,
+                           chs.cyl,
+                           chs.sector,
+                           size < 512 ? 1 : size/512,
+                           buf);
+
+  if(!HW_OK())
+  {
+    _dio_error = ERR_HARDWARE;
+    return EFAULT;
+  }
+
+  return 0;
+}
+
+static errcode_t dos_write_blk(io_channel channel, unsigned long block,
+                               int count, const void *buf)
+{
+  PARTITION     *part;
+  size_t        size;
+  ext2_loff_t   loc;
+  CHS           chs;
+
+  EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+  part = (PARTITION*)channel->private_data;
+
+  if(count == 1)
+    size = (size_t)channel->block_size;
+  else
+  {
+    if (count < 0)
+      size = (size_t)-count;
+    else
+      size = (size_t)(count * channel->block_size);
+  }
+
+  loc = (ext2_loff_t)block * channel->block_size;
+  lba2chs(loc, &chs, part);
+  _dio_hw_error = biosdisk(DISK_WRITE,
+                           part->phys,
+                           chs.head,
+                           chs.cyl,
+                           chs.sector,
+                           size < 512 ? 1 : size/512,
+                           (void*)buf);
+
+  if(!HW_OK())
+  {
+    _dio_error = ERR_HARDWARE;
+    return EFAULT;
+  }
+
+  return 0;
+}
+
+#ifdef __TURBOC__
+#pragma argsused
+#endif
+static errcode_t dos_flush(io_channel channel)
+{
+  /*
+   * No buffers, no flush...
+   */
+  return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/dosio.h silo-1.4.11/libext2fs/dosio.h
--- silo-1.4.11.orig/libext2fs/dosio.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dosio.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,153 @@
+/*
+ * v1.0
+ *
+ * Disk I/O include file for the ext2fs/DOS library.
+ *
+ * Copyright (c) 1997 Mark Habersack
+ * This file may be distributed under the terms of the GNU Public License.
+ *
+ */
+#ifndef __diskio_h
+#define __diskio_h
+#ifdef __TURBOC__
+#ifndef __LARGE__
+# error "ext2fs/DOS library requires LARGE model!"
+#endif
+#endif
+
+#ifdef __TURBOC__
+#include "msdos.h"
+#endif
+
+/*
+ * A helper structure used in LBA => CHS conversion
+ */
+typedef struct
+{
+  unsigned short       cyl;     /* Cylinder (or track) */
+  unsigned short       head;
+  unsigned short       sector;
+  unsigned short       offset;  /* Offset of byte within the sector */
+} CHS;
+
+/*
+ * All partition data we need is here
+ */
+typedef struct
+{
+  char                 *dev;  /* _Linux_ device name (like "/dev/hda1") */
+  unsigned char        phys;  /* Physical DOS drive number */
+  unsigned long        start; /* LBA address of partition start */
+  unsigned long        len;   /* length of partition in sectors */
+  unsigned char        pno;   /* Partition number (read from *dev) */
+
+  /* This partition's drive geometry */
+  unsigned short       cyls;
+  unsigned short       heads;
+  unsigned short       sects;
+} PARTITION;
+
+/*
+ * PC partition table entry format
+ */
+#ifdef __DJGPP__
+#pragma pack(1)
+#endif
+typedef struct
+{
+  unsigned char        active;
+  unsigned char        start_head;
+  unsigned char        start_sec;
+  unsigned char        start_cyl;
+  unsigned char        type;
+  unsigned char        end_head;
+  unsigned char        end_sec;
+  unsigned char        end_cyl;
+  unsigned long        first_sec_rel;
+  unsigned long        size;
+} PTABLE_ENTRY;
+#ifdef __DJGPP__
+#pragma pack()
+#endif
+
+/*
+ * INT 0x13 operation codes
+ */
+#define DISK_READ          0x02
+#define DISK_WRITE         0x03
+#define DISK_GET_GEOMETRY  0x08
+#define DISK_READY         0x10
+
+/*
+ * Errors to put in _dio_error
+ */
+#define ERR_BADDEV         0x00000001L
+#define ERR_HARDWARE       0x00000002L
+#define ERR_NOTSUPP        0x00000003L
+#define ERR_NOTEXT2FS      0x00000004L
+#define ERR_EMPTYPART      0x00000005L
+#define ERR_LINUXSWAP      0x00000006L
+
+/*
+ * Functions in diskio.c
+ */
+
+/*
+ * Variable contains last module's error
+ */
+extern unsigned long        _dio_error;
+
+/*
+ * This one contains last hardware error (if _dio_error == ERR_HARDWARE)
+ */
+extern unsigned long        _dio_hw_error;
+
+/*
+ * Macros to check for disk hardware errors
+ */
+#define HW_OK()             ((unsigned char)_dio_hw_error == 0x00)
+#define HW_BAD_CMD()        ((unsigned char)_dio_hw_error == 0x01)
+#define HW_NO_ADDR_MARK()   ((unsigned char)_dio_hw_error == 0x02)
+#define HW_WRITE_PROT()     ((unsigned char)_dio_hw_error == 0x03)
+#define HW_NO_SECTOR()      ((unsigned char)_dio_hw_error == 0x04)
+#define HW_RESET_FAIL()     ((unsigned char)_dio_hw_error == 0x05)
+#define HW_DISK_CHANGED()   ((unsigned char)_dio_hw_error == 0x06)
+#define HW_DRIVE_FAIL()     ((unsigned char)_dio_hw_error == 0x07)
+#define HW_DMA_OVERRUN()    ((unsigned char)_dio_hw_error == 0x08)
+#define HW_DMA_BOUNDARY()   ((unsigned char)_dio_hw_error == 0x09)
+#define HW_BAD_SECTOR()     ((unsigned char)_dio_hw_error == 0x0A)
+#define HW_BAD_TRACK()      ((unsigned char)_dio_hw_error == 0x0B)
+#define HW_UNSUPP_TRACK()   ((unsigned char)_dio_hw_error == 0x0C)
+#define HW_BAD_CRC_ECC()    ((unsigned char)_dio_hw_error == 0x10)
+#define HW_CRC_ECC_CORR()   ((unsigned char)_dio_hw_error == 0x11)
+#define HW_CONTR_FAIL()     ((unsigned char)_dio_hw_error == 0x20)
+#define HW_SEEK_FAIL()      ((unsigned char)_dio_hw_error == 0x40)
+#define HW_ATTACH_FAIL()    ((unsigned char)_dio_hw_error == 0x80)
+#define HW_DRIVE_NREADY()   ((unsigned char)_dio_hw_error == 0xAA)
+#define HW_UNDEF_ERROR()    ((unsigned char)_dio_hw_error == 0xBB)
+#define HW_WRITE_FAULT()    ((unsigned char)_dio_hw_error == 0xCC)
+#define HW_STATUS_ERROR()   ((unsigned char)_dio_hw_error == 0xE0)
+#define HW_SENSE_FAIL()     ((unsigned char)_dio_hw_error == 0xFF)
+
+
+/*
+ * Open the specified partition.
+ * String 'dev' must have a format:
+ *
+ *  /dev/{sd|hd|fd}[X]
+ *
+ * where,
+ *
+ *  only one of the option in curly braces can be used and X is an optional
+ *  partition number for the given device. If X is not specified, function
+ *  scans the drive's partition table in search for the first Linux ext2fs
+ *  partition (signature 0x83). Along the way it dives into every extended
+ *  partition encountered.
+ *  Scan ends if either (a) there are no more used partition entries, or
+ *  (b) there is no Xth partition.
+ *
+ * Routine returns 0 on success and !=0 otherwise.
+ */
+int open_partition(char *dev);
+
+#endif /* __diskio_h */
diff -Naur silo-1.4.11.orig/libext2fs/dupfs.c silo-1.4.11/libext2fs/dupfs.c
--- silo-1.4.11.orig/libext2fs/dupfs.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/dupfs.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,96 @@
+/*
+ * dupfs.c --- duplicate a ext2 filesystem handle
+ * 
+ * Copyright (C) 1997, 1998, 2001, 2003, 2005 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <time.h>
+#include <string.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+
+	EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+	
+	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+	if (retval)
+		return retval;
+
+	*fs = *src;
+	fs->device_name = 0;
+	fs->super = 0;
+	fs->orig_super = 0;
+	fs->group_desc = 0;
+	fs->inode_map = 0;
+	fs->block_map = 0;
+	fs->badblocks = 0;
+	fs->dblist = 0;
+
+	io_channel_bumpcount(fs->io);
+	if (fs->icache)
+		fs->icache->refcount++;
+
+	retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
+	if (retval)
+		goto errout;
+	strcpy(fs->device_name, src->device_name);
+
+	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
+	if (retval)
+		goto errout;
+	memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
+
+	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
+	if (retval)
+		goto errout;
+	memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
+
+	retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
+				&fs->group_desc);
+	if (retval)
+		goto errout;
+	memcpy(fs->group_desc, src->group_desc,
+	       (size_t) fs->desc_blocks * fs->blocksize);
+
+	if (src->inode_map) {
+		retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
+		if (retval)
+			goto errout;
+	}
+	if (src->block_map) {
+		retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
+		if (retval)
+			goto errout;
+	}
+	if (src->badblocks) {
+		retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
+		if (retval)
+			goto errout;
+	}
+	if (src->dblist) {
+		retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
+		if (retval)
+			goto errout;
+	}
+	*dest = fs;
+	return 0;
+errout:
+	ext2fs_free(fs);
+	return retval;
+	
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/e2image.h silo-1.4.11/libext2fs/e2image.h
--- silo-1.4.11.orig/libext2fs/e2image.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/e2image.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,51 @@
+/*
+ * e2image.h --- header file describing the ext2 image format
+ * 
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * Note: this uses the POSIX IO interfaces, unlike most of the other
+ * functions in this library.  So sue me.  
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+struct ext2_image_hdr {
+	__u32	magic_number;	/* This must be EXT2_ET_MAGIC_E2IMAGE */
+	char	magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */
+	char	fs_hostname[64];/* Hostname of machine of image */
+	char	fs_netaddr[32];	/* Network address */
+	__u32	fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */
+	__u32	fs_device;	/* Device number of image */
+	char	fs_device_name[64]; /* Device name */
+	char	fs_uuid[16];	/* UUID of filesystem */
+	__u32	fs_blocksize;	/* Block size of the filesystem */
+	__u32	fs_reserved[8];
+	
+	__u32	image_device;	/* Device number of image file */
+	__u32	image_inode;	/* Inode number of image file */
+	__u32	image_time;	/* Time of image creation */
+	__u32	image_reserved[8];
+
+	__u32	offset_super;	/* Byte offset of the sb and descriptors */
+	__u32	offset_inode;	/* Byte offset of the inode table  */
+	__u32	offset_inodemap; /* Byte offset of the inode bitmaps */
+	__u32	offset_blockmap; /* Byte offset of the inode bitmaps */
+	__u32	offset_reserved[8];
+};
+
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
+	
diff -Naur silo-1.4.11.orig/libext2fs/expanddir.c silo-1.4.11/libext2fs/expanddir.c
--- silo-1.4.11.orig/libext2fs/expanddir.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/expanddir.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,126 @@
+/*
+ * expand.c --- expand an ext2fs directory
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999  Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct expand_dir_struct {
+	int		done;
+	int		newblocks;
+	errcode_t	err;
+};
+
+static int expand_dir_proc(ext2_filsys	fs,
+			   blk_t	*blocknr,
+			   e2_blkcnt_t	blockcnt,
+			   blk_t	ref_block EXT2FS_ATTR((unused)),
+			   int		ref_offset EXT2FS_ATTR((unused)),
+			   void		*priv_data)
+{
+	struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
+	blk_t	new_blk;
+	static blk_t	last_blk = 0;
+	char		*block;
+	errcode_t	retval;
+	
+	if (*blocknr) {
+		last_blk = *blocknr;
+		return 0;
+	}
+	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
+	if (retval) {
+		es->err = retval;
+		return BLOCK_ABORT;
+	}
+	if (blockcnt > 0) {
+		retval = ext2fs_new_dir_block(fs, 0, 0, &block);
+		if (retval) {
+			es->err = retval;
+			return BLOCK_ABORT;
+		}
+		es->done = 1;
+		retval = ext2fs_write_dir_block(fs, new_blk, block);
+	} else {
+		retval = ext2fs_get_mem(fs->blocksize, &block);
+		if (retval) {
+			es->err = retval;
+			return BLOCK_ABORT;
+		}
+		memset(block, 0, fs->blocksize);
+		retval = io_channel_write_blk(fs->io, new_blk, 1, block);
+	}	
+	if (retval) {
+		es->err = retval;
+		return BLOCK_ABORT;
+	}
+	ext2fs_free_mem(&block);
+	*blocknr = new_blk;
+	ext2fs_block_alloc_stats(fs, new_blk, +1);
+	es->newblocks++;
+
+	if (es->done)
+		return (BLOCK_CHANGED | BLOCK_ABORT);
+	else
+		return BLOCK_CHANGED;
+}
+
+errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
+{
+	errcode_t	retval;
+	struct expand_dir_struct es;
+	struct ext2_inode	inode;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	if (!fs->block_map)
+		return EXT2_ET_NO_BLOCK_BITMAP;
+
+	retval = ext2fs_check_directory(fs, dir);
+	if (retval)
+		return retval;
+	
+	es.done = 0;
+	es.err = 0;
+	es.newblocks = 0;
+	
+	retval = ext2fs_block_iterate2(fs, dir, BLOCK_FLAG_APPEND,
+				       0, expand_dir_proc, &es);
+
+	if (es.err)
+		return es.err;
+	if (!es.done)
+		return EXT2_ET_EXPAND_DIR_ERR;
+
+	/*
+	 * Update the size and block count fields in the inode.
+	 */
+	retval = ext2fs_read_inode(fs, dir, &inode);
+	if (retval)
+		return retval;
+	
+	inode.i_size += fs->blocksize;
+	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+
+	retval = ext2fs_write_inode(fs, dir, &inode);
+	if (retval)
+		return retval;
+
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/ext2_err.c silo-1.4.11/libext2fs/ext2_err.c
--- silo-1.4.11.orig/libext2fs/ext2_err.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2_err.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,148 @@
+/*
+ * ext2_err.c:
+ * This file is automatically generated; please do not edit it.
+ */
+
+#include <stdlib.h>
+
+static const char * const text[] = {
+		"EXT2FS Library version 1.38",
+		"Wrong magic number for ext2_filsys structure",
+		"Wrong magic number for badblocks_list structure",
+		"Wrong magic number for badblocks_iterate structure",
+		"Wrong magic number for inode_scan structure",
+		"Wrong magic number for io_channel structure",
+		"Wrong magic number for unix io_channel structure",
+		"Wrong magic number for io_manager structure",
+		"Wrong magic number for block_bitmap structure",
+		"Wrong magic number for inode_bitmap structure",
+		"Wrong magic number for generic_bitmap structure",
+		"Wrong magic number for test io_channel structure",
+		"Wrong magic number for directory block list structure",
+		"Wrong magic number for icount structure",
+		"Wrong magic number for Powerquest io_channel structure",
+		"Wrong magic number for ext2 file structure",
+		"Wrong magic number for Ext2 Image Header",
+		"Wrong magic number for inode io_channel structure",
+		"Wrong magic number --- RESERVED_9",
+		"Bad magic number in super-block",
+		"Filesystem revision too high",
+		"Attempt to write to filesystem opened read-only",
+		"Can't read group descriptors",
+		"Can't write group descriptors",
+		"Corrupt group descriptor: bad block for block bitmap",
+		"Corrupt group descriptor: bad block for inode bitmap",
+		"Corrupt group descriptor: bad block for inode table",
+		"Can't write an inode bitmap",
+		"Can't read an inode bitmap",
+		"Can't write an block bitmap",
+		"Can't read an block bitmap",
+		"Can't write an inode table",
+		"Can't read an inode table",
+		"Can't read next inode",
+		"Filesystem has unexpected block size",
+		"EXT2 directory corrupted",
+		"Attempt to read block from filesystem resulted in short read",
+		"Attempt to write block from filesystem resulted in short write",
+		"No free space in the directory",
+		"Inode bitmap not loaded",
+		"Block bitmap not loaded",
+		"Illegal inode number",
+		"Illegal block number",
+		"Internal error in ext2fs_expand_dir",
+		"Not enough space to build proposed filesystem",
+		"Illegal block number passed to ext2fs_mark_block_bitmap",
+		"Illegal block number passed to ext2fs_unmark_block_bitmap",
+		"Illegal block number passed to ext2fs_test_block_bitmap",
+		"Illegal inode number passed to ext2fs_mark_inode_bitmap",
+		"Illegal inode number passed to ext2fs_unmark_inode_bitmap",
+		"Illegal inode number passed to ext2fs_test_inode_bitmap",
+		"Attempt to fudge end of block bitmap past the real end",
+		"Attempt to fudge end of inode bitmap past the real end",
+		"Illegal indirect block found" ,
+		"Illegal doubly indirect block found" ,
+		"Illegal triply indirect block found" ,
+		"Block bitmaps are not the same",
+		"Inode bitmaps are not the same",
+		"Illegal or malformed device name",
+		"A block group is missing an inode table",
+		"The ext2 superblock is corrupt",
+		"Illegal generic bit number passed to ext2fs_mark_generic_bitmap",
+		"Illegal generic bit number passed to ext2fs_unmark_generic_bitmap",
+		"Illegal generic bit number passed to ext2fs_test_generic_bitmap",
+		"Too many symbolic links encountered.",
+		"The callback function will not handle this case",
+		"The inode is from a bad block in the inode table",
+		"Filesystem has unsupported feature(s)",
+		"Filesystem has unsupported read-only feature(s)",
+		"IO Channel failed to seek on read or write",
+		"Memory allocation failed",
+		"Invalid argument passed to ext2 library",
+		"Could not allocate block in ext2 filesystem",
+		"Could not allocate inode in ext2 filesystem",
+		"Ext2 inode is not a directory",
+		"Too many references in table",
+		"File not found by ext2_lookup",
+		"File open read-only",
+		"Ext2 directory block not found",
+		"Ext2 directory already exists",
+		"Unimplemented ext2 library function",
+		"User cancel requested",
+		"Ext2 file too big",
+		"Supplied journal device not a block device",
+		"Journal superblock not found",
+		"Journal must be at least 1024 blocks",
+		"Unsupported journal version",
+		"Error loading external journal",
+		"Journal not found",
+		"Directory hash unsupported",
+		"Illegal extended attribute block number",
+		"Cannot create filesystem with requested number of inodes",
+		"E2image snapshot not in use",
+		"Too many reserved group descriptor blocks",
+		"Resize inode is corrupt",
+		"Missing indirect block not present",
+    0
+};
+
+struct error_table {
+    char const * const * msgs;
+    long base;
+    int n_msgs;
+};
+struct et_list {
+    struct et_list *next;
+    const struct error_table * table;
+};
+extern struct et_list *_et_list;
+
+const struct error_table et_ext2_error_table = { text, 2133571328L, 96 };
+
+static struct et_list link = { 0, 0 };
+
+void initialize_ext2_error_table_r(struct et_list **list);
+void initialize_ext2_error_table(void);
+
+void initialize_ext2_error_table(void) {
+    initialize_ext2_error_table_r(&_et_list);
+}
+
+/* For Heimdal compatibility */
+void initialize_ext2_error_table_r(struct et_list **list)
+{
+    struct et_list *et, **end;
+
+    for (end = list, et = *list; et; end = &et->next, et = et->next)
+        if (et->table->msgs == text)
+            return;
+    et = malloc(sizeof(struct et_list));
+    if (et == 0) {
+        if (!link.table)
+            et = &link;
+        else
+            return;
+    }
+    et->table = &et_ext2_error_table;
+    et->next = 0;
+    *end = et;
+}
diff -Naur silo-1.4.11.orig/libext2fs/ext2_ext_attr.h silo-1.4.11/libext2fs/ext2_ext_attr.h
--- silo-1.4.11.orig/libext2fs/ext2_ext_attr.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2_ext_attr.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,69 @@
+/*
+  File: linux/ext2_ext_attr.h
+
+  On-disk format of extended attributes for the ext2 filesystem.
+
+  (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+*/
+
+/* Magic value in attribute blocks */
+#define EXT2_EXT_ATTR_MAGIC_v1		0xEA010000
+#define EXT2_EXT_ATTR_MAGIC		0xEA020000
+
+/* Maximum number of references to one attribute block */
+#define EXT2_EXT_ATTR_REFCOUNT_MAX	1024
+
+struct ext2_ext_attr_header {
+	__u32	h_magic;	/* magic number for identification */
+	__u32	h_refcount;	/* reference count */
+	__u32	h_blocks;	/* number of disk blocks used */
+	__u32	h_hash;		/* hash value of all attributes */
+	__u32	h_reserved[4];	/* zero right now */
+};
+
+struct ext2_ext_attr_entry {
+	__u8	e_name_len;	/* length of name */
+	__u8	e_name_index;	/* attribute name index */
+	__u16	e_value_offs;	/* offset in disk block of value */
+	__u32	e_value_block;	/* disk block attribute is stored on (n/i) */
+	__u32	e_value_size;	/* size of attribute value */
+	__u32	e_hash;		/* hash value of name and value */
+#if 0
+	char	e_name[0];	/* attribute name */
+#endif
+};
+
+#define EXT2_EXT_ATTR_PAD_BITS		2
+#define EXT2_EXT_ATTR_PAD		(1<<EXT2_EXT_ATTR_PAD_BITS)
+#define EXT2_EXT_ATTR_ROUND		(EXT2_EXT_ATTR_PAD-1)
+#define EXT2_EXT_ATTR_LEN(name_len) \
+	(((name_len) + EXT2_EXT_ATTR_ROUND + \
+	sizeof(struct ext2_ext_attr_entry)) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_EXT_ATTR_NEXT(entry) \
+	( (struct ext2_ext_attr_entry *)( \
+	  (char *)(entry) + EXT2_EXT_ATTR_LEN((entry)->e_name_len)) )
+#define EXT2_EXT_ATTR_SIZE(size) \
+	(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL)
+#define EXT2_EXT_ATTR_NAME(entry) \
+	(((char *) (entry)) + sizeof(struct ext2_ext_attr_entry))
+#define EXT2_XATTR_LEN(name_len) \
+	(((name_len) + EXT2_EXT_ATTR_ROUND + \
+	sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND)
+#define EXT2_XATTR_SIZE(size) \
+	(((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND)
+
+#ifdef __KERNEL__
+# ifdef CONFIG_EXT2_FS_EXT_ATTR
+extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int);
+extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int);
+extern void ext2_ext_attr_free_inode(struct inode *inode);
+extern void ext2_ext_attr_put_super(struct super_block *sb);
+extern int ext2_ext_attr_init(void);
+extern void ext2_ext_attr_done(void);
+# else
+#  define ext2_get_ext_attr NULL
+#  define ext2_set_ext_attr NULL
+# endif
+#endif  /* __KERNEL__ */
+
diff -Naur silo-1.4.11.orig/libext2fs/ext2_fs.h silo-1.4.11/libext2fs/ext2_fs.h
--- silo-1.4.11.orig/libext2fs/ext2_fs.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2_fs.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,644 @@
+/*
+ *  linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT2_FS_H
+#define _LINUX_EXT2_FS_H
+
+#include <ext2fs/ext2_types.h>		/* Changed from linux/types.h */
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS	8
+
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE		"95/08/09"
+#define EXT2FS_VERSION		"0.5b"
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO		 1	/* Bad blocks inode */
+#define EXT2_ROOT_INO		 2	/* Root inode */
+#define EXT2_ACL_IDX_INO	 3	/* ACL inode */
+#define EXT2_ACL_DATA_INO	 4	/* ACL inode */
+#define EXT2_BOOT_LOADER_INO	 5	/* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO	 6	/* Undelete directory inode */
+#define EXT2_RESIZE_INO		 7	/* Reserved group descriptors inode */
+#define EXT2_JOURNAL_INO	 8	/* Journal inode */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO	11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC	0xEF53
+
+#ifdef __KERNEL__
+#define EXT2_SB(sb)	(&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block.  This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb)	(sb)
+#endif
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX		32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_LOG_SIZE		10	/* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE		16	/* 65536 */
+#define EXT2_MIN_BLOCK_SIZE	(1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define EXT2_MAX_BLOCK_SIZE	(1 << EXT2_MAX_BLOCK_LOG_SIZE)
+#ifdef __KERNEL__
+#define EXT2_BLOCK_SIZE(s)	((s)->s_blocksize)
+#define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
+#define EXT2_ADDR_PER_BLOCK_BITS(s)	(EXT2_SB(s)->addr_per_block_bits)
+#define EXT2_INODE_SIZE(s)	(EXT2_SB(s)->s_inode_size)
+#define EXT2_FIRST_INO(s)	(EXT2_SB(s)->s_first_ino)
+#else
+#define EXT2_BLOCK_SIZE(s)	(EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+				 EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
+#define EXT2_FIRST_INO(s)	(((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+				 EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
+#endif
+#define EXT2_ADDR_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / sizeof(__u32))
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT2_MIN_FRAG_SIZE		EXT2_MIN_BLOCK_SIZE
+#define EXT2_MAX_FRAG_SIZE		EXT2_MAX_BLOCK_SIZE
+#define EXT2_MIN_FRAG_LOG_SIZE		EXT2_MIN_BLOCK_LOG_SIZE
+#ifdef __KERNEL__
+# define EXT2_FRAG_SIZE(s)		(EXT2_SB(s)->s_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_SB(s)->s_frags_per_block)
+#else
+# define EXT2_FRAG_SIZE(s)		(EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT2_FRAGS_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
+#endif
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header	/* Header of Access Control Lists */
+{
+	__u32	aclh_size;
+	__u32	aclh_file_count;
+	__u32	aclh_acle_count;
+	__u32	aclh_first_acle;
+};
+
+struct ext2_acl_entry	/* Access Control List Entry */
+{
+	__u32	acle_size;
+	__u16	acle_perms;	/* Access permissions */
+	__u16	acle_type;	/* Type of entry */
+	__u16	acle_tag;	/* User or group identity */
+	__u16	acle_pad1;
+	__u32	acle_next;	/* Pointer on next entry for the */
+					/* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+	__u32	bg_block_bitmap;		/* Blocks bitmap block */
+	__u32	bg_inode_bitmap;		/* Inodes bitmap block */
+	__u32	bg_inode_table;		/* Inodes table block */
+	__u16	bg_free_blocks_count;	/* Free blocks count */
+	__u16	bg_free_inodes_count;	/* Free inodes count */
+	__u16	bg_used_dirs_count;	/* Directories count */
+	__u16	bg_pad;
+	__u32	bg_reserved[3];
+};
+
+/*
+ * Data structures used by the directory indexing feature
+ *
+ * Note: all of the multibyte integer fields are little endian.
+ */
+
+/*
+ * Note: dx_root_info is laid out so that if it should somehow get
+ * overlaid by a dirent the two low bits of the hash version will be
+ * zero.  Therefore, the hash version mod 4 should never be 0.
+ * Sincerely, the paranoia department.
+ */
+struct ext2_dx_root_info {
+	__u32 reserved_zero;
+	__u8 hash_version; /* 0 now, 1 at release */
+	__u8 info_length; /* 8 */
+	__u8 indirect_levels;
+	__u8 unused_flags;
+};
+
+#define EXT2_HASH_LEGACY	0
+#define EXT2_HASH_HALF_MD4	1
+#define EXT2_HASH_TEA		2
+
+#define EXT2_HASH_FLAG_INCOMPAT	0x1
+
+struct ext2_dx_entry {
+	__u32 hash;
+	__u32 block;
+};
+
+struct ext2_dx_countlimit {
+	__u16 limit;
+	__u16 count;
+};
+
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s)	(EXT2_SB(s)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(s)	(EXT2_SB(s)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(s)	(EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
+/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
+#define EXT2_MAX_BLOCKS_PER_GROUP(s)	((1 << 16) - 8)
+#define EXT2_MAX_INODES_PER_GROUP(s)	((1 << 16) - EXT2_INODES_PER_BLOCK(s))
+#ifdef __KERNEL__
+#define EXT2_DESC_PER_BLOCK(s)		(EXT2_SB(s)->s_desc_per_block)
+#define EXT2_DESC_PER_BLOCK_BITS(s)	(EXT2_SB(s)->s_desc_per_block_bits)
+#else
+#define EXT2_DESC_PER_BLOCK(s)		(EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS		12
+#define EXT2_IND_BLOCK			EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK			(EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK			(EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS			(EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL			0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL			0x00000002 /* Undelete */
+#define EXT2_COMPR_FL			0x00000004 /* Compress file */
+#define EXT2_SYNC_FL			0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL		0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL			0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL			0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL			0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL			0x00000100
+#define EXT2_COMPRBLK_FL		0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMPR_FL			0x00000400 /* Access raw compressed data */
+#define EXT2_ECOMPR_FL			0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL			0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL			0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL			0x00002000
+#define EXT3_JOURNAL_DATA_FL		0x00004000 /* file data should be journaled */
+#define EXT2_NOTAIL_FL			0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL 		0x00010000 /* Synchronous directory modifications */
+#define EXT2_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
+#define EXT3_EXTENTS_FL 		0x00080000 /* Inode uses extents */
+#define EXT2_RESERVED_FL		0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE		0x000080FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define EXT2_IOC_GETFLAGS		_IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS		_IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION		_IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION		_IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+	__u16	i_mode;		/* File mode */
+	__u16	i_uid;		/* Low 16 bits of Owner Uid */
+	__u32	i_size;		/* Size in bytes */
+	__u32	i_atime;	/* Access time */
+	__u32	i_ctime;	/* Creation time */
+	__u32	i_mtime;	/* Modification time */
+	__u32	i_dtime;	/* Deletion Time */
+	__u16	i_gid;		/* Low 16 bits of Group Id */
+	__u16	i_links_count;	/* Links count */
+	__u32	i_blocks;	/* Blocks count */
+	__u32	i_flags;	/* File flags */
+	union {
+		struct {
+			__u32  l_i_reserved1;
+		} linux1;
+		struct {
+			__u32  h_i_translator;
+		} hurd1;
+		struct {
+			__u32  m_i_reserved1;
+		} masix1;
+	} osd1;				/* OS dependent 1 */
+	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+	__u32	i_generation;	/* File version (for NFS) */
+	__u32	i_file_acl;	/* File ACL */
+	__u32	i_dir_acl;	/* Directory ACL */
+	__u32	i_faddr;	/* Fragment address */
+	union {
+		struct {
+			__u8	l_i_frag;	/* Fragment number */
+			__u8	l_i_fsize;	/* Fragment size */
+			__u16	i_pad1;
+			__u16	l_i_uid_high;	/* these 2 fields    */
+			__u16	l_i_gid_high;	/* were reserved2[0] */
+			__u32	l_i_reserved2;
+		} linux2;
+		struct {
+			__u8	h_i_frag;	/* Fragment number */
+			__u8	h_i_fsize;	/* Fragment size */
+			__u16	h_i_mode_high;
+			__u16	h_i_uid_high;
+			__u16	h_i_gid_high;
+			__u32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	/* Fragment number */
+			__u8	m_i_fsize;	/* Fragment size */
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				/* OS dependent 2 */
+};
+
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+	__u16	i_mode;		/* File mode */
+	__u16	i_uid;		/* Low 16 bits of Owner Uid */
+	__u32	i_size;		/* Size in bytes */
+	__u32	i_atime;	/* Access time */
+	__u32	i_ctime;	/* Creation time */
+	__u32	i_mtime;	/* Modification time */
+	__u32	i_dtime;	/* Deletion Time */
+	__u16	i_gid;		/* Low 16 bits of Group Id */
+	__u16	i_links_count;	/* Links count */
+	__u32	i_blocks;	/* Blocks count */
+	__u32	i_flags;	/* File flags */
+	union {
+		struct {
+			__u32  l_i_reserved1;
+		} linux1;
+		struct {
+			__u32  h_i_translator;
+		} hurd1;
+		struct {
+			__u32  m_i_reserved1;
+		} masix1;
+	} osd1;				/* OS dependent 1 */
+	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+	__u32	i_generation;	/* File version (for NFS) */
+	__u32	i_file_acl;	/* File ACL */
+	__u32	i_dir_acl;	/* Directory ACL */
+	__u32	i_faddr;	/* Fragment address */
+	union {
+		struct {
+			__u8	l_i_frag;	/* Fragment number */
+			__u8	l_i_fsize;	/* Fragment size */
+			__u16	i_pad1;
+			__u16	l_i_uid_high;	/* these 2 fields    */
+			__u16	l_i_gid_high;	/* were reserved2[0] */
+			__u32	l_i_reserved2;
+		} linux2;
+		struct {
+			__u8	h_i_frag;	/* Fragment number */
+			__u8	h_i_fsize;	/* Fragment size */
+			__u16	h_i_mode_high;
+			__u16	h_i_uid_high;
+			__u16	h_i_gid_high;
+			__u32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	/* Fragment number */
+			__u8	m_i_fsize;	/* Fragment size */
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				/* OS dependent 2 */
+	__u16	i_extra_isize;
+	__u16	i_pad1;
+};
+
+#define i_size_high	i_dir_acl
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1	osd1.linux1.l_i_reserved1
+#define i_frag		osd2.linux2.l_i_frag
+#define i_fsize		osd2.linux2.l_i_fsize
+#define i_uid_low	i_uid
+#define i_gid_low	i_gid
+#define i_uid_high	osd2.linux2.l_i_uid_high
+#define i_gid_high	osd2.linux2.l_i_gid_high
+#define i_reserved2	osd2.linux2.l_i_reserved2
+
+#else
+#if defined(__GNU__)
+
+#define i_translator	osd1.hurd1.h_i_translator
+#define i_frag		osd2.hurd2.h_i_frag;
+#define i_fsize		osd2.hurd2.h_i_fsize;
+#define i_uid_high	osd2.hurd2.h_i_uid_high
+#define i_gid_high	osd2.hurd2.h_i_gid_high
+#define i_author	osd2.hurd2.h_i_author
+
+#else
+#if defined(__masix__)
+
+#define i_reserved1	osd1.masix1.m_i_reserved1
+#define i_frag		osd2.masix2.m_i_frag
+#define i_fsize		osd2.masix2.m_i_fsize
+#define i_reserved2	osd2.masix2.m_i_reserved2
+
+#endif  /* __masix__ */
+#endif  /* __GNU__ */
+#endif	/* defined(__KERNEL__) || defined(__linux__) */
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS			0x0001	/* Unmounted cleanly */
+#define EXT2_ERROR_FS			0x0002	/* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK		0x0001	/* Do mount-time checks */
+#define EXT2_MOUNT_GRPID		0x0004	/* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG		0x0008	/* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT		0x0010	/* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32		0x0200  /* Disable 32-bit UIDs */
+
+#define clear_opt(o, opt)		o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt)			o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt)		(EXT2_SB(sb)->s_mount_opt & \
+					 EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL		0	/* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE		1	/* Continue execution */
+#define EXT2_ERRORS_RO			2	/* Remount fs read-only */
+#define EXT2_ERRORS_PANIC		3	/* Panic */
+#define EXT2_ERRORS_DEFAULT		EXT2_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+	__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_algorithm_usage_bitmap; /* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+	 */
+	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
+	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__u16	s_reserved_gdt_blocks;	/* Per group table for online growth */
+	/*
+	 * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
+	 */
+	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
+	__u32	s_journal_inum;		/* inode number of journal file */
+	__u32	s_journal_dev;		/* device number of journal file */
+	__u32	s_last_orphan;		/* start of list of inodes to delete */
+	__u32	s_hash_seed[4];		/* HTREE hash seed */
+	__u8	s_def_hash_version;	/* Default hash version to use */
+	__u8	s_jnl_backup_type; 	/* Default type of journal backup */
+	__u16	s_reserved_word_pad;
+	__u32	s_default_mount_opts;
+	__u32	s_first_meta_bg;	/* First metablock group */
+	__u32	s_mkfs_time;		/* When the filesystem was created */
+	__u32	s_jnl_blocks[17]; 	/* Backup of the journal inode */
+	__u32	s_reserved[172];	/* Padding to the end of the block */
+};
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX		0
+#define EXT2_OS_HURD		1
+#define EXT2_OS_MASIX		2
+#define EXT2_OS_FREEBSD		3
+#define EXT2_OS_LITES		4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV	0	/* The good old (original) format */
+#define EXT2_DYNAMIC_REV	1	/* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV	EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV	EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Journal inode backup types
+ */
+#define EXT3_JNL_BACKUP_BLOCKS	1
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)			\
+	( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC	0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES	0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR		0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INODE	0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX		0x0020
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR	0x0004 not used */
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION	0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008 /* Journal device */
+#define EXT2_FEATURE_INCOMPAT_META_BG		0x0010
+#define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040
+
+
+#define EXT2_FEATURE_COMPAT_SUPP	0
+#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE)
+#define EXT2_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID		0
+#define EXT2_DEF_RESGID		0
+
+/*
+ * Default mount options
+ */
+#define EXT2_DEFM_DEBUG		0x0001
+#define EXT2_DEFM_BSDGROUPS	0x0002
+#define EXT2_DEFM_XATTR_USER	0x0004
+#define EXT2_DEFM_ACL		0x0008
+#define EXT2_DEFM_UID16		0x0010
+#define EXT3_DEFM_JMODE		0x0060 
+#define EXT3_DEFM_JMODE_DATA	0x0020
+#define EXT3_DEFM_JMODE_ORDERED	0x0040
+#define EXT3_DEFM_JMODE_WBACK	0x0060
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+	__u32	inode;			/* Inode number */
+	__u16	rec_len;		/* Directory entry length */
+	__u16	name_len;		/* Name length */
+	char	name[EXT2_NAME_LEN];	/* File name */
+};
+
+/*
+ * The new version of the directory entry.  Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+	__u32	inode;			/* Inode number */
+	__u16	rec_len;		/* Directory entry length */
+	__u8	name_len;		/* Name length */
+	__u8	file_type;
+	char	name[EXT2_NAME_LEN];	/* File name */
+};
+
+/*
+ * Ext2 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN		0
+#define EXT2_FT_REG_FILE	1
+#define EXT2_FT_DIR		2
+#define EXT2_FT_CHRDEV		3
+#define EXT2_FT_BLKDEV		4
+#define EXT2_FT_FIFO		5
+#define EXT2_FT_SOCK		6
+#define EXT2_FT_SYMLINK		7
+
+#define EXT2_FT_MAX		8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD			4
+#define EXT2_DIR_ROUND			(EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT2_DIR_ROUND) & \
+					 ~EXT2_DIR_ROUND)
+
+#endif	/* _LINUX_EXT2_FS_H */
diff -Naur silo-1.4.11.orig/libext2fs/ext2_io.h silo-1.4.11/libext2fs/ext2_io.h
--- silo-1.4.11.orig/libext2fs/ext2_io.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2_io.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,108 @@
+/*
+ * io.h --- the I/O manager abstraction
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifndef _EXT2FS_EXT2_IO_H
+#define _EXT2FS_EXT2_IO_H
+
+/*
+ * ext2_loff_t is defined here since unix_io.c needs it.
+ */
+#if defined(__GNUC__) || defined(HAS_LONG_LONG)
+typedef long long	ext2_loff_t;
+#else
+typedef long		ext2_loff_t;
+#endif
+
+/* llseek.c */
+ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int);
+
+typedef struct struct_io_manager *io_manager;
+typedef struct struct_io_channel *io_channel;
+
+#define CHANNEL_FLAGS_WRITETHROUGH	0x01
+
+struct struct_io_channel {
+	errcode_t	magic;
+	io_manager	manager;
+	char		*name;
+	int		block_size;
+	errcode_t	(*read_error)(io_channel channel,
+				      unsigned long block,
+				      int count,
+				      void *data,
+				      size_t size,
+				      int actual_bytes_read,
+				      errcode_t	error);
+	errcode_t	(*write_error)(io_channel channel,
+				       unsigned long block,
+				       int count,
+				       const void *data,
+				       size_t size,
+				       int actual_bytes_written,
+				       errcode_t error);
+	int		refcount;
+	int		flags;
+	int		reserved[14];
+	void		*private_data;
+	void		*app_data;
+};
+
+struct struct_io_manager {
+	errcode_t magic;
+	const char *name;
+	errcode_t (*open)(const char *name, int flags, io_channel *channel);
+	errcode_t (*close)(io_channel channel);
+	errcode_t (*set_blksize)(io_channel channel, int blksize);
+	errcode_t (*read_blk)(io_channel channel, unsigned long block,
+			      int count, void *data);
+	errcode_t (*write_blk)(io_channel channel, unsigned long block,
+			       int count, const void *data);
+	errcode_t (*flush)(io_channel channel);
+	errcode_t (*write_byte)(io_channel channel, unsigned long offset,
+				int count, const void *data);
+	errcode_t (*set_option)(io_channel channel, const char *option, 
+				const char *arg);
+	int		reserved[14];
+};
+
+#define IO_FLAG_RW	1
+
+/*
+ * Convenience functions....
+ */
+#define io_channel_close(c) 		((c)->manager->close((c)))
+#define io_channel_set_blksize(c,s)	((c)->manager->set_blksize((c),s))
+#define io_channel_read_blk(c,b,n,d)	((c)->manager->read_blk((c),b,n,d))
+#define io_channel_write_blk(c,b,n,d)	((c)->manager->write_blk((c),b,n,d))
+#define io_channel_flush(c) 		((c)->manager->flush((c)))
+#define io_channel_bumpcount(c)		((c)->refcount++)
+	
+/* io_manager.c */
+extern errcode_t io_channel_set_options(io_channel channel, 
+					const char *options);
+extern errcode_t io_channel_write_byte(io_channel channel, 
+				       unsigned long offset,
+				       int count, const void *data);
+
+/* unix_io.c */
+extern io_manager unix_io_manager;
+
+/* test_io.c */
+extern io_manager test_io_manager, test_io_backing_manager;
+extern void (*test_io_cb_read_blk)
+	(unsigned long block, int count, errcode_t err);
+extern void (*test_io_cb_write_blk)
+	(unsigned long block, int count, errcode_t err);
+extern void (*test_io_cb_set_blksize)
+	(int blksize, errcode_t err);
+
+#endif /* _EXT2FS_EXT2_IO_H */
+	
diff -Naur silo-1.4.11.orig/libext2fs/ext2fs.h silo-1.4.11/libext2fs/ext2fs.h
--- silo-1.4.11.orig/libext2fs/ext2fs.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2fs.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,1140 @@
+/*
+ * ext2fs.h --- ext2fs
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifndef _EXT2FS_EXT2FS_H
+#define _EXT2FS_EXT2FS_H
+
+#ifdef __GNUC__
+#define EXT2FS_ATTR(x) __attribute__(x)
+#else
+#define EXT2FS_ATTR(x)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Non-GNU C compilers won't necessarily understand inline
+ */
+#if (!defined(__GNUC__) && !defined(__WATCOMC__))
+#define NO_INLINE_FUNCS
+#endif
+
+/*
+ * Build in support for byte-swapping filesystems if we the feature
+ * has been configured or if we're being built on a CPU architecture
+ * with a non-native byte order.
+ */
+#if defined(ENABLE_SWAPFS) || defined(WORDS_BIGENDIAN)
+#define EXT2FS_ENABLE_SWAPFS
+#endif
+
+/*
+ * Where the master copy of the superblock is located, and how big
+ * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because
+ * the size of the superblock structure is not necessarily trustworthy
+ * (some versions have the padding set up so that the superblock is
+ * 1032 bytes long).
+ */
+#define SUPERBLOCK_OFFSET	1024
+#define SUPERBLOCK_SIZE 	1024
+
+/*
+ * The last ext2fs revision level that this version of the library is
+ * able to support.
+ */
+#define EXT2_LIB_CURRENT_REV	EXT2_DYNAMIC_REV
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if EXT2_FLAT_INCLUDES
+#include "e2_types.h"
+#include "ext2_fs.h"
+#else
+#include <ext2fs/ext2_types.h>
+#include <ext2fs/ext2_fs.h>
+#endif /* EXT2_FLAT_INCLUDES */
+
+typedef __u32		ext2_ino_t;
+typedef __u32		blk_t;
+typedef __u32		dgrp_t;
+typedef __u32		ext2_off_t;
+typedef __s64		e2_blkcnt_t;
+typedef __u32		ext2_dirhash_t;
+
+#if EXT2_FLAT_INCLUDES
+#include "com_err.h"
+#include "ext2_io.h"
+#include "ext2_err.h"
+#else
+#include <et/com_err.h>
+#include <ext2fs/ext2_io.h>
+#include <ext2fs/ext2_err.h>
+#endif
+
+/*
+ * Portability help for Microsoft Visual C++
+ */
+#ifdef _MSC_VER
+#define EXT2_QSORT_TYPE int __cdecl
+#else
+#define EXT2_QSORT_TYPE int
+#endif
+
+typedef struct struct_ext2_filsys *ext2_filsys;
+
+struct ext2fs_struct_generic_bitmap {
+	errcode_t	magic;
+	ext2_filsys 	fs;
+	__u32		start, end;
+	__u32		real_end;
+	char	*	description;
+	char	*	bitmap;
+	errcode_t	base_error_code;
+	__u32		reserved[7];
+};
+
+#define EXT2FS_MARK_ERROR 	0
+#define EXT2FS_UNMARK_ERROR 	1
+#define EXT2FS_TEST_ERROR	2
+
+typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_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)
+#else
+#define EXT2_FIRST_INODE(s)	EXT2_FIRST_INO
+#define EXT2_INODE_SIZE(s)	sizeof(struct ext2_inode)
+#endif
+
+/*
+ * badblocks list definitions
+ */
+
+typedef struct ext2_struct_u32_list *ext2_badblocks_list;
+typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
+
+typedef struct ext2_struct_u32_list *ext2_u32_list;
+typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
+
+/* old */
+typedef struct ext2_struct_u32_list *badblocks_list;
+typedef struct ext2_struct_u32_iterate *badblocks_iterate;
+
+#define BADBLOCKS_FLAG_DIRTY	1
+
+/*
+ * ext2_dblist structure and abstractions (see dblist.c)
+ */
+struct ext2_db_entry {
+	ext2_ino_t	ino;
+	blk_t	blk;
+	int	blockcnt;
+};
+
+typedef struct ext2_struct_dblist *ext2_dblist;
+
+#define DBLIST_ABORT	1
+
+/*
+ * ext2_fileio definitions
+ */
+
+#define EXT2_FILE_WRITE		0x0001
+#define EXT2_FILE_CREATE	0x0002
+
+#define EXT2_FILE_MASK		0x00FF
+
+#define EXT2_FILE_BUF_DIRTY	0x4000
+#define EXT2_FILE_BUF_VALID	0x2000
+
+typedef struct ext2_file *ext2_file_t;
+
+#define EXT2_SEEK_SET	0
+#define EXT2_SEEK_CUR	1
+#define EXT2_SEEK_END	2
+
+/*
+ * Flags for the ext2_filsys structure and for ext2fs_open()
+ */
+#define EXT2_FLAG_RW			0x01
+#define EXT2_FLAG_CHANGED		0x02
+#define EXT2_FLAG_DIRTY			0x04
+#define EXT2_FLAG_VALID			0x08
+#define EXT2_FLAG_IB_DIRTY		0x10
+#define EXT2_FLAG_BB_DIRTY		0x20
+#define EXT2_FLAG_SWAP_BYTES		0x40
+#define EXT2_FLAG_SWAP_BYTES_READ	0x80
+#define EXT2_FLAG_SWAP_BYTES_WRITE	0x100
+#define EXT2_FLAG_MASTER_SB_ONLY	0x200
+#define EXT2_FLAG_FORCE			0x400
+#define EXT2_FLAG_SUPER_ONLY		0x800
+#define EXT2_FLAG_JOURNAL_DEV_OK	0x1000
+#define EXT2_FLAG_IMAGE_FILE		0x2000
+
+/*
+ * Special flag in the ext2 inode i_flag field that means that this is
+ * a new inode.  (So that ext2_write_inode() can clear extra fields.)
+ */
+#define EXT2_NEW_INODE_FL	0x80000000
+
+/*
+ * Flags for mkjournal
+ *
+ * EXT2_MKJOURNAL_V1_SUPER	Make a (deprecated) V1 journal superblock
+ */
+#define EXT2_MKJOURNAL_V1_SUPER	0x0000001
+
+struct struct_ext2_filsys {
+	errcode_t			magic;
+	io_channel			io;
+	int				flags;
+	char *				device_name;
+	struct ext2_super_block	* 	super;
+	unsigned int			blocksize;
+	int				fragsize;
+	dgrp_t				group_desc_count;
+	unsigned long			desc_blocks;
+	struct ext2_group_desc *	group_desc;
+	int				inode_blocks_per_group;
+	ext2fs_inode_bitmap		inode_map;
+	ext2fs_block_bitmap		block_map;
+	errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
+	errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino);
+	errcode_t (*write_bitmaps)(ext2_filsys fs);
+	errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino,
+				struct ext2_inode *inode);
+	errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
+				struct ext2_inode *inode);
+	ext2_badblocks_list		badblocks;
+	ext2_dblist			dblist;
+	__u32				stride;	/* for mke2fs */
+	struct ext2_super_block *	orig_super;
+	struct ext2_image_hdr *		image_header;
+	__u32				umask;
+	/*
+	 * Reserved for future expansion
+	 */
+	__u32				reserved[8];
+
+	/*
+	 * Reserved for the use of the calling application.
+	 */
+	void *				priv_data;
+
+	/*
+	 * Inode cache
+	 */
+	struct ext2_inode_cache		*icache;
+	io_channel			image_io;
+};
+
+#if EXT2_FLAT_INCLUDES
+#include "e2_bitops.h"
+#else
+#include <ext2fs/bitops.h>
+#endif
+
+/*
+ * Return flags for the block iterator functions
+ */
+#define BLOCK_CHANGED	1
+#define BLOCK_ABORT	2
+#define BLOCK_ERROR	4
+
+/*
+ * Block interate flags
+ *
+ * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator
+ * function should be called on blocks where the block number is zero.
+ * This is used by ext2fs_expand_dir() to be able to add a new block
+ * to an inode.  It can also be used for programs that want to be able
+ * to deal with files that contain "holes".
+ * 
+ * BLOCK_FLAG_TRAVERSE indicates that the iterator function for the
+ * indirect, doubly indirect, etc. blocks should be called after all
+ * 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.
+ *
+ * BLOCK_FLAG_NO_LARGE is for internal use only.  It informs
+ * ext2fs_block_iterate2 that large files won't be accepted.
+ */
+#define BLOCK_FLAG_APPEND	1
+#define BLOCK_FLAG_HOLE		1
+#define BLOCK_FLAG_DEPTH_TRAVERSE	2
+#define BLOCK_FLAG_DATA_ONLY	4
+
+#define BLOCK_FLAG_NO_LARGE	0x1000
+
+/*
+ * 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)
+
+#if 0
+/*
+ * Flags for ext2fs_move_blocks
+ */
+#define EXT2_BMOVE_GET_DBLIST	0x0001	
+#define EXT2_BMOVE_DEBUG	0x0002
+#endif
+
+/*
+ * Flags for directory block reading and writing functions
+ */
+#define EXT2_DIRBLOCK_V2_STRUCT	0x0001
+
+/*
+ * Return flags for the directory iterator functions
+ */
+#define DIRENT_CHANGED	1
+#define DIRENT_ABORT	2
+#define DIRENT_ERROR	3
+
+/*
+ * Directory iterator flags
+ */
+
+#define DIRENT_FLAG_INCLUDE_EMPTY	1
+#define DIRENT_FLAG_INCLUDE_REMOVED	2
+
+#define DIRENT_DOT_FILE		1
+#define DIRENT_DOT_DOT_FILE	2
+#define DIRENT_OTHER_FILE	3
+#define DIRENT_DELETED_FILE	4
+
+/*
+ * Inode scan definitions
+ */
+typedef struct ext2_struct_inode_scan *ext2_inode_scan;
+
+/*
+ * ext2fs_scan flags
+ */
+#define EXT2_SF_CHK_BADBLOCKS	0x0001
+#define EXT2_SF_BAD_INODE_BLK	0x0002
+#define EXT2_SF_BAD_EXTRA_BYTES	0x0004
+#define EXT2_SF_SKIP_MISSING_ITABLE	0x0008
+
+/*
+ * ext2fs_check_if_mounted flags
+ */
+#define EXT2_MF_MOUNTED		1
+#define EXT2_MF_ISROOT		2
+#define EXT2_MF_READONLY	4
+#define EXT2_MF_SWAP		8
+#define EXT2_MF_BUSY		16
+
+/*
+ * Ext2/linux mode flags.  We define them here so that we don't need
+ * to depend on the OS's sys/stat.h, since we may be compiling on a
+ * non-Linux system.
+ */
+#define LINUX_S_IFMT  00170000
+#define LINUX_S_IFSOCK 0140000
+#define LINUX_S_IFLNK	 0120000
+#define LINUX_S_IFREG  0100000
+#define LINUX_S_IFBLK  0060000
+#define LINUX_S_IFDIR  0040000
+#define LINUX_S_IFCHR  0020000
+#define LINUX_S_IFIFO  0010000
+#define LINUX_S_ISUID  0004000
+#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)
+#define LINUX_S_ISCHR(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
+#define LINUX_S_ISBLK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
+#define LINUX_S_ISFIFO(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
+#define LINUX_S_ISSOCK(m)	(((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
+
+/*
+ * ext2 size of an inode
+ */
+#define EXT2_I_SIZE(i)	((i)->i_size | ((__u64) (i)->i_size_high << 32))
+
+/*
+ * ext2_icount_t abstraction
+ */
+#define EXT2_ICOUNT_OPT_INCREMENT	0x01
+
+typedef struct ext2_icount *ext2_icount_t;
+
+/*
+ * Flags for ext2fs_bmap
+ */
+#define BMAP_ALLOC	0x0001
+#define BMAP_SET	0x0002
+
+/*
+ * Flags for imager.c functions
+ */
+#define IMAGER_FLAG_INODEMAP	1
+#define IMAGER_FLAG_SPARSEWRITE	2
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+
+/*
+ * For ext2 compression support
+ */
+#define EXT2FS_COMPRESSED_BLKADDR ((blk_t) 0xffffffff)
+#define HOLE_BLKADDR(_b) ((_b) == 0 || (_b) == EXT2FS_COMPRESSED_BLKADDR)
+
+/*
+ * Features supported by this version of the library
+ */
+#define EXT2_LIB_FEATURE_COMPAT_SUPP	(EXT2_FEATURE_COMPAT_DIR_PREALLOC|\
+					 EXT2_FEATURE_COMPAT_IMAGIC_INODES|\
+					 EXT3_FEATURE_COMPAT_HAS_JOURNAL|\
+					 EXT2_FEATURE_COMPAT_RESIZE_INODE|\
+					 EXT2_FEATURE_COMPAT_DIR_INDEX|\
+					 EXT2_FEATURE_COMPAT_EXT_ATTR)
+
+/* This #ifdef is temporary until compression is fully supported */
+#ifdef ENABLE_COMPRESSION
+#ifndef I_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL
+/* If the below warning bugs you, then have
+   `CPPFLAGS=-DI_KNOW_THAT_COMPRESSION_IS_EXPERIMENTAL' in your
+   environment at configure time. */
+ #warning "Compression support is experimental"
+#endif
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\
+					 EXT2_FEATURE_INCOMPAT_COMPRESSION|\
+					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
+					 EXT2_FEATURE_INCOMPAT_META_BG|\
+					 EXT3_FEATURE_INCOMPAT_RECOVER)
+#else
+#define EXT2_LIB_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE|\
+					 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\
+					 EXT2_FEATURE_INCOMPAT_META_BG|\
+					 EXT3_FEATURE_INCOMPAT_RECOVER)
+#endif
+#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP	(EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\
+					 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)
+/*
+ * function prototypes
+ */
+
+/* alloc.c */
+extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode,
+				  ext2fs_inode_bitmap map, ext2_ino_t *ret);
+extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
+				  ext2fs_block_bitmap map, blk_t *ret);
+extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start,
+					blk_t finish, int num,
+					ext2fs_block_bitmap map,
+					blk_t *ret);
+extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+				    char *block_buf, blk_t *ret);
+
+/* alloc_sb.c */
+extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, 
+					dgrp_t group,
+					ext2fs_block_bitmap bmap);
+
+/* alloc_stats.c */
+void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse);
+void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
+			       int inuse, int isdir);
+void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse);
+
+/* alloc_tables.c */
+extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
+					     ext2fs_block_bitmap bmap);
+
+/* badblocks.c */
+extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
+extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
+extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk);
+extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
+extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+					       ext2_u32_iterate *ret);
+extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
+extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
+extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
+extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
+
+extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
+					    int size);
+extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
+					   blk_t blk);
+extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb,
+				    blk_t blk);
+extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk);
+extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk);
+extern errcode_t
+	ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+					    ext2_badblocks_iterate *ret);
+extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter,
+					 blk_t *blk);
+extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter);
+extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
+				       ext2_badblocks_list *dest);
+extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1,
+				  ext2_badblocks_list bb2);
+extern int ext2fs_u32_list_count(ext2_u32_list bb);
+
+/* bb_compat */
+extern errcode_t badblocks_list_create(badblocks_list *ret, int size);
+extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk);
+extern int badblocks_list_test(badblocks_list bb, blk_t blk);
+extern errcode_t badblocks_list_iterate_begin(badblocks_list bb,
+					      badblocks_iterate *ret);
+extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk);
+extern void badblocks_list_iterate_end(badblocks_iterate iter);
+extern void badblocks_list_free(badblocks_list bb);
+
+/* bb_inode.c */
+extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs,
+					ext2_badblocks_list bb_list);
+
+/* bitmaps.c */
+extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs);
+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);
+extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
+					      const char *descr,
+					      ext2fs_inode_bitmap *ret);
+extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
+					       ext2_ino_t end, ext2_ino_t *oend);
+extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
+					       blk_t end, blk_t *oend);
+extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap);
+extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap);
+extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs);
+extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs);
+
+/* block.c */
+extern errcode_t ext2fs_block_iterate(ext2_filsys fs,
+				      ext2_ino_t	ino,
+				      int	flags,
+				      char *block_buf,
+				      int (*func)(ext2_filsys fs,
+						  blk_t	*blocknr,
+						  int	blockcnt,
+						  void	*priv_data),
+				      void *priv_data);
+errcode_t ext2fs_block_iterate2(ext2_filsys fs,
+				ext2_ino_t	ino,
+				int	flags,
+				char *block_buf,
+				int (*func)(ext2_filsys fs,
+					    blk_t	*blocknr,
+					    e2_blkcnt_t	blockcnt,
+					    blk_t	ref_blk,
+					    int		ref_offset,
+					    void	*priv_data),
+				void *priv_data);
+
+/* bmap.c */
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
+			     struct ext2_inode *inode, 
+			     char *block_buf, int bmap_flags,
+			     blk_t block, blk_t *phys_blk);
+
+
+#if 0
+/* bmove.c */
+extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
+				    ext2fs_block_bitmap reserve,
+				    ext2fs_block_bitmap alloc_map,
+				    int flags);
+#endif
+
+/* check_desc.c */
+extern errcode_t ext2fs_check_desc(ext2_filsys fs);
+
+/* closefs.c */
+extern errcode_t ext2fs_close(ext2_filsys fs);
+extern errcode_t ext2fs_flush(ext2_filsys fs);
+extern int ext2fs_bg_has_super(ext2_filsys fs, int group_block);
+extern int ext2fs_super_and_bgd_loc(ext2_filsys fs, 
+				    dgrp_t group,
+				    blk_t *ret_super_blk,
+				    blk_t *ret_old_desc_blk,
+				    blk_t *ret_new_desc_blk,
+				    int *ret_meta_bg);
+extern void ext2fs_update_dynamic_rev(ext2_filsys fs);
+
+/* cmp_bitmaps.c */
+extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
+					     ext2fs_block_bitmap bm2);
+extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
+					     ext2fs_inode_bitmap bm2);
+
+/* dblist.c */
+
+extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
+extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
+extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
+				      blk_t blk, int blockcnt);
+extern void ext2fs_dblist_sort(ext2_dblist dblist,
+			       EXT2_QSORT_TYPE (*sortfunc)(const void *,
+							   const void *));
+extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
+	int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
+		    void	*priv_data),
+       void *priv_data);
+extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino,
+				      blk_t blk, int blockcnt);
+extern errcode_t ext2fs_copy_dblist(ext2_dblist src,
+				    ext2_dblist *dest);
+extern int ext2fs_dblist_count(ext2_dblist dblist);
+
+/* dblist_dir.c */
+extern errcode_t
+	ext2fs_dblist_dir_iterate(ext2_dblist dblist,
+				  int	flags,
+				  char	*block_buf,
+				  int (*func)(ext2_ino_t	dir,
+					      int		entry,
+					      struct ext2_dir_entry *dirent,
+					      int	offset,
+					      int	blocksize,
+					      char	*buf,
+					      void	*priv_data),
+				  void *priv_data);
+
+/* dirblock.c */
+extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
+				       void *buf);
+extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
+					void *buf, int flags);
+extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
+					void *buf);
+extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
+					 void *buf, int flags);
+
+/* dirhash.c */
+extern errcode_t ext2fs_dirhash(int version, const char *name, int len,
+				const __u32 *seed,
+				ext2_dirhash_t *ret_hash,
+				ext2_dirhash_t *ret_minor_hash);
+
+
+/* dir_iterate.c */
+extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, 
+			      ext2_ino_t dir,
+			      int flags,
+			      char *block_buf,
+			      int (*func)(struct ext2_dir_entry *dirent,
+					  int	offset,
+					  int	blocksize,
+					  char	*buf,
+					  void	*priv_data),
+			      void *priv_data);
+extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs, 
+			      ext2_ino_t dir,
+			      int flags,
+			      char *block_buf,
+			      int (*func)(ext2_ino_t	dir,
+					  int	entry,
+					  struct ext2_dir_entry *dirent,
+					  int	offset,
+					  int	blocksize,
+					  char	*buf,
+					  void	*priv_data),
+			      void *priv_data);
+
+/* dupfs.c */
+extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
+
+/* expanddir.c */
+extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir);
+
+/* ext_attr.c */
+extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf);
+extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block,
+				       void *buf);
+extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
+					   char *block_buf,
+					   int adjust, __u32 *newcount);
+
+/* fileio.c */
+extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
+				   struct ext2_inode *inode,
+				   int flags, ext2_file_t *ret);
+extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
+				  int flags, ext2_file_t *ret);
+extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file);
+extern errcode_t ext2fs_file_close(ext2_file_t file);
+extern errcode_t ext2fs_file_flush(ext2_file_t file);
+extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+				  unsigned int wanted, unsigned int *got);
+extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
+				   unsigned int nbytes, unsigned int *written);
+extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
+				   int whence, __u64 *ret_pos);
+extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
+				   int whence, ext2_off_t *ret_pos);
+errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size);
+extern ext2_off_t ext2fs_file_get_size(ext2_file_t file);
+extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size);
+
+/* finddev.c */
+extern char *ext2fs_find_block_device(dev_t device);
+
+/* flushb.c */
+extern errcode_t ext2fs_sync_device(int fd, int flushb);
+
+/* 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);
+extern void ext2fs_free_dblist(ext2_dblist dblist);
+extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
+extern void ext2fs_u32_list_free(ext2_u32_list bb);
+
+/* getsize.c */
+extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+					blk_t *retblocks);
+
+/* getsectsize.c */
+errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize);
+
+/* imager.c */
+extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags);
+extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags);
+
+/* ind_block.c */
+errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf);
+errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf);
+
+/* initialize.c */
+extern errcode_t ext2fs_initialize(const char *name, int flags,
+				   struct ext2_super_block *param,
+				   io_manager manager, ext2_filsys *ret_fs);
+
+/* icount.c */
+extern void ext2fs_free_icount(ext2_icount_t icount);
+extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, 
+				       unsigned int size,
+				       ext2_icount_t hint, ext2_icount_t *ret);
+extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 
+				      unsigned int size,
+				      ext2_icount_t *ret);
+extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino,
+				     __u16 *ret);
+extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
+					 __u16 *ret);
+extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+					 __u16 *ret);
+extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
+				     __u16 count);
+extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount);
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *);
+
+/* inode.c */
+extern errcode_t ext2fs_flush_icache(ext2_filsys fs);
+extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, 
+					    ext2_ino_t *ino,
+					    struct ext2_inode *inode, 
+					    int bufsize);
+extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+				  ext2_inode_scan *ret_scan);
+extern void ext2fs_close_inode_scan(ext2_inode_scan scan);
+extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+			       struct ext2_inode *inode);
+extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
+						   int	group);
+extern void ext2fs_set_inode_callback
+	(ext2_inode_scan scan,
+	 errcode_t (*done_group)(ext2_filsys fs,
+				 ext2_inode_scan scan,
+				 dgrp_t group,
+				 void * priv_data),
+	 void *done_group_data);
+extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
+				   int clear_flags);
+extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+					struct ext2_inode * inode, 
+					int bufsize);
+extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino,
+			    struct ext2_inode * inode);
+extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+					 struct ext2_inode * inode, 
+					 int bufsize);
+extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+			    struct ext2_inode * inode);
+extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
+			    struct ext2_inode * inode);
+extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks);
+extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino);
+
+/* inode_io.c */
+extern io_manager inode_io_manager;
+extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, 
+					char **name);
+extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
+					 struct ext2_inode *inode,
+					 char **name);
+	
+/* ismounted.c */
+extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags);
+extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
+					  char *mtpt, int mtlen);
+
+/* namei.c */
+extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
+			 int namelen, char *buf, ext2_ino_t *inode);
+extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+			const char *name, ext2_ino_t *inode);
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+			      const char *name, ext2_ino_t *inode);
+extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+			ext2_ino_t inode, ext2_ino_t *res_inode);
+
+/* native.c */
+int ext2fs_native_flag(void);
+
+/* newdir.c */
+extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
+				ext2_ino_t parent_ino, char **block);
+
+/* mkdir.c */
+extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
+			      const char *name);
+
+/* mkjournal.c */
+extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
+						  __u32 size, int flags,
+						  char  **ret_jsb);
+extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
+					   ext2_filsys journal_dev);
+extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size,
+					  int flags);
+
+/* openfs.c */
+extern errcode_t ext2fs_open(const char *name, int flags, int superblock,
+			     unsigned int block_size, io_manager manager,
+			     ext2_filsys *ret_fs);
+extern errcode_t ext2fs_open2(const char *name, const char *io_options, 
+			      int flags, int superblock, 
+			      unsigned int block_size, io_manager manager,
+			      ext2_filsys *ret_fs);
+extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, 
+					 dgrp_t i);
+errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io);
+errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io);
+errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io);
+
+/* get_pathname.c */
+extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
+			       char **name);
+
+/* link.c */
+errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name,
+		      ext2_ino_t ino, int flags);
+errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name,
+			ext2_ino_t ino, int flags);
+
+/* read_bb.c */
+extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs,
+				      ext2_badblocks_list *bb_list);
+
+/* read_bb_file.c */
+extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, 
+				      ext2_badblocks_list *bb_list,
+				      void *priv_data,
+				      void (*invalid)(ext2_filsys fs,
+						      blk_t blk,
+						      char *badstr,
+						      void *priv_data));
+extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
+				     ext2_badblocks_list *bb_list,
+				     void (*invalid)(ext2_filsys fs,
+						     blk_t blk));
+
+/* res_gdt.c */
+extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs);
+
+/* rs_bitmap.c */
+extern errcode_t ext2fs_resize_generic_bitmap(__u32 new_end,
+					      __u32 new_real_end,
+					      ext2fs_generic_bitmap bmap);
+extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+					    ext2fs_inode_bitmap bmap);
+extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+					    ext2fs_block_bitmap bmap);
+extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
+				    ext2fs_generic_bitmap *dest);
+
+/* swapfs.c */
+extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, 
+				 int has_header);
+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_full(ext2_filsys fs, struct ext2_inode_large *t,
+				   struct ext2_inode_large *f, int hostorder,
+				   int bufsize);
+extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t,
+			      struct ext2_inode *f, int hostorder);
+
+/* valid_blk.c */
+extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode);
+
+/* version.c */
+extern int ext2fs_parse_version_string(const char *ver_string);
+extern int ext2fs_get_library_version(const char **ver_string,
+				      const char **date_string);
+
+/* write_bb_file.c */
+extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
+				      unsigned int flags,
+				      FILE *f);
+
+
+/* inline functions */
+extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr);
+extern errcode_t ext2fs_free_mem(void *ptr);
+extern errcode_t ext2fs_resize_mem(unsigned long old_size,
+				   unsigned long size, void *ptr);
+extern void ext2fs_mark_super_dirty(ext2_filsys fs);
+extern void ext2fs_mark_changed(ext2_filsys fs);
+extern int ext2fs_test_changed(ext2_filsys fs);
+extern void ext2fs_mark_valid(ext2_filsys fs);
+extern void ext2fs_unmark_valid(ext2_filsys fs);
+extern int ext2fs_test_valid(ext2_filsys fs);
+extern void ext2fs_mark_ib_dirty(ext2_filsys fs);
+extern void ext2fs_mark_bb_dirty(ext2_filsys fs);
+extern int ext2fs_test_ib_dirty(ext2_filsys fs);
+extern int ext2fs_test_bb_dirty(ext2_filsys fs);
+extern int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk);
+extern int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino);
+extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
+				      struct ext2_inode *inode);
+
+/*
+ * The actual inlined functions definitions themselves...
+ *
+ * If NO_INLINE_FUNCS is defined, then we won't try to do inline
+ * functions at all!
+ */
+#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS))
+#ifdef INCLUDE_INLINE_FUNCS
+#define _INLINE_ extern
+#else
+#ifdef __GNUC__
+#define _INLINE_ extern __inline__
+#else				/* For Watcom C */
+#define _INLINE_ extern inline
+#endif
+#endif
+
+#ifndef EXT2_CUSTOM_MEMORY_ROUTINES
+/*
+ *  Allocate memory
+ */
+_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr)
+{
+	void **pp = (void **)ptr;
+
+	*pp = malloc(size);
+	if (!*pp)
+		return EXT2_ET_NO_MEMORY;
+	return 0;
+}
+
+/*
+ * Free memory
+ */
+_INLINE_ errcode_t ext2fs_free_mem(void *ptr)
+{
+	void **pp = (void **)ptr;
+
+	free(*pp);
+	*pp = 0;
+	return 0;
+}
+	
+/*
+ *  Resize memory
+ */
+_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size,
+				     unsigned long size, void *ptr)
+{
+	void *p;
+
+	/* Use "memcpy" for pointer assignments here to avoid problems
+	 * with C99 strict type aliasing rules. */
+	memcpy(&p, ptr, sizeof (p));
+	p = realloc(p, size);
+	if (!p)
+		return EXT2_ET_NO_MEMORY;
+	memcpy(ptr, &p, sizeof (p));
+	return 0;
+}
+#endif	/* Custom memory routines */
+
+/*
+ * Mark a filesystem superblock as dirty
+ */
+_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark a filesystem as changed
+ */
+_INLINE_ void ext2fs_mark_changed(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem has changed
+ */
+_INLINE_ int ext2fs_test_changed(ext2_filsys fs)
+{
+	return (fs->flags & EXT2_FLAG_CHANGED);
+}
+
+/*
+ * Mark a filesystem as valid
+ */
+_INLINE_ void ext2fs_mark_valid(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_VALID;
+}
+
+/*
+ * Mark a filesystem as NOT valid
+ */
+_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs)
+{
+	fs->flags &= ~EXT2_FLAG_VALID;
+}
+
+/*
+ * Check to see if a filesystem is valid
+ */
+_INLINE_ int ext2fs_test_valid(ext2_filsys fs)
+{
+	return (fs->flags & EXT2_FLAG_VALID);
+}
+
+/*
+ * Mark the inode bitmap as dirty
+ */
+_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Mark the block bitmap as dirty
+ */
+_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs)
+{
+	fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED;
+}
+
+/*
+ * Check to see if a filesystem's inode bitmap is dirty
+ */
+_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs)
+{
+	return (fs->flags & EXT2_FLAG_IB_DIRTY);
+}
+
+/*
+ * Check to see if a filesystem's block bitmap is dirty
+ */
+_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs)
+{
+	return (fs->flags & EXT2_FLAG_BB_DIRTY);
+}
+
+/*
+ * Return the group # of a block
+ */
+_INLINE_ int ext2fs_group_of_blk(ext2_filsys fs, blk_t blk)
+{
+	return (blk - fs->super->s_first_data_block) /
+		fs->super->s_blocks_per_group;
+}
+
+/*
+ * Return the group # of an inode number
+ */
+_INLINE_ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino)
+{
+	return (ino - 1) / fs->super->s_inodes_per_group;
+}
+
+_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs,
+					struct ext2_inode *inode)
+{
+       return inode->i_blocks -
+              (inode->i_file_acl ? fs->blocksize >> 9 : 0);
+}
+#undef _INLINE_
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EXT2FS_EXT2FS_H */
diff -Naur silo-1.4.11.orig/libext2fs/ext2fsP.h silo-1.4.11/libext2fs/ext2fsP.h
--- silo-1.4.11.orig/libext2fs/ext2fsP.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext2fsP.h	2006-03-09 21:34:56 +0000
@@ -0,0 +1,88 @@
+/*
+ * ext2fsP.h --- private header file for ext2 library
+ * 
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include "ext2fs.h"
+
+/*
+ * Badblocks list
+ */
+struct ext2_struct_u32_list {
+	int	magic;
+	int	num;
+	int	size;
+	__u32	*list;
+	int	badblocks_flags;
+};
+
+struct ext2_struct_u32_iterate {
+	int			magic;
+	ext2_u32_list		bb;
+	int			ptr;
+};
+
+
+/*
+ * Directory block iterator definition
+ */
+struct ext2_struct_dblist {
+	int			magic;
+	ext2_filsys		fs;
+	ext2_ino_t		size;
+	ext2_ino_t		count;
+	int			sorted;
+	struct ext2_db_entry *	list;
+};
+
+/*
+ * For directory iterators
+ */
+struct dir_context {
+	ext2_ino_t		dir;
+	int		flags;
+	char		*buf;
+	int (*func)(ext2_ino_t	dir,
+		    int	entry,
+		    struct ext2_dir_entry *dirent,
+		    int	offset,
+		    int	blocksize,
+		    char	*buf,
+		    void	*priv_data);
+	void		*priv_data;
+	errcode_t	errcode;
+};
+
+/*
+ * Inode cache structure
+ */
+struct ext2_inode_cache {
+	void *				buffer;
+	blk_t				buffer_blk;
+	int				cache_last;
+	int				cache_size;
+	int				refcount;
+	struct ext2_inode_cache_ent	*cache;
+};
+
+struct ext2_inode_cache_ent {
+	ext2_ino_t		ino;
+	struct ext2_inode	inode;
+};
+
+/* Function prototypes */
+
+extern int ext2fs_process_dir_block(ext2_filsys  	fs,
+				    blk_t		*blocknr,
+				    e2_blkcnt_t		blockcnt,
+				    blk_t		ref_block,
+				    int			ref_offset,
+				    void		*priv_data);
+
+
diff -Naur silo-1.4.11.orig/libext2fs/ext_attr.c silo-1.4.11/libext2fs/ext_attr.c
--- silo-1.4.11.orig/libext2fs/ext_attr.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ext_attr.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,105 @@
+/*
+ * ext_attr.c --- extended attribute blocks
+ * 
+ * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ *
+ * Copyright (C) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2_ext_attr.h"
+
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf)
+{
+	errcode_t	retval;
+
+ 	retval = io_channel_read_blk(fs->io, block, 1, buf);
+	if (retval)
+		return retval;
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->flags & (EXT2_FLAG_SWAP_BYTES|
+			  EXT2_FLAG_SWAP_BYTES_READ)) != 0)
+		ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1);
+#endif
+	return 0;
+}
+
+errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf)
+{
+	errcode_t	retval;
+	char		*write_buf;
+	char		*buf = NULL;
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)) {
+		retval = ext2fs_get_mem(fs->blocksize, &buf);
+		if (retval)
+			return retval;
+		write_buf = buf;
+		ext2fs_swap_ext_attr(buf, inbuf, fs->blocksize, 1);
+	} else
+#endif
+		write_buf = (char *) inbuf;
+ 	retval = io_channel_write_blk(fs->io, block, 1, write_buf);
+	if (buf)
+		ext2fs_free_mem(&buf);
+	if (!retval)
+		ext2fs_mark_changed(fs);
+	return retval;
+}
+
+/*
+ * This function adjusts the reference count of the EA block.
+ */
+errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk,
+				    char *block_buf, int adjust,
+				    __u32 *newcount)
+{
+	errcode_t	retval;
+	struct ext2_ext_attr_header *header;
+	char	*buf = 0;
+
+	if ((blk >= fs->super->s_blocks_count) ||
+	    (blk < fs->super->s_first_data_block))
+		return EXT2_ET_BAD_EA_BLOCK_NUM;
+
+	if (!block_buf) {
+		retval = ext2fs_get_mem(fs->blocksize, &buf);
+		if (retval)
+			return retval;
+		block_buf = buf;
+	}
+
+	retval = ext2fs_read_ext_attr(fs, blk, block_buf);
+	if (retval)
+		goto errout;
+
+	header = (struct ext2_ext_attr_header *) block_buf;
+	header->h_refcount += adjust;
+	if (newcount)
+		*newcount = header->h_refcount;
+
+	retval = ext2fs_write_ext_attr(fs, blk, block_buf);
+	if (retval)
+		goto errout;
+
+errout:
+	if (buf)
+		ext2fs_free_mem(&buf);
+	return retval;
+}
diff -Naur silo-1.4.11.orig/libext2fs/fileio.c silo-1.4.11/libext2fs/fileio.c
--- silo-1.4.11.orig/libext2fs/fileio.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/fileio.c	2006-03-09 21:34:56 +0000
@@ -0,0 +1,378 @@
+/*
+ * fileio.c --- Simple file I/O routines
+ * 
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct ext2_file {
+	errcode_t		magic;
+	ext2_filsys 		fs;
+	ext2_ino_t		ino;
+	struct ext2_inode	inode;
+	int 			flags;
+	__u64			pos;
+	blk_t			blockno;
+	blk_t			physblock;
+	char 			*buf;
+};
+
+#define BMAP_BUFFER (file->buf + fs->blocksize)
+
+errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
+			    struct ext2_inode *inode,
+			    int flags, ext2_file_t *ret)
+{
+	ext2_file_t 	file;
+	errcode_t	retval;
+
+	/*
+	 * Don't let caller create or open a file for writing if the
+	 * filesystem is read-only.
+	 */
+	if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
+	    !(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
+	if (retval)
+		return retval;
+	
+	memset(file, 0, sizeof(struct ext2_file));
+	file->magic = EXT2_ET_MAGIC_EXT2_FILE;
+	file->fs = fs;
+	file->ino = ino;
+	file->flags = flags & EXT2_FILE_MASK;
+
+	if (inode) {
+		memcpy(&file->inode, inode, sizeof(struct ext2_inode));
+	} else {
+		retval = ext2fs_read_inode(fs, ino, &file->inode);
+		if (retval)
+			goto fail;
+	}
+	
+	retval = ext2fs_get_mem(fs->blocksize * 3, &file->buf);
+	if (retval)
+		goto fail;
+
+	*ret = file;
+	return 0;
+	
+fail:
+	if (file->buf)
+		ext2fs_free_mem(&file->buf);
+	ext2fs_free_mem(&file);
+	return retval;
+}
+
+errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
+			   int flags, ext2_file_t *ret)
+{
+	return ext2fs_file_open2(fs, ino, NULL, flags, ret);
+}
+
+/*
+ * This function returns the filesystem handle of a file from the structure
+ */
+ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
+{
+	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
+		return 0;
+	return file->fs;
+}
+
+/*
+ * This function flushes the dirty block buffer out to disk if
+ * necessary.
+ */
+errcode_t ext2fs_file_flush(ext2_file_t file)
+{
+	errcode_t	retval;
+	ext2_filsys fs;
+	
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	fs = file->fs;
+
+	if (!(file->flags & EXT2_FILE_BUF_VALID) ||
+	    !(file->flags & EXT2_FILE_BUF_DIRTY))
+		return 0;
+
+	/*
+	 * OK, the physical block hasn't been allocated yet.
+	 * Allocate it.
+	 */
+	if (!file->physblock) {
+		retval = ext2fs_bmap(fs, file->ino, &file->inode,
+				     BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
+				     file->blockno, &file->physblock);
+		if (retval)
+			return retval;
+	}
+
+	retval = io_channel_write_blk(fs->io, file->physblock,
+				      1, file->buf);
+	if (retval)
+		return retval;
+
+	file->flags &= ~EXT2_FILE_BUF_DIRTY;
+
+	return retval;
+}
+
+/*
+ * This function synchronizes the file's block buffer and the current
+ * file position, possibly invalidating block buffer if necessary
+ */
+static errcode_t sync_buffer_position(ext2_file_t file)
+{
+	blk_t	b;
+	errcode_t	retval;
+
+	b = file->pos / file->fs->blocksize;
+	if (b != file->blockno) {
+		retval = ext2fs_file_flush(file);
+		if (retval)
+			return retval;
+		file->flags &= ~EXT2_FILE_BUF_VALID;
+	}
+	file->blockno = b;
+	return 0;
+}
+
+/*
+ * This function loads the file's block buffer with valid data from
+ * the disk as necessary.
+ *
+ * If dontfill is true, then skip initializing the buffer since we're
+ * going to be replacing its entire contents anyway.  If set, then the
+ * function basically only sets file->physblock and EXT2_FILE_BUF_VALID
+ */
+#define DONTFILL 1
+static errcode_t load_buffer(ext2_file_t file, int dontfill)
+{
+	ext2_filsys	fs = file->fs;
+	errcode_t	retval;
+
+	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
+		retval = ext2fs_bmap(fs, file->ino, &file->inode,
+				     BMAP_BUFFER, 0, file->blockno,
+				     &file->physblock);
+		if (retval)
+			return retval;
+		if (!dontfill) {
+			if (file->physblock) {
+				retval = io_channel_read_blk(fs->io,
+							     file->physblock, 
+							     1, file->buf);
+				if (retval)
+					return retval;
+			} else
+				memset(file->buf, 0, fs->blocksize);
+		}
+		file->flags |= EXT2_FILE_BUF_VALID;
+	}
+	return 0;
+}
+	
+
+errcode_t ext2fs_file_close(ext2_file_t file)
+{
+	errcode_t	retval;
+	
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+	retval = ext2fs_file_flush(file);
+	
+	if (file->buf)
+		ext2fs_free_mem(&file->buf);
+	ext2fs_free_mem(&file);
+
+	return retval;
+}
+
+
+errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+			   unsigned int wanted, unsigned int *got)
+{
+	ext2_filsys	fs;
+	errcode_t	retval = 0;
+	unsigned int	start, c, count = 0;
+	__u64		left;
+	char		*ptr = (char *) buf;
+
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	fs = file->fs;
+
+	while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
+		retval = sync_buffer_position(file);
+		if (retval)
+			goto fail;
+		retval = load_buffer(file, 0);
+		if (retval)
+			goto fail;
+
+		start = file->pos % fs->blocksize;
+		c = fs->blocksize - start;
+		if (c > wanted)
+			c = wanted;
+		left = EXT2_I_SIZE(&file->inode) - file->pos ;
+		if (c > left)
+			c = left;
+	
+		memcpy(ptr, file->buf+start, c);
+		file->pos += c;
+		ptr += c;
+		count += c;
+		wanted -= c;
+	}
+	
+fail:
+	if (got)
+		*got = count;
+	return retval;
+}
+
+
+errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
+			    unsigned int nbytes, unsigned int *written)
+{
+	ext2_filsys	fs;
+	errcode_t	retval = 0;
+	unsigned int	start, c, count = 0;
+	const char	*ptr = (const char *) buf;
+
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	fs = file->fs;
+
+	if (!(file->flags & EXT2_FILE_WRITE))
+		return EXT2_ET_FILE_RO;
+
+	while (nbytes > 0) {
+		retval = sync_buffer_position(file);
+		if (retval)
+			goto fail;
+		
+		start = file->pos % fs->blocksize;
+		c = fs->blocksize - start;
+		if (c > nbytes)
+			c = nbytes;
+
+		/*
+		 * We only need to do a read-modify-update cycle if
+		 * we're doing a partial write.
+		 */
+		retval = load_buffer(file, (c == fs->blocksize));
+		if (retval)
+			goto fail;
+
+		file->flags |= EXT2_FILE_BUF_DIRTY;
+		memcpy(file->buf+start, ptr, c);
+		file->pos += c;
+		ptr += c;
+		count += c;
+		nbytes -= c;
+	}
+	
+fail:
+	if (written)
+		*written = count;
+	return retval;
+}
+
+errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
+			    int whence, __u64 *ret_pos)
+{
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+	if (whence == EXT2_SEEK_SET)
+		file->pos = offset;
+	else if (whence == EXT2_SEEK_CUR)
+		file->pos += offset;
+	else if (whence == EXT2_SEEK_END)
+		file->pos = EXT2_I_SIZE(&file->inode) + offset;
+	else
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	if (ret_pos)
+		*ret_pos = file->pos;
+
+	return 0;
+}
+
+errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
+			    int whence, ext2_off_t *ret_pos)
+{
+	__u64		loffset, ret_loffset;
+	errcode_t	retval;
+	
+	loffset = offset;
+	retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
+	if (ret_pos)
+		*ret_pos = (ext2_off_t) ret_loffset;
+	return retval;
+}
+
+
+/*
+ * This function returns the size of the file, according to the inode
+ */
+errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
+{
+	if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
+		return EXT2_ET_MAGIC_EXT2_FILE;
+	*ret_size = EXT2_I_SIZE(&file->inode);
+	return 0;
+}
+
+/*
+ * This function returns the size of the file, according to the inode
+ */
+ext2_off_t ext2fs_file_get_size(ext2_file_t file)
+{
+	__u64	size;
+
+	if (ext2fs_file_get_lsize(file, &size))
+		return 0;
+	if ((size >> 32) != 0)
+		return 0;
+	return size;
+}
+
+/*
+ * This function sets the size of the file, truncating it if necessary
+ * 
+ * XXX still need to call truncate
+ */
+errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
+{
+	errcode_t	retval;
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	
+	file->inode.i_size = size;
+	file->inode.i_size_high = 0;
+	if (file->ino) {
+		retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
+		if (retval)
+			return retval;
+	}
+
+	/* 
+	 * XXX truncate inode if necessary
+	 */
+
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/finddev.c silo-1.4.11/libext2fs/finddev.c
--- silo-1.4.11.orig/libext2fs/finddev.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/finddev.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,208 @@
+/*
+ * finddev.c -- this routine attempts to find a particular device in
+ * 	/dev
+ * 
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#include <dirent.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_MKDEV_H
+#include <sys/mkdev.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct dir_list {
+	char	*name;
+	struct dir_list *next;
+};
+
+/*
+ * This function adds an entry to the directory list
+ */
+static void add_to_dirlist(const char *name, struct dir_list **list)
+{
+	struct dir_list *dp;
+
+	dp = malloc(sizeof(struct dir_list));
+	if (!dp)
+		return;
+	dp->name = malloc(strlen(name)+1);
+	if (!dp->name) {
+		free(dp);
+		return;
+	}
+	strcpy(dp->name, name);
+	dp->next = *list;
+	*list = dp;
+}
+
+/*
+ * This function frees a directory list
+ */
+static void free_dirlist(struct dir_list **list)
+{
+	struct dir_list *dp, *next;
+
+	for (dp = *list; dp; dp = next) {
+		next = dp->next;
+		free(dp->name);
+		free(dp);
+	}
+	*list = 0;
+}
+
+static int scan_dir(char *dirname, dev_t device, struct dir_list **list,
+		    char **ret_path)
+{
+	DIR	*dir;
+	struct dirent *dp;
+	char	path[1024], *cp;
+	int	dirlen;
+	struct stat st;
+
+	dirlen = strlen(dirname);
+	if ((dir = opendir(dirname)) == NULL)
+		return errno;
+	dp = readdir(dir);
+	while (dp) {
+		if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
+			goto skip_to_next;
+		if (dp->d_name[0] == '.' &&
+		    ((dp->d_name[1] == 0) ||
+		     ((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
+			goto skip_to_next;
+		sprintf(path, "%s/%s", dirname, dp->d_name);
+		if (stat(path, &st) < 0)
+			goto skip_to_next;
+		if (S_ISDIR(st.st_mode))
+			add_to_dirlist(path, list);
+		if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
+			cp = malloc(strlen(path)+1);
+			if (!cp) {
+				closedir(dir);
+				return ENOMEM;
+			}
+			strcpy(cp, path);
+			*ret_path = cp;
+			goto success;
+		}
+	skip_to_next:
+		dp = readdir(dir);
+	}
+success:
+	closedir(dir);
+	return 0;
+}
+
+/*
+ * This function finds the pathname to a block device with a given
+ * device number.  It returns a pointer to allocated memory to the
+ * pathname on success, and NULL on failure.
+ */
+char *ext2fs_find_block_device(dev_t device)
+{
+	struct dir_list *list = 0, *new_list = 0;
+	struct dir_list *current;
+	char	*ret_path = 0;
+
+	/*
+	 * Add the starting directories to search...
+	 */
+	add_to_dirlist("/devices", &list);
+	add_to_dirlist("/devfs", &list);
+	add_to_dirlist("/dev", &list);
+	
+	while (list) {
+		current = list;
+		list = list->next;
+#ifdef DEBUG
+		printf("Scanning directory %s\n", current->name);
+#endif
+		scan_dir(current->name, device, &new_list, &ret_path);
+		free(current->name);
+		free(current);
+		if (ret_path)
+			break;
+		/*
+		 * If we're done checking at this level, descend to
+		 * the next level of subdirectories. (breadth-first)
+		 */
+		if (list == 0) {
+			list = new_list;
+			new_list = 0;
+		}
+	}
+	free_dirlist(&list);
+	free_dirlist(&new_list);
+	return ret_path;
+}
+
+	
+#ifdef DEBUG
+int main(int argc, char** argv)
+{
+	char	*devname, *tmp;
+	int	major, minor;
+	dev_t	device;
+	const char *errmsg = "Couldn't parse %s: %s\n";
+
+	if ((argc != 2) && (argc != 3)) {
+		fprintf(stderr, "Usage: %s device_number\n", argv[0]);
+		fprintf(stderr, "\t: %s major minor\n", argv[0]);
+		exit(1);
+	}
+	if (argc == 2) {
+		device = strtoul(argv[1], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "device number", argv[1]);
+			exit(1);
+		}
+	} else {
+		major = strtoul(argv[1], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "major number", argv[1]);
+			exit(1);
+		}
+		minor = strtoul(argv[2], &tmp, 0);
+		if (*tmp) {
+			fprintf(stderr, errmsg, "minor number", argv[2]);
+			exit(1);
+		}
+		device = makedev(major, minor);
+		printf("Looking for device 0x%04x (%d:%d)\n", device,
+		       major, minor);
+	}
+	devname = ext2fs_find_block_device(device);
+	if (devname) {
+		printf("Found device!  %s\n", devname);
+		free(devname);
+	} else {
+		printf("Couldn't find device.\n");
+	}
+	return 0;
+}
+	
+#endif
diff -Naur silo-1.4.11.orig/libext2fs/flushb.c silo-1.4.11/libext2fs/flushb.c
--- silo-1.4.11.orig/libext2fs/flushb.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/flushb.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,82 @@
+/*
+ * flushb.c --- Hides system-dependent information for both syncing a
+ * 	device to disk and to flush any buffers from disk cache.
+ * 
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_SYS_MOUNT_H
+#include <sys/param.h>
+#include <sys/mount.h>		/* This may define BLKFLSBUF */
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For Linux, define BLKFLSBUF and FDFLUSH if necessary, since 
+ * not all portable header file does so for us.  This really should be
+ * fixed in the glibc header files.  (Recent glibcs appear to define
+ * BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
+ * defined anywhere portable.)  Until then....
+ */
+#ifdef __linux__
+#ifndef BLKFLSBUF
+#define BLKFLSBUF	_IO(0x12,97)	/* flush buffer cache */
+#endif
+#ifndef FDFLUSH
+#define FDFLUSH		_IO(2,0x4b)	/* flush floppy disk */
+#endif
+#endif
+
+/*
+ * This function will sync a device/file, and optionally attempt to
+ * flush the buffer cache.  The latter is basically only useful for
+ * system benchmarks and for torturing systems in burn-in tests.  :)
+ */
+errcode_t ext2fs_sync_device(int fd, int flushb)
+{
+	/*
+	 * We always sync the device in case we're running on old
+	 * kernels for which we can lose data if we don't.  (There
+	 * still is a race condition for those kernels, but this
+	 * reduces it greatly.)
+	 */
+	if (fsync (fd) == -1)
+		return errno;
+
+	if (flushb) {
+
+#ifdef BLKFLSBUF
+		if (ioctl (fd, BLKFLSBUF, 0) == 0)
+			return 0;
+#else
+#ifdef __GNUC__
+ #warning BLKFLSBUF not defined
+#endif /* __GNUC__ */
+#endif
+#ifdef FDFLUSH
+		ioctl (fd, FDFLUSH, 0);   /* In case this is a floppy */
+#else
+#ifdef __GNUC__
+ #warning FDFLUSH not defined
+#endif /* __GNUC__ */
+#endif
+	}
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/freefs.c silo-1.4.11/libext2fs/freefs.c
--- silo-1.4.11.orig/libext2fs/freefs.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/freefs.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,147 @@
+/*
+ * freefs.c --- free an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache);
+
+void ext2fs_free(ext2_filsys fs)
+{
+	if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
+		return;
+	if (fs->image_io != fs->io) {
+		if (fs->image_io)
+			io_channel_close(fs->image_io);
+	}
+	if (fs->io) {
+		io_channel_close(fs->io);
+	}
+	if (fs->device_name)
+		ext2fs_free_mem(&fs->device_name);
+	if (fs->super)
+		ext2fs_free_mem(&fs->super);
+	if (fs->orig_super)
+		ext2fs_free_mem(&fs->orig_super);
+	if (fs->group_desc)
+		ext2fs_free_mem(&fs->group_desc);
+	if (fs->block_map)
+		ext2fs_free_block_bitmap(fs->block_map);
+	if (fs->inode_map)
+		ext2fs_free_inode_bitmap(fs->inode_map);
+
+	if (fs->badblocks)
+		ext2fs_badblocks_list_free(fs->badblocks);
+	fs->badblocks = 0;
+
+	if (fs->dblist)
+		ext2fs_free_dblist(fs->dblist);
+
+	if (fs->icache)
+		ext2fs_free_inode_cache(fs->icache);
+	
+	fs->magic = 0;
+
+	ext2fs_free_mem(&fs);
+}
+
+void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap)
+{
+	if (!bitmap || (bitmap->magic != EXT2_ET_MAGIC_GENERIC_BITMAP))
+		return;
+
+	bitmap->magic = 0;
+	if (bitmap->description) {
+		ext2fs_free_mem(&bitmap->description);
+		bitmap->description = 0;
+	}
+	if (bitmap->bitmap) {
+		ext2fs_free_mem(&bitmap->bitmap);
+		bitmap->bitmap = 0;
+	}
+	ext2fs_free_mem(&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 = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	ext2fs_free_generic_bitmap(bitmap);
+}
+
+/*
+ * Free the inode cache structure
+ */
+static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
+{
+	if (--icache->refcount)
+		return;
+	if (icache->buffer)
+		ext2fs_free_mem(&icache->buffer);
+	if (icache->cache)
+		ext2fs_free_mem(&icache->cache);
+	icache->buffer_blk = 0;
+	ext2fs_free_mem(&icache);
+}
+
+/*
+ * This procedure frees a badblocks list.
+ */
+void ext2fs_u32_list_free(ext2_u32_list bb)
+{
+	if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
+		return;
+
+	if (bb->list)
+		ext2fs_free_mem(&bb->list);
+	bb->list = 0;
+	ext2fs_free_mem(&bb);
+}
+
+void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
+{
+	ext2fs_u32_list_free((ext2_u32_list) bb);
+}
+
+
+/*
+ * Free a directory block list
+ */
+void ext2fs_free_dblist(ext2_dblist dblist)
+{
+	if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
+		return;
+
+	if (dblist->list)
+		ext2fs_free_mem(&dblist->list);
+	dblist->list = 0;
+	if (dblist->fs && dblist->fs->dblist == dblist)
+		dblist->fs->dblist = 0;
+	dblist->magic = 0;
+	ext2fs_free_mem(&dblist);
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/gen_bitmap.c silo-1.4.11/libext2fs/gen_bitmap.c
--- silo-1.4.11.orig/libext2fs/gen_bitmap.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/gen_bitmap.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,48 @@
+/*
+ * gen_bitmap.c --- Generic bitmap routines that used to be inlined.
+ * 
+ * Copyright (C) 2001 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int 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 0;
+	}
+	return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap);
+}
+
+int 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 0;
+	}
+	return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap);
+}
diff -Naur silo-1.4.11.orig/libext2fs/get_pathname.c silo-1.4.11/libext2fs/get_pathname.c
--- silo-1.4.11.orig/libext2fs/get_pathname.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/get_pathname.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,157 @@
+/*
+ * get_pathname.c --- do directry/inode -> name translation
+ * 
+ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ *
+ * 	ext2fs_get_pathname(fs, dir, ino, name)
+ *
+ * 	This function translates takes two inode numbers into a
+ * 	string, placing the result in <name>.  <dir> is the containing
+ * 	directory inode, and <ino> is the inode number itself.  If
+ * 	<ino> is zero, then ext2fs_get_pathname will return pathname
+ * 	of the the directory <dir>.
+ * 
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct get_pathname_struct {
+	ext2_ino_t	search_ino;
+	ext2_ino_t	parent;
+	char		*name;
+	errcode_t	errcode;
+};
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int get_pathname_proc(struct ext2_dir_entry *dirent,
+			     int	offset EXT2FS_ATTR((unused)),
+			     int	blocksize EXT2FS_ATTR((unused)),
+			     char	*buf EXT2FS_ATTR((unused)),
+			     void	*priv_data)
+{
+	struct get_pathname_struct	*gp;
+	errcode_t			retval;
+
+	gp = (struct get_pathname_struct *) priv_data;
+
+	if (((dirent->name_len & 0xFF) == 2) &&
+	    !strncmp(dirent->name, "..", 2))
+		gp->parent = dirent->inode;
+	if (dirent->inode == gp->search_ino) {
+		retval = ext2fs_get_mem((dirent->name_len & 0xFF) + 1,
+					&gp->name);
+		if (retval) {
+			gp->errcode = retval;
+			return DIRENT_ABORT;
+		}
+		strncpy(gp->name, dirent->name, (dirent->name_len & 0xFF));
+		gp->name[dirent->name_len & 0xFF] = '\0';
+		return DIRENT_ABORT;
+	}
+	return 0;
+}
+
+static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir, 
+					 ext2_ino_t ino, int maxdepth, 
+					 char *buf, char **name)
+{
+	struct get_pathname_struct gp;
+	char	*parent_name, *ret;
+	errcode_t	retval;
+
+	if (dir == ino) {
+		retval = ext2fs_get_mem(2, name);
+		if (retval)
+			return retval;
+		strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
+		return 0;
+	}
+
+	if (!dir || (maxdepth < 0)) {
+		retval = ext2fs_get_mem(4, name);
+		if (retval)
+			return retval;
+		strcpy(*name, "...");
+		return 0;
+	}
+
+	gp.search_ino = ino;
+	gp.parent = 0;
+	gp.name = 0;
+	gp.errcode = 0;
+	
+	retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
+	if (retval)
+		goto cleanup;
+	if (gp.errcode) {
+		retval = gp.errcode;
+		goto cleanup;
+	}
+
+	retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
+					 buf, &parent_name);
+	if (retval)
+		goto cleanup;
+	if (!ino) {
+		*name = parent_name;
+		return 0;
+	}
+	
+	if (gp.name) 
+		retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
+					&ret);
+	else
+		retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
+	if (retval)
+		goto cleanup;
+	
+	ret[0] = 0;
+	if (parent_name[1])
+		strcat(ret, parent_name);
+	strcat(ret, "/");
+	if (gp.name)
+		strcat(ret, gp.name);
+	else
+		strcat(ret, "???");
+	*name = ret;
+	ext2fs_free_mem(&parent_name);
+	retval = 0;
+	
+cleanup:
+	if (gp.name)
+		ext2fs_free_mem(&gp.name);
+	return retval;
+}
+
+errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
+			      char **name)
+{
+	char	*buf;
+	errcode_t	retval;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	if (dir == ino)
+		ino = 0;
+	retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
+	ext2fs_free_mem(&buf);
+	return retval;
+	
+}
diff -Naur silo-1.4.11.orig/libext2fs/getsectsize.c silo-1.4.11/libext2fs/getsectsize.c
--- silo-1.4.11.orig/libext2fs/getsectsize.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/getsectsize.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,60 @@
+/*
+ * getsectsize.c --- get the sector size of a device.
+ * 
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ * Copyright (C) 2003 VMware, Inc.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINUX_FD_H
+#include <sys/ioctl.h>
+#include <linux/fd.h>
+#endif
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET)
+#define BLKSSZGET  _IO(0x12,104)/* get block device sector size */
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Returns the number of blocks in a partition
+ */
+errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
+{
+	int	fd;
+
+#ifdef HAVE_OPEN64
+	fd = open64(file, O_RDONLY);
+#else
+	fd = open(file, O_RDONLY);
+#endif
+	if (fd < 0)
+		return errno;
+
+#ifdef BLKSSZGET
+	if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
+		close(fd);
+		return 0;
+	}
+#endif
+	*sectsize = 0;
+	close(fd);
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/getsize.c silo-1.4.11/libext2fs/getsize.c
--- silo-1.4.11.orig/libext2fs/getsize.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/getsize.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,293 @@
+/*
+ * getsize.c --- get the size of a partition.
+ * 
+ * Copyright (C) 1995, 1995 Theodore Ts'o.
+ * Copyright (C) 2003 VMware, Inc.
+ *
+ * Windows version of ext2fs_get_device_size by Chris Li, VMware.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+#include <sys/disklabel.h>
+#endif
+#ifdef HAVE_SYS_DISK_H
+#ifdef HAVE_SYS_QUEUE_H
+#include <sys/queue.h> /* for LIST_HEAD */
+#endif
+#include <sys/disk.h>
+#endif
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+
+#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
+#define BLKGETSIZE _IO(0x12,96)	/* return device size */
+#endif
+
+#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)	/* return device size in bytes (u64 *arg) */
+#endif
+
+#ifdef APPLE_DARWIN
+#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
+#endif /* APPLE_DARWIN */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if defined(__CYGWIN__) || defined (WIN32)
+#include "windows.h"
+#include "winioctl.h"
+
+#if (_WIN32_WINNT >= 0x0500)
+#define HAVE_GET_FILE_SIZE_EX 1
+#endif
+
+errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+				 blk_t *retblocks)
+{
+	HANDLE dev;
+	PARTITION_INFORMATION pi;
+	DISK_GEOMETRY gi;
+	DWORD retbytes;
+#ifdef HAVE_GET_FILE_SIZE_EX
+	LARGE_INTEGER filesize;
+#else
+	DWORD filesize;
+#endif /* HAVE_GET_FILE_SIZE_EX */
+
+	dev = CreateFile(file, GENERIC_READ, 
+			 FILE_SHARE_READ | FILE_SHARE_WRITE ,
+                	 NULL,  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,  NULL); 
+ 
+	if (dev == INVALID_HANDLE_VALUE)
+		return EBADF;
+	if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO,
+			    &pi, sizeof(PARTITION_INFORMATION),
+			    &pi, sizeof(PARTITION_INFORMATION),
+			    &retbytes, NULL)) {
+
+		*retblocks = pi.PartitionLength.QuadPart / blocksize;
+	
+	} else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+				&gi, sizeof(DISK_GEOMETRY),
+				&gi, sizeof(DISK_GEOMETRY),
+				&retbytes, NULL)) {
+
+		*retblocks = gi.BytesPerSector *
+			     gi.SectorsPerTrack *
+			     gi.TracksPerCylinder *
+			     gi.Cylinders.QuadPart / blocksize;
+
+#ifdef HAVE_GET_FILE_SIZE_EX
+	} else if (GetFileSizeEx(dev, &filesize)) {
+		*retblocks = filesize.QuadPart / blocksize;
+	}
+#else
+	} else {
+		filesize = GetFileSize(dev, NULL);
+		if (INVALID_FILE_SIZE != filesize) {
+			*retblocks = filesize / blocksize;
+		}
+	}
+#endif /* HAVE_GET_FILE_SIZE_EX */
+
+	CloseHandle(dev);
+	return 0;
+}
+
+#else
+
+static int valid_offset (int fd, ext2_loff_t offset)
+{
+	char ch;
+
+	if (ext2fs_llseek (fd, offset, 0) < 0)
+		return 0;
+	if (read (fd, &ch, 1) < 1)
+		return 0;
+	return 1;
+}
+
+/*
+ * Returns the number of blocks in a partition
+ */
+errcode_t ext2fs_get_device_size(const char *file, int blocksize,
+				 blk_t *retblocks)
+{
+	int	fd;
+	int valid_blkgetsize64 = 1;
+#ifdef __linux__
+	struct 		utsname ut;
+#endif
+	unsigned long long size64;
+	unsigned long	size;
+	ext2_loff_t high, low;
+#ifdef FDGETPRM
+	struct floppy_struct this_floppy;
+#endif
+#ifdef HAVE_SYS_DISKLABEL_H
+	int part;
+	struct disklabel lab;
+	struct partition *pp;
+	char ch;
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+#ifdef HAVE_OPEN64
+	fd = open64(file, O_RDONLY);
+#else
+	fd = open(file, O_RDONLY);
+#endif
+	if (fd < 0)
+		return errno;
+
+#ifdef DKIOCGETBLOCKCOUNT	/* For Apple Darwin */
+	if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0) {
+		if ((sizeof(*retblocks) < sizeof(unsigned long long))
+		    && ((size64 / (blocksize / 512)) > 0xFFFFFFFF))
+			return EFBIG;
+		close(fd);
+		*retblocks = size64 / (blocksize / 512);
+		return 0;
+	}
+#endif
+
+#ifdef BLKGETSIZE64
+#ifdef __linux__
+	if ((uname(&ut) == 0) &&
+	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+	     (ut.release[2] < '6') && (ut.release[3] == '.')))
+		valid_blkgetsize64 = 0;
+#endif
+	if (valid_blkgetsize64 &&
+	    ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
+		if ((sizeof(*retblocks) < sizeof(unsigned long long))
+		    && ((size64 / blocksize) > 0xFFFFFFFF))
+			return EFBIG;
+		close(fd);
+		*retblocks = size64 / blocksize;
+		return 0;
+	}
+#endif
+
+#ifdef BLKGETSIZE
+	if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
+		close(fd);
+		*retblocks = size / (blocksize / 512);
+		return 0;
+	}
+#endif
+
+#ifdef FDGETPRM
+	if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
+		close(fd);
+		*retblocks = this_floppy.size / (blocksize / 512);
+		return 0;
+	}
+#endif
+
+#ifdef HAVE_SYS_DISKLABEL_H
+#if defined(DIOCGMEDIASIZE)
+	{
+	    off_t ms;
+	    u_int bs;
+	    if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
+		*retblocks = ms / blocksize;
+		return 0;
+	    }
+	}
+#elif defined(DIOCGDINFO)
+	/* old disklabel interface */
+	part = strlen(file) - 1;
+	if (part >= 0) {
+		ch = file[part];
+		if (isdigit(ch))
+			part = 0;
+		else if (ch >= 'a' && ch <= 'h')
+			part = ch - 'a';
+		else
+			part = -1;
+	}
+	if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
+		pp = &lab.d_partitions[part];
+		if (pp->p_size) {
+			close(fd);
+			*retblocks = pp->p_size / (blocksize / 512);
+			return 0;
+		}
+	}
+#endif /* defined(DIOCG*) */
+#endif /* HAVE_SYS_DISKLABEL_H */
+
+	/*
+	 * OK, we couldn't figure it out by using a specialized ioctl,
+	 * which is generally the best way.  So do binary search to
+	 * find the size of the partition.
+	 */
+	low = 0;
+	for (high = 1024; valid_offset (fd, high); high *= 2)
+		low = high;
+	while (low < high - 1)
+	{
+		const ext2_loff_t mid = (low + high) / 2;
+
+		if (valid_offset (fd, mid))
+			low = mid;
+		else
+			high = mid;
+	}
+	valid_offset (fd, 0);
+	close(fd);
+	size64 = low + 1;
+	if ((sizeof(*retblocks) < sizeof(unsigned long long))
+	    && ((size64 / blocksize) > 0xFFFFFFFF))
+		return EFBIG;
+	*retblocks = size64 / blocksize;
+	return 0;
+}
+
+#endif /* WIN32 */
+
+#ifdef DEBUG
+int main(int argc, char **argv)
+{
+	blk_t	blocks;
+	int	retval;
+	
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s device\n", argv[0]);
+		exit(1);
+	}
+
+	retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
+	if (retval) {
+		com_err(argv[0], retval,
+			"while calling ext2fs_get_device_size");
+		exit(1);
+	}
+	printf("Device %s has %d 1k blocks.\n", argv[1], blocks);
+	exit(0);
+}
+#endif
diff -Naur silo-1.4.11.orig/libext2fs/icount.c silo-1.4.11/libext2fs/icount.c
--- silo-1.4.11.orig/libext2fs/icount.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/icount.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,483 @@
+/*
+ * icount.c --- an efficient inode count abstraction
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * The data storage strategy used by icount relies on the observation
+ * that most inode counts are either zero (for non-allocated inodes),
+ * one (for most files), and only a few that are two or more
+ * (directories and files that are linked to more than one directory).
+ *
+ * Also, e2fsck tends to load the icount data sequentially.
+ *
+ * So, we use an inode bitmap to indicate which inodes have a count of
+ * one, and then use a sorted list to store the counts for inodes
+ * which are greater than one.
+ *
+ * We also use an optional bitmap to indicate which inodes are already
+ * in the sorted list, to speed up the use of this abstraction by
+ * e2fsck's pass 2.  Pass 2 increments inode counts as it finds them,
+ * so this extra bitmap avoids searching the sorted list to see if a
+ * particular inode is on the sorted list already.
+ */
+
+struct ext2_icount_el {
+	ext2_ino_t	ino;
+	__u16	count;
+};
+
+struct ext2_icount {
+	errcode_t		magic;
+	ext2fs_inode_bitmap	single;
+	ext2fs_inode_bitmap	multiple;
+	ext2_ino_t		count;
+	ext2_ino_t		size;
+	ext2_ino_t		num_inodes;
+	ext2_ino_t		cursor;
+	struct ext2_icount_el	*list;
+};
+
+void ext2fs_free_icount(ext2_icount_t icount)
+{
+	if (!icount)
+		return;
+
+	icount->magic = 0;
+	if (icount->list)
+		ext2fs_free_mem(&icount->list);
+	if (icount->single)
+		ext2fs_free_inode_bitmap(icount->single);
+	if (icount->multiple)
+		ext2fs_free_inode_bitmap(icount->multiple);
+	ext2fs_free_mem(&icount);
+}
+
+errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
+				ext2_icount_t hint, ext2_icount_t *ret)
+{
+	ext2_icount_t	icount;
+	errcode_t	retval;
+	size_t		bytes;
+	ext2_ino_t	i;
+
+	if (hint) {
+		EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
+		if (hint->size > size)
+			size = (size_t) hint->size;
+	}
+	
+	retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
+	if (retval)
+		return retval;
+	memset(icount, 0, sizeof(struct ext2_icount));
+
+	retval = ext2fs_allocate_inode_bitmap(fs, 0, 
+					      &icount->single);
+	if (retval)
+		goto errout;
+
+	if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
+		retval = ext2fs_allocate_inode_bitmap(fs, 0, 
+						      &icount->multiple);
+		if (retval)
+			goto errout;
+	} else
+		icount->multiple = 0;
+
+	if (size) {
+		icount->size = size;
+	} else {
+		/*
+		 * Figure out how many special case inode counts we will
+		 * have.  We know we will need one for each directory;
+		 * we also need to reserve some extra room for file links
+		 */
+		retval = ext2fs_get_num_dirs(fs, &icount->size);
+		if (retval)
+			goto errout;
+		icount->size += fs->super->s_inodes_count / 50;
+	}
+	
+	bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
+#if 0
+	printf("Icount allocated %d entries, %d bytes.\n",
+	       icount->size, bytes);
+#endif
+	retval = ext2fs_get_mem(bytes, &icount->list);
+	if (retval)
+		goto errout;
+	memset(icount->list, 0, bytes);
+
+	icount->magic = EXT2_ET_MAGIC_ICOUNT;
+	icount->count = 0;
+	icount->cursor = 0;
+	icount->num_inodes = fs->super->s_inodes_count;
+
+	/*
+	 * Populate the sorted list with those entries which were
+	 * found in the hint icount (since those are ones which will
+	 * likely need to be in the sorted list this time around).
+	 */
+	if (hint) {
+		for (i=0; i < hint->count; i++)
+			icount->list[i].ino = hint->list[i].ino;
+		icount->count = hint->count;
+	}
+
+	*ret = icount;
+	return 0;
+
+errout:
+	ext2fs_free_icount(icount);
+	return(retval);
+}
+
+errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, 
+			       unsigned int size,
+			       ext2_icount_t *ret)
+{
+	return ext2fs_create_icount2(fs, flags, size, 0, ret);
+}
+
+/*
+ * insert_icount_el() --- Insert a new entry into the sorted list at a
+ * 	specified position.
+ */
+static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
+					    ext2_ino_t ino, int pos)
+{
+	struct ext2_icount_el 	*el;
+	errcode_t		retval;
+	ext2_ino_t			new_size = 0;
+	int			num;
+
+	if (icount->count >= icount->size) {
+		if (icount->count) {
+			new_size = icount->list[(unsigned)icount->count-1].ino;
+			new_size = (ext2_ino_t) (icount->count * 
+				((float) icount->num_inodes / new_size));
+		}
+		if (new_size < (icount->size + 100))
+			new_size = icount->size + 100;
+#if 0
+		printf("Reallocating icount %d entries...\n", new_size);
+#endif	
+		retval = ext2fs_resize_mem((size_t) icount->size *
+					   sizeof(struct ext2_icount_el),
+					   (size_t) new_size *
+					   sizeof(struct ext2_icount_el),
+					   &icount->list);
+		if (retval)
+			return 0;
+		icount->size = new_size;
+	}
+	num = (int) icount->count - pos;
+	if (num < 0)
+		return 0;	/* should never happen */
+	if (num) {
+		memmove(&icount->list[pos+1], &icount->list[pos],
+			sizeof(struct ext2_icount_el) * num);
+	}
+	icount->count++;
+	el = &icount->list[pos];
+	el->count = 0;
+	el->ino = ino;
+	return el;
+}
+
+/*
+ * get_icount_el() --- given an inode number, try to find icount
+ * 	information in the sorted list.  If the create flag is set,
+ * 	and we can't find an entry, create one in the sorted list.
+ */
+static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
+					    ext2_ino_t ino, int create)
+{
+	float	range;
+	int	low, high, mid;
+	ext2_ino_t	lowval, highval;
+
+	if (!icount || !icount->list)
+		return 0;
+
+	if (create && ((icount->count == 0) ||
+		       (ino > icount->list[(unsigned)icount->count-1].ino))) {
+		return insert_icount_el(icount, ino, (unsigned) icount->count);
+	}
+	if (icount->count == 0)
+		return 0;
+	
+	if (icount->cursor >= icount->count)
+		icount->cursor = 0;
+	if (ino == icount->list[icount->cursor].ino)
+		return &icount->list[icount->cursor++];
+#if 0
+	printf("Non-cursor get_icount_el: %u\n", ino);
+#endif
+	low = 0;
+	high = (int) icount->count-1;
+	while (low <= high) {
+#if 0
+		mid = (low+high)/2;
+#else
+		if (low == high)
+			mid = low;
+		else {
+			/* Interpolate for efficiency */
+			lowval = icount->list[low].ino;
+			highval = icount->list[high].ino;
+
+			if (ino < lowval)
+				range = 0;
+			else if (ino > highval)
+				range = 1;
+			else 
+				range = ((float) (ino - lowval)) /
+					(highval - lowval);
+			mid = low + ((int) (range * (high-low)));
+		}
+#endif
+		if (ino == icount->list[mid].ino) {
+			icount->cursor = mid+1;
+			return &icount->list[mid];
+		}
+		if (ino < icount->list[mid].ino)
+			high = mid-1;
+		else
+			low = mid+1;
+	}
+	/*
+	 * If we need to create a new entry, it should be right at
+	 * low (where high will be left at low-1).
+	 */
+	if (create)
+		return insert_icount_el(icount, ino, low);
+	return 0;
+}
+
+errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
+{
+	errcode_t	ret = 0;
+	unsigned int	i;
+	const char *bad = "bad icount";
+	
+	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+	if (icount->count > icount->size) {
+		fprintf(out, "%s: count > size\n", bad);
+		return EXT2_ET_INVALID_ARGUMENT;
+	}
+	for (i=1; i < icount->count; i++) {
+		if (icount->list[i-1].ino >= icount->list[i].ino) {
+			fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
+				bad, i-1, icount->list[i-1].ino,
+				i, icount->list[i].ino);
+			ret = EXT2_ET_INVALID_ARGUMENT;
+		}
+	}
+	return ret;
+}
+
+errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
+{
+	struct ext2_icount_el	*el;
+	
+	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+	if (!ino || (ino > icount->num_inodes))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+		*ret = 1;
+		return 0;
+	}
+	if (icount->multiple &&
+	    !ext2fs_test_inode_bitmap(icount->multiple, ino)) {
+		*ret = 0;
+		return 0;
+	}
+	el = get_icount_el(icount, ino, 0);
+	if (!el) {
+		*ret = 0;
+		return 0;
+	}
+	*ret = el->count;
+	return 0;
+}
+
+errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
+				  __u16 *ret)
+{
+	struct ext2_icount_el	*el;
+
+	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+	if (!ino || (ino > icount->num_inodes))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+		/*
+		 * If the existing count is 1, then we know there is
+		 * no entry in the list.
+		 */
+		el = get_icount_el(icount, ino, 1);
+		if (!el)
+			return EXT2_ET_NO_MEMORY;
+		ext2fs_unmark_inode_bitmap(icount->single, ino);
+		el->count = 2;
+	} else if (icount->multiple) {
+		/*
+		 * The count is either zero or greater than 1; if the
+		 * inode is set in icount->multiple, then there should
+		 * be an entry in the list, so find it using
+		 * get_icount_el().
+		 */
+		if (ext2fs_test_inode_bitmap(icount->multiple, ino)) {
+			el = get_icount_el(icount, ino, 1);
+			if (!el)
+				return EXT2_ET_NO_MEMORY;
+			el->count++;
+		} else {
+			/*
+			 * The count was zero; mark the single bitmap
+			 * and return.
+			 */
+		zero_count:
+			ext2fs_mark_inode_bitmap(icount->single, ino);
+			if (ret)
+				*ret = 1;
+			return 0;
+		}
+	} else {
+		/*
+		 * The count is either zero or greater than 1; try to
+		 * find an entry in the list to determine which.
+		 */
+		el = get_icount_el(icount, ino, 0);
+		if (!el) {
+			/* No entry means the count was zero */
+			goto zero_count;
+		}
+		el = get_icount_el(icount, ino, 1);
+		if (!el)
+			return EXT2_ET_NO_MEMORY;
+		el->count++;
+	}
+	if (icount->multiple)
+		ext2fs_mark_inode_bitmap(icount->multiple, ino);
+	if (ret)
+		*ret = el->count;
+	return 0;
+}
+
+errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
+				  __u16 *ret)
+{
+	struct ext2_icount_el	*el;
+
+	if (!ino || (ino > icount->num_inodes))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+	if (ext2fs_test_inode_bitmap(icount->single, ino)) {
+		ext2fs_unmark_inode_bitmap(icount->single, ino);
+		if (icount->multiple)
+			ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+		else {
+			el = get_icount_el(icount, ino, 0);
+			if (el)
+				el->count = 0;
+		}
+		if (ret)
+			*ret = 0;
+		return 0;
+	}
+
+	if (icount->multiple &&
+	    !ext2fs_test_inode_bitmap(icount->multiple, ino))
+		return EXT2_ET_INVALID_ARGUMENT;
+	
+	el = get_icount_el(icount, ino, 0);
+	if (!el || el->count == 0)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	el->count--;
+	if (el->count == 1)
+		ext2fs_mark_inode_bitmap(icount->single, ino);
+	if ((el->count == 0) && icount->multiple)
+		ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+
+	if (ret)
+		*ret = el->count;
+	return 0;
+}
+
+errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
+			      __u16 count)
+{
+	struct ext2_icount_el	*el;
+
+	if (!ino || (ino > icount->num_inodes))
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
+
+	if (count == 1) {
+		ext2fs_mark_inode_bitmap(icount->single, ino);
+		if (icount->multiple)
+			ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+		return 0;
+	}
+	if (count == 0) {
+		ext2fs_unmark_inode_bitmap(icount->single, ino);
+		if (icount->multiple) {
+			/*
+			 * If the icount->multiple bitmap is enabled,
+			 * we can just clear both bitmaps and we're done
+			 */
+			ext2fs_unmark_inode_bitmap(icount->multiple, ino);
+		} else {
+			el = get_icount_el(icount, ino, 0);
+			if (el)
+				el->count = 0;
+		}
+		return 0;
+	}
+
+	/*
+	 * Get the icount element
+	 */
+	el = get_icount_el(icount, ino, 1);
+	if (!el)
+		return EXT2_ET_NO_MEMORY;
+	el->count = count;
+	ext2fs_unmark_inode_bitmap(icount->single, ino);
+	if (icount->multiple)
+		ext2fs_mark_inode_bitmap(icount->multiple, ino);
+	return 0;
+}
+
+ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
+{
+	if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
+		return 0;
+
+	return icount->size;
+}
diff -Naur silo-1.4.11.orig/libext2fs/imager.c silo-1.4.11/libext2fs/imager.c
--- silo-1.4.11.orig/libext2fs/imager.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/imager.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,387 @@
+/*
+ * image.c --- writes out the critical parts of the filesystem as a
+ * 	flat file.
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ *
+ * Note: this uses the POSIX IO interfaces, unlike most of the other
+ * functions in this library.  So sue me.  
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef HAVE_TYPE_SSIZE_T
+typedef int ssize_t;
+#endif
+
+/*
+ * This function returns 1 if the specified block is all zeros
+ */
+static int check_zero_block(char *buf, int blocksize)
+{
+	char	*cp = buf;
+	int	left = blocksize;
+
+	while (left > 0) {
+		if (*cp++)
+			return 0;
+		left--;
+	}
+	return 1;
+}
+
+/*
+ * Write the inode table out as a single block.
+ */
+#define BUF_BLOCKS	32
+
+errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
+{
+	unsigned int	group, left, c, d;
+	char		*buf, *cp;
+	blk_t		blk;
+	ssize_t		actual;
+	errcode_t	retval;
+
+	buf = malloc(fs->blocksize * BUF_BLOCKS);
+	if (!buf)
+		return ENOMEM;
+	
+	for (group = 0; group < fs->group_desc_count; group++) {
+		blk = fs->group_desc[(unsigned)group].bg_inode_table;
+		if (!blk)
+			return EXT2_ET_MISSING_INODE_TABLE;
+		left = fs->inode_blocks_per_group;
+		while (left) {
+			c = BUF_BLOCKS;
+			if (c > left)
+				c = left;
+			retval = io_channel_read_blk(fs->io, blk, c, buf);
+			if (retval)
+				goto errout;
+			cp = buf;
+			while (c) {
+				if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
+					d = c;
+					goto skip_sparse;
+				}
+				/* Skip zero blocks */
+				if (check_zero_block(cp, fs->blocksize)) {
+					c--;
+					blk++;
+					left--;
+					cp += fs->blocksize;
+					lseek(fd, fs->blocksize, SEEK_CUR);
+					continue;
+				}
+				/* Find non-zero blocks */
+				for (d=1; d < c; d++) {
+					if (check_zero_block(cp + d*fs->blocksize, fs->blocksize))
+						break;
+				}
+			skip_sparse:
+				actual = write(fd, cp, fs->blocksize * d);
+				if (actual == -1) {
+					retval = errno;
+					goto errout;
+				}
+				if (actual != (ssize_t) (fs->blocksize * d)) {
+					retval = EXT2_ET_SHORT_WRITE;
+					goto errout;
+				}
+				blk += d;
+				left -= d;
+				cp += fs->blocksize * d;
+				c -= d;
+			}
+		}
+	}
+	retval = 0;
+
+errout:
+	free(buf);
+	return retval;
+}
+
+/*
+ * Read in the inode table and stuff it into place
+ */
+errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, 
+				  int flags EXT2FS_ATTR((unused)))
+{
+	unsigned int	group, c, left;
+	char		*buf;
+	blk_t		blk;
+	ssize_t		actual;
+	errcode_t	retval;
+
+	buf = malloc(fs->blocksize * BUF_BLOCKS);
+	if (!buf)
+		return ENOMEM;
+	
+	for (group = 0; group < fs->group_desc_count; group++) {
+		blk = fs->group_desc[(unsigned)group].bg_inode_table;
+		if (!blk) {
+			retval = EXT2_ET_MISSING_INODE_TABLE;
+			goto errout;
+		}
+		left = fs->inode_blocks_per_group;
+		while (left) {
+			c = BUF_BLOCKS;
+			if (c > left)
+				c = left;
+			actual = read(fd, buf, fs->blocksize * c);
+			if (actual == -1) {
+				retval = errno;
+				goto errout;
+			}
+			if (actual != (ssize_t) (fs->blocksize * c)) {
+				retval = EXT2_ET_SHORT_READ;
+				goto errout;
+			}
+			retval = io_channel_write_blk(fs->io, blk, c, buf);
+			if (retval)
+				goto errout;
+			
+			blk += c;
+			left -= c;
+		}
+	}
+	retval = ext2fs_flush_icache(fs);
+
+errout:
+	free(buf);
+	return retval;
+}
+
+/*
+ * Write out superblock and group descriptors
+ */
+errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, 
+				   int flags EXT2FS_ATTR((unused)))
+{
+	char		*buf, *cp;
+	ssize_t		actual;
+	errcode_t	retval;
+
+	buf = malloc(fs->blocksize);
+	if (!buf)
+		return ENOMEM;
+
+	/*
+	 * Write out the superblock
+	 */
+	memset(buf, 0, fs->blocksize);
+	memcpy(buf, fs->super, SUPERBLOCK_SIZE);
+	actual = write(fd, buf, fs->blocksize);
+	if (actual == -1) {
+		retval = errno;
+		goto errout;
+	}
+	if (actual != (ssize_t) fs->blocksize) {
+		retval = EXT2_ET_SHORT_WRITE;
+		goto errout;
+	}
+
+	/*
+	 * Now write out the block group descriptors
+	 */
+	cp = (char *) fs->group_desc;
+	actual = write(fd, cp, fs->blocksize * fs->desc_blocks);
+	if (actual == -1) {
+		retval = errno;
+		goto errout;
+	}
+	if (actual != (ssize_t) (fs->blocksize * fs->desc_blocks)) {
+		retval = EXT2_ET_SHORT_WRITE;
+		goto errout;
+	}
+	
+	retval = 0;
+
+errout:
+	free(buf);
+	return retval;
+}
+
+/*
+ * Read the superblock and group descriptors and overwrite them.
+ */
+errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, 
+				  int flags EXT2FS_ATTR((unused)))
+{
+	char		*buf;
+	ssize_t		actual, size;
+	errcode_t	retval;
+
+	size = fs->blocksize * (fs->group_desc_count + 1);
+	buf = malloc(size);
+	if (!buf)
+		return ENOMEM;
+
+	/*
+	 * Read it all in.
+	 */
+	actual = read(fd, buf, size);
+	if (actual == -1) {
+		retval = errno;
+		goto errout;
+	}
+	if (actual != size) {
+		retval = EXT2_ET_SHORT_READ;
+		goto errout;
+	}
+
+	/*
+	 * Now copy in the superblock and group descriptors
+	 */
+	memcpy(fs->super, buf, SUPERBLOCK_SIZE);
+
+	memcpy(fs->group_desc, buf + fs->blocksize,
+	       fs->blocksize * fs->group_desc_count);
+
+	retval = 0;
+
+errout:
+	free(buf);
+	return retval;
+}
+
+/*
+ * Write the block/inode bitmaps.
+ */
+errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
+{
+	char		*ptr;
+	int		c, size;
+	char		zero_buf[1024];
+	ssize_t		actual;
+	errcode_t	retval;
+
+	if (flags & IMAGER_FLAG_INODEMAP) {
+		if (!fs->inode_map) {
+			retval = ext2fs_read_inode_bitmap(fs);
+			if (retval)
+				return retval;
+		}
+		ptr = fs->inode_map->bitmap;
+		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
+	} else {
+		if (!fs->block_map) {
+			retval = ext2fs_read_block_bitmap(fs);
+			if (retval)
+				return retval;
+		}
+		ptr = fs->block_map->bitmap;
+		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	}
+	size = size * fs->group_desc_count;
+
+	actual = write(fd, ptr, size);
+	if (actual == -1) {
+		retval = errno;
+		goto errout;
+	}
+	if (actual != size) {
+		retval = EXT2_ET_SHORT_WRITE;
+		goto errout;
+	}
+	size = size % fs->blocksize;
+	memset(zero_buf, 0, sizeof(zero_buf));
+	if (size) {
+		size = fs->blocksize - size;
+		while (size) {
+			c = size;
+			if (c > (int) sizeof(zero_buf))
+				c = sizeof(zero_buf);
+			actual = write(fd, zero_buf, c);
+			if (actual == -1) {
+				retval = errno;
+				goto errout;
+			}
+			if (actual != c) {
+				retval = EXT2_ET_SHORT_WRITE;
+				goto errout;
+			}
+			size -= c;
+		}
+	}
+	retval = 0;
+errout:
+	return (retval);
+}
+
+
+/*
+ * Read the block/inode bitmaps.
+ */
+errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
+{
+	char		*ptr, *buf = 0;
+	int		size;
+	ssize_t		actual;
+	errcode_t	retval;
+
+	if (flags & IMAGER_FLAG_INODEMAP) {
+		if (!fs->inode_map) {
+			retval = ext2fs_read_inode_bitmap(fs);
+			if (retval)
+				return retval;
+		}
+		ptr = fs->inode_map->bitmap;
+		size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
+	} else {
+		if (!fs->block_map) {
+			retval = ext2fs_read_block_bitmap(fs);
+			if (retval)
+				return retval;
+		}
+		ptr = fs->block_map->bitmap;
+		size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	}
+	size = size * fs->group_desc_count;
+
+	buf = malloc(size);
+	if (!buf)
+		return ENOMEM;
+
+	actual = read(fd, buf, size);
+	if (actual == -1) {
+		retval = errno;
+		goto errout;
+	}
+	if (actual != size) {
+		retval = EXT2_ET_SHORT_WRITE;
+		goto errout;
+	}
+	memcpy(ptr, buf, size);
+	
+	retval = 0;
+errout:
+	if (buf)
+		free(buf);
+	return (retval);
+}
diff -Naur silo-1.4.11.orig/libext2fs/ind_block.c silo-1.4.11/libext2fs/ind_block.c
--- silo-1.4.11.orig/libext2fs/ind_block.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ind_block.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,66 @@
+/*
+ * ind_block.c --- indirect block I/O routines
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 
+ * 	2001, 2002, 2003, 2004, 2005 by  Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+	errcode_t	retval;
+	blk_t		*block_nr;
+	int		i;
+	int		limit = fs->blocksize >> 2;
+
+	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
+	    (fs->io != fs->image_io))
+		memset(buf, 0, fs->blocksize);
+	else {
+		retval = io_channel_read_blk(fs->io, blk, 1, buf);
+		if (retval)
+			return retval;
+	}
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_READ)) {
+		block_nr = (blk_t *) buf;
+		for (i = 0; i < limit; i++, block_nr++)
+			*block_nr = ext2fs_swab32(*block_nr);
+	}
+#endif
+	return 0;
+}
+
+errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
+{
+	blk_t		*block_nr;
+	int		i;
+	int		limit = fs->blocksize >> 2;
+
+	if (fs->flags & EXT2_FLAG_IMAGE_FILE)
+		return 0;
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if (fs->flags & (EXT2_FLAG_SWAP_BYTES | EXT2_FLAG_SWAP_BYTES_WRITE)) {
+		block_nr = (blk_t *) buf;
+		for (i = 0; i < limit; i++, block_nr++)
+			*block_nr = ext2fs_swab32(*block_nr);
+	}
+#endif
+	return io_channel_write_blk(fs->io, blk, 1, buf);
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/initialize.c silo-1.4.11/libext2fs/initialize.c
--- silo-1.4.11.orig/libext2fs/initialize.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/initialize.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,387 @@
+/*
+ * initialize.c --- initialize a filesystem handle given superblock
+ * 	parameters.  Used by mke2fs when initializing a filesystem.
+ * 
+ * Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#if defined(__linux__)    &&	defined(EXT2_OS_LINUX)
+#define CREATOR_OS EXT2_OS_LINUX
+#else
+#if defined(__GNU__)     &&	defined(EXT2_OS_HURD)
+#define CREATOR_OS EXT2_OS_HURD
+#else
+#if defined(__FreeBSD__) &&	defined(EXT2_OS_FREEBSD)
+#define CREATOR_OS EXT2_OS_FREEBSD
+#else
+#if defined(LITES) 	   &&	defined(EXT2_OS_LITES)
+#define CREATOR_OS EXT2_OS_LITES
+#else
+#define CREATOR_OS EXT2_OS_LINUX /* by default */
+#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
+#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
+#endif /* defined(__GNU__)     && defined(EXT2_OS_HURD) */
+#endif /* defined(__linux__)   && defined(EXT2_OS_LINUX) */
+	
+/*
+ * 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 (86400L * 180L)
+
+/*
+ * Calculate the number of GDT blocks to reserve for online filesystem growth.
+ * The absolute maximum number of GDT blocks we can reserve is determined by
+ * the number of block pointers that can fit into a single block.
+ */
+static int calc_reserved_gdt_blocks(ext2_filsys fs)
+{
+	struct ext2_super_block *sb = fs->super;
+	unsigned long bpg = sb->s_blocks_per_group;
+	unsigned int gdpb = fs->blocksize / sizeof(struct ext2_group_desc);
+	unsigned long max_blocks = 0xffffffff;
+	unsigned long rsv_groups;
+	int rsv_gdb;
+
+	/* We set it at 1024x the current filesystem size, or
+	 * the upper block count limit (2^32), whichever is lower.
+	 */
+	if (sb->s_blocks_count < max_blocks / 1024)
+		max_blocks = sb->s_blocks_count * 1024;
+	rsv_groups = (max_blocks - sb->s_first_data_block + bpg - 1) / bpg;
+	rsv_gdb = (rsv_groups + gdpb - 1) / gdpb - fs->desc_blocks;
+	if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
+		rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
+#ifdef RES_GDT_DEBUG
+	printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n",
+	       max_blocks, rsv_groups, rsv_gdb);
+#endif
+
+	return rsv_gdb;
+}
+
+errcode_t ext2fs_initialize(const char *name, int flags,
+			    struct ext2_super_block *param,
+			    io_manager manager, ext2_filsys *ret_fs)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+	struct ext2_super_block *super;
+	int		frags_per_block;
+	unsigned int	rem;
+	unsigned int	overhead = 0;
+	blk_t		group_block;
+	unsigned int	ipg;
+	dgrp_t		i;
+	blk_t		numblocks;
+	int		rsv_gdt;
+	char		*buf;
+
+	if (!param || !param->s_blocks_count)
+		return EXT2_ET_INVALID_ARGUMENT;
+	
+	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+	if (retval)
+		return retval;
+	
+	memset(fs, 0, sizeof(struct struct_ext2_filsys));
+	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
+	fs->flags = flags | EXT2_FLAG_RW;
+	fs->umask = 022;
+#ifdef WORDS_BIGENDIAN
+	fs->flags |= EXT2_FLAG_SWAP_BYTES;
+#endif
+	retval = manager->open(name, IO_FLAG_RW, &fs->io);
+	if (retval)
+		goto cleanup;
+	fs->image_io = fs->io;
+	fs->io->app_data = fs;
+	retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
+	if (retval)
+		goto cleanup;
+
+	strcpy(fs->device_name, name);
+	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
+	if (retval)
+		goto cleanup;
+	fs->super = super;
+
+	memset(super, 0, SUPERBLOCK_SIZE);
+
+#define set_field(field, default) (super->field = param->field ? \
+				   param->field : (default))
+
+	super->s_magic = EXT2_SUPER_MAGIC;
+	super->s_state = EXT2_VALID_FS;
+
+	set_field(s_log_block_size, 0);	/* default blocksize: 1024 bytes */
+	set_field(s_log_frag_size, 0); /* default fragsize: 1024 bytes */
+	set_field(s_first_data_block, super->s_log_block_size ? 0 : 1);
+	set_field(s_max_mnt_count, EXT2_DFL_MAX_MNT_COUNT);
+	set_field(s_errors, EXT2_ERRORS_DEFAULT);
+	set_field(s_feature_compat, 0);
+	set_field(s_feature_incompat, 0);
+	set_field(s_feature_ro_compat, 0);
+	set_field(s_first_meta_bg, 0);
+	if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
+		retval = EXT2_ET_UNSUPP_FEATURE;
+		goto cleanup;
+	}
+	if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
+		retval = EXT2_ET_RO_UNSUPP_FEATURE;
+		goto cleanup;
+	}
+
+	set_field(s_rev_level, EXT2_GOOD_OLD_REV);
+	if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
+		set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
+		set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
+	}
+
+	set_field(s_checkinterval, EXT2_DFL_CHECKINTERVAL);
+	super->s_mkfs_time = super->s_lastcheck = time(NULL);
+
+	super->s_creator_os = CREATOR_OS;
+
+	fs->blocksize = EXT2_BLOCK_SIZE(super);
+	fs->fragsize = EXT2_FRAG_SIZE(super);
+	frags_per_block = fs->blocksize / fs->fragsize;
+
+	/* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */
+	set_field(s_blocks_per_group, fs->blocksize * 8);
+	if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
+		super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
+	super->s_frags_per_group = super->s_blocks_per_group * frags_per_block;
+	
+	super->s_blocks_count = param->s_blocks_count;
+	super->s_r_blocks_count = param->s_r_blocks_count;
+	if (super->s_r_blocks_count >= param->s_blocks_count) {
+		retval = EXT2_ET_INVALID_ARGUMENT;
+		goto cleanup;
+	}
+
+	/*
+	 * If we're creating an external journal device, we don't need
+	 * to bother with the rest.
+	 */
+	if (super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+		fs->group_desc_count = 0;
+		ext2fs_mark_super_dirty(fs);
+		*ret_fs = fs;
+		return 0;
+	}
+
+retry:
+	fs->group_desc_count = (super->s_blocks_count -
+				super->s_first_data_block +
+				EXT2_BLOCKS_PER_GROUP(super) - 1)
+		/ EXT2_BLOCKS_PER_GROUP(super);
+	if (fs->group_desc_count == 0) {
+		retval = EXT2_ET_TOOSMALL;
+		goto cleanup;
+	}
+	fs->desc_blocks = (fs->group_desc_count +
+			   EXT2_DESC_PER_BLOCK(super) - 1)
+		/ EXT2_DESC_PER_BLOCK(super);
+
+	i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
+	set_field(s_inodes_count, super->s_blocks_count / i);
+
+	/*
+	 * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
+	 * that we have enough inodes for the filesystem(!)
+	 */
+	if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
+		super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
+	
+	/*
+	 * There should be at least as many inodes as the user
+	 * requested.  Figure out how many inodes per group that
+	 * should be.  But make sure that we don't allocate more than
+	 * one bitmap's worth of inodes each group.
+	 */
+	ipg = (super->s_inodes_count + fs->group_desc_count - 1) /
+		fs->group_desc_count;
+	if (ipg > fs->blocksize * 8) {
+		if (super->s_blocks_per_group >= 256) {
+			/* Try again with slightly different parameters */
+			super->s_blocks_per_group -= 8;
+			super->s_blocks_count = param->s_blocks_count;
+			super->s_frags_per_group = super->s_blocks_per_group *
+				frags_per_block;
+			goto retry;
+		} else
+			return EXT2_ET_TOO_MANY_INODES;
+	}
+
+	if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
+		ipg = EXT2_MAX_INODES_PER_GROUP(super);
+
+	super->s_inodes_per_group = ipg;
+	if (super->s_inodes_count > ipg * fs->group_desc_count)
+		super->s_inodes_count = ipg * fs->group_desc_count;
+
+	/*
+	 * Make sure the number of inodes per group completely fills
+	 * the inode table blocks in the descriptor.  If not, add some
+	 * additional inodes/group.  Waste not, want not...
+	 */
+	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+					EXT2_INODE_SIZE(super)) +
+				       EXT2_BLOCK_SIZE(super) - 1) /
+				      EXT2_BLOCK_SIZE(super));
+	super->s_inodes_per_group = ((fs->inode_blocks_per_group *
+				      EXT2_BLOCK_SIZE(super)) /
+				     EXT2_INODE_SIZE(super));
+	/*
+	 * Finally, make sure the number of inodes per group is a
+	 * multiple of 8.  This is needed to simplify the bitmap
+	 * splicing code.
+	 */
+	super->s_inodes_per_group &= ~7;
+	fs->inode_blocks_per_group = (((super->s_inodes_per_group *
+					EXT2_INODE_SIZE(super)) +
+				       EXT2_BLOCK_SIZE(super) - 1) /
+				      EXT2_BLOCK_SIZE(super));
+
+	/*
+	 * adjust inode count to reflect the adjusted inodes_per_group
+	 */
+	super->s_inodes_count = super->s_inodes_per_group *
+		fs->group_desc_count;
+	super->s_free_inodes_count = super->s_inodes_count;
+
+	/*
+	 * check the number of reserved group descriptor table blocks
+	 */
+	if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE)
+		rsv_gdt = calc_reserved_gdt_blocks(fs);
+	else
+		rsv_gdt = 0;
+	set_field(s_reserved_gdt_blocks, rsv_gdt);
+	if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
+		retval = EXT2_ET_RES_GDT_BLOCKS;
+		goto cleanup;
+	}
+
+	/*
+	 * Overhead is the number of bookkeeping blocks per group.  It
+	 * includes the superblock backup, the group descriptor
+	 * backups, the inode bitmap, the block bitmap, and the inode
+	 * table.
+	 */
+
+	overhead = (int) (2 + fs->inode_blocks_per_group);
+
+	if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
+		overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
+
+	/* This can only happen if the user requested too many inodes */
+	if (overhead > super->s_blocks_per_group)
+		return EXT2_ET_TOO_MANY_INODES;
+
+	/*
+	 * See if the last group is big enough to support the
+	 * necessary data structures.  If not, we need to get rid of
+	 * it.
+	 */
+	rem = ((super->s_blocks_count - super->s_first_data_block) %
+	       super->s_blocks_per_group);
+	if ((fs->group_desc_count == 1) && rem && (rem < overhead))
+		return EXT2_ET_TOOSMALL;
+	if (rem && (rem < overhead+50)) {
+		super->s_blocks_count -= rem;
+		goto retry;
+	}
+
+	/*
+	 * At this point we know how big the filesystem will be.  So
+	 * we can do any and all allocations that depend on the block
+	 * count.
+	 */
+
+	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
+	if (retval)
+		goto cleanup;
+	
+	sprintf(buf, "block bitmap for %s", fs->device_name);
+	retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
+	if (retval)
+		goto cleanup;
+	
+	sprintf(buf, "inode bitmap for %s", fs->device_name);
+	retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
+	if (retval)
+		goto cleanup;
+
+	ext2fs_free_mem(&buf);
+
+	retval = ext2fs_get_mem((size_t) fs->desc_blocks * fs->blocksize,
+				&fs->group_desc);
+	if (retval)
+		goto cleanup;
+
+	memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
+
+	/*
+	 * Reserve the superblock and group descriptors for each
+	 * group, and fill in the correct group statistics for group.
+	 * Note that although the block bitmap, inode bitmap, and
+	 * inode table have not been allocated (and in fact won't be
+	 * by this routine), they are accounted for nevertheless.
+	 */
+	group_block = super->s_first_data_block;
+	super->s_free_blocks_count = 0;
+	for (i = 0; i < fs->group_desc_count; i++) {
+		numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
+
+		super->s_free_blocks_count += numblocks;
+		fs->group_desc[i].bg_free_blocks_count = numblocks;
+		fs->group_desc[i].bg_free_inodes_count =
+			fs->super->s_inodes_per_group;
+		fs->group_desc[i].bg_used_dirs_count = 0;
+		
+		group_block += super->s_blocks_per_group;
+	}
+	
+	ext2fs_mark_super_dirty(fs);
+	ext2fs_mark_bb_dirty(fs);
+	ext2fs_mark_ib_dirty(fs);
+	
+	io_channel_set_blksize(fs->io, fs->blocksize);
+
+	*ret_fs = fs;
+	return 0;
+cleanup:
+	ext2fs_free(fs);
+	return retval;
+}
diff -Naur silo-1.4.11.orig/libext2fs/inline.c silo-1.4.11/libext2fs/inline.c
--- silo-1.4.11.orig/libext2fs/inline.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/inline.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,32 @@
+/*
+ * inline.c --- Includes the inlined functions defined in the header
+ * 	files as standalone functions, in case the application program
+ * 	is compiled with inlining turned off.
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#define INCLUDE_INLINE_FUNCS
+#include "ext2fs.h"
+
diff -Naur silo-1.4.11.orig/libext2fs/inode.c silo-1.4.11/libext2fs/inode.c
--- silo-1.4.11.orig/libext2fs/inode.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/inode.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,794 @@
+/*
+ * inode.c --- utility routines to read and write inodes
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+#include "e2image.h"
+
+struct ext2_struct_inode_scan {
+	errcode_t		magic;
+	ext2_filsys		fs;
+	ext2_ino_t		current_inode;
+	blk_t			current_block;
+	dgrp_t			current_group;
+	ext2_ino_t		inodes_left;
+	blk_t			blocks_left;
+	dgrp_t			groups_left;
+	blk_t			inode_buffer_blocks;
+	char *			inode_buffer;
+	int			inode_size;
+	char *			ptr;
+	int			bytes_left;
+	char			*temp_buffer;
+	errcode_t		(*done_group)(ext2_filsys fs,
+					      ext2_inode_scan scan,
+					      dgrp_t group,
+					      void * priv_data);
+	void *			done_group_data;
+	int			bad_block_ptr;
+	int			scan_flags;
+	int			reserved[6];
+};
+
+/*
+ * This routine flushes the icache, if it exists.
+ */
+errcode_t ext2fs_flush_icache(ext2_filsys fs)
+{
+	int	i;
+	
+	if (!fs->icache)
+		return 0;
+
+	for (i=0; i < fs->icache->cache_size; i++)
+		fs->icache->cache[i].ino = 0;
+
+	fs->icache->buffer_blk = 0;
+	return 0;
+}
+
+static errcode_t create_icache(ext2_filsys fs)
+{
+	errcode_t	retval;
+	
+	if (fs->icache)
+		return 0;
+	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache);
+	if (retval)
+		return retval;
+
+	memset(fs->icache, 0, sizeof(struct ext2_inode_cache));
+	retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer);
+	if (retval) {
+		ext2fs_free_mem(&fs->icache);
+		return retval;
+	}
+	fs->icache->buffer_blk = 0;
+	fs->icache->cache_last = -1;
+	fs->icache->cache_size = 4;
+	fs->icache->refcount = 1;
+	retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache_ent)
+				* fs->icache->cache_size,
+				&fs->icache->cache);
+	if (retval) {
+		ext2fs_free_mem(&fs->icache->buffer);
+		ext2fs_free_mem(&fs->icache);
+		return retval;
+	}
+	ext2fs_flush_icache(fs);
+	return 0;
+}
+
+errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks,
+				 ext2_inode_scan *ret_scan)
+{
+	ext2_inode_scan	scan;
+	errcode_t	retval;
+	errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks);
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	/*
+	 * If fs->badblocks isn't set, then set it --- since the inode
+	 * scanning functions require it.
+	 */
+	if (fs->badblocks == 0) {
+		/*
+		 * Temporarly save fs->get_blocks and set it to zero,
+		 * for compatibility with old e2fsck's.
+		 */
+		save_get_blocks = fs->get_blocks;
+		fs->get_blocks = 0;
+		retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
+		if (retval && fs->badblocks) {
+			ext2fs_badblocks_list_free(fs->badblocks);
+			fs->badblocks = 0;
+		}
+		fs->get_blocks = save_get_blocks;
+	}
+
+	retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan);
+	if (retval)
+		return retval;
+	memset(scan, 0, sizeof(struct ext2_struct_inode_scan));
+
+	scan->magic = EXT2_ET_MAGIC_INODE_SCAN;
+	scan->fs = fs;
+	scan->inode_size = EXT2_INODE_SIZE(fs->super);
+	scan->bytes_left = 0;
+	scan->current_group = 0;
+	scan->groups_left = fs->group_desc_count - 1;
+	scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : 8;
+	scan->current_block = scan->fs->
+		group_desc[scan->current_group].bg_inode_table;
+	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+	scan->blocks_left = scan->fs->inode_blocks_per_group;
+	retval = ext2fs_get_mem((size_t) (scan->inode_buffer_blocks * 
+					  fs->blocksize),
+				&scan->inode_buffer);
+	scan->done_group = 0;
+	scan->done_group_data = 0;
+	scan->bad_block_ptr = 0;
+	if (retval) {
+		ext2fs_free_mem(&scan);
+		return retval;
+	}
+	retval = ext2fs_get_mem(scan->inode_size, &scan->temp_buffer);
+	if (retval) {
+		ext2fs_free_mem(&scan->inode_buffer);
+		ext2fs_free_mem(&scan);
+		return retval;
+	}
+	if (scan->fs->badblocks && scan->fs->badblocks->num)
+		scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS;
+	*ret_scan = scan;
+	return 0;
+}
+
+void ext2fs_close_inode_scan(ext2_inode_scan scan)
+{
+	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+		return;
+	
+	ext2fs_free_mem(&scan->inode_buffer);
+	scan->inode_buffer = NULL;
+	ext2fs_free_mem(&scan->temp_buffer);
+	scan->temp_buffer = NULL;
+	ext2fs_free_mem(&scan);
+	return;
+}
+
+void ext2fs_set_inode_callback(ext2_inode_scan scan,
+			       errcode_t (*done_group)(ext2_filsys fs,
+						       ext2_inode_scan scan,
+						       dgrp_t group,
+						       void * priv_data),
+			       void *done_group_data)
+{
+	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+		return;
+	
+	scan->done_group = done_group;
+	scan->done_group_data = done_group_data;
+}
+
+int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags,
+			    int clear_flags)
+{
+	int	old_flags;
+
+	if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN))
+		return 0;
+
+	old_flags = scan->scan_flags;
+	scan->scan_flags &= ~clear_flags;
+	scan->scan_flags |= set_flags;
+	return old_flags;
+}
+
+/*
+ * This function is called by ext2fs_get_next_inode when it needs to
+ * get ready to read in a new blockgroup.
+ */
+static errcode_t get_next_blockgroup(ext2_inode_scan scan)
+{
+	scan->current_group++;
+	scan->groups_left--;
+			
+	scan->current_block = scan->fs->
+		group_desc[scan->current_group].bg_inode_table;
+
+	scan->current_inode = scan->current_group *
+		EXT2_INODES_PER_GROUP(scan->fs->super);
+
+	scan->bytes_left = 0;
+	scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super);
+	scan->blocks_left = scan->fs->inode_blocks_per_group;
+	return 0;
+}
+
+errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan,
+					    int	group)
+{
+	scan->current_group = group - 1;
+	scan->groups_left = scan->fs->group_desc_count - group;
+	return get_next_blockgroup(scan);
+}
+
+/*
+ * This function is called by get_next_blocks() to check for bad
+ * blocks in the inode table.
+ *
+ * This function assumes that badblocks_list->list is sorted in
+ * increasing order.
+ */
+static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan,
+					    blk_t *num_blocks)
+{
+	blk_t	blk = scan->current_block;
+	badblocks_list	bb = scan->fs->badblocks;
+
+	/*
+	 * If the inode table is missing, then obviously there are no
+	 * bad blocks.  :-)
+	 */
+	if (blk == 0)
+		return 0;
+
+	/*
+	 * If the current block is greater than the bad block listed
+	 * in the bad block list, then advance the pointer until this
+	 * is no longer the case.  If we run out of bad blocks, then
+	 * we don't need to do any more checking!
+	 */
+	while (blk > bb->list[scan->bad_block_ptr]) {
+		if (++scan->bad_block_ptr >= bb->num) {
+			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+			return 0;
+		}
+	}
+
+	/*
+	 * If the current block is equal to the bad block listed in
+	 * the bad block list, then handle that one block specially.
+	 * (We could try to handle runs of bad blocks, but that
+	 * only increases CPU efficiency by a small amount, at the
+	 * expense of a huge expense of code complexity, and for an
+	 * uncommon case at that.)
+	 */
+	if (blk == bb->list[scan->bad_block_ptr]) {
+		scan->scan_flags |= EXT2_SF_BAD_INODE_BLK;
+		*num_blocks = 1;
+		if (++scan->bad_block_ptr >= bb->num)
+			scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS;
+		return 0;
+	}
+
+	/*
+	 * If there is a bad block in the range that we're about to
+	 * read in, adjust the number of blocks to read so that we we
+	 * don't read in the bad block.  (Then the next block to read
+	 * will be the bad block, which is handled in the above case.)
+	 */
+	if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr])
+		*num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk);
+
+	return 0;
+}
+
+/*
+ * This function is called by ext2fs_get_next_inode when it needs to
+ * read in more blocks from the current blockgroup's inode table.
+ */
+static errcode_t get_next_blocks(ext2_inode_scan scan)
+{
+	blk_t		num_blocks;
+	errcode_t	retval;
+
+	/*
+	 * Figure out how many blocks to read; we read at most
+	 * inode_buffer_blocks, and perhaps less if there aren't that
+	 * many blocks left to read.
+	 */
+	num_blocks = scan->inode_buffer_blocks;
+	if (num_blocks > scan->blocks_left)
+		num_blocks = scan->blocks_left;
+
+	/*
+	 * If the past block "read" was a bad block, then mark the
+	 * left-over extra bytes as also being bad.
+	 */
+	if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) {
+		if (scan->bytes_left)
+			scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES;
+		scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK;
+	}
+
+	/*
+	 * Do inode bad block processing, if necessary.
+	 */
+	if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) {
+		retval = check_for_inode_bad_blocks(scan, &num_blocks);
+		if (retval)
+			return retval;
+	}
+		
+	if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) ||
+	    (scan->current_block == 0)) {
+		memset(scan->inode_buffer, 0,
+		       (size_t) num_blocks * scan->fs->blocksize);
+	} else {
+		retval = io_channel_read_blk(scan->fs->io,
+					     scan->current_block,
+					     (int) num_blocks,
+					     scan->inode_buffer);
+		if (retval)
+			return EXT2_ET_NEXT_INODE_READ;
+	}
+	scan->ptr = scan->inode_buffer;
+	scan->bytes_left = num_blocks * scan->fs->blocksize;
+
+	scan->blocks_left -= num_blocks;
+	if (scan->current_block)
+		scan->current_block += num_blocks;
+	return 0;
+}
+
+#if 0
+/*
+ * Returns 1 if the entire inode_buffer has a non-zero size and
+ * contains all zeros.  (Not just deleted inodes, since that means
+ * that part of the inode table was used at one point; we want all
+ * zeros, which means that the inode table is pristine.)
+ */
+static inline int is_empty_scan(ext2_inode_scan scan)
+{
+	int	i;
+	
+	if (scan->bytes_left == 0)
+		return 0;
+
+	for (i=0; i < scan->bytes_left; i++)
+		if (scan->ptr[i])
+			return 0;
+	return 1;
+}
+#endif
+
+errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino,
+				     struct ext2_inode *inode, int bufsize)
+{
+	errcode_t	retval;
+	int		extra_bytes = 0;
+	
+	EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN);
+
+	/*
+	 * Do we need to start reading a new block group?
+	 */
+	if (scan->inodes_left <= 0) {
+	force_new_group:
+		if (scan->done_group) {
+			retval = (scan->done_group)
+				(scan->fs, scan, scan->current_group,
+				 scan->done_group_data);
+			if (retval)
+				return retval;
+		}
+		if (scan->groups_left <= 0) {
+			*ino = 0;
+			return 0;
+		}
+		retval = get_next_blockgroup(scan);
+		if (retval)
+			return retval;
+	}
+	/*
+	 * This is done outside the above if statement so that the
+	 * check can be done for block group #0.
+	 */
+	if (scan->current_block == 0) {
+		if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) {
+			goto force_new_group;
+		} else
+			return EXT2_ET_MISSING_INODE_TABLE;
+	}
+	
+
+	/*
+	 * Have we run out of space in the inode buffer?  If so, we
+	 * need to read in more blocks.
+	 */
+	if (scan->bytes_left < scan->inode_size) {
+		memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left);
+		extra_bytes = scan->bytes_left;
+
+		retval = get_next_blocks(scan);
+		if (retval)
+			return retval;
+#if 0
+		/*
+		 * XXX test  Need check for used inode somehow.
+		 * (Note: this is hard.)
+		 */
+		if (is_empty_scan(scan))
+			goto force_new_group;
+#endif
+	}
+
+	retval = 0;
+	if (extra_bytes) {
+		memcpy(scan->temp_buffer+extra_bytes, scan->ptr,
+		       scan->inode_size - extra_bytes);
+		scan->ptr += scan->inode_size - extra_bytes;
+		scan->bytes_left -= scan->inode_size - extra_bytes;
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+			ext2fs_swap_inode_full(scan->fs, 
+				(struct ext2_inode_large *) inode,
+				(struct ext2_inode_large *) scan->temp_buffer, 
+				0, bufsize);
+		else
+#endif
+			*inode = *((struct ext2_inode *) scan->temp_buffer);
+		if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES)
+			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
+		scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES;
+	} else {
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if ((scan->fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+		    (scan->fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+			ext2fs_swap_inode_full(scan->fs, 
+				(struct ext2_inode_large *) inode,
+				(struct ext2_inode_large *) scan->ptr,
+				0, bufsize);
+		else
+#endif
+			memcpy(inode, scan->ptr, bufsize);
+		scan->ptr += scan->inode_size;
+		scan->bytes_left -= scan->inode_size;
+		if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK)
+			retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE;
+	}
+
+	scan->inodes_left--;
+	scan->current_inode++;
+	*ino = scan->current_inode;
+	return retval;
+}
+
+errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino,
+				struct ext2_inode *inode)
+{
+	return ext2fs_get_next_inode_full(scan, ino, inode,
+						sizeof(struct ext2_inode));
+}
+
+/*
+ * Functions to read and write a single inode.
+ */
+errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino,
+				 struct ext2_inode * inode, int bufsize)
+{
+	unsigned long 	group, block, block_nr, offset;
+	char 		*ptr;
+	errcode_t	retval;
+	int 		clen, i, inodes_per_block, length;
+	io_channel	io;
+
+	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;
+	}
+	/* Create inode cache if not present */
+	if (!fs->icache) {
+		retval = create_icache(fs);
+		if (retval)
+			return retval;
+	}
+	/* Check to see if it's in the inode cache */
+	if (bufsize == sizeof(struct ext2_inode)) {
+		/* only old good inode can be retrieve from the cache */
+		for (i=0; i < fs->icache->cache_size; i++) {
+			if (fs->icache->cache[i].ino == ino) {
+				*inode = fs->icache->cache[i].inode;
+				return 0;
+			}
+		}
+	}
+	if ((ino == 0) || (ino > fs->super->s_inodes_count))
+		return EXT2_ET_BAD_INODE_NUM;
+	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
+		inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super);
+		block_nr = fs->image_header->offset_inode / fs->blocksize;
+		block_nr += (ino - 1) / inodes_per_block;
+		offset = ((ino - 1) % inodes_per_block) *
+			EXT2_INODE_SIZE(fs->super);
+		io = fs->image_io;
+	} else {
+		group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+		offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+			EXT2_INODE_SIZE(fs->super);
+		block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+		if (!fs->group_desc[(unsigned)group].bg_inode_table)
+			return EXT2_ET_MISSING_INODE_TABLE;
+		block_nr = fs->group_desc[(unsigned)group].bg_inode_table + 
+			block;
+		io = fs->io;
+	}
+	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+
+	length = EXT2_INODE_SIZE(fs->super);
+	if (bufsize < length)
+		length = bufsize;
+
+	ptr = (char *) inode;
+	while (length) {
+		clen = length;
+		if ((offset + length) > fs->blocksize)
+			clen = fs->blocksize - offset;
+
+		if (block_nr != fs->icache->buffer_blk) {
+			retval = io_channel_read_blk(io, block_nr, 1,
+						     fs->icache->buffer);
+			if (retval)
+				return retval;
+			fs->icache->buffer_blk = block_nr;
+		}
+
+		memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset,
+		       clen);
+
+		offset = 0;
+		length -= clen;
+		ptr += clen;
+		block_nr++;
+	}
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+		ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) inode, 
+				       (struct ext2_inode_large *) inode, 
+				       0, length);
+#endif
+
+	/* Update the inode cache */
+	fs->icache->cache_last = (fs->icache->cache_last + 1) %
+		fs->icache->cache_size;
+	fs->icache->cache[fs->icache->cache_last].ino = ino;
+	fs->icache->cache[fs->icache->cache_last].inode = *inode;
+	
+	return 0;
+}
+
+errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino,
+			    struct ext2_inode * inode)
+{
+	return ext2fs_read_inode_full(fs, ino, inode,
+					sizeof(struct ext2_inode));
+}
+
+errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino,
+				  struct ext2_inode * inode, int bufsize)
+{
+	unsigned long group, block, block_nr, offset;
+	errcode_t retval = 0;
+	struct ext2_inode_large temp_inode, *w_inode;
+	char *ptr;
+	int clen, i, length;
+
+	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 */
+	if (fs->icache) {
+		for (i=0; i < fs->icache->cache_size; i++) {
+			if (fs->icache->cache[i].ino == ino) {
+				fs->icache->cache[i].inode = *inode;
+				break;
+			}
+		}
+	} else {
+		retval = create_icache(fs);
+		if (retval)
+			return retval;
+	}
+		
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	if ((ino == 0) || (ino > fs->super->s_inodes_count))
+		return EXT2_ET_BAD_INODE_NUM;
+
+	length = bufsize;
+	if (length < EXT2_INODE_SIZE(fs->super))
+		length = EXT2_INODE_SIZE(fs->super);
+
+	if (length > (int) sizeof(struct ext2_inode_large)) {
+		w_inode = malloc(length);
+		if (!w_inode)
+			return ENOMEM;
+	} else
+		w_inode = &temp_inode;
+	memset(w_inode, 0, length);
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+		ext2fs_swap_inode_full(fs, w_inode, 
+				       (struct ext2_inode_large *) inode, 
+				       1, bufsize);
+	else
+#endif
+		memcpy(w_inode, inode, bufsize);
+	
+	group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super);
+	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) *
+		EXT2_INODE_SIZE(fs->super);
+	block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super);
+	if (!fs->group_desc[(unsigned) group].bg_inode_table)
+		return EXT2_ET_MISSING_INODE_TABLE;
+	block_nr = fs->group_desc[(unsigned) group].bg_inode_table + block;
+
+	offset &= (EXT2_BLOCK_SIZE(fs->super) - 1);
+
+	length = EXT2_INODE_SIZE(fs->super);
+	if (length > bufsize)
+		length = bufsize;
+
+	ptr = (char *) w_inode;
+
+	while (length) {
+		clen = length;
+		if ((offset + length) > fs->blocksize)
+			clen = fs->blocksize - offset;
+
+		if (fs->icache->buffer_blk != block_nr) {
+			retval = io_channel_read_blk(fs->io, block_nr, 1,
+						     fs->icache->buffer);
+			if (retval)
+				goto errout;
+			fs->icache->buffer_blk = block_nr;
+		}
+
+	
+		memcpy((char *) fs->icache->buffer + (unsigned) offset, 
+		       ptr, clen);
+
+		retval = io_channel_write_blk(fs->io, block_nr, 1, 
+					      fs->icache->buffer);
+		if (retval)
+			goto errout;
+
+		offset = 0;
+		ptr += clen;
+		length -= clen;
+		block_nr++;
+	}
+		
+	fs->flags |= EXT2_FLAG_CHANGED;
+errout:
+	if (w_inode && w_inode != &temp_inode)
+		free(w_inode);
+	return retval;
+}
+
+errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino,
+			     struct ext2_inode *inode)
+{
+	return ext2fs_write_inode_full(fs, ino, inode,
+				       sizeof(struct ext2_inode));
+}
+
+/* 
+ * This function should be called when writing a new inode.  It makes
+ * sure that extra part of large inodes is initialized properly.
+ */
+errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
+				 struct ext2_inode *inode)
+{
+	struct ext2_inode	*buf;
+	int 			size = EXT2_INODE_SIZE(fs->super);
+	struct ext2_inode_large	*large_inode;
+
+	if (size == sizeof(struct ext2_inode))
+		return ext2fs_write_inode_full(fs, ino, inode,
+					       sizeof(struct ext2_inode));
+
+	buf = malloc(size);
+	if (!buf)
+		return ENOMEM;
+
+	memset(buf, 0, size);
+	*buf = *inode;
+
+	large_inode = (struct ext2_inode_large *) buf;
+	large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - 
+		EXT2_GOOD_OLD_INODE_SIZE;
+
+	return ext2fs_write_inode_full(fs, ino, buf, size);
+}
+
+ 
+errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks)
+{
+	struct ext2_inode	inode;
+	int			i;
+	errcode_t		retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (ino > fs->super->s_inodes_count)
+		return EXT2_ET_BAD_INODE_NUM;
+
+	if (fs->get_blocks) {
+		if (!(*fs->get_blocks)(fs, ino, blocks))
+			return 0;
+	}
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval)
+		return retval;
+	for (i=0; i < EXT2_N_BLOCKS; i++)
+		blocks[i] = inode.i_block[i];
+	return 0;
+}
+
+errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino)
+{
+	struct	ext2_inode	inode;
+	errcode_t		retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (ino > fs->super->s_inodes_count)
+		return EXT2_ET_BAD_INODE_NUM;
+
+	if (fs->check_directory) {
+		retval = (fs->check_directory)(fs, ino);
+		if (retval != EXT2_ET_CALLBACK_NOTHANDLED)
+			return retval;
+	}
+	retval = ext2fs_read_inode(fs, ino, &inode);
+	if (retval)
+		return retval;
+	if (!LINUX_S_ISDIR(inode.i_mode))
+		return EXT2_ET_NO_DIRECTORY;
+	return 0;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/inode_io.c silo-1.4.11/libext2fs/inode_io.c
--- silo-1.4.11.orig/libext2fs/inode_io.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/inode_io.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,270 @@
+/*
+ * inode_io.c --- This is allows an inode in an ext2 filesystem image
+ * 	to be accessed via the I/O manager interface.
+ *
+ * Copyright (C) 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+struct inode_private_data {
+	int				magic;
+	char				name[32];
+	ext2_file_t			file;
+	ext2_filsys			fs;
+	ext2_ino_t 			ino;
+	struct ext2_inode		inode;
+	int				flags;
+	struct inode_private_data	*next;
+};
+
+#define CHANNEL_HAS_INODE	0x8000
+
+static struct inode_private_data *top_intern;
+static int ino_unique = 0;
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel);
+static errcode_t inode_close(io_channel channel);
+static errcode_t inode_set_blksize(io_channel channel, int blksize);
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t inode_flush(io_channel channel);
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+				int size, const void *data);
+
+static struct struct_io_manager struct_inode_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"Inode I/O Manager",
+	inode_open,
+	inode_close,
+	inode_set_blksize,
+	inode_read_blk,
+	inode_write_blk,
+	inode_flush,
+	inode_write_byte
+};
+
+io_manager inode_io_manager = &struct_inode_manager;
+
+errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino,
+				  struct ext2_inode *inode,
+				  char **name)
+{
+	struct inode_private_data 	*data;
+	errcode_t			retval;
+
+	if ((retval = ext2fs_get_mem(sizeof(struct inode_private_data),
+				     &data)))
+		return retval;
+	data->magic = EXT2_ET_MAGIC_INODE_IO_CHANNEL;
+	sprintf(data->name, "%u:%d", ino, ino_unique++);
+	data->file = 0;
+	data->fs = fs;
+	data->ino = ino;
+	data->flags = 0;
+	if (inode) {
+		memcpy(&data->inode, inode, sizeof(struct ext2_inode));
+		data->flags |= CHANNEL_HAS_INODE;
+	}
+	data->next = top_intern;
+	top_intern = data;
+	*name = data->name;
+	return 0;
+}
+
+errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino,
+				 char **name)
+{
+	return ext2fs_inode_io_intern2(fs, ino, NULL, name);
+}
+
+
+static errcode_t inode_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel	io = NULL;
+	struct inode_private_data *prev, *data = NULL;
+	errcode_t	retval;
+	int		open_flags;
+
+	if (name == 0)
+		return EXT2_ET_BAD_DEVICE_NAME;
+
+	for (data = top_intern, prev = NULL; data;
+	     prev = data, data = data->next)
+		if (strcmp(name, data->name) == 0)
+			break;
+	if (!data)
+		return ENOENT;
+	if (prev)
+		prev->next = data->next;
+	else
+		top_intern = data->next;
+
+	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+	if (retval)
+		goto cleanup;
+	memset(io, 0, sizeof(struct struct_io_channel));
+
+	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+	io->manager = inode_io_manager;
+	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+	if (retval)
+		goto cleanup;
+
+	strcpy(io->name, name);
+	io->private_data = data;
+	io->block_size = 1024;
+	io->read_error = 0;
+	io->write_error = 0;
+	io->refcount = 1;
+
+	open_flags = (flags & IO_FLAG_RW) ? EXT2_FILE_WRITE : 0;
+	retval = ext2fs_file_open2(data->fs, data->ino,
+				   (data->flags & CHANNEL_HAS_INODE) ?
+				   &data->inode : 0, open_flags,
+				   &data->file);
+	if (retval)
+		goto cleanup;
+		
+	*channel = io;
+	return 0;
+
+cleanup:
+	if (data) {
+		ext2fs_free_mem(&data);
+	}
+	if (io)
+		ext2fs_free_mem(&io);
+	return retval;
+}
+
+static errcode_t inode_close(io_channel channel)
+{
+	struct inode_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+		return 0;
+
+	retval = ext2fs_file_close(data->file);
+	
+	ext2fs_free_mem(&channel->private_data);
+	if (channel->name)
+		ext2fs_free_mem(&channel->name);
+	ext2fs_free_mem(&channel);
+	return retval;
+}
+
+static errcode_t inode_set_blksize(io_channel channel, int blksize)
+{
+	struct inode_private_data *data;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	channel->block_size = blksize;
+	return 0;
+}
+
+
+static errcode_t inode_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	struct inode_private_data *data;
+	errcode_t	retval;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	if ((retval = ext2fs_file_lseek(data->file,
+					block * channel->block_size,
+					EXT2_SEEK_SET, 0)))
+		return retval;
+
+	count = (count < 0) ? -count : (count * channel->block_size);
+
+	return ext2fs_file_read(data->file, buf, count, 0);
+}
+
+static errcode_t inode_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	struct inode_private_data *data;
+	errcode_t	retval;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	if ((retval = ext2fs_file_lseek(data->file,
+					block * channel->block_size,
+					EXT2_SEEK_SET, 0)))
+		return retval;
+
+	count = (count < 0) ? -count : (count * channel->block_size);
+
+	return ext2fs_file_write(data->file, buf, count, 0);
+}
+
+static errcode_t inode_write_byte(io_channel channel, unsigned long offset,
+				 int size, const void *buf)
+{
+	struct inode_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	if ((retval = ext2fs_file_lseek(data->file, offset,
+					EXT2_SEEK_SET, 0)))
+		return retval;
+
+	return ext2fs_file_write(data->file, buf, size, 0);
+}
+
+/*
+ * Flush data buffers to disk.  
+ */
+static errcode_t inode_flush(io_channel channel)
+{
+	struct inode_private_data *data;
+	
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct inode_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_INODE_IO_CHANNEL);
+
+	return ext2fs_file_flush(data->file);
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/io_manager.c silo-1.4.11/libext2fs/io_manager.c
--- silo-1.4.11.orig/libext2fs/io_manager.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/io_manager.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,69 @@
+/*
+ * io_manager.c --- the I/O manager abstraction
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t io_channel_set_options(io_channel channel, const char *opts)
+{
+	errcode_t retval = 0;
+	char *next, *ptr, *options, *arg;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+	if (!opts)
+		return 0;
+
+	if (!channel->manager->set_option)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	options = malloc(strlen(opts)+1);
+	if (!options)
+		return EXT2_ET_NO_MEMORY;
+	strcpy(options, opts);
+	ptr = options;
+
+	while (ptr && *ptr) {
+		next = strchr(ptr, '&');
+		if (next)
+			*next++ = 0;
+
+		arg = strchr(ptr, '=');
+		if (arg)
+			*arg++ = 0;
+
+		retval = (channel->manager->set_option)(channel, ptr, arg);
+		if (retval)
+			break;
+		ptr = next;
+	}
+	free(options);
+	return retval;
+}
+
+errcode_t io_channel_write_byte(io_channel channel, unsigned long offset,
+				int count, const void *data)
+{
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+
+	if (channel->manager->write_byte) 
+		return channel->manager->write_byte(channel, offset, 
+						    count, data);
+
+	return EXT2_ET_UNIMPLEMENTED;
+}
diff -Naur silo-1.4.11.orig/libext2fs/irel.h silo-1.4.11/libext2fs/irel.h
--- silo-1.4.11.orig/libext2fs/irel.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/irel.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,114 @@
+/*
+ * irel.h
+ * 
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+struct ext2_inode_reference {
+	blk_t	block;
+	__u16 offset;
+};
+
+struct ext2_inode_relocate_entry {
+	ext2_ino_t	new;
+	ext2_ino_t	orig;
+	__u16		flags;
+	__u16		max_refs;
+};
+
+typedef struct ext2_inode_relocation_table *ext2_irel;
+
+struct ext2_inode_relocation_table {
+	__u32	magic;
+	char	*name;
+	ext2_ino_t	current;
+	void	*priv_data;
+
+	/*
+	 * Add an inode relocation entry.
+	 */
+	errcode_t (*put)(ext2_irel irel, ext2_ino_t old,
+			      struct ext2_inode_relocate_entry *ent);
+	/*
+	 * Get an inode relocation entry.
+	 */
+	errcode_t (*get)(ext2_irel irel, ext2_ino_t old,
+			      struct ext2_inode_relocate_entry *ent);
+
+	/*
+	 * Get an inode relocation entry by its original inode number
+	 */
+	errcode_t (*get_by_orig)(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+				 struct ext2_inode_relocate_entry *ent);
+
+	/*
+	 * Initialize for iterating over the inode relocation entries.
+	 */
+	errcode_t (*start_iter)(ext2_irel irel);
+
+	/*
+	 * The iterator function for the inode relocation entries.
+	 * Returns an inode number of 0 when out of entries.
+	 */
+	errcode_t (*next)(ext2_irel irel, ext2_ino_t *old,
+			  struct ext2_inode_relocate_entry *ent);
+
+	/*
+	 * Add an inode reference (i.e., note the fact that a
+	 * particular block/offset contains a reference to an inode)
+	 */
+	errcode_t (*add_ref)(ext2_irel irel, ext2_ino_t ino,
+			     struct ext2_inode_reference *ref);
+
+	/*
+	 * Initialize for iterating over the inode references for a
+	 * particular inode.
+	 */
+	errcode_t (*start_iter_ref)(ext2_irel irel, ext2_ino_t ino);
+
+	/*
+	 * The iterator function for the inode references for an
+	 * inode.  The references for only one inode can be interator
+	 * over at a time, as the iterator state is stored in ext2_irel.
+	 */
+	errcode_t (*next_ref)(ext2_irel irel,
+			      struct ext2_inode_reference *ref);
+
+	/*
+	 * Move the inode relocation table from one inode number to
+	 * another.  Note that the inode references also must move.
+	 */
+	errcode_t (*move)(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
+
+	/*
+	 * Remove an inode relocation entry, along with all of the
+	 * inode references.
+	 */
+	errcode_t (*delete)(ext2_irel irel, ext2_ino_t old);
+
+	/*
+	 * Free the inode relocation table.
+	 */
+	errcode_t (*free)(ext2_irel irel);
+};
+
+errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
+				    ext2_irel *irel);
+
+#define ext2fs_irel_put(irel, old, ent) ((irel)->put((irel), old, ent))
+#define ext2fs_irel_get(irel, old, ent) ((irel)->get((irel), old, ent))
+#define ext2fs_irel_get_by_orig(irel, orig, old, ent) \
+			((irel)->get_by_orig((irel), orig, old, ent))
+#define ext2fs_irel_start_iter(irel) ((irel)->start_iter((irel)))
+#define ext2fs_irel_next(irel, old, ent) ((irel)->next((irel), old, ent))
+#define ext2fs_irel_add_ref(irel, ino, ref) ((irel)->add_ref((irel), ino, ref))
+#define ext2fs_irel_start_iter_ref(irel, ino) ((irel)->start_iter_ref((irel), ino))
+#define ext2fs_irel_next_ref(irel, ref) ((irel)->next_ref((irel), ref))
+#define ext2fs_irel_move(irel, old, new) ((irel)->move((irel), old, new))
+#define ext2fs_irel_delete(irel, old) ((irel)->delete((irel), old))
+#define ext2fs_irel_free(irel) ((irel)->free((irel)))
diff -Naur silo-1.4.11.orig/libext2fs/irel_ma.c silo-1.4.11/libext2fs/irel_ma.c
--- silo-1.4.11.orig/libext2fs/irel_ma.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/irel_ma.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,372 @@
+/*
+ * irel_ma.c
+ * 
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "irel.h"
+
+static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
+			 struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
+			 struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+				 struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_start_iter(ext2_irel irel);
+static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
+			  struct ext2_inode_relocate_entry *ent);
+static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
+			     struct ext2_inode_reference *ref);
+static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino);
+static errcode_t ima_next_ref(ext2_irel irel, struct ext2_inode_reference *ref);
+static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new);
+static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old);
+static errcode_t ima_free(ext2_irel irel);
+
+/*
+ * This data structure stores the array of inode references; there is
+ * a structure for each inode.
+ */
+struct inode_reference_entry {
+	__u16 num;
+	struct ext2_inode_reference *refs;
+};
+
+struct irel_ma {
+	__u32 magic;
+	ext2_ino_t max_inode;
+	ext2_ino_t ref_current;
+	int   ref_iter;
+	ext2_ino_t	*orig_map;
+	struct ext2_inode_relocate_entry *entries;
+	struct inode_reference_entry *ref_entries;
+};
+
+errcode_t ext2fs_irel_memarray_create(char *name, ext2_ino_t max_inode,
+				      ext2_irel *new_irel)
+{
+	ext2_irel		irel = 0;
+	errcode_t	retval;
+	struct irel_ma 	*ma = 0;
+	size_t		size;
+
+	*new_irel = 0;
+
+	/*
+	 * Allocate memory structures
+	 */
+	retval = ext2fs_get_mem(sizeof(struct ext2_inode_relocation_table),
+				&irel);
+	if (retval)
+		goto errout;
+	memset(irel, 0, sizeof(struct ext2_inode_relocation_table));
+	
+	retval = ext2fs_get_mem(strlen(name)+1, &irel->name);
+	if (retval)
+		goto errout;
+	strcpy(irel->name, name);
+	
+	retval = ext2fs_get_mem(sizeof(struct irel_ma), &ma);
+	if (retval)
+		goto errout;
+	memset(ma, 0, sizeof(struct irel_ma));
+	irel->priv_data = ma;
+	
+	size = (size_t) (sizeof(ext2_ino_t) * (max_inode+1));
+	retval = ext2fs_get_mem(size, &ma->orig_map);
+	if (retval)
+		goto errout;
+	memset(ma->orig_map, 0, size);
+
+	size = (size_t) (sizeof(struct ext2_inode_relocate_entry) *
+			 (max_inode+1));
+	retval = ext2fs_get_mem(size, &ma->entries);
+	if (retval)
+		goto errout;
+	memset(ma->entries, 0, size);
+
+	size = (size_t) (sizeof(struct inode_reference_entry) *
+			 (max_inode+1));
+	retval = ext2fs_get_mem(size, &ma->ref_entries);
+	if (retval)
+		goto errout;
+	memset(ma->ref_entries, 0, size);
+	ma->max_inode = max_inode;
+
+	/*
+	 * Fill in the irel data structure
+	 */
+	irel->put = ima_put;
+	irel->get = ima_get;
+	irel->get_by_orig = ima_get_by_orig;
+	irel->start_iter = ima_start_iter;
+	irel->next = ima_next;
+	irel->add_ref = ima_add_ref;
+	irel->start_iter_ref = ima_start_iter_ref;
+	irel->next_ref = ima_next_ref;
+	irel->move = ima_move;
+	irel->delete = ima_delete;
+	irel->free = ima_free;
+	
+	*new_irel = irel;
+	return 0;
+
+errout:
+	ima_free(irel);
+	return retval;
+}
+
+static errcode_t ima_put(ext2_irel irel, ext2_ino_t old,
+			struct ext2_inode_relocate_entry *ent)
+{
+	struct inode_reference_entry	*ref_ent;
+	struct irel_ma 			*ma;
+	errcode_t			retval;
+	size_t				size, old_size;
+
+	ma = irel->priv_data;
+	if (old > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	/*
+	 * Force the orig field to the correct value; the application
+	 * program shouldn't be messing with this field.
+	 */
+	if (ma->entries[(unsigned) old].new == 0)
+		ent->orig = old;
+	else
+		ent->orig = ma->entries[(unsigned) old].orig;
+	
+	/*
+	 * If max_refs has changed, reallocate the refs array
+	 */
+	ref_ent = ma->ref_entries + (unsigned) old;
+	if (ref_ent->refs && ent->max_refs !=
+	    ma->entries[(unsigned) old].max_refs) {
+		size = (sizeof(struct ext2_inode_reference) * ent->max_refs);
+		old_size = (sizeof(struct ext2_inode_reference) *
+			    ma->entries[(unsigned) old].max_refs);
+		retval = ext2fs_resize_mem(old_size, size, &ref_ent->refs);
+		if (retval)
+			return retval;
+	}
+
+	ma->entries[(unsigned) old] = *ent;
+	ma->orig_map[(unsigned) ent->orig] = old;
+	return 0;
+}
+
+static errcode_t ima_get(ext2_irel irel, ext2_ino_t old,
+			struct ext2_inode_relocate_entry *ent)
+{
+	struct irel_ma 	*ma;
+
+	ma = irel->priv_data;
+	if (old > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned) old].new == 0)
+		return ENOENT;
+	*ent = ma->entries[(unsigned) old];
+	return 0;
+}
+
+static errcode_t ima_get_by_orig(ext2_irel irel, ext2_ino_t orig, ext2_ino_t *old,
+			struct ext2_inode_relocate_entry *ent)
+{
+	struct irel_ma 	*ma;
+	ext2_ino_t	ino;
+
+	ma = irel->priv_data;
+	if (orig > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+	ino = ma->orig_map[(unsigned) orig];
+	if (ino == 0)
+		return ENOENT;
+	*old = ino;
+	*ent = ma->entries[(unsigned) ino];
+	return 0;
+}
+
+static errcode_t ima_start_iter(ext2_irel irel)
+{
+	irel->current = 0;
+	return 0;
+}
+
+static errcode_t ima_next(ext2_irel irel, ext2_ino_t *old,
+			 struct ext2_inode_relocate_entry *ent)
+{
+	struct irel_ma 	*ma;
+
+	ma = irel->priv_data;
+	while (++irel->current < ma->max_inode) {
+		if (ma->entries[(unsigned) irel->current].new == 0)
+			continue;
+		*old = irel->current;
+		*ent = ma->entries[(unsigned) irel->current];
+		return 0;
+	}
+	*old = 0;
+	return 0;
+}
+
+static errcode_t ima_add_ref(ext2_irel irel, ext2_ino_t ino,
+			     struct ext2_inode_reference *ref)
+{
+	struct irel_ma 	*ma;
+	size_t		size;
+	struct inode_reference_entry *ref_ent;
+	struct ext2_inode_relocate_entry *ent;
+	errcode_t		retval;
+
+	ma = irel->priv_data;
+	if (ino > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	ref_ent = ma->ref_entries + (unsigned) ino;
+	ent = ma->entries + (unsigned) ino;
+	
+	/*
+	 * If the inode reference array doesn't exist, create it.
+	 */
+	if (ref_ent->refs == 0) {
+		size = (size_t) ((sizeof(struct ext2_inode_reference) * 
+				  ent->max_refs));
+		retval = ext2fs_get_mem(size, &ref_ent->refs);
+		if (retval)
+			return retval;
+		memset(ref_ent->refs, 0, size);
+		ref_ent->num = 0;
+	}
+
+	if (ref_ent->num >= ent->max_refs)
+		return EXT2_ET_TOO_MANY_REFS;
+
+	ref_ent->refs[(unsigned) ref_ent->num++] = *ref;
+	return 0;
+}
+
+static errcode_t ima_start_iter_ref(ext2_irel irel, ext2_ino_t ino)
+{
+	struct irel_ma 	*ma;
+
+	ma = irel->priv_data;
+	if (ino > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned) ino].new == 0)
+		return ENOENT;
+	ma->ref_current = ino;
+	ma->ref_iter = 0;
+	return 0;
+}
+
+static errcode_t ima_next_ref(ext2_irel irel,
+			      struct ext2_inode_reference *ref)
+{
+	struct irel_ma 	*ma;
+	struct inode_reference_entry *ref_ent;
+
+	ma = irel->priv_data;
+	
+	ref_ent = ma->ref_entries + ma->ref_current;
+
+	if ((ref_ent->refs == NULL) ||
+	    (ma->ref_iter >= ref_ent->num)) {
+		ref->block = 0;
+		ref->offset = 0;
+		return 0;
+	}
+	*ref = ref_ent->refs[ma->ref_iter++];
+	return 0;
+}
+
+
+static errcode_t ima_move(ext2_irel irel, ext2_ino_t old, ext2_ino_t new)
+{
+	struct irel_ma 	*ma;
+
+	ma = irel->priv_data;
+	if ((old > ma->max_inode) || (new > ma->max_inode))
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned) old].new == 0)
+		return ENOENT;
+	
+	ma->entries[(unsigned) new] = ma->entries[(unsigned) old];
+	if (ma->ref_entries[(unsigned) new].refs)
+		ext2fs_free_mem(&ma->ref_entries[(unsigned) new].refs);
+	ma->ref_entries[(unsigned) new] = ma->ref_entries[(unsigned) old];
+	
+	ma->entries[(unsigned) old].new = 0;
+	ma->ref_entries[(unsigned) old].num = 0;
+	ma->ref_entries[(unsigned) old].refs = 0;
+
+	ma->orig_map[ma->entries[new].orig] = new;
+	return 0;
+}
+
+static errcode_t ima_delete(ext2_irel irel, ext2_ino_t old)
+{
+	struct irel_ma 	*ma;
+
+	ma = irel->priv_data;
+	if (old > ma->max_inode)
+		return EXT2_ET_INVALID_ARGUMENT;
+	if (ma->entries[(unsigned) old].new == 0)
+		return ENOENT;
+	
+	ma->entries[old].new = 0;
+	if (ma->ref_entries[(unsigned) old].refs)
+		ext2fs_free_mem(&ma->ref_entries[(unsigned) old].refs);
+	ma->orig_map[ma->entries[(unsigned) old].orig] = 0;
+	
+	ma->ref_entries[(unsigned) old].num = 0;
+	ma->ref_entries[(unsigned) old].refs = 0;
+	return 0;
+}
+
+static errcode_t ima_free(ext2_irel irel)
+{
+	struct irel_ma 	*ma;
+	ext2_ino_t	ino;
+
+	if (!irel)
+		return 0;
+
+	ma = irel->priv_data;
+
+	if (ma) {
+		if (ma->orig_map)
+			ext2fs_free_mem(&ma->orig_map);
+		if (ma->entries)
+			ext2fs_free_mem(&ma->entries);
+		if (ma->ref_entries) {
+			for (ino = 0; ino <= ma->max_inode; ino++) {
+				if (ma->ref_entries[(unsigned) ino].refs)
+					ext2fs_free_mem(&ma->ref_entries[(unsigned) ino].refs);
+			}
+			ext2fs_free_mem(&ma->ref_entries);
+		}
+		ext2fs_free_mem(&ma);
+	}
+	if (irel->name)
+		ext2fs_free_mem(&irel->name);
+	ext2fs_free_mem(&irel);
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/ismounted.c silo-1.4.11/libext2fs/ismounted.c
--- silo-1.4.11.orig/libext2fs/ismounted.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/ismounted.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,377 @@
+/*
+ * ismounted.c --- Check to see if the filesystem was mounted
+ * 
+ * Copyright (C) 1995,1996,1997,1998,1999,2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINUX_FD_H
+#include <linux/fd.h>
+#endif
+#ifdef HAVE_MNTENT_H
+#include <mntent.h>
+#endif
+#ifdef HAVE_GETMNTINFO
+#include <paths.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* HAVE_GETMNTINFO */
+#include <string.h>
+#include <sys/stat.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifdef HAVE_MNTENT_H
+/*
+ * Helper function which checks a file in /etc/mtab format to see if a
+ * filesystem is mounted.  Returns an error if the file doesn't exist
+ * or can't be opened.  
+ */
+static errcode_t check_mntent_file(const char *mtab_file, const char *file, 
+				   int *mount_flags, char *mtpt, int mtlen)
+{
+	struct mntent 	*mnt;
+	struct stat	st_buf;
+	errcode_t	retval = 0;
+	dev_t		file_dev=0, file_rdev=0;
+	ino_t		file_ino=0;
+	FILE 		*f;
+	int		fd;
+
+	*mount_flags = 0;
+	if ((f = setmntent (mtab_file, "r")) == NULL)
+		return errno;
+	if (stat(file, &st_buf) == 0) {
+		if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+			file_rdev = st_buf.st_rdev;
+#endif	/* __GNU__ */
+		} else {
+			file_dev = st_buf.st_dev;
+			file_ino = st_buf.st_ino;
+		}
+	}
+	while ((mnt = getmntent (f)) != NULL) {
+		if (strcmp(file, mnt->mnt_fsname) == 0)
+			break;
+		if (stat(mnt->mnt_fsname, &st_buf) == 0) {
+			if (S_ISBLK(st_buf.st_mode)) {
+#ifndef __GNU__
+				if (file_rdev && (file_rdev == st_buf.st_rdev))
+					break;
+#endif	/* __GNU__ */
+			} else {
+				if (file_dev && ((file_dev == st_buf.st_dev) &&
+						 (file_ino == st_buf.st_ino)))
+					break;
+			}
+		}
+	}
+
+	if (mnt == 0) {
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+		/*
+		 * Do an extra check to see if this is the root device.  We
+		 * can't trust /etc/mtab, and /proc/mounts will only list
+		 * /dev/root for the root filesystem.  Argh.  Instead we
+		 * check if the given device has the same major/minor number
+		 * as the device that the root directory is on.
+		 */
+		if (file_rdev && stat("/", &st_buf) == 0) {
+			if (st_buf.st_dev == file_rdev) {
+				*mount_flags = EXT2_MF_MOUNTED;
+				if (mtpt)
+					strncpy(mtpt, "/", mtlen);
+				goto is_root;
+			}
+		}
+#endif	/* __GNU__ */
+		goto errout;
+	}
+#ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */
+	/* Validate the entry in case /etc/mtab is out of date */
+	/* 
+	 * We need to be paranoid, because some broken distributions
+	 * (read: Slackware) don't initialize /etc/mtab before checking
+	 * all of the non-root filesystems on the disk.
+	 */
+	if (stat(mnt->mnt_dir, &st_buf) < 0) {
+		retval = errno;
+		if (retval == ENOENT) {
+#ifdef DEBUG
+			printf("Bogus entry in %s!  (%s does not exist)\n",
+			       mtab_file, mnt->mnt_dir);
+#endif /* DEBUG */
+			retval = 0;
+		}
+		goto errout;
+	}
+	if (file_rdev && (st_buf.st_dev != file_rdev)) {
+#ifdef DEBUG
+		printf("Bogus entry in %s!  (%s not mounted on %s)\n",
+		       mtab_file, file, mnt->mnt_dir);
+#endif /* DEBUG */
+		goto errout;
+	}
+#endif /* __GNU__ */
+	*mount_flags = EXT2_MF_MOUNTED;
+	
+#ifdef MNTOPT_RO
+	/* Check to see if the ro option is set */
+	if (hasmntopt(mnt, MNTOPT_RO))
+		*mount_flags |= EXT2_MF_READONLY;
+#endif
+
+	if (mtpt)
+		strncpy(mtpt, mnt->mnt_dir, mtlen);
+	/*
+	 * Check to see if we're referring to the root filesystem.
+	 * If so, do a manual check to see if we can open /etc/mtab
+	 * read/write, since if the root is mounted read/only, the
+	 * contents of /etc/mtab may not be accurate.
+	 */
+	if (!strcmp(mnt->mnt_dir, "/")) {
+is_root:
+#define TEST_FILE "/.ismount-test-file"		
+		*mount_flags |= EXT2_MF_ISROOT;
+		fd = open(TEST_FILE, O_RDWR|O_CREAT);
+		if (fd < 0) {
+			if (errno == EROFS)
+				*mount_flags |= EXT2_MF_READONLY;
+		} else
+			close(fd);
+		(void) unlink(TEST_FILE);
+	}
+	retval = 0;
+errout:
+	endmntent (f);
+	return retval;
+}
+
+static errcode_t check_mntent(const char *file, int *mount_flags,
+			      char *mtpt, int mtlen)
+{
+	errcode_t	retval;
+
+#ifdef DEBUG
+	retval = check_mntent_file("/tmp/mtab", file, mount_flags,
+				   mtpt, mtlen);
+	if (retval == 0)
+		return 0;
+#endif /* DEBUG */
+#ifdef __linux__
+	retval = check_mntent_file("/proc/mounts", file, mount_flags,
+				   mtpt, mtlen);
+	if (retval == 0 && (*mount_flags != 0))
+		return 0;
+#endif /* __linux__ */
+#if defined(MOUNTED) || defined(_PATH_MOUNTED)
+#ifndef MOUNTED
+#define MOUNTED _PATH_MOUNTED
+#endif /* MOUNTED */
+	retval = check_mntent_file(MOUNTED, file, mount_flags, mtpt, mtlen);
+	return retval;
+#else 
+	*mount_flags = 0;
+	return 0;
+#endif /* defined(MOUNTED) || defined(_PATH_MOUNTED) */
+}
+
+#else
+#if defined(HAVE_GETMNTINFO)
+
+static errcode_t check_getmntinfo(const char *file, int *mount_flags,
+				  char *mtpt, int mtlen)
+{
+	struct statfs *mp;
+        int    len, n;
+        const  char   *s1;
+	char	*s2;
+
+        n = getmntinfo(&mp, MNT_NOWAIT);
+        if (n == 0)
+		return errno;
+
+        len = sizeof(_PATH_DEV) - 1;
+        s1 = file;
+        if (strncmp(_PATH_DEV, s1, len) == 0)
+                s1 += len;
+ 
+	*mount_flags = 0;
+        while (--n >= 0) {
+                s2 = mp->f_mntfromname;
+                if (strncmp(_PATH_DEV, s2, len) == 0) {
+                        s2 += len - 1;
+                        *s2 = 'r';
+                }
+                if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) {
+			*mount_flags = EXT2_MF_MOUNTED;
+			break;
+		}
+                ++mp;
+	}
+	if (mtpt)
+		strncpy(mtpt, mp->f_mntonname, mtlen);
+	return 0;
+}
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+
+/*
+ * Check to see if we're dealing with the swap device.
+ */
+static int is_swap_device(const char *file)
+{
+	FILE		*f;
+	char		buf[1024], *cp;
+	dev_t		file_dev;
+	struct stat	st_buf;
+	int		ret = 0;
+
+	file_dev = 0;
+#ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
+	if ((stat(file, &st_buf) == 0) &&
+	    S_ISBLK(st_buf.st_mode))
+		file_dev = st_buf.st_rdev;
+#endif	/* __GNU__ */
+
+	if (!(f = fopen("/proc/swaps", "r")))
+		return 0;
+	/* Skip the first line */
+	fgets(buf, sizeof(buf), f);
+	while (!feof(f)) {
+		if (!fgets(buf, sizeof(buf), f))
+			break;
+		if ((cp = strchr(buf, ' ')) != NULL)
+			*cp = 0;
+		if ((cp = strchr(buf, '\t')) != NULL)
+			*cp = 0;
+		if (strcmp(buf, file) == 0) {
+			ret++;
+			break;
+		}
+#ifndef __GNU__
+		if (file_dev && (stat(buf, &st_buf) == 0) &&
+		    S_ISBLK(st_buf.st_mode) &&
+		    file_dev == st_buf.st_rdev) {
+			ret++;
+			break;
+		}
+#endif 	/* __GNU__ */
+	}
+	fclose(f);
+	return ret;
+}
+
+
+/*
+ * ext2fs_check_mount_point() fills determines if the device is
+ * mounted or otherwise busy, and fills in mount_flags with one or
+ * more of the following flags: EXT2_MF_MOUNTED, EXT2_MF_ISROOT,
+ * EXT2_MF_READONLY, EXT2_MF_SWAP, and EXT2_MF_BUSY.  If mtpt is
+ * non-NULL, the directory where the device is mounted is copied to
+ * where mtpt is pointing, up to mtlen characters.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags,
+				  char *mtpt, int mtlen)
+{
+	struct stat	st_buf;
+	errcode_t	retval = 0;
+	int		fd;
+
+	if (is_swap_device(device)) {
+		*mount_flags = EXT2_MF_MOUNTED | EXT2_MF_SWAP;
+		strncpy(mtpt, "<swap>", mtlen);
+	} else {
+#ifdef HAVE_MNTENT_H
+		retval = check_mntent(device, mount_flags, mtpt, mtlen);
+#else 
+#ifdef HAVE_GETMNTINFO
+		retval = check_getmntinfo(device, mount_flags, mtpt, mtlen);
+#else
+#ifdef __GNUC__
+ #warning "Can't use getmntent or getmntinfo to check for mounted filesystems!"
+#endif
+		*mount_flags = 0;
+#endif /* HAVE_GETMNTINFO */
+#endif /* HAVE_MNTENT_H */
+	}
+	if (retval)
+		return retval;
+
+#ifdef __linux__ /* This only works on Linux 2.6+ systems */
+	if ((stat(device, &st_buf) != 0) ||
+	    !S_ISBLK(st_buf.st_mode))
+		return 0;
+	fd = open(device, O_RDONLY | O_EXCL);
+	if (fd < 0) {
+		if (errno == EBUSY)
+			*mount_flags |= EXT2_MF_BUSY;
+	} else
+		close(fd);
+
+	return 0;
+#endif
+}
+
+/*
+ * ext2fs_check_if_mounted() sets the mount_flags EXT2_MF_MOUNTED,
+ * EXT2_MF_READONLY, and EXT2_MF_ROOT
+ * 
+ */
+errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags)
+{
+	return ext2fs_check_mount_point(file, mount_flags, NULL, 0);
+}
+
+#ifdef DEBUG
+int main(int argc, char **argv)
+{
+	int	retval, mount_flags;
+	char	mntpt[80];
+	
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s device\n", argv[0]);
+		exit(1);
+	}
+
+	mntpt[0] = 0;
+	retval = ext2fs_check_mount_point(argv[1], &mount_flags,
+					  mntpt, sizeof(mntpt));
+	if (retval) {
+		com_err(argv[0], retval,
+			"while calling ext2fs_check_if_mounted");
+		exit(1);
+	}
+	printf("Device %s reports flags %02x\n", argv[1], mount_flags);
+	if (mount_flags & EXT2_MF_BUSY)
+		printf("\t%s is apparently in use.\n", argv[1]);
+	if (mount_flags & EXT2_MF_MOUNTED)
+		printf("\t%s is mounted.\n", argv[1]);
+	if (mount_flags & EXT2_MF_SWAP)
+		printf("\t%s is a swap device.\n", argv[1]);
+	if (mount_flags & EXT2_MF_READONLY)
+		printf("\t%s is read-only.\n", argv[1]);
+	if (mount_flags & EXT2_MF_ISROOT)
+		printf("\t%s is the root filesystem.\n", argv[1]);
+	if (mntpt[0])
+		printf("\t%s is mounted on %s.\n", argv[1], mntpt);
+	exit(0);
+}
+#endif /* DEBUG */
diff -Naur silo-1.4.11.orig/libext2fs/jfs_compat.h silo-1.4.11/libext2fs/jfs_compat.h
--- silo-1.4.11.orig/libext2fs/jfs_compat.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/jfs_compat.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,67 @@
+
+#ifndef _JFS_COMPAT_H
+#define _JFS_COMPAT_H
+
+#include "kernel-list.h"
+#include <errno.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#define printk printf
+#define KERN_ERR ""
+#define KERN_DEBUG ""
+
+#define READ 0
+#define WRITE 1
+
+#define cpu_to_be32(n) htonl(n)
+#define be32_to_cpu(n) ntohl(n)
+
+typedef unsigned int tid_t;
+typedef struct journal_s journal_t;
+
+struct buffer_head;
+struct inode;
+
+struct journal_s
+{
+	unsigned long		j_flags;
+	int			j_errno;
+	struct buffer_head *	j_sb_buffer;
+	struct journal_superblock_s *j_superblock;
+	int			j_format_version;
+	unsigned long		j_head;
+	unsigned long		j_tail;
+	unsigned long		j_free;
+	unsigned long		j_first, j_last;
+	kdev_t			j_dev;
+	kdev_t			j_fs_dev;
+	int			j_blocksize;
+	unsigned int		j_blk_offset;
+	unsigned int		j_maxlen;
+	struct inode *		j_inode;
+	tid_t			j_tail_sequence;
+	tid_t			j_transaction_sequence;
+	__u8			j_uuid[16];
+	struct jbd_revoke_table_s *j_revoke;
+};
+
+#define J_ASSERT(assert)						\
+	do { if (!(assert)) {						\
+		printf ("Assertion failure in %s() at %s line %d: "	\
+			"\"%s\"\n",					\
+			__FUNCTION__, __FILE__, __LINE__, # assert);	\
+		fatal_error(e2fsck_global_ctx, 0);			\
+	} } while (0)
+
+#define is_journal_abort(x) 0
+
+#define BUFFER_TRACE(bh, info)	do {} while (0)
+
+/* Need this so we can compile with configure --enable-gcc-wall */
+#ifdef NO_INLINE_FUNCS
+#define inline
+#endif
+
+#endif /* _JFS_COMPAT_H */
diff -Naur silo-1.4.11.orig/libext2fs/jfs_dat.h silo-1.4.11/libext2fs/jfs_dat.h
--- silo-1.4.11.orig/libext2fs/jfs_dat.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/jfs_dat.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,64 @@
+/*
+ * jfs_dat.h --- stripped down header file which only contains the JFS
+ * 	on-disk data structures
+ */
+
+#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+/*
+ * On-disk structures
+ */
+
+/* 
+ * Descriptor block types:
+ */
+
+#define JFS_DESCRIPTOR_BLOCK	1
+#define JFS_COMMIT_BLOCK	2
+#define JFS_SUPERBLOCK		3
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+typedef struct journal_header_s
+{
+	__u32		h_magic;
+	__u32		h_blocktype;
+	__u32		h_sequence;
+} journal_header_t;
+
+
+/* 
+ * The block tag: used to describe a single buffer in the journal 
+ */
+typedef struct journal_block_tag_s
+{
+	__u32		t_blocknr;	/* The on-disk block number */
+	__u32		t_flags;	/* See below */
+} journal_block_tag_t;
+
+/* Definitions for the journal tag flags word: */
+#define JFS_FLAG_ESCAPE		1	/* on-disk block is escaped */
+#define JFS_FLAG_SAME_UUID	2	/* block has same uuid as previous */
+#define JFS_FLAG_DELETED	4	/* block deleted by this transaction */
+#define JFS_FLAG_LAST_TAG	8	/* last tag in this descriptor block */
+
+
+/*
+ * The journal superblock
+ */
+typedef struct journal_superblock_s
+{
+	journal_header_t s_header;
+
+	/* Static information describing the journal */
+	__u32		s_blocksize;	/* journal device blocksize */
+	__u32		s_maxlen;	/* total blocks in journal file */
+	__u32		s_first;	/* first block of log information */
+	
+	/* Dynamic information describing the current state of the log */
+	__u32		s_sequence;	/* first commit ID expected in log */
+	__u32		s_start;	/* blocknr of start of log */
+	
+} journal_superblock_t;
+
diff -Naur silo-1.4.11.orig/libext2fs/jfs_user.h silo-1.4.11/libext2fs/jfs_user.h
--- silo-1.4.11.orig/libext2fs/jfs_user.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/jfs_user.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,8 @@
+#ifndef _JFS_USER_H
+#define _JFS_USER_H
+
+typedef unsigned short kdev_t;
+
+#include "kernel-jbd.h"
+
+#endif /* _JFS_USER_H */
diff -Naur silo-1.4.11.orig/libext2fs/kernel-jbd.h silo-1.4.11/libext2fs/kernel-jbd.h
--- silo-1.4.11.orig/libext2fs/kernel-jbd.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/kernel-jbd.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,910 @@
+/*
+ * linux/include/linux/jbd.h
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Definitions for transaction data structures for the buffer cache
+ * filesystem journaling support.
+ */
+
+#ifndef _LINUX_JBD_H
+#define _LINUX_JBD_H
+
+#if defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE) || !defined(__KERNEL__)
+
+/* Allow this file to be included directly into e2fsprogs */
+#ifndef __KERNEL__
+#include "jfs_compat.h"
+#define JFS_DEBUG
+#define jfs_debug jbd_debug
+#else
+
+#include <linux/journal-head.h>
+#include <linux/stddef.h>
+#include <asm/semaphore.h>
+#endif
+
+#ifndef __GNUC__
+#define __FUNCTION__ ""
+#endif
+
+#define journal_oom_retry 1
+
+#ifdef __STDC__
+#ifdef CONFIG_JBD_DEBUG
+/*
+ * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
+ * consistency checks.  By default we don't do this unless
+ * CONFIG_JBD_DEBUG is on.
+ */
+#define JBD_EXPENSIVE_CHECKING
+extern int journal_enable_debug;
+
+#define jbd_debug(n, f, a...)						\
+	do {								\
+		if ((n) <= journal_enable_debug) {			\
+			printk (KERN_DEBUG "(%s, %d): %s: ",		\
+				__FILE__, __LINE__, __FUNCTION__);	\
+		  	printk (f, ## a);				\
+		}							\
+	} while (0)
+#else
+#ifdef __GNUC__
+#define jbd_debug(f, a...)	/**/
+#else
+#define jbd_debug(f, ...)	/**/
+#endif	
+#endif
+#else
+#define jbd_debug(x)		/* AIX doesn't do STDC */
+#endif
+
+extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry);
+#define jbd_kmalloc(size, flags) \
+	__jbd_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
+#define jbd_rep_kmalloc(size, flags) \
+	__jbd_kmalloc(__FUNCTION__, (size), (flags), 1)
+
+#define JFS_MIN_JOURNAL_BLOCKS 1024
+
+#ifdef __KERNEL__
+typedef struct handle_s		handle_t;	/* Atomic operation type */
+typedef struct journal_s	journal_t;	/* Journal control structure */
+#endif
+
+/*
+ * Internal structures used by the logging mechanism:
+ */
+
+#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+/*
+ * On-disk structures
+ */
+
+/* 
+ * Descriptor block types:
+ */
+
+#define JFS_DESCRIPTOR_BLOCK	1
+#define JFS_COMMIT_BLOCK	2
+#define JFS_SUPERBLOCK_V1	3
+#define JFS_SUPERBLOCK_V2	4
+#define JFS_REVOKE_BLOCK	5
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+typedef struct journal_header_s
+{
+	__u32		h_magic;
+	__u32		h_blocktype;
+	__u32		h_sequence;
+} journal_header_t;
+
+
+/* 
+ * The block tag: used to describe a single buffer in the journal 
+ */
+typedef struct journal_block_tag_s
+{
+	__u32		t_blocknr;	/* The on-disk block number */
+	__u32		t_flags;	/* See below */
+} journal_block_tag_t;
+
+/* 
+ * The revoke descriptor: used on disk to describe a series of blocks to
+ * be revoked from the log 
+ */
+typedef struct journal_revoke_header_s
+{
+	journal_header_t r_header;
+	int		 r_count;	/* Count of bytes used in the block */
+} journal_revoke_header_t;
+
+
+/* Definitions for the journal tag flags word: */
+#define JFS_FLAG_ESCAPE		1	/* on-disk block is escaped */
+#define JFS_FLAG_SAME_UUID	2	/* block has same uuid as previous */
+#define JFS_FLAG_DELETED	4	/* block deleted by this transaction */
+#define JFS_FLAG_LAST_TAG	8	/* last tag in this descriptor block */
+
+
+/*
+ * The journal superblock.  All fields are in big-endian byte order.
+ */
+typedef struct journal_superblock_s
+{
+/* 0x0000 */
+	journal_header_t s_header;
+
+/* 0x000C */
+	/* Static information describing the journal */
+	__u32	s_blocksize;		/* journal device blocksize */
+	__u32	s_maxlen;		/* total blocks in journal file */
+	__u32	s_first;		/* first block of log information */
+	
+/* 0x0018 */
+	/* Dynamic information describing the current state of the log */
+	__u32	s_sequence;		/* first commit ID expected in log */
+	__u32	s_start;		/* blocknr of start of log */
+
+/* 0x0020 */
+	/* Error value, as set by journal_abort(). */
+	__s32	s_errno;
+
+/* 0x0024 */
+	/* Remaining fields are only valid in a version-2 superblock */
+	__u32	s_feature_compat; 	/* compatible feature set */
+	__u32	s_feature_incompat; 	/* incompatible feature set */
+	__u32	s_feature_ro_compat; 	/* readonly-compatible feature set */
+/* 0x0030 */
+	__u8	s_uuid[16];		/* 128-bit uuid for journal */
+
+/* 0x0040 */
+	__u32	s_nr_users;		/* Nr of filesystems sharing log */
+	
+	__u32	s_dynsuper;		/* Blocknr of dynamic superblock copy*/
+	
+/* 0x0048 */
+	__u32	s_max_transaction;	/* Limit of journal blocks per trans.*/
+	__u32	s_max_trans_data;	/* Limit of data blocks per trans. */
+
+/* 0x0050 */
+	__u32	s_padding[44];
+
+/* 0x0100 */
+	__u8	s_users[16*48];		/* ids of all fs'es sharing the log */
+/* 0x0400 */
+} journal_superblock_t;
+
+#define JFS_HAS_COMPAT_FEATURE(j,mask)					\
+	((j)->j_format_version >= 2 &&					\
+	 ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
+#define JFS_HAS_RO_COMPAT_FEATURE(j,mask)				\
+	((j)->j_format_version >= 2 &&					\
+	 ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
+#define JFS_HAS_INCOMPAT_FEATURE(j,mask)				\
+	((j)->j_format_version >= 2 &&					\
+	 ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
+
+#define JFS_FEATURE_INCOMPAT_REVOKE	0x00000001
+
+/* Features known to this kernel version: */
+#define JFS_KNOWN_COMPAT_FEATURES	0
+#define JFS_KNOWN_ROCOMPAT_FEATURES	0
+#define JFS_KNOWN_INCOMPAT_FEATURES	JFS_FEATURE_INCOMPAT_REVOKE
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+#define JBD_ASSERTIONS
+#ifdef JBD_ASSERTIONS
+#define J_ASSERT(assert)						\
+do {									\
+	if (!(assert)) {						\
+		printk (KERN_EMERG					\
+			"Assertion failure in %s() at %s:%d: \"%s\"\n",	\
+			__FUNCTION__, __FILE__, __LINE__, # assert);	\
+		BUG();							\
+	}								\
+} while (0)
+
+#if defined(CONFIG_BUFFER_DEBUG)
+void buffer_assertion_failure(struct buffer_head *bh);
+#define J_ASSERT_BH(bh, expr)						\
+	do {								\
+		if (!(expr))						\
+			buffer_assertion_failure(bh);			\
+		J_ASSERT(expr);						\
+	} while (0)
+#define J_ASSERT_JH(jh, expr)	J_ASSERT_BH(jh2bh(jh), expr)
+#else
+#define J_ASSERT_BH(bh, expr)	J_ASSERT(expr)
+#define J_ASSERT_JH(jh, expr)	J_ASSERT(expr)
+#endif
+
+#else
+#define J_ASSERT(assert)
+#endif		/* JBD_ASSERTIONS */
+
+enum jbd_state_bits {
+	BH_JWrite
+	  = BH_PrivateStart,	/* 1 if being written to log (@@@ DEBUGGING) */
+	BH_Freed,		/* 1 if buffer has been freed (truncated) */
+	BH_Revoked,		/* 1 if buffer has been revoked from the log */
+	BH_RevokeValid,		/* 1 if buffer revoked flag is valid */
+	BH_JBDDirty,		/* 1 if buffer is dirty but journaled */
+};
+
+/* Return true if the buffer is one which JBD is managing */
+static inline int buffer_jbd(struct buffer_head *bh)
+{
+	return __buffer_state(bh, JBD);
+}
+
+static inline struct buffer_head *jh2bh(struct journal_head *jh)
+{
+	return jh->b_bh;
+}
+
+static inline struct journal_head *bh2jh(struct buffer_head *bh)
+{
+	return bh->b_private;
+}
+
+struct jbd_revoke_table_s;
+
+/* The handle_t type represents a single atomic update being performed
+ * by some process.  All filesystem modifications made by the process go
+ * through this handle.  Recursive operations (such as quota operations)
+ * are gathered into a single update.
+ *
+ * The buffer credits field is used to account for journaled buffers
+ * being modified by the running process.  To ensure that there is
+ * enough log space for all outstanding operations, we need to limit the
+ * number of outstanding buffers possible at any time.  When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+ * outstanding updates on a transaction might possibly touch. */
+
+struct handle_s 
+{
+	/* Which compound transaction is this update a part of? */
+	transaction_t	      * h_transaction;
+
+	/* Number of remaining buffers we are allowed to dirty: */
+	int			h_buffer_credits;
+
+	/* Reference count on this handle */
+	int			h_ref;
+
+	/* Field for caller's use to track errors through large fs
+	   operations */
+	int			h_err;
+
+	/* Flags */
+	unsigned int	h_sync:		1;	/* sync-on-close */
+	unsigned int	h_jdata:	1;	/* force data journaling */
+	unsigned int	h_aborted:	1;	/* fatal error on handle */
+};
+
+
+/* The transaction_t type is the guts of the journaling mechanism.  It
+ * tracks a compound transaction through its various states:
+ *
+ * RUNNING:	accepting new updates
+ * LOCKED:	Updates still running but we don't accept new ones
+ * RUNDOWN:	Updates are tidying up but have finished requesting
+ *		new buffers to modify (state not used for now)
+ * FLUSH:       All updates complete, but we are still writing to disk
+ * COMMIT:      All data on disk, writing commit record
+ * FINISHED:	We still have to keep the transaction for checkpointing.
+ *
+ * The transaction keeps track of all of the buffers modified by a
+ * running transaction, and all of the buffers committed but not yet
+ * flushed to home for finished transactions.
+ */
+
+struct transaction_s 
+{
+	/* Pointer to the journal for this transaction. */
+	journal_t *		t_journal;
+	
+	/* Sequence number for this transaction */
+	tid_t			t_tid;
+	
+	/* Transaction's current state */
+	enum {
+		T_RUNNING,
+		T_LOCKED,
+		T_RUNDOWN,
+		T_FLUSH,
+		T_COMMIT,
+		T_FINISHED 
+	}			t_state;
+
+	/* Where in the log does this transaction's commit start? */
+	unsigned long		t_log_start;
+	
+	/* Doubly-linked circular list of all inodes owned by this
+           transaction */	/* AKPM: unused */
+	struct inode *		t_ilist;
+	
+	/* Number of buffers on the t_buffers list */
+	int			t_nr_buffers;
+	
+	/* Doubly-linked circular list of all buffers reserved but not
+           yet modified by this transaction */
+	struct journal_head *	t_reserved_list;
+	
+	/* Doubly-linked circular list of all metadata buffers owned by this
+           transaction */
+	struct journal_head *	t_buffers;
+	
+	/*
+	 * Doubly-linked circular list of all data buffers still to be
+	 * flushed before this transaction can be committed.
+	 * Protected by journal_datalist_lock.
+	 */
+	struct journal_head *	t_sync_datalist;
+	
+	/*
+	 * Doubly-linked circular list of all writepage data buffers
+	 * still to be written before this transaction can be committed.
+	 * Protected by journal_datalist_lock.
+	 */
+	struct journal_head *	t_async_datalist;
+	
+	/* Doubly-linked circular list of all forget buffers (superceded
+           buffers which we can un-checkpoint once this transaction
+           commits) */
+	struct journal_head *	t_forget;
+	
+	/*
+	 * Doubly-linked circular list of all buffers still to be
+	 * flushed before this transaction can be checkpointed.
+	 */
+	/* Protected by journal_datalist_lock */
+	struct journal_head *	t_checkpoint_list;
+	
+	/* Doubly-linked circular list of temporary buffers currently
+           undergoing IO in the log */
+	struct journal_head *	t_iobuf_list;
+	
+	/* Doubly-linked circular list of metadata buffers being
+           shadowed by log IO.  The IO buffers on the iobuf list and the
+           shadow buffers on this list match each other one for one at
+           all times. */
+	struct journal_head *	t_shadow_list;
+	
+	/* Doubly-linked circular list of control buffers being written
+           to the log. */
+	struct journal_head *	t_log_list;
+	
+	/* Number of outstanding updates running on this transaction */
+	int			t_updates;
+
+	/* Number of buffers reserved for use by all handles in this
+	 * transaction handle but not yet modified. */
+	int			t_outstanding_credits;
+	
+	/*
+	 * Forward and backward links for the circular list of all
+	 * transactions awaiting checkpoint.
+	 */
+	/* Protected by journal_datalist_lock */
+	transaction_t		*t_cpnext, *t_cpprev;
+
+	/* When will the transaction expire (become due for commit), in
+	 * jiffies ? */
+	unsigned long		t_expires;
+
+	/* How many handles used this transaction? */
+	int t_handle_count;
+};
+
+
+/* The journal_t maintains all of the journaling state information for a
+ * single filesystem.  It is linked to from the fs superblock structure.
+ * 
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process. */
+
+struct journal_s
+{
+	/* General journaling state flags */
+	unsigned long		j_flags;
+
+	/* Is there an outstanding uncleared error on the journal (from
+	 * a prior abort)? */
+	int			j_errno;
+	
+	/* The superblock buffer */
+	struct buffer_head *	j_sb_buffer;
+	journal_superblock_t *	j_superblock;
+
+	/* Version of the superblock format */
+	int			j_format_version;
+
+	/* Number of processes waiting to create a barrier lock */
+	int			j_barrier_count;
+	
+	/* The barrier lock itself */
+	struct semaphore	j_barrier;
+	
+	/* Transactions: The current running transaction... */
+	transaction_t *		j_running_transaction;
+	
+	/* ... the transaction we are pushing to disk ... */
+	transaction_t *		j_committing_transaction;
+	
+	/* ... and a linked circular list of all transactions waiting
+	 * for checkpointing. */
+	/* Protected by journal_datalist_lock */
+	transaction_t *		j_checkpoint_transactions;
+
+	/* Wait queue for waiting for a locked transaction to start
+           committing, or for a barrier lock to be released */
+	wait_queue_head_t	j_wait_transaction_locked;
+	
+	/* Wait queue for waiting for checkpointing to complete */
+	wait_queue_head_t	j_wait_logspace;
+	
+	/* Wait queue for waiting for commit to complete */
+	wait_queue_head_t	j_wait_done_commit;
+	
+	/* Wait queue to trigger checkpointing */
+	wait_queue_head_t	j_wait_checkpoint;
+	
+	/* Wait queue to trigger commit */
+	wait_queue_head_t	j_wait_commit;
+	
+	/* Wait queue to wait for updates to complete */
+	wait_queue_head_t	j_wait_updates;
+
+	/* Semaphore for locking against concurrent checkpoints */
+	struct semaphore 	j_checkpoint_sem;
+
+	/* The main journal lock, used by lock_journal() */
+	struct semaphore	j_sem;
+		
+	/* Journal head: identifies the first unused block in the journal. */
+	unsigned long		j_head;
+	
+	/* Journal tail: identifies the oldest still-used block in the
+	 * journal. */
+	unsigned long		j_tail;
+
+	/* Journal free: how many free blocks are there in the journal? */
+	unsigned long		j_free;
+
+	/* Journal start and end: the block numbers of the first usable
+	 * block and one beyond the last usable block in the journal. */
+	unsigned long		j_first, j_last;
+
+	/* Device, blocksize and starting block offset for the location
+	 * where we store the journal. */
+	kdev_t			j_dev;
+	int			j_blocksize;
+	unsigned int		j_blk_offset;
+
+	/* Device which holds the client fs.  For internal journal this
+	 * will be equal to j_dev. */
+	kdev_t			j_fs_dev;
+
+	/* Total maximum capacity of the journal region on disk. */
+	unsigned int		j_maxlen;
+
+	/* Optional inode where we store the journal.  If present, all
+	 * journal block numbers are mapped into this inode via
+	 * bmap(). */
+	struct inode *		j_inode;
+
+	/* Sequence number of the oldest transaction in the log */
+	tid_t			j_tail_sequence;
+	/* Sequence number of the next transaction to grant */
+	tid_t			j_transaction_sequence;
+	/* Sequence number of the most recently committed transaction */
+	tid_t			j_commit_sequence;
+	/* Sequence number of the most recent transaction wanting commit */
+	tid_t			j_commit_request;
+
+	/* Journal uuid: identifies the object (filesystem, LVM volume
+	 * etc) backed by this journal.  This will eventually be
+	 * replaced by an array of uuids, allowing us to index multiple
+	 * devices within a single journal and to perform atomic updates
+	 * across them.  */
+
+	__u8			j_uuid[16];
+
+	/* Pointer to the current commit thread for this journal */
+	struct task_struct *	j_task;
+
+	/* Maximum number of metadata buffers to allow in a single
+	 * compound commit transaction */
+	int			j_max_transaction_buffers;
+
+	/* What is the maximum transaction lifetime before we begin a
+	 * commit? */
+	unsigned long		j_commit_interval;
+
+	/* The timer used to wakeup the commit thread: */
+	struct timer_list *	j_commit_timer;
+	int			j_commit_timer_active;
+
+	/* Link all journals together - system-wide */
+	struct list_head	j_all_journals;
+
+	/* The revoke table: maintains the list of revoked blocks in the
+           current transaction. */
+	struct jbd_revoke_table_s *j_revoke;
+};
+
+/* 
+ * Journal flag definitions 
+ */
+#define JFS_UNMOUNT	0x001	/* Journal thread is being destroyed */
+#define JFS_ABORT	0x002	/* Journaling has been aborted for errors. */
+#define JFS_ACK_ERR	0x004	/* The errno in the sb has been acked */
+#define JFS_FLUSHED	0x008	/* The journal superblock has been flushed */
+#define JFS_LOADED	0x010	/* The journal superblock has been loaded */
+
+/* 
+ * Function declarations for the journaling transaction and buffer
+ * management
+ */
+
+/* Filing buffers */
+extern void __journal_unfile_buffer(struct journal_head *);
+extern void journal_unfile_buffer(struct journal_head *);
+extern void __journal_refile_buffer(struct journal_head *);
+extern void journal_refile_buffer(struct journal_head *);
+extern void __journal_file_buffer(struct journal_head *, transaction_t *, int);
+extern void __journal_free_buffer(struct journal_head *bh);
+extern void journal_file_buffer(struct journal_head *, transaction_t *, int);
+extern void __journal_clean_data_list(transaction_t *transaction);
+
+/* Log buffer allocation */
+extern struct journal_head * journal_get_descriptor_buffer(journal_t *);
+extern unsigned long journal_next_log_block(journal_t *);
+
+/* Commit management */
+extern void journal_commit_transaction(journal_t *);
+
+/* Checkpoint list management */
+int __journal_clean_checkpoint_list(journal_t *journal);
+extern void journal_remove_checkpoint(struct journal_head *);
+extern void __journal_remove_checkpoint(struct journal_head *);
+extern void journal_insert_checkpoint(struct journal_head *, transaction_t *);
+extern void __journal_insert_checkpoint(struct journal_head *,transaction_t *);
+
+/* Buffer IO */
+extern int 
+journal_write_metadata_buffer(transaction_t	  *transaction,
+			      struct journal_head  *jh_in,
+			      struct journal_head **jh_out,
+			      int		   blocknr);
+
+/* Transaction locking */
+extern void		__wait_on_journal (journal_t *);
+
+/*
+ * Journal locking.
+ *
+ * We need to lock the journal during transaction state changes so that
+ * nobody ever tries to take a handle on the running transaction while
+ * we are in the middle of moving it to the commit phase.  
+ *
+ * Note that the locking is completely interrupt unsafe.  We never touch
+ * journal structures from interrupts.
+ *
+ * In 2.2, the BKL was required for lock_journal.  This is no longer
+ * the case.
+ */
+
+static inline void lock_journal(journal_t *journal)
+{
+	down(&journal->j_sem);
+}
+
+/* This returns zero if we acquired the semaphore */
+static inline int try_lock_journal(journal_t * journal)
+{
+	return down_trylock(&journal->j_sem);
+}
+
+static inline void unlock_journal(journal_t * journal)
+{
+	up(&journal->j_sem);
+}
+
+
+static inline handle_t *journal_current_handle(void)
+{
+	return current->journal_info;
+}
+
+/* The journaling code user interface:
+ *
+ * Create and destroy handles
+ * Register buffer modifications against the current transaction. 
+ */
+
+extern handle_t *journal_start(journal_t *, int nblocks);
+extern handle_t *journal_try_start(journal_t *, int nblocks);
+extern int	 journal_restart (handle_t *, int nblocks);
+extern int	 journal_extend (handle_t *, int nblocks);
+extern int	 journal_get_write_access (handle_t *, struct buffer_head *);
+extern int	 journal_get_create_access (handle_t *, struct buffer_head *);
+extern int	 journal_get_undo_access (handle_t *, struct buffer_head *);
+extern int	 journal_dirty_data (handle_t *,
+				struct buffer_head *, int async);
+extern int	 journal_dirty_metadata (handle_t *, struct buffer_head *);
+extern void	 journal_release_buffer (handle_t *, struct buffer_head *);
+extern void	 journal_forget (handle_t *, struct buffer_head *);
+extern void	 journal_sync_buffer (struct buffer_head *);
+extern int	 journal_flushpage(journal_t *, struct page *, unsigned long);
+extern int	 journal_try_to_free_buffers(journal_t *, struct page *, int);
+extern int	 journal_stop(handle_t *);
+extern int	 journal_flush (journal_t *);
+
+extern void	 journal_lock_updates (journal_t *);
+extern void	 journal_unlock_updates (journal_t *);
+
+extern journal_t * journal_init_dev(kdev_t dev, kdev_t fs_dev,
+				int start, int len, int bsize);
+extern journal_t * journal_init_inode (struct inode *);
+extern int	   journal_update_format (journal_t *);
+extern int	   journal_check_used_features 
+		   (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int	   journal_check_available_features 
+		   (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int	   journal_set_features 
+		   (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int	   journal_create     (journal_t *);
+extern int	   journal_load       (journal_t *journal);
+extern void	   journal_destroy    (journal_t *);
+extern int	   journal_recover    (journal_t *journal);
+extern int	   journal_wipe       (journal_t *, int);
+extern int	   journal_skip_recovery (journal_t *);
+extern void	   journal_update_superblock (journal_t *, int);
+extern void	   __journal_abort      (journal_t *);
+extern void	   journal_abort      (journal_t *, int);
+extern int	   journal_errno      (journal_t *);
+extern void	   journal_ack_err    (journal_t *);
+extern int	   journal_clear_err  (journal_t *);
+extern unsigned long journal_bmap(journal_t *journal, unsigned long blocknr);
+extern int	    journal_force_commit(journal_t *journal);
+
+/*
+ * journal_head management
+ */
+extern struct journal_head
+		*journal_add_journal_head(struct buffer_head *bh);
+extern void	journal_remove_journal_head(struct buffer_head *bh);
+extern void	__journal_remove_journal_head(struct buffer_head *bh);
+extern void	journal_unlock_journal_head(struct journal_head *jh);
+
+/* Primary revoke support */
+#define JOURNAL_REVOKE_DEFAULT_HASH 256
+extern int	   journal_init_revoke(journal_t *, int);
+extern void	   journal_destroy_revoke_caches(void);
+extern int	   journal_init_revoke_caches(void);
+
+extern void	   journal_destroy_revoke(journal_t *);
+extern int	   journal_revoke (handle_t *,
+				unsigned long, struct buffer_head *);
+extern int	   journal_cancel_revoke(handle_t *, struct journal_head *);
+extern void	   journal_write_revoke_records(journal_t *, transaction_t *);
+
+/* Recovery revoke support */
+extern int	   journal_set_revoke(journal_t *, unsigned long, tid_t);
+extern int	   journal_test_revoke(journal_t *, unsigned long, tid_t);
+extern void	   journal_clear_revoke(journal_t *);
+extern void	   journal_brelse_array(struct buffer_head *b[], int n);
+
+/* The log thread user interface:
+ *
+ * Request space in the current transaction, and force transaction commit
+ * transitions on demand.
+ */
+
+extern int	log_space_left (journal_t *); /* Called with journal locked */
+extern tid_t	log_start_commit (journal_t *, transaction_t *);
+extern void	log_wait_commit (journal_t *, tid_t);
+extern int	log_do_checkpoint (journal_t *, int);
+
+extern void	log_wait_for_space(journal_t *, int nblocks);
+extern void	__journal_drop_transaction(journal_t *, transaction_t *);
+extern int	cleanup_journal_tail(journal_t *);
+
+/* Reduce journal memory usage by flushing */
+extern void shrink_journal_memory(void);
+
+/* Debugging code only: */
+
+#define jbd_ENOSYS() \
+do {								      \
+	printk (KERN_ERR "JBD unimplemented function " __FUNCTION__); \
+	current->state = TASK_UNINTERRUPTIBLE;			      \
+	schedule();						      \
+} while (1)
+
+/*
+ * is_journal_abort
+ *
+ * Simple test wrapper function to test the JFS_ABORT state flag.  This
+ * bit, when set, indicates that we have had a fatal error somewhere,
+ * either inside the journaling layer or indicated to us by the client
+ * (eg. ext3), and that we and should not commit any further
+ * transactions.  
+ */
+
+static inline int is_journal_aborted(journal_t *journal)
+{
+	return journal->j_flags & JFS_ABORT;
+}
+
+static inline int is_handle_aborted(handle_t *handle)
+{
+	if (handle->h_aborted)
+		return 1;
+	return is_journal_aborted(handle->h_transaction->t_journal);
+}
+
+static inline void journal_abort_handle(handle_t *handle)
+{
+	handle->h_aborted = 1;
+}
+
+/* Not all architectures define BUG() */
+#ifndef BUG
+#define BUG() do { \
+        printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+	* ((char *) 0) = 0; \
+ } while (0)
+#endif /* BUG */
+
+#else
+
+extern int	   journal_recover    (journal_t *journal);
+extern int	   journal_skip_recovery (journal_t *);
+
+/* Primary revoke support */
+extern int	   journal_init_revoke(journal_t *, int);
+extern void	   journal_destroy_revoke_caches(void);
+extern int	   journal_init_revoke_caches(void);
+
+/* Recovery revoke support */
+extern int	   journal_set_revoke(journal_t *, unsigned long, tid_t);
+extern int	   journal_test_revoke(journal_t *, unsigned long, tid_t);
+extern void	   journal_clear_revoke(journal_t *);
+extern void	   journal_brelse_array(struct buffer_head *b[], int n);
+
+extern void	   journal_destroy_revoke(journal_t *);
+#endif /* __KERNEL__   */
+
+/* Comparison functions for transaction IDs: perform comparisons using
+ * modulo arithmetic so that they work over sequence number wraps. */
+
+static inline int tid_gt(tid_t x, tid_t y)
+{
+	int difference = (x - y);
+	return (difference > 0);
+}
+
+static inline int tid_geq(tid_t x, tid_t y)
+{
+	int difference = (x - y);
+	return (difference >= 0);
+}
+
+extern int journal_blocks_per_page(struct inode *inode);
+
+/*
+ * Definitions which augment the buffer_head layer
+ */
+
+/* journaling buffer types */
+#define BJ_None		0	/* Not journaled */
+#define BJ_SyncData	1	/* Normal data: flush before commit */
+#define BJ_AsyncData	2	/* writepage data: wait on it before commit */
+#define BJ_Metadata	3	/* Normal journaled metadata */
+#define BJ_Forget	4	/* Buffer superceded by this transaction */
+#define BJ_IO		5	/* Buffer is for temporary IO use */
+#define BJ_Shadow	6	/* Buffer contents being shadowed to the log */
+#define BJ_LogCtl	7	/* Buffer contains log descriptors */
+#define BJ_Reserved	8	/* Buffer is reserved for access by journal */
+#define BJ_Types	9
+ 
+extern int jbd_blocks_per_page(struct inode *inode);
+
+#ifdef __KERNEL__
+
+extern spinlock_t jh_splice_lock;
+/*
+ * Once `expr1' has been found true, take jh_splice_lock
+ * and then reevaluate everything.
+ */
+#define SPLICE_LOCK(expr1, expr2)				\
+	({							\
+		int ret = (expr1);				\
+		if (ret) {					\
+			spin_lock(&jh_splice_lock);		\
+			ret = (expr1) && (expr2);		\
+			spin_unlock(&jh_splice_lock);		\
+		}						\
+		ret;						\
+	})
+
+/*
+ * A number of buffer state predicates.  They test for
+ * buffer_jbd() because they are used in core kernel code.
+ *
+ * These will be racy on SMP unless we're *sure* that the
+ * buffer won't be detached from the journalling system
+ * in parallel.
+ */
+
+/* Return true if the buffer is on journal list `list' */
+static inline int buffer_jlist_eq(struct buffer_head *bh, int list)
+{
+	return SPLICE_LOCK(buffer_jbd(bh), bh2jh(bh)->b_jlist == list);
+}
+
+/* Return true if this bufer is dirty wrt the journal */
+static inline int buffer_jdirty(struct buffer_head *bh)
+{
+	return buffer_jbd(bh) && __buffer_state(bh, JBDDirty);
+}
+
+/* Return true if it's a data buffer which journalling is managing */
+static inline int buffer_jbd_data(struct buffer_head *bh)
+{
+	return SPLICE_LOCK(buffer_jbd(bh),
+			bh2jh(bh)->b_jlist == BJ_SyncData ||
+			bh2jh(bh)->b_jlist == BJ_AsyncData);
+}
+
+#ifdef CONFIG_SMP
+#define assert_spin_locked(lock)	J_ASSERT(spin_is_locked(lock))
+#else
+#define assert_spin_locked(lock)	do {} while(0)
+#endif
+
+#define buffer_trace_init(bh)	do {} while (0)
+#define print_buffer_fields(bh)	do {} while (0)
+#define print_buffer_trace(bh)	do {} while (0)
+#define BUFFER_TRACE(bh, info)	do {} while (0)
+#define BUFFER_TRACE2(bh, bh2, info)	do {} while (0)
+#define JBUFFER_TRACE(jh, info)	do {} while (0)
+
+#endif	/* __KERNEL__ */
+
+#endif	/* CONFIG_JBD || CONFIG_JBD_MODULE || !__KERNEL__ */
+
+/*
+ * Compatibility no-ops which allow the kernel to compile without CONFIG_JBD
+ * go here.
+ */
+
+#if defined(__KERNEL__) && !(defined(CONFIG_JBD) || defined(CONFIG_JBD_MODULE))
+
+#define J_ASSERT(expr)			do {} while (0)
+#define J_ASSERT_BH(bh, expr)		do {} while (0)
+#define buffer_jbd(bh)			0
+#define buffer_jlist_eq(bh, val)	0
+#define journal_buffer_journal_lru(bh)	0
+
+#endif	/* defined(__KERNEL__) && !defined(CONFIG_JBD) */
+#endif	/* _LINUX_JBD_H */
diff -Naur silo-1.4.11.orig/libext2fs/kernel-list.h silo-1.4.11/libext2fs/kernel-list.h
--- silo-1.4.11.orig/libext2fs/kernel-list.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/kernel-list.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,112 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = { &name, &name }
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+#if (!defined(__GNUC__) && !defined(__WATCOMC__))
+#define __inline__
+#endif
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/*
+ * Insert a new entry after the specified head..
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/*
+ * Insert a new entry at the tail
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+static __inline__ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/*
+ * Splice in "list" into "head"
+ */
+static __inline__ void list_splice(struct list_head *list, struct list_head *head)
+{
+	struct list_head *first = list->next;
+
+	if (first != list) {
+		struct list_head *last = list->prev;
+		struct list_head *at = head->next;
+
+		first->prev = head;
+		head->next = first;
+
+		last->next = at;
+		at->prev = last;
+	}
+}
+
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+#define list_for_each(pos, head) \
+        for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#endif
diff -Naur silo-1.4.11.orig/libext2fs/link.c silo-1.4.11/libext2fs/link.c
--- silo-1.4.11.orig/libext2fs/link.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/link.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,134 @@
+/*
+ * link.c --- create links in a ext2fs directory
+ * 
+ * Copyright (C) 1993, 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct link_struct  {
+	const char	*name;
+	int		namelen;
+	ext2_ino_t	inode;
+	int		flags;
+	int		done;
+	struct ext2_super_block *sb;
+};	
+
+static int link_proc(struct ext2_dir_entry *dirent,
+		     int	offset,
+		     int	blocksize,
+		     char	*buf,
+		     void	*priv_data)
+{
+	struct link_struct *ls = (struct link_struct *) priv_data;
+	struct ext2_dir_entry *next;
+	int rec_len, min_rec_len;
+	int ret = 0;
+
+	rec_len = EXT2_DIR_REC_LEN(ls->namelen);
+
+	/*
+	 * See if the following directory entry (if any) is unused;
+	 * if so, absorb it into this one.
+	 */
+	next = (struct ext2_dir_entry *) (buf + offset + dirent->rec_len);
+	if ((offset + dirent->rec_len < blocksize - 8) &&
+	    (next->inode == 0) &&
+	    (offset + dirent->rec_len + next->rec_len <= blocksize)) {
+		dirent->rec_len += next->rec_len;
+		ret = DIRENT_CHANGED;
+	}
+
+	/*
+	 * If the directory entry is used, see if we can split the
+	 * directory entry to make room for the new name.  If so,
+	 * truncate it and return.
+	 */
+	if (dirent->inode) {
+		min_rec_len = EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+		if (dirent->rec_len < (min_rec_len + rec_len))
+			return ret;
+		rec_len = dirent->rec_len - min_rec_len;
+		dirent->rec_len = min_rec_len;
+		next = (struct ext2_dir_entry *) (buf + offset +
+						  dirent->rec_len);
+		next->inode = 0;
+		next->name_len = 0;
+		next->rec_len = rec_len;
+		return DIRENT_CHANGED;
+	}
+
+	/*
+	 * If we get this far, then the directory entry is not used.
+	 * See if we can fit the request entry in.  If so, do it.
+	 */
+	if (dirent->rec_len < rec_len)
+		return ret;
+	dirent->inode = ls->inode;
+	dirent->name_len = ls->namelen;
+	strncpy(dirent->name, ls->name, ls->namelen);
+	if (ls->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
+		dirent->name_len |= (ls->flags & 0x7) << 8;
+
+	ls->done++;
+	return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+/*
+ * Note: the low 3 bits of the flags field are used as the directory
+ * entry filetype.
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, 
+		      ext2_ino_t ino, int flags)
+{
+	errcode_t		retval;
+	struct link_struct	ls;
+	struct ext2_inode	inode;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	ls.name = name;
+	ls.namelen = name ? strlen(name) : 0;
+	ls.inode = ino;
+	ls.flags = flags;
+	ls.done = 0;
+	ls.sb = fs->super;
+
+	retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY,
+				    0, link_proc, &ls);
+	if (retval)
+		return retval;
+
+	if (!ls.done)
+		return EXT2_ET_DIR_NO_SPACE;
+
+	if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0)
+		return retval;
+
+	if (inode.i_flags & EXT2_INDEX_FL) {
+		inode.i_flags &= ~EXT2_INDEX_FL;
+		if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0)
+			return retval;
+	}
+
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/llseek.c silo-1.4.11/libext2fs/llseek.c
--- silo-1.4.11.orig/libext2fs/llseek.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/llseek.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,138 @@
+/*
+ * llseek.c -- stub calling the llseek system call
+ *
+ * Copyright (C) 1994, 1995, 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __MSDOS__
+#include <io.h>
+#endif
+#include "et/com_err.h"
+#include "ext2fs/ext2_io.h"
+
+#ifdef __linux__
+
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+
+#define my_llseek lseek64
+
+#else
+#if defined(HAVE_LLSEEK)
+#include <syscall.h>
+
+#ifndef HAVE_LLSEEK_PROTOTYPE
+extern long long llseek (int fd, long long offset, int origin);
+#endif
+
+#define my_llseek llseek
+
+#else	/* ! HAVE_LLSEEK */
+
+#if defined(__alpha__) || defined (__ia64__)
+
+#define llseek lseek
+
+#else /* !__alpha__ && !__ia64__*/
+
+#include <linux/unistd.h>
+
+#ifndef __NR__llseek
+#define __NR__llseek            140
+#endif
+
+#ifndef __i386__
+static int _llseek (unsigned int, unsigned long,
+		   unsigned long, ext2_loff_t *, unsigned int);
+
+static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high,
+		 unsigned long, offset_low,ext2_loff_t *,result,
+		 unsigned int, origin)
+#endif
+
+static ext2_loff_t my_llseek (int fd, ext2_loff_t offset, int origin)
+{
+	ext2_loff_t result;
+	int retval;
+
+#ifndef __i386__
+	retval = _llseek(fd, ((unsigned long long) offset) >> 32,
+#else			  
+	retval = syscall(__NR__llseek, fd, (unsigned long long) (offset >> 32),
+#endif
+			  ((unsigned long long) offset) & 0xffffffff,
+			&result, origin);
+	return (retval == -1 ? (ext2_loff_t) retval : result);
+}
+
+#endif	/* __alpha__ || __ia64__ */
+
+#endif /* HAVE_LLSEEK */
+#endif /* defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE) */
+
+ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
+{
+	ext2_loff_t result;
+	static int do_compat = 0;
+
+	if ((sizeof(off_t) >= sizeof(ext2_loff_t)) ||
+	    (offset < ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1))))
+		return lseek(fd, (off_t) offset, origin);
+
+	if (do_compat) {
+		errno = EINVAL;
+		return -1;
+	}
+	
+	result = my_llseek (fd, offset, origin);
+	if (result == -1 && errno == ENOSYS) {
+		/*
+		 * Just in case this code runs on top of an old kernel
+		 * which does not support the llseek system call
+		 */
+		do_compat++;
+		errno = EINVAL;
+	}
+	return result;
+}
+
+#else /* !linux */
+
+#ifndef EINVAL
+#define EINVAL EXT2_ET_INVALID_ARGUMENT
+#endif
+
+ext2_loff_t ext2fs_llseek (int fd, ext2_loff_t offset, int origin)
+{
+#if defined(HAVE_LSEEK64) && defined(HAVE_LSEEK64_PROTOTYPE)
+	return lseek64 (fd, offset, origin);
+#else
+	if ((sizeof(off_t) < sizeof(ext2_loff_t)) &&
+	    (offset >= ((ext2_loff_t) 1 << ((sizeof(off_t)*8) -1)))) {
+		errno = EINVAL;
+		return -1;
+	}
+	return lseek (fd, (off_t) offset, origin);
+#endif
+}
+
+#endif 	/* linux */
+
+
diff -Naur silo-1.4.11.orig/libext2fs/lookup.c silo-1.4.11/libext2fs/lookup.c
--- silo-1.4.11.orig/libext2fs/lookup.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/lookup.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,69 @@
+/*
+ * lookup.c --- ext2fs directory lookup operations
+ * 
+ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct lookup_struct  {
+	const char	*name;
+	int		len;
+	ext2_ino_t	*inode;
+	int		found;
+};	
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int lookup_proc(struct ext2_dir_entry *dirent,
+		       int	offset EXT2FS_ATTR((unused)),
+		       int	blocksize EXT2FS_ATTR((unused)),
+		       char	*buf EXT2FS_ATTR((unused)),
+		       void	*priv_data)
+{
+	struct lookup_struct *ls = (struct lookup_struct *) priv_data;
+
+	if (ls->len != (dirent->name_len & 0xFF))
+		return 0;
+	if (strncmp(ls->name, dirent->name, (dirent->name_len & 0xFF)))
+		return 0;
+	*ls->inode = dirent->inode;
+	ls->found++;
+	return DIRENT_ABORT;
+}
+
+
+errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name,
+			int namelen, char *buf, ext2_ino_t *inode)
+{
+	errcode_t	retval;
+	struct lookup_struct ls;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	ls.name = name;
+	ls.len = namelen;
+	ls.inode = inode;
+	ls.found = 0;
+
+	retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls);
+	if (retval)
+		return retval;
+
+	return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND;
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/mkdir.c silo-1.4.11/libext2fs/mkdir.c
--- silo-1.4.11.orig/libext2fs/mkdir.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/mkdir.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,142 @@
+/*
+ * mkdir.c --- make a directory in the filesystem
+ * 
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef EXT2_FT_DIR
+#define EXT2_FT_DIR		2
+#endif
+
+errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum,
+		       const char *name)
+{
+	errcode_t		retval;
+	struct ext2_inode	parent_inode, inode;
+	ext2_ino_t		ino = inum;
+	ext2_ino_t		scratch_ino;
+	blk_t			blk;
+	char			*block = 0;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	/*
+	 * Allocate an inode, if necessary
+	 */
+	if (!ino) {
+		retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755,
+					  0, &ino);
+		if (retval)
+			goto cleanup;
+	}
+
+	/*
+	 * Allocate a data block for the directory
+	 */
+	retval = ext2fs_new_block(fs, 0, 0, &blk);
+	if (retval)
+		goto cleanup;
+
+	/*
+	 * Create a scratch template for the directory
+	 */
+	retval = ext2fs_new_dir_block(fs, ino, parent, &block);
+	if (retval)
+		goto cleanup;
+
+	/*
+	 * Get the parent's inode, if necessary
+	 */
+	if (parent != ino) {
+		retval = ext2fs_read_inode(fs, parent, &parent_inode);
+		if (retval)
+			goto cleanup;
+	} else
+		memset(&parent_inode, 0, sizeof(parent_inode));
+
+	/*
+	 * Create the inode structure....
+	 */
+	memset(&inode, 0, sizeof(struct ext2_inode));
+	inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask);
+	inode.i_uid = inode.i_gid = 0;
+	inode.i_blocks = fs->blocksize / 512;
+	inode.i_block[0] = blk;
+	inode.i_links_count = 2;
+	inode.i_ctime = inode.i_atime = inode.i_mtime = time(NULL);
+	inode.i_size = fs->blocksize;
+
+	/*
+	 * Write out the inode and inode data block
+	 */
+	retval = ext2fs_write_dir_block(fs, blk, block);
+	if (retval)
+		goto cleanup;
+	retval = ext2fs_write_new_inode(fs, ino, &inode); 
+	if (retval)
+		goto cleanup;
+
+	/*
+	 * Link the directory into the filesystem hierarchy
+	 */
+	if (name) {
+		retval = ext2fs_lookup(fs, parent, name, strlen(name), 0,
+				       &scratch_ino);
+		if (!retval) {
+			retval = EXT2_ET_DIR_EXISTS;
+			name = 0;
+			goto cleanup;
+		}
+		if (retval != EXT2_ET_FILE_NOT_FOUND)
+			goto cleanup;
+		retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR);
+		if (retval)
+			goto cleanup;
+	}
+
+	/*
+	 * Update parent inode's counts
+	 */
+	if (parent != ino) {
+		parent_inode.i_links_count++;
+		retval = ext2fs_write_inode(fs, parent, &parent_inode);
+		if (retval)
+			goto cleanup;
+	}
+	
+	/*
+	 * Update accounting....
+	 */
+	ext2fs_block_alloc_stats(fs, blk, +1);
+	ext2fs_inode_alloc_stats2(fs, ino, +1, 1);
+
+cleanup:
+	if (block)
+		ext2fs_free_mem(&block);
+	return retval;
+
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/mkjournal.c silo-1.4.11/libext2fs/mkjournal.c
--- silo-1.4.11.orig/libext2fs/mkjournal.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/mkjournal.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,425 @@
+/*
+ * mkjournal.c --- make a journal for a filesystem
+ *
+ * Copyright (C) 2000 Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "ext2_fs.h"
+#include "e2p/e2p.h"
+#include "ext2fs.h"
+#include "jfs_user.h"
+
+/*
+ * This function automatically sets up the journal superblock and
+ * returns it as an allocated block.
+ */
+errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
+					   __u32 size, int flags,
+					   char  **ret_jsb)
+{
+	errcode_t		retval;
+	journal_superblock_t	*jsb;
+
+	if (size < 1024)
+		return EXT2_ET_JOURNAL_TOO_SMALL;
+
+	if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
+		return retval;
+
+	memset (jsb, 0, fs->blocksize);
+
+	jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
+	if (flags & EXT2_MKJOURNAL_V1_SUPER)
+		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
+	else
+		jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
+	jsb->s_blocksize = htonl(fs->blocksize);
+	jsb->s_maxlen = htonl(size);
+	jsb->s_nr_users = htonl(1);
+	jsb->s_first = htonl(1);
+	jsb->s_sequence = htonl(1);
+	memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
+	/*
+	 * If we're creating an external journal device, we need to
+	 * adjust these fields.
+	 */
+	if (fs->super->s_feature_incompat &
+	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+		jsb->s_nr_users = 0;
+		if (fs->blocksize == 1024)
+			jsb->s_first = htonl(3);
+		else
+			jsb->s_first = htonl(2);
+	}
+
+	*ret_jsb = (char *) jsb;
+	return 0;
+}
+
+/*
+ * This function writes a journal using POSIX routines.  It is used
+ * for creating external journals and creating journals on live
+ * filesystems.
+ */
+static errcode_t write_journal_file(ext2_filsys fs, char *filename,
+				    blk_t size, int flags)
+{
+	errcode_t	retval;
+	char		*buf = 0;
+	int		fd, ret_size;
+	blk_t		i;
+
+	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
+		return retval;
+
+	/* Open the device or journal file */
+	if ((fd = open(filename, O_WRONLY)) < 0) {
+		retval = errno;
+		goto errout;
+	}
+
+	/* Write the superblock out */
+	retval = EXT2_ET_SHORT_WRITE;
+	ret_size = write(fd, buf, fs->blocksize);
+	if (ret_size < 0) {
+		retval = errno;
+		goto errout;
+	}
+	if (ret_size != (int) fs->blocksize)
+		goto errout;
+	memset(buf, 0, fs->blocksize);
+
+	for (i = 1; i < size; i++) {
+		ret_size = write(fd, buf, fs->blocksize);
+		if (ret_size < 0) {
+			retval = errno;
+			goto errout;
+		}
+		if (ret_size != (int) fs->blocksize)
+			goto errout;
+	}
+	close(fd);
+
+	retval = 0;
+errout:
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
+/*
+ * Helper function for creating the journal using direct I/O routines
+ */
+struct mkjournal_struct {
+	int		num_blocks;
+	int		newblocks;
+	char		*buf;
+	errcode_t	err;
+};
+
+static int mkjournal_proc(ext2_filsys	fs,
+			   blk_t	*blocknr,
+			   e2_blkcnt_t	blockcnt,
+			   blk_t	ref_block EXT2FS_ATTR((unused)),
+			   int		ref_offset EXT2FS_ATTR((unused)),
+			   void		*priv_data)
+{
+	struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
+	blk_t	new_blk;
+	static blk_t	last_blk = 0;
+	errcode_t	retval;
+	
+	if (*blocknr) {
+		last_blk = *blocknr;
+		return 0;
+	}
+	retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
+	if (retval) {
+		es->err = retval;
+		return BLOCK_ABORT;
+	}
+	if (blockcnt > 0)
+		es->num_blocks--;
+
+	es->newblocks++;
+	retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
+
+	if (blockcnt == 0)
+		memset(es->buf, 0, fs->blocksize);
+
+	if (retval) {
+		es->err = retval;
+		return BLOCK_ABORT;
+	}
+	*blocknr = new_blk;
+	last_blk = new_blk;
+	ext2fs_block_alloc_stats(fs, new_blk, +1);
+
+	if (es->num_blocks == 0)
+		return (BLOCK_CHANGED | BLOCK_ABORT);
+	else
+		return BLOCK_CHANGED;
+	
+}
+
+/*
+ * This function creates a journal using direct I/O routines.
+ */
+static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
+				     blk_t size, int flags)
+{
+	char			*buf;
+	errcode_t		retval;
+	struct ext2_inode	inode;
+	struct mkjournal_struct	es;
+
+	if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
+		return retval;
+	
+	if ((retval = ext2fs_read_bitmaps(fs)))
+		return retval;
+
+	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
+		return retval;
+
+	if (inode.i_blocks > 0)
+		return EEXIST;
+
+	es.num_blocks = size;
+	es.newblocks = 0;
+	es.buf = buf;
+	es.err = 0;
+
+	retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
+				       0, mkjournal_proc, &es);
+	if (es.err) {
+		retval = es.err;
+		goto errout;
+	}
+
+	if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
+		goto errout;
+
+ 	inode.i_size += fs->blocksize * size;
+	inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
+	inode.i_mtime = inode.i_ctime = time(0);
+	inode.i_links_count = 1;
+	inode.i_mode = LINUX_S_IFREG | 0600;
+
+	if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
+		goto errout;
+	retval = 0;
+
+	memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
+	fs->super->s_jnl_blocks[16] = inode.i_size;
+	fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
+	ext2fs_mark_super_dirty(fs);
+
+errout:
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
+/*
+ * This function adds a journal device to a filesystem
+ */
+errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
+{
+	struct stat	st;
+	errcode_t	retval;
+	char		buf[1024];
+	journal_superblock_t	*jsb;
+	int		start;
+	__u32		i, nr_users;
+
+	/* Make sure the device exists and is a block device */
+	if (stat(journal_dev->device_name, &st) < 0)
+		return errno;
+	
+	if (!S_ISBLK(st.st_mode))
+		return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
+
+	/* Get the journal superblock */
+	start = 1;
+	if (journal_dev->blocksize == 1024)
+		start++;
+	if ((retval = io_channel_read_blk(journal_dev->io, start, -1024, buf)))
+		return retval;
+
+	jsb = (journal_superblock_t *) buf;
+	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+	    (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
+		return EXT2_ET_NO_JOURNAL_SB;
+
+	if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
+		return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+
+	/* Check and see if this filesystem has already been added */
+	nr_users = ntohl(jsb->s_nr_users);
+	for (i=0; i < nr_users; i++) {
+		if (memcmp(fs->super->s_uuid,
+			   &jsb->s_users[i*16], 16) == 0)
+			break;
+	}
+	if (i >= nr_users) {
+		memcpy(&jsb->s_users[nr_users*16],
+		       fs->super->s_uuid, 16);
+		jsb->s_nr_users = htonl(nr_users+1);
+	}
+
+	/* Writeback the journal superblock */
+	if ((retval = io_channel_write_blk(journal_dev->io, start, -1024, buf)))
+		return retval;
+	
+	fs->super->s_journal_inum = 0;
+	fs->super->s_journal_dev = st.st_rdev;
+	memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
+	       sizeof(fs->super->s_journal_uuid));
+	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+	ext2fs_mark_super_dirty(fs);
+	return 0;
+}
+
+/*
+ * This function adds a journal inode to a filesystem, using either
+ * POSIX routines if the filesystem is mounted, or using direct I/O
+ * functions if it is not.
+ */
+errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
+{
+	errcode_t		retval;
+	ext2_ino_t		journal_ino;
+	struct stat		st;
+	char			jfile[1024];
+	int			fd, mount_flags, f;
+
+	if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
+					       jfile, sizeof(jfile)-10)))
+		return retval;
+
+	if (mount_flags & EXT2_MF_MOUNTED) {
+		strcat(jfile, "/.journal");
+
+		/*
+		 * If .../.journal already exists, make sure any 
+		 * immutable or append-only flags are cleared.
+		 */
+#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
+		(void) chflags (jfile, 0);
+#else
+#if HAVE_EXT2_IOCTLS
+		fd = open(jfile, O_RDONLY);
+		if (fd >= 0) {
+			f = 0;
+			ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+			close(fd);
+		}
+#endif
+#endif
+
+		/* Create the journal file */
+		if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
+			return errno;
+
+		if ((retval = write_journal_file(fs, jfile, size, flags)))
+			goto errout;
+		
+		/* Get inode number of the journal file */
+		if (fstat(fd, &st) < 0)
+			goto errout;
+
+#if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
+		retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
+#else
+#if HAVE_EXT2_IOCTLS
+		f = EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
+		retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
+#endif
+#endif
+		if (retval)
+			goto errout;
+		
+		close(fd);
+		journal_ino = st.st_ino;
+	} else {
+		journal_ino = EXT2_JOURNAL_INO;
+		if ((retval = write_journal_inode(fs, journal_ino,
+						  size, flags)))
+			return retval;
+	}
+	
+	fs->super->s_journal_inum = journal_ino;
+	fs->super->s_journal_dev = 0;
+	memset(fs->super->s_journal_uuid, 0,
+	       sizeof(fs->super->s_journal_uuid));
+	fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+
+	ext2fs_mark_super_dirty(fs);
+	return 0;
+errout:
+	close(fd);
+	return retval;
+}
+
+#ifdef DEBUG
+main(int argc, char **argv)
+{
+	errcode_t	retval;
+	char		*device_name;
+	ext2_filsys 	fs;
+
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
+		exit(1);
+	}
+	device_name = argv[1];
+	
+	retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
+			      unix_io_manager, &fs);
+	if (retval) {
+		com_err(argv[0], retval, "while opening %s", device_name);
+		exit(1);
+	}
+
+	retval = ext2fs_add_journal_inode(fs, 1024);
+	if (retval) {
+		com_err(argv[0], retval, "while adding journal to %s",
+			device_name);
+		exit(1);
+	}
+	retval = ext2fs_flush(fs);
+	if (retval) {
+		printf("Warning, had trouble writing out superblocks.\n");
+	}
+	ext2fs_close(fs);
+	exit(0);
+	
+}
+#endif
diff -Naur silo-1.4.11.orig/libext2fs/namei.c silo-1.4.11/libext2fs/namei.c
--- silo-1.4.11.orig/libext2fs/namei.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/namei.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,205 @@
+/*
+ * namei.c --- ext2fs directory lookup operations
+ * 
+ * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* #define NAMEI_DEBUG */
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+static errcode_t open_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t base,
+			    const char *pathname, size_t pathlen, int follow,
+			    int link_count, char *buf, ext2_ino_t *res_inode);
+
+static errcode_t follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t dir,
+			     ext2_ino_t inode, int link_count,
+			     char *buf, ext2_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 (ext2fs_inode_data_blocks(fs,&ei)) {
+		retval = ext2fs_get_mem(fs->blocksize, &buffer);
+		if (retval)
+			return retval;
+		retval = io_channel_read_blk(fs->io, ei.i_block[0], 1, buffer);
+		if (retval) {
+			ext2fs_free_mem(&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)
+		ext2fs_free_mem(&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, ext2_ino_t root, ext2_ino_t dir,
+			   const char *pathname, int pathlen,
+			   int link_count, char *buf,
+			   const char **name, int *namelen,
+			   ext2_ino_t *res_inode)
+{
+	char c;
+	const char *thisname;
+	int len;
+	ext2_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, ext2_ino_t root, ext2_ino_t base,
+			    const char *pathname, size_t pathlen, int follow,
+			    int link_count, char *buf, ext2_ino_t *res_inode)
+{
+	const char *basename;
+	int namelen;
+	ext2_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, ext2_ino_t root, ext2_ino_t cwd,
+		       const char *name, ext2_ino_t *inode)
+{
+	char *buf;
+	errcode_t retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	
+	retval = open_namei(fs, root, cwd, name, strlen(name), 0, 0,
+			    buf, inode);
+
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
+errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+			      const char *name, ext2_ino_t *inode)
+{
+	char *buf;
+	errcode_t retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	
+	retval = open_namei(fs, root, cwd, name, strlen(name), 1, 0,
+			    buf, inode);
+
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
+errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd,
+			ext2_ino_t inode, ext2_ino_t *res_inode)
+{
+	char *buf;
+	errcode_t retval;
+	
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+
+	retval = follow_link(fs, root, cwd, inode, 0, buf, res_inode);
+
+	ext2fs_free_mem(&buf);
+	return retval;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/native.c silo-1.4.11/libext2fs/native.c
--- silo-1.4.11.orig/libext2fs/native.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/native.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,27 @@
+/*
+ * native.c --- returns the ext2_flag for a native byte order
+ * 
+ * Copyright (C) 1996 Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int ext2fs_native_flag(void)
+{
+#ifdef WORDS_BIGENDIAN
+	return EXT2_FLAG_SWAP_BYTES;
+#else
+	return 0;
+#endif
+}
+
+	
+	
diff -Naur silo-1.4.11.orig/libext2fs/newdir.c silo-1.4.11/libext2fs/newdir.c
--- silo-1.4.11.orig/libext2fs/newdir.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/newdir.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,72 @@
+/*
+ * newdir.c --- create a new directory block
+ * 
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#ifndef EXT2_FT_DIR
+#define EXT2_FT_DIR		2
+#endif
+
+/*
+ * Create new directory block
+ */
+errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino,
+			       ext2_ino_t parent_ino, char **block)
+{
+	struct ext2_dir_entry 	*dir = NULL;
+	errcode_t		retval;
+	char			*buf;
+	int			rec_len;
+	int			filetype = 0;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	retval = ext2fs_get_mem(fs->blocksize, &buf);
+	if (retval)
+		return retval;
+	memset(buf, 0, fs->blocksize);
+	dir = (struct ext2_dir_entry *) buf;
+	dir->rec_len = fs->blocksize;
+
+	if (dir_ino) {
+		if (fs->super->s_feature_incompat &
+		    EXT2_FEATURE_INCOMPAT_FILETYPE)
+			filetype = EXT2_FT_DIR << 8;
+		/*
+		 * Set up entry for '.'
+		 */
+		dir->inode = dir_ino;
+		dir->name_len = 1 | filetype;
+		dir->name[0] = '.';
+		rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
+		dir->rec_len = EXT2_DIR_REC_LEN(1);
+
+		/*
+		 * Set up entry for '..'
+		 */
+		dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
+		dir->rec_len = rec_len;
+		dir->inode = parent_ino;
+		dir->name_len = 2 | filetype;
+		dir->name[0] = '.';
+		dir->name[1] = '.';
+		
+	}
+	*block = buf;
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/nt_io.c silo-1.4.11/libext2fs/nt_io.c
--- silo-1.4.11.orig/libext2fs/nt_io.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/nt_io.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,1513 @@
+/*
+ * nt_io.c --- This is the Nt I/O interface to the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
+ * Copyright (C) 1998 Andrey Shedel (andreys@ns.cr.cyco.com)
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+
+//
+// I need some warnings to disable...
+//
+
+
+#pragma warning(disable:4514) // unreferenced inline function has been removed
+#pragma warning(push,4)
+
+#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union)
+#pragma warning(disable:4214) // nonstandard extension used : bit field types other than int
+#pragma warning(disable:4115) // named type definition in parentheses
+
+#include <ntddk.h>
+#include <ntdddisk.h>
+#include <ntstatus.h>
+
+#pragma warning(pop)
+
+
+//
+// Some native APIs.
+//
+
+NTSYSAPI
+ULONG
+NTAPI
+RtlNtStatusToDosError(
+    IN NTSTATUS Status
+   );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtClose(
+    IN HANDLE Handle
+   );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtOpenFile(
+    OUT PHANDLE FileHandle,
+    IN ACCESS_MASK DesiredAccess,
+    IN POBJECT_ATTRIBUTES ObjectAttributes,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG ShareAccess,
+    IN ULONG OpenOptions
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFlushBuffersFile(
+    IN HANDLE FileHandle,
+    OUT PIO_STATUS_BLOCK IoStatusBlock
+   );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtReadFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    OUT PVOID Buffer,
+    IN ULONG Length,
+    IN PLARGE_INTEGER ByteOffset OPTIONAL,
+    IN PULONG Key OPTIONAL
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtWriteFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN PVOID Buffer,
+    IN ULONG Length,
+    IN PLARGE_INTEGER ByteOffset OPTIONAL,
+    IN PULONG Key OPTIONAL
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDeviceIoControlFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG IoControlCode,
+    IN PVOID InputBuffer OPTIONAL,
+    IN ULONG InputBufferLength,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength
+    );
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtFsControlFile(
+    IN HANDLE FileHandle,
+    IN HANDLE Event OPTIONAL,
+    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+    IN PVOID ApcContext OPTIONAL,
+    OUT PIO_STATUS_BLOCK IoStatusBlock,
+    IN ULONG IoControlCode,
+    IN PVOID InputBuffer OPTIONAL,
+    IN ULONG InputBufferLength,
+    OUT PVOID OutputBuffer OPTIONAL,
+    IN ULONG OutputBufferLength
+    );
+
+
+NTSYSAPI
+NTSTATUS
+NTAPI
+NtDelayExecution(
+    IN BOOLEAN Alertable,
+    IN PLARGE_INTEGER Interval
+    );
+
+
+#define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 6, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM,10, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+//
+// useful macros
+//
+
+#define BooleanFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
+
+
+//
+// Include Win32 error codes.
+//
+
+#include <winerror.h>
+
+//
+// standard stuff
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <malloc.h>
+
+#include <linux/types.h>
+#include "ext2_fs.h"
+#include <errno.h>
+
+#include "et/com_err.h"
+#include "ext2fs/ext2fs.h"
+#include "ext2fs/ext2_err.h"
+
+
+
+
+//
+// For checking structure magic numbers...
+//
+
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+#define EXT2_ET_MAGIC_NT_IO_CHANNEL  0x10ed
+
+
+//
+// Private data block
+//
+
+typedef struct _NT_PRIVATE_DATA {
+	int	   magic;
+	HANDLE Handle;
+	int	   Flags;
+	PCHAR  Buffer;
+	__u32  BufferBlockNumber;
+	ULONG  BufferSize;
+	BOOLEAN OpenedReadonly;
+	BOOLEAN Written;
+}NT_PRIVATE_DATA, *PNT_PRIVATE_DATA;
+
+
+
+//
+// Standard interface prototypes
+//
+
+static errcode_t nt_open(const char *name, int flags, io_channel *channel);
+static errcode_t nt_close(io_channel channel);
+static errcode_t nt_set_blksize(io_channel channel, int blksize);
+static errcode_t nt_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t nt_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t nt_flush(io_channel channel);
+
+static struct struct_io_manager struct_nt_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"NT I/O Manager",
+	nt_open,
+	nt_close,
+	nt_set_blksize,
+	nt_read_blk,
+	nt_write_blk,
+	nt_flush
+};
+
+
+
+//
+// function to get API
+//
+
+io_manager nt_io_manager()
+{
+	return &struct_nt_manager;
+}
+
+
+
+
+
+//
+// This is a code to convert Win32 errors to unix errno
+//
+
+typedef struct {
+	ULONG WinError;
+	int errnocode;
+}ERROR_ENTRY;
+
+static ERROR_ENTRY ErrorTable[] = {
+        {  ERROR_INVALID_FUNCTION,       EINVAL    },
+        {  ERROR_FILE_NOT_FOUND,         ENOENT    },
+        {  ERROR_PATH_NOT_FOUND,         ENOENT    },
+        {  ERROR_TOO_MANY_OPEN_FILES,    EMFILE    },
+        {  ERROR_ACCESS_DENIED,          EACCES    },
+        {  ERROR_INVALID_HANDLE,         EBADF     },
+        {  ERROR_ARENA_TRASHED,          ENOMEM    },
+        {  ERROR_NOT_ENOUGH_MEMORY,      ENOMEM    },
+        {  ERROR_INVALID_BLOCK,          ENOMEM    },
+        {  ERROR_BAD_ENVIRONMENT,        E2BIG     },
+        {  ERROR_BAD_FORMAT,             ENOEXEC   },
+        {  ERROR_INVALID_ACCESS,         EINVAL    },
+        {  ERROR_INVALID_DATA,           EINVAL    },
+        {  ERROR_INVALID_DRIVE,          ENOENT    },
+        {  ERROR_CURRENT_DIRECTORY,      EACCES    },
+        {  ERROR_NOT_SAME_DEVICE,        EXDEV     },
+        {  ERROR_NO_MORE_FILES,          ENOENT    },
+        {  ERROR_LOCK_VIOLATION,         EACCES    },
+        {  ERROR_BAD_NETPATH,            ENOENT    },
+        {  ERROR_NETWORK_ACCESS_DENIED,  EACCES    },
+        {  ERROR_BAD_NET_NAME,           ENOENT    },
+        {  ERROR_FILE_EXISTS,            EEXIST    },
+        {  ERROR_CANNOT_MAKE,            EACCES    },
+        {  ERROR_FAIL_I24,               EACCES    },
+        {  ERROR_INVALID_PARAMETER,      EINVAL    },
+        {  ERROR_NO_PROC_SLOTS,          EAGAIN    },
+        {  ERROR_DRIVE_LOCKED,           EACCES    },
+        {  ERROR_BROKEN_PIPE,            EPIPE     },
+        {  ERROR_DISK_FULL,              ENOSPC    },
+        {  ERROR_INVALID_TARGET_HANDLE,  EBADF     },
+        {  ERROR_INVALID_HANDLE,         EINVAL    },
+        {  ERROR_WAIT_NO_CHILDREN,       ECHILD    },
+        {  ERROR_CHILD_NOT_COMPLETE,     ECHILD    },
+        {  ERROR_DIRECT_ACCESS_HANDLE,   EBADF     },
+        {  ERROR_NEGATIVE_SEEK,          EINVAL    },
+        {  ERROR_SEEK_ON_DEVICE,         EACCES    },
+        {  ERROR_DIR_NOT_EMPTY,          ENOTEMPTY },
+        {  ERROR_NOT_LOCKED,             EACCES    },
+        {  ERROR_BAD_PATHNAME,           ENOENT    },
+        {  ERROR_MAX_THRDS_REACHED,      EAGAIN    },
+        {  ERROR_LOCK_FAILED,            EACCES    },
+        {  ERROR_ALREADY_EXISTS,         EEXIST    },
+        {  ERROR_FILENAME_EXCED_RANGE,   ENOENT    },
+        {  ERROR_NESTING_NOT_ALLOWED,    EAGAIN    },
+        {  ERROR_NOT_ENOUGH_QUOTA,       ENOMEM    }
+};
+
+
+
+
+static
+unsigned
+_MapDosError (
+    IN ULONG WinError
+   )
+{
+	int i;
+
+	//
+	// Lookup
+	//
+
+	for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i)
+	{
+		if (WinError == ErrorTable[i].WinError)
+		{
+			return ErrorTable[i].errnocode;
+		}
+	}
+
+	//
+	// not in table. Check ranges
+	//
+
+	if ((WinError >= ERROR_WRITE_PROTECT) &&
+		(WinError <= ERROR_SHARING_BUFFER_EXCEEDED))
+	{
+		return EACCES;
+	}
+	else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) &&
+			 (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN))
+	{
+		return ENOEXEC;
+	}
+	else
+	{
+		return EINVAL;
+	}
+}
+
+
+
+
+
+
+
+//
+// Function to map NT status to dos error.
+//
+
+static
+__inline
+unsigned
+_MapNtStatus(
+    IN NTSTATUS Status
+   )
+{
+	return _MapDosError(RtlNtStatusToDosError(Status));
+}
+
+
+
+
+
+//
+// Helper functions to make things easyer
+//
+
+static
+NTSTATUS
+_OpenNtName(
+    IN PCSTR Name,
+    IN BOOLEAN Readonly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL
+   )
+{
+	UNICODE_STRING UnicodeString;
+	ANSI_STRING    AnsiString;
+	WCHAR Buffer[512];
+	NTSTATUS Status;
+	OBJECT_ATTRIBUTES ObjectAttributes;
+	IO_STATUS_BLOCK IoStatusBlock;
+
+	//
+	// Make Unicode name from inlut string
+	//
+
+	UnicodeString.Buffer = &Buffer[0];
+	UnicodeString.Length = 0;
+	UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!!
+
+	RtlInitAnsiString(&AnsiString, Name);
+
+	Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
+
+	if(!NT_SUCCESS(Status))
+	{
+		return Status; // Unpappable character?
+	}
+
+	//
+	// Initialize object
+	//
+
+	InitializeObjectAttributes(&ObjectAttributes,
+							   &UnicodeString,
+							   OBJ_CASE_INSENSITIVE,
+							   NULL,
+							   NULL );
+
+	//
+	// Try to open it in initial mode
+	//
+
+	if(ARGUMENT_PRESENT(OpenedReadonly))
+	{
+		*OpenedReadonly = Readonly;
+	}
+
+
+	Status = NtOpenFile(Handle,
+						SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+						&ObjectAttributes,
+						&IoStatusBlock,
+						FILE_SHARE_WRITE | FILE_SHARE_READ,
+						FILE_SYNCHRONOUS_IO_NONALERT);
+
+	if(!NT_SUCCESS(Status))
+	{
+		//
+		// Maybe was just mounted? wait 0.5 sec and retry.
+		//
+
+		LARGE_INTEGER Interval;
+		Interval.QuadPart = -5000000; // 0.5 sec. from now
+
+		NtDelayExecution(FALSE, &Interval);
+
+		Status = NtOpenFile(Handle,
+							SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA),
+							&ObjectAttributes,
+							&IoStatusBlock,
+							FILE_SHARE_WRITE | FILE_SHARE_READ,
+							FILE_SYNCHRONOUS_IO_NONALERT);
+
+		//
+		// Try to satisfy mode
+		//
+
+		if((STATUS_ACCESS_DENIED == Status) && !Readonly)
+		{
+			if(ARGUMENT_PRESENT(OpenedReadonly))
+			{
+				*OpenedReadonly = TRUE;
+			}
+
+			Status = NtOpenFile(Handle,
+							SYNCHRONIZE | FILE_READ_DATA,
+							&ObjectAttributes,
+							&IoStatusBlock,
+							FILE_SHARE_WRITE | FILE_SHARE_READ,
+							FILE_SYNCHRONOUS_IO_NONALERT);
+		}
+	}
+
+
+
+	//
+	// done
+	//
+
+	return Status;
+}
+
+
+static
+NTSTATUS
+_OpenDriveLetter(
+    IN CHAR Letter,
+    IN BOOLEAN ReadOnly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL
+   )
+{
+	CHAR Buffer[100];
+
+	sprintf(Buffer, "\\DosDevices\\%c:", Letter);
+
+	return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly);
+}
+
+
+//
+// Flush device
+//
+
+static
+__inline
+NTSTATUS
+_FlushDrive(
+		IN HANDLE Handle
+		)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFlushBuffersFile(Handle, &IoStatusBlock);
+}
+
+
+//
+// lock drive
+//
+
+static
+__inline
+NTSTATUS
+_LockDrive(
+		IN HANDLE Handle
+		)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// unlock drive
+//
+
+static
+__inline
+NTSTATUS
+_UnlockDrive(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0);
+}
+
+static
+__inline
+NTSTATUS
+_DismountDrive(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0);
+}
+
+
+//
+// is mounted
+//
+
+static
+__inline
+BOOLEAN
+_IsMounted(
+	IN HANDLE Handle
+	)
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	NTSTATUS Status;
+	Status = NtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0);
+	return (BOOLEAN)(STATUS_SUCCESS == Status);
+}
+
+
+static
+__inline
+NTSTATUS
+_CloseDisk(
+		IN HANDLE Handle
+		)
+{
+	return NtClose(Handle);
+}
+
+
+
+
+//
+// Make NT name from any recognized name
+//
+
+static
+PCSTR
+_NormalizeDeviceName(
+    IN PCSTR Device,
+    IN PSTR NormalizedDeviceNameBuffer
+   )
+{
+	int PartitionNumber = -1;
+	UCHAR DiskNumber;
+	PSTR p;
+
+
+	//
+	// Do not try to parse NT name
+	//
+
+	if('\\' == *Device)
+		return Device;
+
+
+
+	//
+	// Strip leading '/dev/' if any
+	//
+
+	if(('/' == *(Device)) &&
+		('d' == *(Device + 1)) &&
+		('e' == *(Device + 2)) &&
+		('v' == *(Device + 3)) &&
+		('/' == *(Device + 4)))
+	{
+		Device += 5;
+	}
+
+	if('\0' == *Device)
+	{
+		return NULL;
+	}
+
+
+	//
+	// forms: hda[n], fd[n]
+	//
+
+	if('d' != *(Device + 1))
+	{
+		return NULL;
+	}
+
+	if('h' == *Device)
+	{
+		if((*(Device + 2) < 'a') || (*(Device + 2) > ('a' + 9)) ||
+		   ((*(Device + 3) != '\0') &&
+			((*(Device + 4) != '\0') ||
+			 ((*(Device + 3) < '0') || (*(Device + 3) > '9'))
+			)
+		   )
+		  )
+		{
+			return NULL;
+		}
+
+		DiskNumber = (UCHAR)(*(Device + 2) - 'a');
+
+		if(*(Device + 3) != '\0')
+		{
+			PartitionNumber = (*(Device + 3) - '0');
+		}
+
+	}
+	else if('f' == *Device)
+	{
+		//
+		// 3-d letted should be a digit.
+		//
+
+		if((*(Device + 3) != '\0') ||
+		   (*(Device + 2) < '0') || (*(Device + 2) > '9'))
+		{
+			return NULL;
+		}
+
+		DiskNumber = (UCHAR)(*(Device + 2) - '0');
+
+	}
+	else
+	{
+		//
+		// invalid prefix
+		//
+
+		return NULL;
+	}
+
+
+
+	//
+	// Prefix
+	//
+
+	strcpy(NormalizedDeviceNameBuffer, "\\Device\\");
+
+	//
+	// Media name
+	//
+
+	switch(*Device)
+	{
+
+	case 'f':
+		strcat(NormalizedDeviceNameBuffer, "Floppy0");
+		break;
+
+	case 'h':
+		strcat(NormalizedDeviceNameBuffer, "Harddisk0");
+		break;
+	}
+
+
+	p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+	*p = (CHAR)(*p + DiskNumber);
+
+
+	//
+	// Partition nr.
+	//
+
+	if(PartitionNumber >= 0)
+	{
+		strcat(NormalizedDeviceNameBuffer, "\\Partition0");
+
+		p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1;
+		*p = (CHAR)(*p + PartitionNumber);
+	}
+
+
+	return NormalizedDeviceNameBuffer;
+}
+
+
+
+
+static
+VOID
+_GetDeviceSize(
+    IN HANDLE h,
+    OUT unsigned __int64 *FsSize
+   )
+{
+	PARTITION_INFORMATION pi;
+	DISK_GEOMETRY gi;
+	NTSTATUS Status;
+	IO_STATUS_BLOCK IoStatusBlock;
+
+	//
+	// Zero it
+	//
+
+	*FsSize = 0;
+
+	//
+	// Call driver
+	//
+
+	RtlZeroMemory(&pi, sizeof(PARTITION_INFORMATION));
+
+	Status = NtDeviceIoControlFile(
+		h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO,
+		&pi, sizeof(PARTITION_INFORMATION),
+		&pi, sizeof(PARTITION_INFORMATION));
+
+
+	if(NT_SUCCESS(Status))
+	{
+		*FsSize = pi.PartitionLength.QuadPart;
+	}
+	else if(STATUS_INVALID_DEVICE_REQUEST == Status)
+	{
+		//
+		// No partitions: get device info.
+		//
+
+		RtlZeroMemory(&gi, sizeof(DISK_GEOMETRY));
+
+		Status = NtDeviceIoControlFile(
+				h, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+				&gi, sizeof(DISK_GEOMETRY),
+				&gi, sizeof(DISK_GEOMETRY));
+
+
+		if(NT_SUCCESS(Status))
+		{
+			*FsSize =
+				gi.BytesPerSector *
+				gi.SectorsPerTrack *
+				gi.TracksPerCylinder *
+				gi.Cylinders.QuadPart;
+		}
+
+	}
+}
+
+
+
+//
+// Open device by name.
+//
+
+static
+BOOLEAN
+_Ext2OpenDevice(
+    IN PCSTR Name,
+    IN BOOLEAN ReadOnly,
+    OUT PHANDLE Handle,
+    OUT PBOOLEAN OpenedReadonly OPTIONAL,
+    OUT unsigned *Errno OPTIONAL
+   )
+{
+	CHAR NormalizedDeviceName[512];
+	NTSTATUS Status;
+
+	if(NULL == Name)
+	{
+		//
+		// Set not found
+		//
+
+		if(ARGUMENT_PRESENT(Errno))
+			*Errno = ENOENT;
+
+		return FALSE;
+	}
+
+
+	if((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') &&
+		(':' == *(Name + 1)) && ('\0' == *(Name + 2)))
+	{
+		Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly);
+	}
+	else
+	{
+		//
+		// Make name
+		//
+
+		Name = _NormalizeDeviceName(Name, NormalizedDeviceName);
+
+		if(NULL == Name)
+		{
+			//
+			// Set not found
+			//
+
+			if(ARGUMENT_PRESENT(Errno))
+				*Errno = ENOENT;
+
+			return FALSE;
+		}
+
+		//
+		// Try to open it
+		//
+
+		Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly);
+	}
+
+
+	if(!NT_SUCCESS(Status))
+	{
+		if(ARGUMENT_PRESENT(Errno))
+			*Errno = _MapNtStatus(Status);
+
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+//
+// Raw block io. Sets dos errno
+//
+
+static
+BOOLEAN
+_BlockIo(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    IN OUT PCHAR Buffer,
+    IN BOOLEAN Read,
+    OUT unsigned* Errno
+   )
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	NTSTATUS Status;
+
+	//
+	// Should be aligned
+	//
+
+	ASSERT(0 == (Bytes % 512));
+	ASSERT(0 == (Offset.LowPart % 512));
+
+
+	//
+	// perform io
+	//
+
+	if(Read)
+	{
+		Status = NtReadFile(Handle, NULL, NULL, NULL,
+			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+	}
+	else
+	{
+		Status = NtWriteFile(Handle, NULL, NULL, NULL,
+			&IoStatusBlock, Buffer, Bytes, &Offset, NULL);
+	}
+
+
+	//
+	// translate error
+	//
+
+	if(NT_SUCCESS(Status))
+	{
+		*Errno = 0;
+		return TRUE;
+	}
+
+	*Errno = _MapNtStatus(Status);
+
+	return FALSE;
+}
+
+
+
+__inline
+BOOLEAN
+_RawWrite(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    OUT const CHAR* Buffer,
+    OUT unsigned* Errno
+   )
+{
+	return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno);
+}
+
+__inline
+BOOLEAN
+_RawRead(
+    IN HANDLE Handle,
+    IN LARGE_INTEGER Offset,
+    IN ULONG Bytes,
+    IN PCHAR Buffer,
+    OUT unsigned* Errno
+   )
+{
+	return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno);
+}
+
+
+
+__inline
+BOOLEAN
+_SetPartType(
+    IN HANDLE Handle,
+    IN UCHAR Type
+   )
+{
+	IO_STATUS_BLOCK IoStatusBlock;
+	return STATUS_SUCCESS == NtDeviceIoControlFile(
+												   Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_PARTITION_INFO,
+												   &Type, sizeof(Type),
+												   NULL, 0);
+}
+
+
+
+//--------------------- interface part
+
+//
+// Interface functions.
+// Is_mounted is set to 1 if the device is mounted, 0 otherwise
+//
+
+errcode_t
+ext2fs_check_if_mounted(const char *file, int *mount_flags)
+{
+	HANDLE h;
+	BOOLEAN Readonly;
+
+	*mount_flags = 0;
+
+	if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+	{
+		return 0;
+	}
+
+
+	__try{
+		*mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0;
+	}
+	__finally{
+		_CloseDisk(h);
+	}
+
+	return 0;
+}
+
+
+
+//
+// Returns the number of blocks in a partition
+//
+
+static __int64 FsSize = 0;
+static char knowndevice[1024] = "";
+
+
+errcode_t
+ext2fs_get_device_size(const char *file, int blocksize,
+				 blk_t *retblocks)
+{
+	HANDLE h;
+	BOOLEAN Readonly;
+
+	if((0 == FsSize) || (0 != strcmp(knowndevice, file)))
+	{
+
+		if(!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL))
+		{
+			return 0;
+		}
+
+
+		__try{
+
+			//
+			// Get size
+			//
+
+			_GetDeviceSize(h, &FsSize);
+			strcpy(knowndevice, file);
+		}
+		__finally{
+			_CloseDisk(h);
+		}
+
+	}
+
+	*retblocks = (blk_t)(unsigned __int64)(FsSize / blocksize);
+	UNREFERENCED_PARAMETER(file);
+	return 0;
+}
+
+
+
+
+
+
+//
+// Table elements
+//
+
+
+static
+errcode_t
+nt_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel      io = NULL;
+	PNT_PRIVATE_DATA NtData = NULL;
+	errcode_t Errno = 0;
+
+	//
+	// Check name
+	//
+
+	if (NULL == name)
+	{
+		return EXT2_ET_BAD_DEVICE_NAME;
+	}
+
+	__try{
+
+		//
+		// Allocate channel handle
+		//
+
+		io = (io_channel) malloc(sizeof(struct struct_io_channel));
+
+		if (NULL == io)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		RtlZeroMemory(io, sizeof(struct struct_io_channel));
+		io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+
+		NtData = (PNT_PRIVATE_DATA)malloc(sizeof(NT_PRIVATE_DATA));
+
+		if (NULL == NtData)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+
+		io->manager = nt_io_manager();
+		io->name = malloc(strlen(name) + 1);
+		if (NULL == io->name)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		strcpy(io->name, name);
+		io->private_data = NtData;
+		io->block_size = 1024;
+		io->read_error = 0;
+		io->write_error = 0;
+		io->refcount = 1;
+
+		//
+		// Initialize data
+		//
+
+		RtlZeroMemory(NtData, sizeof(NT_PRIVATE_DATA));
+
+		NtData->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL;
+		NtData->BufferBlockNumber = 0xffffffff;
+		NtData->BufferSize = 1024;
+		NtData->Buffer = malloc(NtData->BufferSize);
+
+		if (NULL == NtData->Buffer)
+		{
+			Errno = ENOMEM;
+			__leave;
+		}
+
+		//
+		// Open it
+		//
+
+		if(!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &NtData->Handle, &NtData->OpenedReadonly, &Errno))
+		{
+			__leave;
+		}
+
+
+		//
+		// get size
+		//
+
+		_GetDeviceSize(NtData->Handle, &FsSize);
+		strcpy(knowndevice, name);
+
+
+		//
+		// Lock/dismount
+		//
+
+		if(!NT_SUCCESS(_LockDrive(NtData->Handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/)
+		{
+			NtData->OpenedReadonly = TRUE;
+		}
+
+		//
+		// Done
+		//
+
+		*channel = io;
+
+
+	}
+	__finally{
+
+		if(0 != Errno)
+		{
+			//
+			// Cleanup
+			//
+
+			if (NULL != io)
+			{
+				if(NULL != io->name)
+				{
+					free(io->name);
+				}
+
+				free(io);
+			}
+
+			if (NULL != NtData)
+			{
+				if(NULL != NtData->Handle)
+				{
+					_UnlockDrive(NtData->Handle);
+					_CloseDisk(NtData->Handle);
+				}
+
+				if(NULL != NtData->Buffer)
+				{
+					free(NtData->Buffer);
+				}
+
+				free(NtData);
+			}
+		}
+	}
+
+	return Errno;
+}
+
+
+//
+// Close api
+//
+
+static
+errcode_t
+nt_close(io_channel channel)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	if(NULL == channel)
+	{
+		return 0;
+	}
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+	{
+		return 0;
+	}
+
+	if(NULL != channel->name)
+	{
+		free(channel->name);
+	}
+
+
+	free(channel);
+
+	if (NULL != NtData)
+	{
+		if(NULL != NtData->Handle)
+		{
+			_DismountDrive(NtData->Handle);
+			_UnlockDrive(NtData->Handle);
+			_CloseDisk(NtData->Handle);
+		}
+
+		if(NULL != NtData->Buffer)
+		{
+			free(NtData->Buffer);
+		}
+
+		free(NtData);
+	}
+
+	return 0;
+}
+
+
+
+//
+// set block size
+//
+
+static
+errcode_t
+nt_set_blksize(io_channel channel, int blksize)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if (channel->block_size != blksize)
+	{
+		channel->block_size = blksize;
+
+		free(NtData->Buffer);
+		NtData->BufferBlockNumber = 0xffffffff;
+		NtData->BufferSize = channel->block_size;
+		ASSERT(0 == (NtData->BufferSize % 512));
+
+		NtData->Buffer = malloc(NtData->BufferSize);
+
+		if (NULL == NtData->Buffer)
+		{
+			return ENOMEM;
+		}
+
+	}
+
+	return 0;
+}
+
+
+//
+// read block
+//
+
+static
+errcode_t
+nt_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	PVOID BufferToRead;
+	ULONG SizeToRead;
+	ULONG Size;
+	LARGE_INTEGER Offset;
+	PNT_PRIVATE_DATA NtData = NULL;
+	unsigned Errno = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	//
+	// If it's in the cache, use it!
+	//
+
+	if ((1 == count) &&
+		(block == NtData->BufferBlockNumber) &&
+		(NtData->BufferBlockNumber != 0xffffffff))
+	{
+		memcpy(buf, NtData->Buffer, channel->block_size);
+		return 0;
+	}
+
+	Size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size);
+
+	Offset.QuadPart = block * channel->block_size;
+
+	//
+	// If not fit to the block
+	//
+
+	if(Size <= NtData->BufferSize)
+	{
+		//
+		// Update the cache
+		//
+
+		NtData->BufferBlockNumber = block;
+		BufferToRead = NtData->Buffer;
+		SizeToRead = NtData->BufferSize;
+	}
+	else
+	{
+		SizeToRead = Size;
+		BufferToRead = buf;
+		ASSERT(0 == (SizeToRead % channel->block_size));
+	}
+
+	if(!_RawRead(NtData->Handle, Offset, SizeToRead, BufferToRead, &Errno))
+	{
+
+		if (channel->read_error)
+		{
+			return (channel->read_error)(channel, block, count, buf,
+					       Size, 0, Errno);
+		}
+		else
+		{
+			return Errno;
+		}
+	}
+
+
+	if(BufferToRead != buf)
+	{
+		ASSERT(Size <= SizeToRead);
+		memcpy(buf, BufferToRead, Size);
+	}
+
+	return 0;
+}
+
+
+//
+// write block
+//
+
+static
+errcode_t
+nt_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	ULONG SizeToWrite;
+	LARGE_INTEGER Offset;
+	PNT_PRIVATE_DATA NtData = NULL;
+	unsigned Errno = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if(NtData->OpenedReadonly)
+	{
+		return EACCES;
+	}
+
+	if (count == 1)
+	{
+		SizeToWrite = channel->block_size;
+	}
+	else
+	{
+		NtData->BufferBlockNumber = 0xffffffff;
+
+		if (count < 0)
+		{
+			SizeToWrite = (ULONG)(-count);
+		}
+		else
+		{
+			SizeToWrite = (ULONG)(count * channel->block_size);
+		}
+	}
+
+
+	ASSERT(0 == (SizeToWrite % 512));
+	Offset.QuadPart = block * channel->block_size;
+
+	if(!_RawWrite(NtData->Handle, Offset, SizeToWrite, buf, &Errno))
+	{
+		if (channel->write_error)
+		{
+			return (channel->write_error)(channel, block, count, buf,
+						SizeToWrite, 0, Errno);
+		}
+		else
+		{
+			return Errno;
+		}
+	}
+
+
+	//
+	// Stash a copy.
+	//
+
+	if(SizeToWrite >= NtData->BufferSize)
+	{
+		NtData->BufferBlockNumber = block;
+		memcpy(NtData->Buffer, buf, NtData->BufferSize);
+	}
+
+	NtData->Written = TRUE;
+
+	return 0;
+
+}
+
+
+
+//
+// Flush data buffers to disk.  Since we are currently using a
+// write-through cache, this is a no-op.
+//
+
+static
+errcode_t
+nt_flush(io_channel channel)
+{
+	PNT_PRIVATE_DATA NtData = NULL;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	NtData = (PNT_PRIVATE_DATA) channel->private_data;
+	EXT2_CHECK_MAGIC(NtData, EXT2_ET_MAGIC_NT_IO_CHANNEL);
+
+	if(NtData->OpenedReadonly)
+	{
+		return 0; // EACCESS;
+	}
+
+
+	//
+	// Flush file buffers.
+	//
+
+	_FlushDrive(NtData->Handle);
+
+
+	//
+	// Test and correct partition type.
+	//
+
+	if(NtData->Written)
+	{
+		_SetPartType(NtData->Handle, 0x83);
+	}
+
+	return 0;
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/openfs.c silo-1.4.11/libext2fs/openfs.c
--- silo-1.4.11.orig/libext2fs/openfs.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/openfs.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,326 @@
+/*
+ * openfs.c --- open an ext2 filesystem
+ * 
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+
+
+#include "ext2fs.h"
+#include "e2image.h"
+
+blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, dgrp_t i)
+{
+	int	bg;
+	int	has_super = 0;
+	int	ret_blk;
+
+	if (!(fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) ||
+	    (i < fs->super->s_first_meta_bg))
+		return (group_block + i + 1);
+
+	bg = (fs->blocksize / sizeof (struct ext2_group_desc)) * i;
+	if (ext2fs_bg_has_super(fs, bg))
+		has_super = 1;
+	ret_blk = (fs->super->s_first_data_block + has_super + 
+		   (bg * fs->super->s_blocks_per_group));
+	/*
+	 * If group_block is not the normal value, we're trying to use
+	 * the backup group descriptors and superblock --- so use the
+	 * alternate location of the second block group in the
+	 * metablock group.  Ideally we should be testing each bg
+	 * descriptor block individually for correctness, but we don't
+	 * have the infrastructure in place to do that.
+	 */
+	if (group_block != fs->super->s_first_data_block &&
+	    ((ret_blk + fs->super->s_blocks_per_group) <
+	     fs->super->s_blocks_count))
+		ret_blk += fs->super->s_blocks_per_group;
+	return ret_blk;
+}
+
+errcode_t ext2fs_open(const char *name, int flags, int superblock,
+		      unsigned int block_size, io_manager manager, 
+		      ext2_filsys *ret_fs)
+{
+	return ext2fs_open2(name, 0, flags, superblock, block_size, 
+			    manager, ret_fs);
+}
+
+/*
+ *  Note: if superblock is non-zero, block-size must also be non-zero.
+ * 	Superblock and block_size can be zero to use the default size.
+ *
+ * Valid flags for ext2fs_open()
+ * 
+ * 	EXT2_FLAG_RW	- Open the filesystem for read/write.
+ * 	EXT2_FLAG_FORCE - Open the filesystem even if some of the
+ *				features aren't supported.
+ *	EXT2_FLAG_JOURNAL_DEV_OK - Open an ext3 journal device
+ */
+errcode_t ext2fs_open2(const char *name, const char *io_options,
+		       int flags, int superblock,
+		       unsigned int block_size, io_manager manager, 
+		       ext2_filsys *ret_fs)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+	unsigned long	i;
+	int		j, groups_per_block, blocks_per_group;
+	blk_t		group_block, blk;
+	char		*dest, *cp;
+	struct ext2_group_desc *gdp;
+	
+	EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER);
+
+	retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
+	if (retval)
+		return retval;
+	
+	memset(fs, 0, sizeof(struct struct_ext2_filsys));
+	fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
+	fs->flags = flags;
+	fs->umask = 022;
+	retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
+	if (retval)
+		goto cleanup;
+	strcpy(fs->device_name, name);
+	cp = strchr(fs->device_name, '?');
+	if (!io_options && cp) {
+		*cp++ = 0;
+		io_options = cp;
+	}
+		
+	retval = manager->open(fs->device_name, 
+			       (flags & EXT2_FLAG_RW) ? IO_FLAG_RW : 0,
+			       &fs->io);
+	if (retval)
+		goto cleanup;
+	if (io_options && 
+	    (retval = io_channel_set_options(fs->io, io_options)))
+		goto cleanup;
+	fs->image_io = fs->io;
+	fs->io->app_data = fs;
+	retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
+	if (retval)
+		goto cleanup;
+	if (flags & EXT2_FLAG_IMAGE_FILE) {
+		retval = ext2fs_get_mem(sizeof(struct ext2_image_hdr),
+					&fs->image_header);
+		if (retval)
+			goto cleanup;
+		retval = io_channel_read_blk(fs->io, 0,
+					     -sizeof(struct ext2_image_hdr),
+					     fs->image_header);
+		if (retval)
+			goto cleanup;
+		if (fs->image_header->magic_number != EXT2_ET_MAGIC_E2IMAGE)
+			return EXT2_ET_MAGIC_E2IMAGE;
+		superblock = 1;
+		block_size = fs->image_header->fs_blocksize;
+	}
+
+	/*
+	 * If the user specifies a specific block # for the
+	 * superblock, then he/she must also specify the block size!
+	 * Otherwise, read the master superblock located at offset
+	 * SUPERBLOCK_OFFSET from the start of the partition.
+	 *
+	 * Note: we only save a backup copy of the superblock if we
+	 * are reading the superblock from the primary superblock location.
+	 */
+	if (superblock) {
+		if (!block_size) {
+			retval = EXT2_ET_INVALID_ARGUMENT;
+			goto cleanup;
+		}
+		io_channel_set_blksize(fs->io, block_size);
+		group_block = superblock;
+		fs->orig_super = 0;
+	} else {
+		io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
+		superblock = 1;
+		group_block = 0;
+		retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
+		if (retval)
+			goto cleanup;
+	}
+	retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE,
+				     fs->super);
+	if (retval)
+		goto cleanup;
+	if (fs->orig_super)
+		memcpy(fs->orig_super, fs->super, SUPERBLOCK_SIZE);
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+	if ((fs->super->s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES)) {
+		fs->flags |= EXT2_FLAG_SWAP_BYTES;
+
+		ext2fs_swap_super(fs->super);
+	}
+#endif
+	
+	if (fs->super->s_magic != EXT2_SUPER_MAGIC) {
+		retval = EXT2_ET_BAD_MAGIC;
+		goto cleanup;
+	}
+	if (fs->super->s_rev_level > EXT2_LIB_CURRENT_REV) {
+		retval = EXT2_ET_REV_TOO_HIGH;
+		goto cleanup;
+	}
+
+	/*
+	 * Check for feature set incompatibility
+	 */
+	if (!(flags & EXT2_FLAG_FORCE)) {
+		if (fs->super->s_feature_incompat &
+		    ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
+			retval = EXT2_ET_UNSUPP_FEATURE;
+			goto cleanup;
+		}
+		if ((flags & EXT2_FLAG_RW) &&
+		    (fs->super->s_feature_ro_compat &
+		     ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP)) {
+			retval = EXT2_ET_RO_UNSUPP_FEATURE;
+			goto cleanup;
+		}
+		if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) &&
+		    (fs->super->s_feature_incompat &
+		     EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+			retval = EXT2_ET_UNSUPP_FEATURE;
+			goto cleanup;
+		}
+	}
+	
+	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) +
+				       EXT2_BLOCK_SIZE(fs->super) - 1) /
+				      EXT2_BLOCK_SIZE(fs->super));
+	if (block_size) {
+		if (block_size != fs->blocksize) {
+			retval = EXT2_ET_UNEXPECTED_BLOCK_SIZE;
+			goto cleanup;
+		}
+	}
+	/*
+	 * Set the blocksize to the filesystem's blocksize.
+	 */
+	io_channel_set_blksize(fs->io, fs->blocksize);
+
+	/*
+	 * If this is an external journal device, don't try to read
+	 * the group descriptors, because they're not there.
+	 */
+	if (fs->super->s_feature_incompat &
+	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+		fs->group_desc_count = 0;
+		*ret_fs = fs;
+		return 0;
+	}
+	
+	/*
+	 * Read group descriptors
+	 */
+	blocks_per_group = EXT2_BLOCKS_PER_GROUP(fs->super);
+	if (blocks_per_group == 0 ||
+	    blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(fs->super) ||
+	    fs->inode_blocks_per_group > EXT2_MAX_INODES_PER_GROUP(fs->super)) {
+		retval = EXT2_ET_CORRUPT_SUPERBLOCK;
+		goto cleanup;
+	}
+	fs->group_desc_count = (fs->super->s_blocks_count -
+				fs->super->s_first_data_block +
+				blocks_per_group - 1) / blocks_per_group;
+	fs->desc_blocks = (fs->group_desc_count +
+			   EXT2_DESC_PER_BLOCK(fs->super) - 1)
+		/ EXT2_DESC_PER_BLOCK(fs->super);
+	retval = ext2fs_get_mem(fs->desc_blocks * fs->blocksize,
+				&fs->group_desc);
+	if (retval)
+		goto cleanup;
+	if (!group_block)
+		group_block = fs->super->s_first_data_block;
+	dest = (char *) fs->group_desc;
+	groups_per_block = fs->blocksize / sizeof(struct ext2_group_desc);
+	for (i=0 ; i < fs->desc_blocks; i++) {
+		blk = ext2fs_descriptor_block_loc(fs, group_block, i);
+		retval = io_channel_read_blk(fs->io, blk, 1, dest);
+		if (retval)
+			goto cleanup;
+#ifdef EXT2FS_ENABLE_SWAPFS
+		if (fs->flags & EXT2_FLAG_SWAP_BYTES) {
+			gdp = (struct ext2_group_desc *) dest;
+			for (j=0; j < groups_per_block; j++)
+				ext2fs_swap_group_desc(gdp++);
+		}
+#endif
+		dest += fs->blocksize;
+	}
+
+	*ret_fs = fs;
+	return 0;
+cleanup:
+	ext2fs_free(fs);
+	return retval;
+}
+
+/*
+ * Set/get the filesystem data I/O channel.
+ * 
+ * These functions are only valid if EXT2_FLAG_IMAGE_FILE is true.
+ */
+errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io)
+{
+	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+		return EXT2_ET_NOT_IMAGE_FILE;
+	if (old_io) {
+		*old_io = (fs->image_io == fs->io) ? 0 : fs->io;
+	}
+	return 0;
+}
+
+errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io)
+{
+	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+		return EXT2_ET_NOT_IMAGE_FILE;
+	fs->io = new_io ? new_io : fs->image_io;
+	return 0;
+}
+
+errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io)
+{
+	if ((fs->flags & EXT2_FLAG_IMAGE_FILE) == 0)
+		return EXT2_ET_NOT_IMAGE_FILE;
+	fs->io = fs->image_io = new_io;
+	fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_RW | 
+		EXT2_FLAG_BB_DIRTY | EXT2_FLAG_IB_DIRTY;
+	fs->flags &= ~EXT2_FLAG_IMAGE_FILE;
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/read_bb.c silo-1.4.11/libext2fs/read_bb.c
--- silo-1.4.11.orig/libext2fs/read_bb.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/read_bb.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,97 @@
+/*
+ * read_bb --- read the bad blocks inode
+ *
+ * Copyright (C) 1994 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct read_bb_record {
+	ext2_badblocks_list	bb_list;
+	errcode_t	err;
+};
+
+/*
+ * Helper function for ext2fs_read_bb_inode()
+ */
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int mark_bad_block(ext2_filsys fs, blk_t *block_nr,
+			  e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 
+			  blk_t ref_block EXT2FS_ATTR((unused)),
+			  int ref_offset EXT2FS_ATTR((unused)), 
+			  void *priv_data)
+{
+	struct read_bb_record *rb = (struct read_bb_record *) priv_data;
+	
+	if (blockcnt < 0)
+		return 0;
+	
+	if ((*block_nr < fs->super->s_first_data_block) ||
+	    (*block_nr >= fs->super->s_blocks_count))
+		return 0;	/* Ignore illegal blocks */
+
+	rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr);
+	if (rb->err)
+		return BLOCK_ABORT;
+	return 0;
+}
+
+/*
+ * Reads the current bad blocks from the bad blocks inode.
+ */
+errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list)
+{
+	errcode_t	retval;
+	struct read_bb_record rb;
+	struct ext2_inode inode;
+	blk_t	numblocks;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!*bb_list) {
+		retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
+		if (retval)
+			return retval;
+		if (inode.i_blocks < 500)
+			numblocks = (inode.i_blocks /
+				     (fs->blocksize / 512)) + 20;
+		else
+			numblocks = 500;
+		retval = ext2fs_badblocks_list_create(bb_list, numblocks);
+		if (retval)
+			return retval;
+	}
+
+	rb.bb_list = *bb_list;
+	rb.err = 0;
+	retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, 0, 0,
+				      mark_bad_block, &rb);
+	if (retval)
+		return retval;
+
+	return rb.err;
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/read_bb_file.c silo-1.4.11/libext2fs/read_bb_file.c
--- silo-1.4.11.orig/libext2fs/read_bb_file.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/read_bb_file.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,97 @@
+/*
+ * read_bb_file.c --- read a list of bad blocks from a FILE *
+ *
+ * Copyright (C) 1994, 1995, 2000 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Reads a list of bad blocks from  a FILE *
+ */
+errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, 
+			       ext2_badblocks_list *bb_list,
+			       void *priv_data,
+			       void (*invalid)(ext2_filsys fs,
+					       blk_t blk,
+					       char *badstr,
+					       void *priv_data))
+{
+	errcode_t	retval;
+	blk_t		blockno;
+	int		count;
+	char		buf[128];
+
+	if (fs)
+		EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!*bb_list) {
+		retval = ext2fs_badblocks_list_create(bb_list, 10);
+		if (retval)
+			return retval;
+	}
+
+	while (!feof (f)) {
+		if (fgets(buf, sizeof(buf), f) == NULL)
+			break;
+		count = sscanf(buf, "%u", &blockno);
+		if (count <= 0)
+			continue;
+		if (fs &&
+		    ((blockno < fs->super->s_first_data_block) ||
+		    (blockno >= fs->super->s_blocks_count))) {
+			if (invalid)
+				(invalid)(fs, blockno, buf, priv_data);
+			continue;
+		}
+		retval = ext2fs_badblocks_list_add(*bb_list, blockno);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}
+
+static void call_compat_invalid(ext2_filsys fs, blk_t blk,
+				char *badstr EXT2FS_ATTR((unused)), 
+				void *priv_data)
+{
+	void (*invalid)(ext2_filsys, blk_t);
+
+	invalid = (void (*)(ext2_filsys, blk_t)) priv_data;
+	if (invalid)
+		invalid(fs, blk);
+}
+
+
+/*
+ * Reads a list of bad blocks from  a FILE *
+ */
+errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, 
+			      ext2_badblocks_list *bb_list,
+			      void (*invalid)(ext2_filsys fs, blk_t blk))
+{
+	return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid,
+				    call_compat_invalid);
+}
+
+
diff -Naur silo-1.4.11.orig/libext2fs/res_gdt.c silo-1.4.11/libext2fs/res_gdt.c
--- silo-1.4.11.orig/libext2fs/res_gdt.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/res_gdt.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,220 @@
+/*
+ * res_gdt.c --- reserve blocks for growing the group descriptor table
+ *               during online resizing.
+ *
+ * Copyright (C) 2002 Andreas Dilger
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
+ * ext3 filesystem.  The counters should be initialized to 1, 5, and 7 before
+ * calling this for the first time.  In a sparse filesystem it will be the
+ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
+ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
+ */
+static unsigned int list_backups(ext2_filsys fs, unsigned int *three,
+				 unsigned int *five, unsigned int *seven)
+{
+	unsigned int *min = three;
+	int mult = 3;
+	unsigned int ret;
+
+	if (!(fs->super->s_feature_ro_compat &
+	      EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+		ret = *min;
+		*min += 1;
+		return ret;
+	}
+
+	if (*five < *min) {
+		min = five;
+		mult = 5;
+	}
+	if (*seven < *min) {
+		min = seven;
+		mult = 7;
+	}
+
+	ret = *min;
+	*min *= mult;
+
+	return ret;
+}
+
+/*
+ * This code assumes that the reserved blocks have already been marked in-use
+ * during ext2fs_initialize(), so that they are not allocated for other
+ * uses before we can add them to the resize inode (which has to come
+ * after the creation of the inode table).
+ */
+errcode_t ext2fs_create_resize_inode(ext2_filsys fs)
+{
+	errcode_t		retval, retval2;
+	struct ext2_super_block	*sb;
+	struct ext2_inode	inode;
+	__u32			*dindir_buf, *gdt_buf;
+	int			rsv_add;
+	unsigned long long	apb, inode_size;
+	blk_t			dindir_blk, rsv_off, gdt_off, gdt_blk;
+	int			dindir_dirty = 0, inode_dirty = 0;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	sb = fs->super;
+
+	retval = ext2fs_get_mem(2 * fs->blocksize, (void **)&dindir_buf);
+	if (retval)
+		goto out_free;
+	gdt_buf = (__u32 *)((char *)dindir_buf + fs->blocksize);
+
+	retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
+	if (retval)
+		goto out_free;
+
+	/* Maximum possible file size (we donly use the dindirect blocks) */
+	apb = EXT2_ADDR_PER_BLOCK(sb);
+	rsv_add = fs->blocksize / 512;
+	if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) {
+#ifdef RES_GDT_DEBUG
+		printf("reading GDT dindir %u\n", dindir_blk);
+#endif
+		retval = ext2fs_read_ind_block(fs, dindir_blk, dindir_buf);
+		if (retval)
+			goto out_inode;
+	} else {
+		blk_t goal = 3 + sb->s_reserved_gdt_blocks +
+			fs->desc_blocks + fs->inode_blocks_per_group;
+
+		retval = ext2fs_alloc_block(fs, goal, 0, &dindir_blk);
+		if (retval)
+			goto out_free;
+		inode.i_mode = LINUX_S_IFREG | 0600;
+		inode.i_links_count = 1;
+		inode.i_block[EXT2_DIND_BLOCK] = dindir_blk;
+		inode.i_blocks = rsv_add;
+		memset(dindir_buf, 0, fs->blocksize);
+#ifdef RES_GDT_DEBUG
+		printf("allocated GDT dindir %u\n", dindir_blk);
+#endif
+		dindir_dirty = inode_dirty = 1;
+		inode_size = apb*apb + apb + EXT2_NDIR_BLOCKS;
+		inode_size *= fs->blocksize;
+		inode.i_size = inode_size & 0xFFFFFFFF;
+		inode.i_size_high = (inode_size >> 32) & 0xFFFFFFFF;
+		if(inode.i_size_high) {
+			sb->s_feature_ro_compat |=
+				EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+		}
+		inode.i_ctime = time(0);
+	}
+
+	for (rsv_off = 0, gdt_off = fs->desc_blocks,
+	     gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks;
+	     rsv_off < sb->s_reserved_gdt_blocks;
+	     rsv_off++, gdt_off++, gdt_blk++) {
+		unsigned int three = 1, five = 5, seven = 7;
+		unsigned int grp, last = 0;
+		int gdt_dirty = 0;
+
+		gdt_off %= apb;
+		if (!dindir_buf[gdt_off]) {
+			/* FIXME XXX XXX
+			blk_t new_blk;
+
+			retval = ext2fs_new_block(fs, gdt_blk, 0, &new_blk);
+			if (retval)
+				goto out_free;
+			if (new_blk != gdt_blk) {
+				// XXX free block
+				retval = -1; // XXX
+			}
+			*/
+			gdt_dirty = dindir_dirty = inode_dirty = 1;
+			memset(gdt_buf, 0, fs->blocksize);
+			dindir_buf[gdt_off] = gdt_blk;
+			inode.i_blocks += rsv_add;
+#ifdef RES_GDT_DEBUG
+			printf("added primary GDT block %u at %u[%u]\n",
+			       gdt_blk, dindir_blk, gdt_off);
+#endif
+		} else if (dindir_buf[gdt_off] == gdt_blk) {
+#ifdef RES_GDT_DEBUG
+			printf("reading primary GDT block %u\n", gdt_blk);
+#endif
+			retval = ext2fs_read_ind_block(fs, gdt_blk, gdt_buf);
+			if (retval)
+				goto out_dindir;
+		} else {
+#ifdef RES_GDT_DEBUG
+			printf("bad primary GDT %u != %u at %u[%u]\n",
+			       dindir_buf[gdt_off], gdt_blk,dindir_blk,gdt_off);
+#endif
+			retval = EXT2_ET_RESIZE_INODE_CORRUPT;
+			goto out_dindir;
+		}
+
+		while ((grp = list_backups(fs, &three, &five, &seven)) <
+		       fs->group_desc_count) {
+			blk_t expect = gdt_blk + grp * sb->s_blocks_per_group;
+
+			if (!gdt_buf[last]) {
+#ifdef RES_GDT_DEBUG
+				printf("added backup GDT %u grp %u@%u[%u]\n",
+				       expect, grp, gdt_blk, last);
+#endif
+				gdt_buf[last] = expect;
+				inode.i_blocks += rsv_add;
+				gdt_dirty = inode_dirty = 1;
+			} else if (gdt_buf[last] != expect) {
+#ifdef RES_GDT_DEBUG
+				printf("bad backup GDT %u != %u at %u[%u]\n",
+				       gdt_buf[last], expect, gdt_blk, last);
+#endif
+				retval = EXT2_ET_RESIZE_INODE_CORRUPT;
+				goto out_dindir;
+			}
+			last++;
+		}
+		if (gdt_dirty) {
+#ifdef RES_GDT_DEBUG
+			printf("writing primary GDT block %u\n", gdt_blk);
+#endif
+			retval = ext2fs_write_ind_block(fs, gdt_blk, gdt_buf);
+			if (retval)
+				goto out_dindir;
+		}
+	}
+
+out_dindir:
+	if (dindir_dirty) {
+		retval2 = ext2fs_write_ind_block(fs, dindir_blk, dindir_buf);
+		if (!retval)
+			retval = retval2;
+	}
+out_inode:
+#ifdef RES_GDT_DEBUG
+	printf("inode.i_blocks = %u, i_size = %u\n", inode.i_blocks,
+	       inode.i_size);
+#endif
+	if (inode_dirty) {
+		inode.i_atime = inode.i_mtime = time(0);
+		retval2 = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
+		if (!retval)
+			retval = retval2;
+	}
+out_free:
+	ext2fs_free_mem((void **)&dindir_buf);
+	return retval;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/rs_bitmap.c silo-1.4.11/libext2fs/rs_bitmap.c
--- silo-1.4.11.orig/libext2fs/rs_bitmap.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/rs_bitmap.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,106 @@
+/*
+ * rs_bitmap.c --- routine for changing the size of a bitmap
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_resize_generic_bitmap(__u32 new_end, __u32 new_real_end,
+				       ext2fs_generic_bitmap bmap)
+{
+	errcode_t	retval;
+	size_t		size, new_size;
+	__u32		bitno;
+
+	if (!bmap)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
+
+	/*
+	 * If we're expanding the bitmap, make sure all of the new
+	 * parts of the bitmap are zero.
+	 */
+	if (new_end > bmap->end) {
+		bitno = bmap->real_end;
+		if (bitno > new_end)
+			bitno = new_end;
+		for (; bitno > bmap->end; bitno--)
+			ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
+	}
+	if (new_real_end == bmap->real_end) {
+		bmap->end = new_end;
+		return 0;
+	}
+	
+	size = ((bmap->real_end - bmap->start) / 8) + 1;
+	new_size = ((new_real_end - bmap->start) / 8) + 1;
+
+	if (size != new_size) {
+		retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
+		if (retval)
+			return retval;
+	}
+	if (new_size > size)
+		memset(bmap->bitmap + size, 0, new_size - size);
+
+	bmap->end = new_end;
+	bmap->real_end = new_real_end;
+	return 0;
+}
+
+errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
+				     ext2fs_inode_bitmap bmap)
+{
+	errcode_t	retval;
+	
+	if (!bmap)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_INODE_BITMAP);
+
+	bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
+					      bmap);
+	bmap->magic = EXT2_ET_MAGIC_INODE_BITMAP;
+	return retval;
+}
+
+errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
+				     ext2fs_block_bitmap bmap)
+{
+	errcode_t	retval;
+	
+	if (!bmap)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
+
+	bmap->magic = EXT2_ET_MAGIC_GENERIC_BITMAP;
+	retval = ext2fs_resize_generic_bitmap(new_end, new_real_end,
+					      bmap);
+	bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP;
+	return retval;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/rw_bitmaps.c silo-1.4.11/libext2fs/rw_bitmaps.c
--- silo-1.4.11.orig/libext2fs/rw_bitmaps.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/rw_bitmaps.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,300 @@
+/*
+ * rw_bitmaps.c --- routines to read and write the  inode and block bitmaps.
+ *
+ * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include "e2image.h"
+
+#if defined(__powerpc__) && defined(EXT2FS_ENABLE_SWAPFS)
+/*
+ * On the PowerPC, the big-endian variant of the ext2 filesystem
+ * has its bitmaps stored as 32-bit words with bit 0 as the LSB
+ * of each word.  Thus a bitmap with only bit 0 set would be, as
+ * a string of bytes, 00 00 00 01 00 ...
+ * To cope with this, we byte-reverse each word of a bitmap if
+ * we have a big-endian filesystem, that is, if we are *not*
+ * byte-swapping other word-sized numbers.
+ */
+#define EXT2_BIG_ENDIAN_BITMAPS
+#endif
+
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+static void ext2fs_swap_bitmap(ext2_filsys fs, char *bitmap, int nbytes)
+{
+	__u32 *p = (__u32 *) bitmap;
+	int n;
+		
+	for (n = nbytes / sizeof(__u32); n > 0; --n, ++p)
+		*p = ext2fs_swab32(*p);
+}
+#endif
+
+errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs)
+{
+	dgrp_t 		i;
+	size_t		nbytes;
+	errcode_t	retval;
+	char * inode_bitmap = fs->inode_map->bitmap;
+	char * bitmap_block = NULL;
+	blk_t		blk;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+	if (!inode_bitmap)
+		return 0;
+	nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8);
+	
+	retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
+	if (retval)
+		return retval;
+	memset(bitmap_block, 0xff, fs->blocksize);
+	for (i = 0; i < fs->group_desc_count; i++) {
+		memcpy(bitmap_block, inode_bitmap, nbytes);
+		blk = fs->group_desc[i].bg_inode_bitmap;
+		if (blk) {
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+			if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+			      (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
+				ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
+#endif
+			retval = io_channel_write_blk(fs->io, blk, 1,
+						      bitmap_block);
+			if (retval)
+				return EXT2_ET_INODE_BITMAP_WRITE;
+		}
+		inode_bitmap += nbytes;
+	}
+	fs->flags &= ~EXT2_FLAG_IB_DIRTY;
+	ext2fs_free_mem(&bitmap_block);
+	return 0;
+}
+
+errcode_t ext2fs_write_block_bitmap (ext2_filsys fs)
+{
+	dgrp_t 		i;
+	unsigned int	j;
+	int		nbytes;
+	unsigned int	nbits;
+	errcode_t	retval;
+	char * block_bitmap = fs->block_map->bitmap;
+	char * bitmap_block = NULL;
+	blk_t		blk;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+	if (!block_bitmap)
+		return 0;
+	nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	retval = ext2fs_get_mem(fs->blocksize, &bitmap_block);
+	if (retval)
+		return retval;
+	memset(bitmap_block, 0xff, fs->blocksize);
+	for (i = 0; i < fs->group_desc_count; i++) {
+		memcpy(bitmap_block, block_bitmap, nbytes);
+		if (i == fs->group_desc_count - 1) {
+			/* Force bitmap padding for the last group */
+			nbits = ((fs->super->s_blocks_count
+				  - fs->super->s_first_data_block)
+				 % EXT2_BLOCKS_PER_GROUP(fs->super));
+			if (nbits)
+				for (j = nbits; j < fs->blocksize * 8; j++)
+					ext2fs_set_bit(j, bitmap_block);
+		}
+		blk = fs->group_desc[i].bg_block_bitmap;
+		if (blk) {
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+			if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+			      (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
+				ext2fs_swap_bitmap(fs, bitmap_block, nbytes);
+#endif
+			retval = io_channel_write_blk(fs->io, blk, 1,
+						      bitmap_block);
+			if (retval)
+				return EXT2_ET_BLOCK_BITMAP_WRITE;
+		}
+		block_bitmap += nbytes;
+	}
+	fs->flags &= ~EXT2_FLAG_BB_DIRTY;
+	ext2fs_free_mem(&bitmap_block);
+	return 0;
+}
+
+static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block)
+{
+	dgrp_t i;
+	char *block_bitmap = 0, *inode_bitmap = 0;
+	char *buf;
+	errcode_t retval;
+	int block_nbytes = (int) EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
+	int inode_nbytes = (int) EXT2_INODES_PER_GROUP(fs->super) / 8;
+	blk_t	blk;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	fs->write_bitmaps = ext2fs_write_bitmaps;
+
+	retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
+	if (retval)
+		return retval;
+	if (do_block) {
+		if (fs->block_map)
+			ext2fs_free_block_bitmap(fs->block_map);
+		sprintf(buf, "block bitmap for %s", fs->device_name);
+		retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map);
+		if (retval)
+			goto cleanup;
+		block_bitmap = fs->block_map->bitmap;
+	}
+	if (do_inode) {
+		if (fs->inode_map)
+			ext2fs_free_inode_bitmap(fs->inode_map);
+		sprintf(buf, "inode bitmap for %s", fs->device_name);
+		retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
+		if (retval)
+			goto cleanup;
+		inode_bitmap = fs->inode_map->bitmap;
+	}
+	ext2fs_free_mem(&buf);
+
+	if (fs->flags & EXT2_FLAG_IMAGE_FILE) {
+		if (inode_bitmap) {
+			blk = (fs->image_header->offset_inodemap /
+			       fs->blocksize);
+			retval = io_channel_read_blk(fs->image_io, blk,
+			     -(inode_nbytes * fs->group_desc_count),
+			     inode_bitmap);
+			if (retval)
+				goto cleanup;
+		}
+		if (block_bitmap) {
+			blk = (fs->image_header->offset_blockmap /
+			       fs->blocksize);
+			retval = io_channel_read_blk(fs->image_io, blk, 
+			     -(block_nbytes * fs->group_desc_count),
+			     block_bitmap);
+			if (retval)
+				goto cleanup;
+		}
+		return 0;
+	}
+
+	for (i = 0; i < fs->group_desc_count; i++) {
+		if (block_bitmap) {
+			blk = fs->group_desc[i].bg_block_bitmap;
+			if (blk) {
+				retval = io_channel_read_blk(fs->io, blk,
+					     -block_nbytes, block_bitmap);
+				if (retval) {
+					retval = EXT2_ET_BLOCK_BITMAP_READ;
+					goto cleanup;
+				}
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+				if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+				      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
+					ext2fs_swap_bitmap(fs, block_bitmap, block_nbytes);
+#endif
+			} else
+				memset(block_bitmap, 0, block_nbytes);
+			block_bitmap += block_nbytes;
+		}
+		if (inode_bitmap) {
+			blk = fs->group_desc[i].bg_inode_bitmap;
+			if (blk) {
+				retval = io_channel_read_blk(fs->io, blk,
+					     -inode_nbytes, inode_bitmap);
+				if (retval) {
+					retval = EXT2_ET_INODE_BITMAP_READ;
+					goto cleanup;
+				}
+#ifdef EXT2_BIG_ENDIAN_BITMAPS
+				if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+				      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
+					ext2fs_swap_bitmap(fs, inode_bitmap, inode_nbytes);
+#endif
+			} else
+				memset(inode_bitmap, 0, inode_nbytes);
+			inode_bitmap += inode_nbytes;
+		}
+	}
+	return 0;
+	
+cleanup:
+	if (do_block) {
+		ext2fs_free_mem(&fs->block_map);
+		fs->block_map = 0;
+	}
+	if (do_inode) {
+		ext2fs_free_mem(&fs->inode_map);
+		fs->inode_map = 0;
+	}
+	if (buf)
+		ext2fs_free_mem(&buf);
+	return retval;
+}
+
+errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs)
+{
+	return read_bitmaps(fs, 1, 0);
+}
+
+errcode_t ext2fs_read_block_bitmap(ext2_filsys fs)
+{
+	return read_bitmaps(fs, 0, 1);
+}
+
+errcode_t ext2fs_read_bitmaps(ext2_filsys fs)
+{
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (fs->inode_map && fs->block_map)
+		return 0;
+
+	return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
+}
+
+errcode_t ext2fs_write_bitmaps(ext2_filsys fs)
+{
+	errcode_t	retval;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (fs->block_map && ext2fs_test_bb_dirty(fs)) {
+		retval = ext2fs_write_block_bitmap(fs);
+		if (retval)
+			return retval;
+	}
+	if (fs->inode_map && ext2fs_test_ib_dirty(fs)) {
+		retval = ext2fs_write_inode_bitmap(fs);
+		if (retval)
+			return retval;
+	}
+	return 0;
+}	
+
diff -Naur silo-1.4.11.orig/libext2fs/sparse.c silo-1.4.11/libext2fs/sparse.c
--- silo-1.4.11.orig/libext2fs/sparse.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/sparse.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,78 @@
+/*
+ * sparse.c --- find the groups in an ext2 filesystem with metadata backups
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o.
+ * Copyright (C) 2002 Andreas Dilger.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fsP.h"
+
+static int test_root(int a, int b)
+{
+	if (a == 0)
+		return 1;
+	while (1) {
+		if (a == 1)
+			return 1;
+		if (a % b)
+			return 0;
+		a = a / b;
+	}
+}
+
+int ext2fs_bg_has_super(ext2_filsys fs, int group_block)
+{
+	if (!(fs->super->s_feature_ro_compat &
+	      EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
+		return 1;
+
+	if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
+	    test_root(group_block, 7))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
+ * ext3 filesystem.  The counters should be initialized to 1, 5, and 7 before
+ * calling this for the first time.  In a sparse filesystem it will be the
+ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
+ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
+ */
+unsigned int ext2fs_list_backups(ext2_filsys fs, unsigned int *three,
+				 unsigned int *five, unsigned int *seven)
+{
+	unsigned int *min = three;
+	int mult = 3;
+	unsigned int ret;
+
+	if (!(fs->super->s_feature_ro_compat &
+	      EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+		ret = *min;
+		*min += 1;
+		return ret;
+	}
+
+	if (*five < *min) {
+		min = five;
+		mult = 5;
+	}
+	if (*seven < *min) {
+		min = seven;
+		mult = 7;
+	}
+
+	ret = *min;
+	*min *= mult;
+
+	return ret;
+}
diff -Naur silo-1.4.11.orig/libext2fs/swapfs.c silo-1.4.11/libext2fs/swapfs.c
--- silo-1.4.11.orig/libext2fs/swapfs.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/swapfs.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,237 @@
+/*
+ * swapfs.c --- swap ext2 filesystem data structures
+ * 
+ * Copyright (C) 1995, 1996, 2002 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+#include <ext2fs/ext2_ext_attr.h>
+
+#ifdef EXT2FS_ENABLE_SWAPFS
+void ext2fs_swap_super(struct ext2_super_block * sb)
+{
+  	int i;
+	sb->s_inodes_count = ext2fs_swab32(sb->s_inodes_count);
+	sb->s_blocks_count = ext2fs_swab32(sb->s_blocks_count);
+	sb->s_r_blocks_count = ext2fs_swab32(sb->s_r_blocks_count);
+	sb->s_free_blocks_count = ext2fs_swab32(sb->s_free_blocks_count);
+	sb->s_free_inodes_count = ext2fs_swab32(sb->s_free_inodes_count);
+	sb->s_first_data_block = ext2fs_swab32(sb->s_first_data_block);
+	sb->s_log_block_size = ext2fs_swab32(sb->s_log_block_size);
+	sb->s_log_frag_size = ext2fs_swab32(sb->s_log_frag_size);
+	sb->s_blocks_per_group = ext2fs_swab32(sb->s_blocks_per_group);
+	sb->s_frags_per_group = ext2fs_swab32(sb->s_frags_per_group);
+	sb->s_inodes_per_group = ext2fs_swab32(sb->s_inodes_per_group);
+	sb->s_mtime = ext2fs_swab32(sb->s_mtime);
+	sb->s_wtime = ext2fs_swab32(sb->s_wtime);
+	sb->s_mnt_count = ext2fs_swab16(sb->s_mnt_count);
+	sb->s_max_mnt_count = ext2fs_swab16(sb->s_max_mnt_count);
+	sb->s_magic = ext2fs_swab16(sb->s_magic);
+	sb->s_state = ext2fs_swab16(sb->s_state);
+	sb->s_errors = ext2fs_swab16(sb->s_errors);
+	sb->s_minor_rev_level = ext2fs_swab16(sb->s_minor_rev_level);
+	sb->s_lastcheck = ext2fs_swab32(sb->s_lastcheck);
+	sb->s_checkinterval = ext2fs_swab32(sb->s_checkinterval);
+	sb->s_creator_os = ext2fs_swab32(sb->s_creator_os);
+	sb->s_rev_level = ext2fs_swab32(sb->s_rev_level);
+	sb->s_def_resuid = ext2fs_swab16(sb->s_def_resuid);
+	sb->s_def_resgid = ext2fs_swab16(sb->s_def_resgid);
+	sb->s_first_ino = ext2fs_swab32(sb->s_first_ino);
+	sb->s_inode_size = ext2fs_swab16(sb->s_inode_size);
+	sb->s_block_group_nr = ext2fs_swab16(sb->s_block_group_nr);
+	sb->s_feature_compat = ext2fs_swab32(sb->s_feature_compat);
+	sb->s_feature_incompat = ext2fs_swab32(sb->s_feature_incompat);
+	sb->s_feature_ro_compat = ext2fs_swab32(sb->s_feature_ro_compat);
+	sb->s_algorithm_usage_bitmap = ext2fs_swab32(sb->s_algorithm_usage_bitmap);
+	sb->s_reserved_gdt_blocks = ext2fs_swab16(sb->s_reserved_gdt_blocks);
+	sb->s_journal_inum = ext2fs_swab32(sb->s_journal_inum);
+	sb->s_journal_dev = ext2fs_swab32(sb->s_journal_dev);
+	sb->s_last_orphan = ext2fs_swab32(sb->s_last_orphan);
+	sb->s_default_mount_opts = ext2fs_swab32(sb->s_default_mount_opts);
+	sb->s_first_meta_bg = ext2fs_swab32(sb->s_first_meta_bg);
+	sb->s_mkfs_time = ext2fs_swab32(sb->s_mkfs_time);
+	for (i=0; i < 4; i++)
+		sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]);
+	for (i=0; i < 17; i++)
+		sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]);
+
+}
+
+void ext2fs_swap_group_desc(struct ext2_group_desc *gdp)
+{
+	gdp->bg_block_bitmap = ext2fs_swab32(gdp->bg_block_bitmap);
+	gdp->bg_inode_bitmap = ext2fs_swab32(gdp->bg_inode_bitmap);
+	gdp->bg_inode_table = ext2fs_swab32(gdp->bg_inode_table);
+	gdp->bg_free_blocks_count = ext2fs_swab16(gdp->bg_free_blocks_count);
+	gdp->bg_free_inodes_count = ext2fs_swab16(gdp->bg_free_inodes_count);
+	gdp->bg_used_dirs_count = ext2fs_swab16(gdp->bg_used_dirs_count);
+}
+
+void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, int has_header)
+{
+	struct ext2_ext_attr_header *from_header =
+		(struct ext2_ext_attr_header *)from;
+	struct ext2_ext_attr_header *to_header =
+		(struct ext2_ext_attr_header *)to;
+	struct ext2_ext_attr_entry *from_entry, *to_entry;
+	char *from_end = (char *)from_header + bufsize;
+	int n;
+
+	if (to_header != from_header)
+		memcpy(to_header, from_header, bufsize);
+
+	from_entry = (struct ext2_ext_attr_entry *)from_header;
+	to_entry   = (struct ext2_ext_attr_entry *)to_header;
+
+	if (has_header) {
+		to_header->h_magic    = ext2fs_swab32(from_header->h_magic);
+		to_header->h_blocks   = ext2fs_swab32(from_header->h_blocks);
+		to_header->h_refcount = ext2fs_swab32(from_header->h_refcount);
+		for (n=0; n<4; n++)
+			to_header->h_reserved[n] =
+				ext2fs_swab32(from_header->h_reserved[n]);
+		from_entry = (struct ext2_ext_attr_entry *)(from_header+1);
+		to_entry   = (struct ext2_ext_attr_entry *)(to_header+1);
+	}
+
+	while ((char *)from_entry < from_end && *(__u32 *)from_entry) {
+		to_entry->e_value_offs  =	
+			ext2fs_swab16(from_entry->e_value_offs);
+		to_entry->e_value_block =	
+			ext2fs_swab32(from_entry->e_value_block);
+		to_entry->e_value_size  =	
+			ext2fs_swab32(from_entry->e_value_size);
+		from_entry = EXT2_EXT_ATTR_NEXT(from_entry);
+		to_entry   = EXT2_EXT_ATTR_NEXT(to_entry);
+	}
+}
+
+void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
+			    struct ext2_inode_large *f, int hostorder,
+			    int bufsize)
+{
+	unsigned i;
+	int islnk = 0;
+	__u32 *eaf, *eat;
+
+	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);
+	t->i_file_acl = ext2fs_swab32(f->i_file_acl);
+	t->i_dir_acl = ext2fs_swab32(f->i_dir_acl);
+	if (!islnk || ext2fs_inode_data_blocks(fs, (struct ext2_inode *)t)) {
+		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_generation = ext2fs_swab32(f->i_generation);
+	t->i_faddr = ext2fs_swab32(f->i_faddr);
+
+	switch (fs->super->s_creator_os) {
+	case EXT2_OS_LINUX:
+		t->osd1.linux1.l_i_reserved1 =
+			ext2fs_swab32(f->osd1.linux1.l_i_reserved1);
+		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);
+		t->osd2.linux2.l_i_uid_high =
+		  ext2fs_swab16 (f->osd2.linux2.l_i_uid_high);
+		t->osd2.linux2.l_i_gid_high =
+		  ext2fs_swab16 (f->osd2.linux2.l_i_gid_high);
+		t->osd2.linux2.l_i_reserved2 =
+			ext2fs_swab32(f->osd2.linux2.l_i_reserved2);
+		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->osd1.masix1.m_i_reserved1 =
+			ext2fs_swab32(f->osd1.masix1.m_i_reserved1);
+		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);
+		t->osd2.masix2.m_i_reserved2[0] =
+			ext2fs_swab32(f->osd2.masix2.m_i_reserved2[0]);
+		t->osd2.masix2.m_i_reserved2[1] =
+			ext2fs_swab32(f->osd2.masix2.m_i_reserved2[1]);
+		break;
+	}
+
+	if (bufsize < (int) (sizeof(struct ext2_inode) + sizeof(__u16)))
+		return; /* no i_extra_isize field */
+
+	t->i_extra_isize = ext2fs_swab16(f->i_extra_isize);
+	if (t->i_extra_isize > EXT2_INODE_SIZE(fs->super) -
+				sizeof(struct ext2_inode)) {
+		/* this is error case: i_extra_size is too large */
+		return;
+	}
+
+	i = sizeof(struct ext2_inode) + t->i_extra_isize + sizeof(__u32);
+	if (bufsize < (int) i)
+		return; /* no space for EA magic */
+
+	eaf = (__u32 *) (((char *) f) + sizeof(struct ext2_inode) +
+					f->i_extra_isize);
+
+	if (ext2fs_swab32(*eaf) != EXT2_EXT_ATTR_MAGIC)
+		return; /* it seems no magic here */
+
+	eat = (__u32 *) (((char *) t) + sizeof(struct ext2_inode) +
+					f->i_extra_isize);
+	*eat = ext2fs_swab32(*eaf);
+
+	/* convert EA(s) */
+	ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1),
+			     bufsize - sizeof(struct ext2_inode) -
+			     t->i_extra_isize - sizeof(__u32), 0);
+
+}
+
+void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t,
+		       struct ext2_inode *f, int hostorder)
+{
+	ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) t,
+				(struct ext2_inode_large *) f, hostorder,
+				sizeof(struct ext2_inode));
+}
+
+#endif
diff -Naur silo-1.4.11.orig/libext2fs/test_io.c silo-1.4.11/libext2fs/test_io.c
--- silo-1.4.11.orig/libext2fs/test_io.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/test_io.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,411 @@
+/*
+ * test_io.c --- This is the Test I/O interface.
+ *
+ * Copyright (C) 1996 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#else
+#define PR_GET_DUMPABLE 3
+#endif
+#if (!defined(HAVE_PRCTL) && defined(linux))
+#include <sys/syscall.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+  
+struct test_private_data {
+	int	magic;
+	io_channel real;
+	int flags;
+	FILE *outfile;
+	unsigned long block;
+	int read_abort_count, write_abort_count;
+	void (*read_blk)(unsigned long block, int count, errcode_t err);
+	void (*write_blk)(unsigned long block, int count, errcode_t err);
+	void (*set_blksize)(int blksize, errcode_t err);
+	void (*write_byte)(unsigned long block, int count, errcode_t err);
+};
+
+static errcode_t test_open(const char *name, int flags, io_channel *channel);
+static errcode_t test_close(io_channel channel);
+static errcode_t test_set_blksize(io_channel channel, int blksize);
+static errcode_t test_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t test_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t test_flush(io_channel channel);
+static errcode_t test_write_byte(io_channel channel, unsigned long offset,
+				 int count, const void *buf);
+static errcode_t test_set_option(io_channel channel, const char *option, 
+				 const char *arg);
+
+static struct struct_io_manager struct_test_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"Test I/O Manager",
+	test_open,
+	test_close,
+	test_set_blksize,
+	test_read_blk,
+	test_write_blk,
+	test_flush,
+	test_write_byte,
+	test_set_option
+};
+
+io_manager test_io_manager = &struct_test_manager;
+
+/*
+ * These global variable can be set by the test program as
+ * necessary *before* calling test_open
+ */
+io_manager test_io_backing_manager = 0;
+void (*test_io_cb_read_blk)
+	(unsigned long block, int count, errcode_t err) = 0;
+void (*test_io_cb_write_blk)
+	(unsigned long block, int count, errcode_t err) = 0;
+void (*test_io_cb_set_blksize)
+	(int blksize, errcode_t err) = 0;
+void (*test_io_cb_write_byte)
+	(unsigned long block, int count, errcode_t err) = 0;
+
+/*
+ * Test flags
+ */
+#define TEST_FLAG_READ			0x01
+#define TEST_FLAG_WRITE			0x02
+#define TEST_FLAG_SET_BLKSIZE		0x04
+#define TEST_FLAG_FLUSH			0x08
+#define TEST_FLAG_DUMP			0x10
+#define TEST_FLAG_SET_OPTION		0x20
+
+static void test_dump_block(io_channel channel,
+			    struct test_private_data *data,
+			    unsigned long block, const void *buf)
+{
+	const unsigned char *cp;
+	FILE *f = data->outfile;
+	int	i;
+	unsigned long	cksum = 0;
+
+	for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
+		cksum += *cp;
+	}
+	fprintf(f, "Contents of block %lu, checksum %08lu: \n", block, cksum);
+	for (i=0, cp = buf; i < channel->block_size; i++, cp++) {
+		if ((i % 16) == 0)
+			fprintf(f, "%04x: ", i);
+		fprintf(f, "%02x%c", *cp, ((i % 16) == 15) ? '\n' : ' ');
+	}
+}
+
+static void test_abort(io_channel channel, unsigned long block)
+{
+	struct test_private_data *data;
+	FILE *f;
+
+	data = (struct test_private_data *) channel->private_data;
+	f = data->outfile;
+	test_flush(channel);
+
+	fprintf(f, "Aborting due to I/O to block %lu\n", block);
+	fflush(f);
+	abort();
+}
+
+static char *safe_getenv(const char *arg)
+{
+	if ((getuid() != geteuid()) || (getgid() != getegid()))
+		return NULL;
+#if HAVE_PRCTL
+	if (prctl(PR_GET_DUMPABLE) == 0)
+		return NULL;
+#else
+#if (defined(linux) && defined(SYS_prctl))
+	if (syscall(SYS_prctl, PR_GET_DUMPABLE) == 0)
+		return NULL;
+#endif
+#endif
+
+#ifdef HAVE___SECURE_GETENV
+	return __secure_getenv(arg);
+#else
+	return getenv(arg);
+#endif
+}
+
+static errcode_t test_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel	io = NULL;
+	struct test_private_data *data = NULL;
+	errcode_t	retval;
+	char		*value;
+
+	if (name == 0)
+		return EXT2_ET_BAD_DEVICE_NAME;
+	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+	if (retval)
+		return retval;
+	memset(io, 0, sizeof(struct struct_io_channel));
+	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+	retval = ext2fs_get_mem(sizeof(struct test_private_data), &data);
+	if (retval) {
+		retval = EXT2_ET_NO_MEMORY;
+		goto cleanup;
+	}
+	io->manager = test_io_manager;
+	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+	if (retval)
+		goto cleanup;
+
+	strcpy(io->name, name);
+	io->private_data = data;
+	io->block_size = 1024;
+	io->read_error = 0;
+	io->write_error = 0;
+	io->refcount = 1;
+
+	memset(data, 0, sizeof(struct test_private_data));
+	data->magic = EXT2_ET_MAGIC_TEST_IO_CHANNEL;
+	if (test_io_backing_manager) {
+		retval = test_io_backing_manager->open(name, flags,
+						       &data->real);
+		if (retval)
+			goto cleanup;
+	} else
+		data->real = 0;
+	data->read_blk = 	test_io_cb_read_blk;
+	data->write_blk = 	test_io_cb_write_blk;
+	data->set_blksize = 	test_io_cb_set_blksize;
+	data->write_byte = 	test_io_cb_write_byte;
+
+	data->outfile = NULL;
+	if ((value = safe_getenv("TEST_IO_LOGFILE")) != NULL)
+		data->outfile = fopen(value, "w");
+	if (!data->outfile)
+		data->outfile = stderr;
+
+	data->flags = 0;
+	if ((value = safe_getenv("TEST_IO_FLAGS")) != NULL)
+		data->flags = strtoul(value, NULL, 0);
+	
+	data->block = 0;
+	if ((value = safe_getenv("TEST_IO_BLOCK")) != NULL)
+		data->block = strtoul(value, NULL, 0);
+
+	data->read_abort_count = 0;
+	if ((value = safe_getenv("TEST_IO_READ_ABORT")) != NULL)
+		data->read_abort_count = strtoul(value, NULL, 0);
+
+	data->write_abort_count = 0;
+	if ((value = safe_getenv("TEST_IO_WRITE_ABORT")) != NULL)
+		data->write_abort_count = strtoul(value, NULL, 0);
+	
+	*channel = io;
+	return 0;
+
+cleanup:
+	if (io)
+		ext2fs_free_mem(&io);
+	if (data)
+		ext2fs_free_mem(&data);
+	return retval;
+}
+
+static errcode_t test_close(io_channel channel)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+		return 0;
+	
+	if (data->real)
+		retval = io_channel_close(data->real);
+
+	if (data->outfile && data->outfile != stderr)
+		fclose(data->outfile);
+	
+	ext2fs_free_mem(&channel->private_data);
+	if (channel->name)
+		ext2fs_free_mem(&channel->name);
+	ext2fs_free_mem(&channel);
+	return retval;
+}
+
+static errcode_t test_set_blksize(io_channel channel, int blksize)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_set_blksize(data->real, blksize);
+	if (data->set_blksize)
+		data->set_blksize(blksize, retval);
+	if (data->flags & TEST_FLAG_SET_BLKSIZE)
+		fprintf(data->outfile,
+			"Test_io: set_blksize(%d) returned %s\n",
+			blksize, retval ? error_message(retval) : "OK");
+	channel->block_size = blksize;
+	return retval;
+}
+
+
+static errcode_t test_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_read_blk(data->real, block, count, buf);
+	if (data->read_blk)
+		data->read_blk(block, count, retval);
+	if (data->flags & TEST_FLAG_READ)
+		fprintf(data->outfile,
+			"Test_io: read_blk(%lu, %d) returned %s\n",
+			block, count, retval ? error_message(retval) : "OK");
+	if (data->block && data->block == block) {
+		if (data->flags & TEST_FLAG_DUMP)
+			test_dump_block(channel, data, block, buf);
+		if (--data->read_abort_count == 0)
+			test_abort(channel, block);
+	} 
+	return retval;
+}
+
+static errcode_t test_write_blk(io_channel channel, unsigned long block,
+			       int count, const void *buf)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_write_blk(data->real, block, count, buf);
+	if (data->write_blk)
+		data->write_blk(block, count, retval);
+	if (data->flags & TEST_FLAG_WRITE)
+		fprintf(data->outfile,
+			"Test_io: write_blk(%lu, %d) returned %s\n",
+			block, count, retval ? error_message(retval) : "OK");
+	if (data->block && data->block == block) {
+		if (data->flags & TEST_FLAG_DUMP)
+			test_dump_block(channel, data, block, buf);
+		if (--data->write_abort_count == 0)
+			test_abort(channel, block);
+	}
+	return retval;
+}
+
+static errcode_t test_write_byte(io_channel channel, unsigned long offset,
+			       int count, const void *buf)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real && data->real->manager->write_byte)
+		retval = io_channel_write_byte(data->real, offset, count, buf);
+	if (data->write_byte)
+		data->write_byte(offset, count, retval);
+	if (data->flags & TEST_FLAG_WRITE)
+		fprintf(data->outfile,
+			"Test_io: write_byte(%lu, %d) returned %s\n",
+			offset, count, retval ? error_message(retval) : "OK");
+	return retval;
+}
+
+/*
+ * Flush data buffers to disk.
+ */
+static errcode_t test_flush(io_channel channel)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+	
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+	if (data->real)
+		retval = io_channel_flush(data->real);
+	
+	if (data->flags & TEST_FLAG_FLUSH)
+		fprintf(data->outfile, "Test_io: flush() returned %s\n",
+			retval ? error_message(retval) : "OK");
+	
+	return retval;
+}
+
+static errcode_t test_set_option(io_channel channel, const char *option, 
+				 const char *arg)
+{
+	struct test_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct test_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_TEST_IO_CHANNEL);
+
+
+	if (data->flags & TEST_FLAG_SET_OPTION)
+		fprintf(data->outfile, "Test_io: set_option(%s, %s) ", 
+			option, arg);
+	if (data->real && data->real->manager->set_option) {
+		retval = (data->real->manager->set_option)(data->real, 
+							   option, arg);
+		if (data->flags & TEST_FLAG_SET_OPTION)
+			fprintf(data->outfile, "returned %s\n",
+				retval ? error_message(retval) : "OK");
+	} else {
+		if (data->flags & TEST_FLAG_SET_OPTION)
+			fprintf(data->outfile, "not implemented\n");
+	}
+	return retval;
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_badblocks.c silo-1.4.11/libext2fs/tst_badblocks.c
--- silo-1.4.11.orig/libext2fs/tst_badblocks.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_badblocks.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,293 @@
+/*
+ * This testing program makes sure the badblocks implementation works.
+ *
+ * Copyright (C) 1996 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#define ADD_BLK	0x0001
+#define DEL_BLK	0x0002
+
+blk_t test1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
+blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1 };
+blk_t test3[] = { 3, 1, 4, 5, 9, 2, 7, 10, 5, 6, 10, 8, 0 };
+blk_t test4[] = { 20, 50, 12, 17, 13, 2, 66, 23, 56, 0 };
+blk_t test4a[] = {
+ 	20, 1,
+	50, 1,
+	3, 0,
+	17, 1,
+	18, 0,
+	16, 0,
+	11, 0,
+	12, 1,
+	13, 1,
+	14, 0, 
+	80, 0,
+	45, 0,
+	66, 1,
+	0 };
+blk_t test5[] = { 31, 20, 17, 51, 23, 1, 56, 57, 0 };
+blk_t test5a[] = {
+	50, ADD_BLK,
+	51, DEL_BLK,
+	57, DEL_BLK,
+	66, ADD_BLK,
+	31, DEL_BLK,
+	12, ADD_BLK,
+	2, ADD_BLK,
+	13, ADD_BLK,
+	1, DEL_BLK,
+	0
+	};
+		
+
+static int test_fail = 0;
+
+static errcode_t create_test_list(blk_t *vec, badblocks_list *ret)
+{
+	errcode_t	retval;
+	badblocks_list	bb;
+	int		i;
+	
+	retval = ext2fs_badblocks_list_create(&bb, 5);
+	if (retval) {
+		com_err("create_test_list", retval, "while creating list");
+		return retval;
+	}
+	for (i=0; vec[i]; i++) {
+		retval = ext2fs_badblocks_list_add(bb, vec[i]);
+		if (retval) {
+			com_err("create_test_list", retval,
+				"while adding test vector %d", i);
+			ext2fs_badblocks_list_free(bb);
+			return retval;
+		}
+	}
+	*ret = bb;
+	return 0;
+}
+
+static void print_list(badblocks_list bb, int verify)
+{
+	errcode_t	retval;
+	badblocks_iterate	iter;
+	blk_t			blk;
+	int			i, ok;
+	
+	retval = ext2fs_badblocks_list_iterate_begin(bb, &iter);
+	if (retval) {
+		com_err("print_list", retval, "while setting up iterator");
+		return;
+	}
+	ok = i = 1;
+	while (ext2fs_badblocks_list_iterate(iter, &blk)) {
+		printf("%d ", blk);
+		if (i++ != blk)
+			ok = 0;
+	}
+	ext2fs_badblocks_list_iterate_end(iter);
+	if (verify) {
+		if (ok)
+			printf("--- OK");
+		else {
+			printf("--- NOT OK");
+			test_fail++;
+		}
+	}
+}
+
+static void validate_test_seq(badblocks_list bb, blk_t *vec)
+{
+	int	i, match, ok;
+
+	for (i = 0; vec[i]; i += 2) {
+		match = ext2fs_badblocks_list_test(bb, vec[i]);
+		if (match == vec[i+1])
+			ok = 1;
+		else {
+			ok = 0;
+			test_fail++;
+		}
+		printf("\tblock %d is %s --- %s\n", vec[i],
+		       match ? "present" : "absent",
+		       ok ? "OK" : "NOT OK");
+	}
+}
+
+static void do_test_seq(badblocks_list bb, blk_t *vec)
+{
+	int	i, match;
+
+	for (i = 0; vec[i]; i += 2) {
+		switch (vec[i+1]) {
+		case ADD_BLK:
+			ext2fs_badblocks_list_add(bb, vec[i]);
+			match = ext2fs_badblocks_list_test(bb, vec[i]);
+			printf("Adding block %d --- now %s\n", vec[i], 
+			       match ? "present" : "absent");
+			if (!match) {
+				printf("FAILURE!\n");
+				test_fail++;
+			}
+			break;
+		case DEL_BLK:
+			ext2fs_badblocks_list_del(bb, vec[i]);
+			match = ext2fs_badblocks_list_test(bb, vec[i]);
+			printf("Removing block %d --- now %s\n", vec[i], 
+			       ext2fs_badblocks_list_test(bb, vec[i]) ? 
+			       "present" : "absent");
+			if (match) {
+				printf("FAILURE!\n");
+				test_fail++;
+			}
+			break;
+		}
+	}
+}
+
+
+int file_test(badblocks_list bb)
+{
+	badblocks_list new_bb = 0;
+	errcode_t	retval;
+	FILE	*f;
+
+	f = tmpfile();
+	if (!f) {
+		fprintf(stderr, "Error opening temp file: %s\n",
+			error_message(errno));
+		return 1;
+	}
+	retval = ext2fs_write_bb_FILE(bb, 0, f);
+	if (retval) {
+		com_err("file_test", retval, "while writing bad blocks");
+		return 1;
+	}
+
+	rewind(f);
+	retval = ext2fs_read_bb_FILE2(0, f, &new_bb, 0, 0);
+	if (retval) {
+		com_err("file_test", retval, "while reading bad blocks");
+		return 1;
+	}
+	fclose(f);
+
+	if (ext2fs_badblocks_equal(bb, new_bb)) {
+		printf("Block bitmap matched after reading and writing.\n");
+	} else {
+		printf("Block bitmap NOT matched.\n");
+		test_fail++;
+	}
+	return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+	badblocks_list bb1, bb2, bb3, bb4, bb5;
+	int	equal;
+	errcode_t	retval;
+
+	bb1 = bb2 = bb3 = bb4 = bb5 = 0;
+
+	printf("test1: ");
+	retval = create_test_list(test1, &bb1);
+	if (retval == 0)
+		print_list(bb1, 1);
+	printf("\n");
+	
+	printf("test2: ");
+	retval = create_test_list(test2, &bb2);
+	if (retval == 0)
+		print_list(bb2, 1);
+	printf("\n");
+
+	printf("test3: ");
+	retval = create_test_list(test3, &bb3);
+	if (retval == 0)
+		print_list(bb3, 1);
+	printf("\n");
+	
+	printf("test4: ");
+	retval = create_test_list(test4, &bb4);
+	if (retval == 0) {
+		print_list(bb4, 0);
+		printf("\n");
+		validate_test_seq(bb4, test4a);
+	}
+	printf("\n");
+
+	printf("test5: ");
+	retval = create_test_list(test5, &bb5);
+	if (retval == 0) {
+		print_list(bb5, 0);
+		printf("\n");
+		do_test_seq(bb5, test5a);
+		printf("After test5 sequence: ");
+		print_list(bb5, 0);
+		printf("\n");
+	}
+	printf("\n");
+
+	if (bb1 && bb2 && bb3 && bb4 && bb5) {
+		printf("Comparison tests:\n");
+		equal = ext2fs_badblocks_equal(bb1, bb2);
+		printf("bb1 and bb2 are %sequal.\n", equal ? "" : "NOT "); 
+		if (equal)
+			test_fail++;
+
+		equal = ext2fs_badblocks_equal(bb1, bb3);
+		printf("bb1 and bb3 are %sequal.\n", equal ? "" : "NOT "); 
+		if (!equal)
+			test_fail++;
+		
+		equal = ext2fs_badblocks_equal(bb1, bb4);
+		printf("bb1 and bb4 are %sequal.\n", equal ? "" : "NOT "); 
+		if (equal)
+			test_fail++;
+
+		equal = ext2fs_badblocks_equal(bb4, bb5);
+		printf("bb4 and bb5 are %sequal.\n", equal ? "" : "NOT "); 
+		if (!equal)
+			test_fail++;
+		printf("\n");
+	}
+	
+	file_test(bb4);
+	
+	if (test_fail == 0)
+		printf("ext2fs library badblocks tests checks out OK!\n");
+
+	if (bb1)
+		ext2fs_badblocks_list_free(bb1);
+	if (bb2)
+		ext2fs_badblocks_list_free(bb2);
+	if (bb3)
+		ext2fs_badblocks_list_free(bb3);
+	if (bb4)
+		ext2fs_badblocks_list_free(bb4);
+
+	return test_fail;
+
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_bitops.c silo-1.4.11/libext2fs/tst_bitops.c
--- silo-1.4.11.orig/libext2fs/tst_bitops.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_bitops.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,44 @@
+/*
+ * This testing program makes sure the bitops functions work
+ *
+ * Copyright (C) 2001 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+/* #define _EXT2_USE_C_VERSIONS_ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+unsigned char bitarray[] = {
+	0x80, 0xF0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x10, 0x20, 0x00, 0x00
+	};
+
+main(int argc, char **argv)
+{
+	int	i, size;
+
+	size = sizeof(bitarray)*8;
+	i = ext2fs_find_first_bit_set(bitarray, size);
+	while (i < size) {
+		printf("Bit set: %d\n", i);
+		i = ext2fs_find_next_bit_set(bitarray, size, i+1);
+	}
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_byteswap.c silo-1.4.11/libext2fs/tst_byteswap.c
--- silo-1.4.11.orig/libext2fs/tst_byteswap.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_byteswap.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,92 @@
+/*
+ * This testing program makes sure the byteswap functions work
+ *
+ * Copyright (C) 2000 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+__u16 test1[] = {
+	0x0001, 0x0100,
+	0x1234, 0x3412,
+	0xff00, 0x00ff,
+	0x4000, 0x0040,
+	0xfeff, 0xfffe,
+	0x0000, 0x0000
+	};
+
+__u32 test2[] = {
+	0x00000001, 0x01000000,
+	0x80000000, 0x00000080,
+	0x12345678, 0x78563412,
+	0xffff0000, 0x0000ffff,
+	0x00ff0000, 0x0000ff00,
+	0xff000000, 0x000000ff,
+	0x00000000, 0x00000000
+	};
+
+int main(int argc, char **argv)
+{
+	int	i;
+	int	errors = 0;
+
+	printf("Testing ext2fs_swab16\n");
+	i=0;
+	do {
+		printf("swab16(0x%04x) = 0x%04x\n", test1[i],
+		       ext2fs_swab16(test1[i]));
+		if (ext2fs_swab16(test1[i]) != test1[i+1]) {
+			printf("Error!!!   %04x != %04x\n",
+			       ext2fs_swab16(test1[i]), test1[i+1]);
+			errors++;
+		}
+		if (ext2fs_swab16(test1[i+1]) != test1[i]) {
+			printf("Error!!!   %04x != %04x\n",
+			       ext2fs_swab16(test1[i+1]), test1[i]);
+			errors++;
+		}
+		i += 2;
+	} while (test1[i] != 0);
+	
+	printf("Testing ext2fs_swab32\n");
+	i = 0;
+	do {
+		printf("swab32(0x%08x) = 0x%08x\n", test2[i],
+		       ext2fs_swab32(test2[i]));
+		if (ext2fs_swab32(test2[i]) != test2[i+1]) {
+			printf("Error!!!   %04x != %04x\n",
+			       ext2fs_swab32(test2[i]), test2[i+1]);
+			errors++;
+		}
+		if (ext2fs_swab32(test2[i+1]) != test2[i]) {
+			printf("Error!!!   %04x != %04x\n",
+			       ext2fs_swab32(test2[i+1]), test2[i]);
+			errors++;
+		}
+		i += 2;
+	} while (test2[i] != 0);
+
+	if (!errors)
+		printf("No errors found in the byteswap implementation!\n");
+	
+	return errors;
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_getsectsize.c silo-1.4.11/libext2fs/tst_getsectsize.c
--- silo-1.4.11.orig/libext2fs/tst_getsectsize.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_getsectsize.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,47 @@
+/*
+ * tst_getsize.c --- this function tests the getsize function
+ * 
+ * Copyright (C) 1997 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int main(int argc, char **argv)
+{
+	int	sectsize;
+	int	retval;
+	
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s device\n", argv[0]);
+		exit(1);
+	}
+
+	retval = ext2fs_get_device_sectsize(argv[1], &sectsize);
+	if (retval) {
+		com_err(argv[0], retval,
+			"while calling ext2fs_get_device_sectsize");
+		exit(1);
+	}
+	printf("Device %s has a hardware sector size of %d.\n",
+	       argv[1], sectsize);
+	exit(0);
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_getsize.c silo-1.4.11/libext2fs/tst_getsize.c
--- silo-1.4.11.orig/libext2fs/tst_getsize.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_getsize.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,44 @@
+/*
+ * tst_getsize.c --- this function tests the getsize function
+ * 
+ * Copyright (C) 1997 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+int main(int argc, const char *argv[])
+{
+	errcode_t	retval;
+	blk_t		blocks;
+
+	if (argc < 2) {
+		fprintf(stderr, "%s device\n", argv[0]);
+		exit(1);
+	}
+	retval = ext2fs_get_device_size(argv[1], 1024, &blocks);
+	if (retval) {
+		com_err(argv[0], retval, "while getting device size");
+		exit(1);
+	}
+	printf("%s is device has %d blocks.\n", argv[1], blocks);
+	return 0;
+}
diff -Naur silo-1.4.11.orig/libext2fs/tst_iscan.c silo-1.4.11/libext2fs/tst_iscan.c
--- silo-1.4.11.orig/libext2fs/tst_iscan.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/tst_iscan.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,218 @@
+/*
+ * tst_inode.c --- this function tests the inode scan function
+ * 
+ * Copyright (C) 1996 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+blk_t test_vec[] = { 8, 12, 24, 34, 43, 44, 100, 0 };
+
+ext2_filsys	test_fs;
+ext2fs_block_bitmap bad_block_map, touched_map;
+ext2fs_inode_bitmap bad_inode_map;
+badblocks_list	test_badblocks;
+
+int first_no_comma = 1;
+int failed = 0;
+
+static void test_read_blk(unsigned long block, int count, errcode_t err)
+{
+	int	i;
+
+	if (first_no_comma)
+		first_no_comma = 0;
+	else
+		printf(", ");
+
+	if (count > 1)
+		printf("%lu-%lu", block, block+count-1);
+	else
+		printf("%lu", block);
+
+	for (i=0; i < count; i++, block++) {
+		if (ext2fs_test_block_bitmap(touched_map, block)) {
+			printf("\nDuplicate block?!? --- %lu\n", block);
+			failed++;
+			first_no_comma = 1;
+		}
+		ext2fs_mark_block_bitmap(touched_map, block);
+	}
+}
+
+/*
+ * Setup the variables for doing the inode scan test.
+ */
+static void setup(void)
+{
+	errcode_t	retval;
+	int		i;
+	struct ext2_super_block param;
+
+	initialize_ext2_error_table();
+
+	memset(&param, 0, sizeof(param));
+	param.s_blocks_count = 12000;
+
+
+	test_io_cb_read_blk = test_read_blk;
+	
+	retval = ext2fs_initialize("test fs", 0, &param,
+				   test_io_manager, &test_fs);
+	if (retval) {
+		com_err("setup", retval,
+			"While initializing filesystem");
+		exit(1);
+	}
+	retval = ext2fs_allocate_tables(test_fs);
+	if (retval) {
+		com_err("setup", retval,
+			"While allocating tables for test filesystem");
+		exit(1);
+	}
+	retval = ext2fs_allocate_block_bitmap(test_fs, "bad block map",
+					      &bad_block_map);
+	if (retval) {
+		com_err("setup", retval,
+			"While allocating bad_block bitmap");
+		exit(1);
+	}
+	retval = ext2fs_allocate_block_bitmap(test_fs, "touched map",
+					      &touched_map);
+	if (retval) {
+		com_err("setup", retval,
+			"While allocating touched block bitmap");
+		exit(1);
+	}
+	retval = ext2fs_allocate_inode_bitmap(test_fs, "bad inode map",
+					      &bad_inode_map);
+	if (retval) {
+		com_err("setup", retval,
+			"While allocating bad inode bitmap");
+		exit(1);
+	}
+	
+	retval = ext2fs_badblocks_list_create(&test_badblocks, 5);
+	if (retval) {
+		com_err("setup", retval, "while creating badblocks list");
+		exit(1);
+	}
+	for (i=0; test_vec[i]; i++) {
+		retval = ext2fs_badblocks_list_add(test_badblocks, test_vec[i]);
+		if (retval) {
+			com_err("setup", retval,
+				"while adding test vector %d", i);
+			exit(1);
+		}
+		ext2fs_mark_block_bitmap(bad_block_map, test_vec[i]);
+	}
+	test_fs->badblocks = test_badblocks;
+}
+
+/*
+ * Iterate using inode_scan
+ */
+static void iterate(void)
+{
+	struct ext2_inode inode;
+	ext2_inode_scan	scan;
+	errcode_t	retval;
+	ext2_ino_t	ino;
+
+	retval = ext2fs_open_inode_scan(test_fs, 8, &scan);
+	if (retval) {
+		com_err("iterate", retval, "While opening inode scan");
+		exit(1);
+	}
+	printf("Reading blocks: ");
+	retval = ext2fs_get_next_inode(scan, &ino, &inode);
+	if (retval) {
+		com_err("iterate", retval, "while reading first inode");
+		exit(1);
+	}
+	while (ino) {
+		retval = ext2fs_get_next_inode(scan, &ino, &inode);
+		if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
+			ext2fs_mark_inode_bitmap(bad_inode_map, ino);
+			continue;
+		}
+		if (retval) {
+			com_err("iterate", retval,
+				"while getting next inode");
+			exit(1);
+		}
+	}
+	printf("\n");
+	ext2fs_close_inode_scan(scan);
+}
+
+/*
+ * Verify the touched map
+ */
+static void check_map(void)
+{
+	int	i, j, first=1;
+	unsigned long	blk;
+
+	for (i=0; test_vec[i]; i++) {
+		if (ext2fs_test_block_bitmap(touched_map, test_vec[i])) {
+			printf("Bad block was touched --- %d\n", test_vec[i]);
+			failed++;
+			first_no_comma = 1;
+		}
+		ext2fs_mark_block_bitmap(touched_map, test_vec[i]);
+	}
+	for (i = 0; i < test_fs->group_desc_count; i++) {
+		for (j=0, blk = test_fs->group_desc[i].bg_inode_table;
+		     j < test_fs->inode_blocks_per_group;
+		     j++, blk++) {
+			if (!ext2fs_test_block_bitmap(touched_map, blk) &&
+			    !ext2fs_test_block_bitmap(bad_block_map, blk)) {
+				printf("Missing block --- %lu\n", blk);
+				failed++;
+			}
+		}
+	}
+	printf("Bad inodes: ");
+	for (i=1; i <= test_fs->super->s_inodes_count; i++) {
+		if (ext2fs_test_inode_bitmap(bad_inode_map, i)) {
+			if (first)
+				first = 0;
+			else
+				printf(", ");
+			printf("%d", i);
+		}
+	}
+	printf("\n");
+}
+
+
+int main(int argc, char **argv)
+{
+	setup();
+	iterate();
+	check_map();
+	if (!failed)
+		printf("Inode scan tested OK!\n");
+	return failed;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/unix_io.c silo-1.4.11/libext2fs/unix_io.c
--- silo-1.4.11.orig/libext2fs/unix_io.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/unix_io.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,710 @@
+/*
+ * unix_io.c --- This is the Unix (well, really POSIX) implementation
+ * 	of the I/O manager.
+ *
+ * Implements a one-block write-through cache.
+ *
+ * Includes support for Windows NT support under Cygwin. 
+ *
+ * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+ * 	2002 by Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <fcntl.h>
+#include <time.h>
+#ifdef __linux__
+#include <sys/utsname.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * For checking structure magic numbers...
+ */
+
+#define EXT2_CHECK_MAGIC(struct, code) \
+	  if ((struct)->magic != (code)) return (code)
+
+struct unix_cache {
+	char		*buf;
+	unsigned long	block;
+	int		access_time;
+	unsigned	dirty:1;
+	unsigned	in_use:1;
+};
+
+#define CACHE_SIZE 8
+#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
+#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
+
+struct unix_private_data {
+	int	magic;
+	int	dev;
+	int	flags;
+	int	access_time;
+	ext2_loff_t offset;
+	struct unix_cache cache[CACHE_SIZE];
+};
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel);
+static errcode_t unix_close(io_channel channel);
+static errcode_t unix_set_blksize(io_channel channel, int blksize);
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+			       int count, void *data);
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+				int count, const void *data);
+static errcode_t unix_flush(io_channel channel);
+static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
+				int size, const void *data);
+static errcode_t unix_set_option(io_channel channel, const char *option, 
+				 const char *arg);
+
+static void reuse_cache(io_channel channel, struct unix_private_data *data,
+		 struct unix_cache *cache, unsigned long block);
+
+/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
+ * does not know buffered block devices - everything is raw. */
+#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#define NEED_BOUNCE_BUFFER
+#else
+#undef NEED_BOUNCE_BUFFER
+#endif
+
+static struct struct_io_manager struct_unix_manager = {
+	EXT2_ET_MAGIC_IO_MANAGER,
+	"Unix I/O Manager",
+	unix_open,
+	unix_close,
+	unix_set_blksize,
+	unix_read_blk,
+	unix_write_blk,
+	unix_flush,
+#ifdef NEED_BOUNCE_BUFFER
+	0,
+#else
+	unix_write_byte,
+#endif
+	unix_set_option
+};
+
+io_manager unix_io_manager = &struct_unix_manager;
+
+/*
+ * Here are the raw I/O functions
+ */
+#ifndef NEED_BOUNCE_BUFFER
+static errcode_t raw_read_blk(io_channel channel,
+			      struct unix_private_data *data,
+			      unsigned long block,
+			      int count, void *buf)
+{
+	errcode_t	retval;
+	ssize_t		size;
+	ext2_loff_t	location;
+	int		actual = 0;
+
+	size = (count < 0) ? -count : count * channel->block_size;
+	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+		goto error_out;
+	}
+	actual = read(data->dev, buf, size);
+	if (actual != size) {
+		if (actual < 0)
+			actual = 0;
+		retval = EXT2_ET_SHORT_READ;
+		goto error_out;
+	}
+	return 0;
+	
+error_out:
+	memset((char *) buf+actual, 0, size-actual);
+	if (channel->read_error)
+		retval = (channel->read_error)(channel, block, count, buf,
+					       size, actual, retval);
+	return retval;
+}
+#else /* NEED_BOUNCE_BUFFER */
+/*
+ * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
+ */
+static errcode_t raw_read_blk(io_channel channel,
+			      struct unix_private_data *data,
+			      unsigned long block,
+			      int count, void *buf)
+{
+	errcode_t	retval;
+	size_t		size, alignsize, fragment;
+	ext2_loff_t	location;
+	int		total = 0, actual;
+#define BLOCKALIGN 512
+	char		sector[BLOCKALIGN];
+
+	size = (count < 0) ? -count : count * channel->block_size;
+	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+#ifdef DEBUG
+	printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
+	 		count, size, block, channel->block_size, location);
+#endif
+	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+		goto error_out;
+	}
+	fragment = size % BLOCKALIGN;
+	alignsize = size - fragment;
+	if (alignsize) {
+		actual = read(data->dev, buf, alignsize);
+		if (actual != alignsize)
+			goto short_read;
+	}
+	if (fragment) {
+		actual = read(data->dev, sector, BLOCKALIGN);
+		if (actual != BLOCKALIGN)
+			goto short_read;
+		memcpy(buf+alignsize, sector, fragment);
+	}
+	return 0;
+
+short_read:
+	if (actual>0)
+		total += actual;
+	retval = EXT2_ET_SHORT_READ;
+
+error_out:
+	memset((char *) buf+total, 0, size-actual);
+	if (channel->read_error)
+		retval = (channel->read_error)(channel, block, count, buf,
+					       size, actual, retval);
+	return retval;
+}
+#endif
+
+static errcode_t raw_write_blk(io_channel channel,
+			       struct unix_private_data *data,
+			       unsigned long block,
+			       int count, const void *buf)
+{
+	ssize_t		size;
+	ext2_loff_t	location;
+	int		actual = 0;
+	errcode_t	retval;
+
+	if (count == 1)
+		size = channel->block_size;
+	else {
+		if (count < 0)
+			size = -count;
+		else
+			size = count * channel->block_size;
+	}
+
+	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
+	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
+		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+		goto error_out;
+	}
+	
+	actual = write(data->dev, buf, size);
+	if (actual != size) {
+		retval = EXT2_ET_SHORT_WRITE;
+		goto error_out;
+	}
+	return 0;
+	
+error_out:
+	if (channel->write_error)
+		retval = (channel->write_error)(channel, block, count, buf,
+						size, actual, retval);
+	return retval;
+}
+
+
+/*
+ * Here we implement the cache functions
+ */
+
+/* Allocate the cache buffers */
+static errcode_t alloc_cache(io_channel channel,
+			     struct unix_private_data *data)
+{
+	errcode_t		retval;
+	struct unix_cache	*cache;
+	int			i;
+	
+	data->access_time = 0;
+	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+		cache->block = 0;
+		cache->access_time = 0;
+		cache->dirty = 0;
+		cache->in_use = 0;
+		if ((retval = ext2fs_get_mem(channel->block_size,
+					     &cache->buf)))
+			return retval;
+	}
+	return 0;
+}
+
+/* Free the cache buffers */
+static void free_cache(struct unix_private_data *data)
+{
+	struct unix_cache	*cache;
+	int			i;
+	
+	data->access_time = 0;
+	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+		cache->block = 0;
+		cache->access_time = 0;
+		cache->dirty = 0;
+		cache->in_use = 0;
+		if (cache->buf)
+			ext2fs_free_mem(&cache->buf);
+		cache->buf = 0;
+	}
+}
+
+#ifndef NO_IO_CACHE
+/*
+ * Try to find a block in the cache.  If the block is not found, and
+ * eldest is a non-zero pointer, then fill in eldest with the cache
+ * entry to that should be reused.
+ */
+static struct unix_cache *find_cached_block(struct unix_private_data *data,
+					    unsigned long block,
+					    struct unix_cache **eldest)
+{
+	struct unix_cache	*cache, *unused_cache, *oldest_cache;
+	int			i;
+	
+	unused_cache = oldest_cache = 0;
+	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+		if (!cache->in_use) {
+			if (!unused_cache)
+				unused_cache = cache;
+			continue;
+		}
+		if (cache->block == block) {
+			cache->access_time = ++data->access_time;
+			return cache;
+		}
+		if (!oldest_cache ||
+		    (cache->access_time < oldest_cache->access_time))
+			oldest_cache = cache;
+	}
+	if (eldest)
+		*eldest = (unused_cache) ? unused_cache : oldest_cache;
+	return 0;
+}
+
+/*
+ * Reuse a particular cache entry for another block.
+ */
+static void reuse_cache(io_channel channel, struct unix_private_data *data,
+		 struct unix_cache *cache, unsigned long block)
+{
+	if (cache->dirty && cache->in_use)
+		raw_write_blk(channel, data, cache->block, 1, cache->buf);
+
+	cache->in_use = 1;
+	cache->dirty = 0;
+	cache->block = block;
+	cache->access_time = ++data->access_time;
+}
+
+/*
+ * Flush all of the blocks in the cache
+ */
+static errcode_t flush_cached_blocks(io_channel channel,
+				     struct unix_private_data *data,
+				     int invalidate)
+
+{
+	struct unix_cache	*cache;
+	errcode_t		retval, retval2;
+	int			i;
+	
+	retval2 = 0;
+	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
+		if (!cache->in_use)
+			continue;
+		
+		if (invalidate)
+			cache->in_use = 0;
+		
+		if (!cache->dirty)
+			continue;
+		
+		retval = raw_write_blk(channel, data,
+				       cache->block, 1, cache->buf);
+		if (retval)
+			retval2 = retval;
+		else
+			cache->dirty = 0;
+	}
+	return retval2;
+}
+#endif /* NO_IO_CACHE */
+
+static errcode_t unix_open(const char *name, int flags, io_channel *channel)
+{
+	io_channel	io = NULL;
+	struct unix_private_data *data = NULL;
+	errcode_t	retval;
+	int		open_flags;
+	struct stat	st;
+#ifdef __linux__
+	struct 		utsname ut;
+#endif
+
+	if (name == 0)
+		return EXT2_ET_BAD_DEVICE_NAME;
+	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
+	if (retval)
+		return retval;
+	memset(io, 0, sizeof(struct struct_io_channel));
+	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
+	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
+	if (retval)
+		goto cleanup;
+
+	io->manager = unix_io_manager;
+	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
+	if (retval)
+		goto cleanup;
+
+	strcpy(io->name, name);
+	io->private_data = data;
+	io->block_size = 1024;
+	io->read_error = 0;
+	io->write_error = 0;
+	io->refcount = 1;
+
+	memset(data, 0, sizeof(struct unix_private_data));
+	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
+
+	if ((retval = alloc_cache(io, data)))
+		goto cleanup;
+
+	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
+#ifdef HAVE_OPEN64
+	data->dev = open64(io->name, open_flags);
+#else
+	data->dev = open(io->name, open_flags);
+#endif
+	if (data->dev < 0) {
+		retval = errno;
+		goto cleanup;
+	}
+
+#ifdef __linux__
+#undef RLIM_INFINITY
+#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
+#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
+#else
+#define RLIM_INFINITY  (~0UL)
+#endif
+	/*
+	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
+	 * block devices are wrongly getting hit by the filesize
+	 * limit.  This workaround isn't perfect, since it won't work
+	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
+	 * 
+	 */
+	if ((flags & IO_FLAG_RW) &&
+	    (uname(&ut) == 0) &&
+	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
+	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
+	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
+	     (ut.release[5] < '8')) &&
+	    (fstat(data->dev, &st) == 0) &&
+	    (S_ISBLK(st.st_mode))) {
+		struct rlimit	rlim;
+		
+		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
+		setrlimit(RLIMIT_FSIZE, &rlim);
+		getrlimit(RLIMIT_FSIZE, &rlim);
+		if (((unsigned long) rlim.rlim_cur) <
+		    ((unsigned long) rlim.rlim_max)) {
+			rlim.rlim_cur = rlim.rlim_max;
+			setrlimit(RLIMIT_FSIZE, &rlim);
+		}
+	}
+#endif
+	*channel = io;
+	return 0;
+
+cleanup:
+	if (data) {
+		free_cache(data);
+		ext2fs_free_mem(&data);
+	}
+	if (io)
+		ext2fs_free_mem(&io);
+	return retval;
+}
+
+static errcode_t unix_close(io_channel channel)
+{
+	struct unix_private_data *data;
+	errcode_t	retval = 0;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (--channel->refcount > 0)
+		return 0;
+
+#ifndef NO_IO_CACHE
+	retval = flush_cached_blocks(channel, data, 0);
+#endif
+
+	if (close(data->dev) < 0)
+		retval = errno;
+	free_cache(data);
+
+	ext2fs_free_mem(&channel->private_data);
+	if (channel->name)
+		ext2fs_free_mem(&channel->name);
+	ext2fs_free_mem(&channel);
+	return retval;
+}
+
+static errcode_t unix_set_blksize(io_channel channel, int blksize)
+{
+	struct unix_private_data *data;
+	errcode_t		retval;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (channel->block_size != blksize) {
+#ifndef NO_IO_CACHE
+		if ((retval = flush_cached_blocks(channel, data, 0)))
+			return retval;
+#endif
+		
+		channel->block_size = blksize;
+		free_cache(data);
+		if ((retval = alloc_cache(channel, data)))
+			return retval;
+	}
+	return 0;
+}
+
+
+static errcode_t unix_read_blk(io_channel channel, unsigned long block,
+			       int count, void *buf)
+{
+	struct unix_private_data *data;
+	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
+	errcode_t	retval;
+	char		*cp;
+	int		i, j;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifdef NO_IO_CACHE
+	return raw_read_blk(channel, data, block, count, buf);
+#else
+	/*
+	 * If we're doing an odd-sized read or a very large read,
+	 * flush out the cache and then do a direct read.
+	 */
+	if (count < 0 || count > WRITE_DIRECT_SIZE) {
+		if ((retval = flush_cached_blocks(channel, data, 0)))
+			return retval;
+		return raw_read_blk(channel, data, block, count, buf);
+	}
+
+	cp = buf;
+	while (count > 0) {
+		/* If it's in the cache, use it! */
+		if ((cache = find_cached_block(data, block, &reuse[0]))) {
+#ifdef DEBUG
+			printf("Using cached block %d\n", block);
+#endif
+			memcpy(cp, cache->buf, channel->block_size);
+			count--;
+			block++;
+			cp += channel->block_size;
+			continue;
+		}
+		/*
+		 * Find the number of uncached blocks so we can do a
+		 * single read request
+		 */
+		for (i=1; i < count; i++)
+			if (find_cached_block(data, block+i, &reuse[i]))
+				break;
+#ifdef DEBUG
+		printf("Reading %d blocks starting at %d\n", i, block);
+#endif
+		if ((retval = raw_read_blk(channel, data, block, i, cp)))
+			return retval;
+		
+		/* Save the results in the cache */
+		for (j=0; j < i; j++) {
+			count--;
+			cache = reuse[j];
+			reuse_cache(channel, data, cache, block++);
+			memcpy(cache->buf, cp, channel->block_size);
+			cp += channel->block_size;
+		}
+	}
+	return 0;
+#endif /* NO_IO_CACHE */
+}
+
+static errcode_t unix_write_blk(io_channel channel, unsigned long block,
+				int count, const void *buf)
+{
+	struct unix_private_data *data;
+	struct unix_cache *cache, *reuse;
+	errcode_t	retval = 0;
+	const char	*cp;
+	int		writethrough;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifdef NO_IO_CACHE
+	return raw_write_blk(channel, data, block, count, buf);
+#else	
+	/*
+	 * If we're doing an odd-sized write or a very large write,
+	 * flush out the cache completely and then do a direct write.
+	 */
+	if (count < 0 || count > WRITE_DIRECT_SIZE) {
+		if ((retval = flush_cached_blocks(channel, data, 1)))
+			return retval;
+		return raw_write_blk(channel, data, block, count, buf);
+	}
+
+	/*
+	 * For a moderate-sized multi-block write, first force a write
+	 * if we're in write-through cache mode, and then fill the
+	 * cache with the blocks.
+	 */
+	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
+	if (writethrough)
+		retval = raw_write_blk(channel, data, block, count, buf);
+	
+	cp = buf;
+	while (count > 0) {
+		cache = find_cached_block(data, block, &reuse);
+		if (!cache) {
+			cache = reuse;
+			reuse_cache(channel, data, cache, block);
+		}
+		memcpy(cache->buf, cp, channel->block_size);
+		cache->dirty = !writethrough;
+		count--;
+		block++;
+		cp += channel->block_size;
+	}
+	return retval;
+#endif /* NO_IO_CACHE */
+}
+
+static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
+				 int size, const void *buf)
+{
+	struct unix_private_data *data;
+	errcode_t	retval = 0;
+	ssize_t		actual;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifndef NO_IO_CACHE
+	/*
+	 * Flush out the cache completely
+	 */
+	if ((retval = flush_cached_blocks(channel, data, 1)))
+		return retval;
+#endif
+
+	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
+		return errno;
+	
+	actual = write(data->dev, buf, size);
+	if (actual != size)
+		return EXT2_ET_SHORT_WRITE;
+
+	return 0;
+}
+
+/*
+ * Flush data buffers to disk.  
+ */
+static errcode_t unix_flush(io_channel channel)
+{
+	struct unix_private_data *data;
+	errcode_t retval = 0;
+	
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+#ifndef NO_IO_CACHE
+	retval = flush_cached_blocks(channel, data, 0);
+#endif
+	fsync(data->dev);
+	return retval;
+}
+
+static errcode_t unix_set_option(io_channel channel, const char *option, 
+				 const char *arg)
+{
+	struct unix_private_data *data;
+	unsigned long tmp;
+	char *end;
+
+	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
+	data = (struct unix_private_data *) channel->private_data;
+	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
+
+	if (!strcmp(option, "offset")) {
+		if (!arg)
+			return EXT2_ET_INVALID_ARGUMENT;
+
+		tmp = strtoul(arg, &end, 0);
+		if (*end)
+			return EXT2_ET_INVALID_ARGUMENT;
+		data->offset = tmp;
+		return 0;
+	}
+	return EXT2_ET_INVALID_ARGUMENT;
+}
diff -Naur silo-1.4.11.orig/libext2fs/unlink.c silo-1.4.11/libext2fs/unlink.c
--- silo-1.4.11.orig/libext2fs/unlink.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/unlink.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,99 @@
+/*
+ * unlink.c --- delete links in a ext2fs directory
+ * 
+ * Copyright (C) 1993, 1994, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+#include <string.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+struct link_struct  {
+	const char	*name;
+	int		namelen;
+	ext2_ino_t	inode;
+	int		flags;
+	struct ext2_dir_entry *prev;
+	int		done;
+};	
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+static int unlink_proc(struct ext2_dir_entry *dirent,
+		     int	offset EXT2FS_ATTR((unused)),
+		     int	blocksize EXT2FS_ATTR((unused)),
+		     char	*buf EXT2FS_ATTR((unused)),
+		     void	*priv_data)
+{
+	struct link_struct *ls = (struct link_struct *) priv_data;
+	struct ext2_dir_entry *prev;
+
+	prev = ls->prev;
+	ls->prev = dirent;
+
+	if (ls->name) {
+		if ((dirent->name_len & 0xFF) != ls->namelen)
+			return 0;
+		if (strncmp(ls->name, dirent->name, dirent->name_len & 0xFF))
+			return 0;
+	}
+	if (ls->inode) {
+		if (dirent->inode != ls->inode)
+			return 0;
+	} else {
+		if (!dirent->inode)
+			return 0;
+	}
+
+	if (prev) 
+		prev->rec_len += dirent->rec_len;
+	else
+		dirent->inode = 0;
+	ls->done++;
+	return DIRENT_ABORT|DIRENT_CHANGED;
+}
+
+#ifdef __TURBOC__
+ #pragma argsused
+#endif
+errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir,
+			const char *name, ext2_ino_t ino,
+			int flags EXT2FS_ATTR((unused)))
+{
+	errcode_t	retval;
+	struct link_struct ls;
+
+	EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
+
+	if (!name && !ino)
+		return EXT2_ET_INVALID_ARGUMENT;
+
+	if (!(fs->flags & EXT2_FLAG_RW))
+		return EXT2_ET_RO_FILSYS;
+
+	ls.name = name;
+	ls.namelen = name ? strlen(name) : 0;
+	ls.inode = ino;
+	ls.flags = 0;
+	ls.done = 0;
+	ls.prev = 0;
+
+	retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, 
+				    0, unlink_proc, &ls);
+	if (retval)
+		return retval;
+
+	return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE;
+}
+
diff -Naur silo-1.4.11.orig/libext2fs/valid_blk.c silo-1.4.11/libext2fs/valid_blk.c
--- silo-1.4.11.orig/libext2fs/valid_blk.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/valid_blk.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,56 @@
+/*
+ * valid_blk.c --- does the inode have valid blocks?
+ *
+ * Copyright 1997 by Theodore Ts'o
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ */
+
+#include <stdio.h>
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <time.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+/*
+ * This function returns 1 if the inode's block entries actually
+ * contain block entries.
+ */
+int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode)
+{
+	/*
+	 * Only directories, regular files, and some symbolic links
+	 * have valid block entries.
+	 */
+	if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
+	    !LINUX_S_ISLNK(inode->i_mode))
+		return 0;
+	
+	/*
+	 * If the symbolic link is a "fast symlink", then the symlink
+	 * target is stored in the block entries.
+	 */
+	if (LINUX_S_ISLNK (inode->i_mode)) {
+		if (inode->i_file_acl == 0) {
+			/* With no EA block, we can rely on i_blocks */
+			if (inode->i_blocks == 0)
+				return 0;
+		} else {
+			/* With an EA block, life gets more tricky */
+			if (inode->i_size >= EXT2_N_BLOCKS*4)
+				return 1; /* definitely using i_block[] */
+			if (inode->i_size > 4 && inode->i_block[1] == 0)
+				return 1; /* definitely using i_block[] */
+			return 0; /* Probably a fast symlink */
+		}
+	}
+	return 1;
+}
diff -Naur silo-1.4.11.orig/libext2fs/version.c silo-1.4.11/libext2fs/version.c
--- silo-1.4.11.orig/libext2fs/version.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/version.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,52 @@
+/*
+ * version.c --- Return the version of the ext2 library
+ *
+ * Copyright (C) 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+#include "version.h"
+
+static const char *lib_version = E2FSPROGS_VERSION;
+static const char *lib_date = E2FSPROGS_DATE;
+
+int ext2fs_parse_version_string(const char *ver_string)
+{
+	const char *cp;
+	int version = 0;
+
+	for (cp = ver_string; *cp; cp++) {
+		if (*cp == '.')
+			continue;
+		if (!isdigit(*cp))
+			break;
+		version = (version * 10) + (*cp - '0');
+	}
+	return version;
+}
+
+
+int ext2fs_get_library_version(const char **ver_string,
+			       const char **date_string)
+{
+	if (ver_string)
+		*ver_string = lib_version;
+	if (date_string)
+		*date_string = lib_date;
+
+	return ext2fs_parse_version_string(lib_version);
+}
diff -Naur silo-1.4.11.orig/libext2fs/version.h silo-1.4.11/libext2fs/version.h
--- silo-1.4.11.orig/libext2fs/version.h	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/version.h	2006-03-09 21:34:57 +0000
@@ -0,0 +1,11 @@
+/*
+ * version.h --- controls the version number printed by the e2fs
+ * programs.
+ * 
+ * Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ * 2004, 2005 by Theodore Ts'o.  This file may be redistributed under
+ * the GNU Public License.
+ */
+
+#define E2FSPROGS_VERSION "1.38"
+#define E2FSPROGS_DATE "30-Jun-2005"
diff -Naur silo-1.4.11.orig/libext2fs/write_bb_file.c silo-1.4.11/libext2fs/write_bb_file.c
--- silo-1.4.11.orig/libext2fs/write_bb_file.c	1970-01-01 00:00:00 +0000
+++ silo-1.4.11/libext2fs/write_bb_file.c	2006-03-09 21:34:57 +0000
@@ -0,0 +1,34 @@
+/*
+ * write_bb_file.c --- write a list of bad blocks to a FILE *
+ *
+ * Copyright (C) 1994, 1995 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "ext2_fs.h"
+#include "ext2fs.h"
+
+errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list,
+			       unsigned int flags EXT2FS_ATTR((unused)),
+			       FILE *f)
+{
+	badblocks_iterate	bb_iter;
+	blk_t			blk;
+	errcode_t		retval;
+
+	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
+	if (retval)
+		return retval;
+
+	while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
+		fprintf(f, "%d\n", blk);
+	}
+	ext2fs_badblocks_list_iterate_end(bb_iter);
+	return 0;
+}
diff -Naur silo-1.4.11.orig/second/Makefile silo-1.4.11/second/Makefile
--- silo-1.4.11.orig/second/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/second/Makefile	2006-03-09 21:34:57 +0000
@@ -27,10 +27,10 @@
 LDFLAGS_LARGE=-N -Ttext $(LARGE_RELOC)
 
 .c.o:
-	$(CC) $(CFLAGS) -c $*.c -o $@
+	$(CC-SILO) $(CFLAGS) -c $*.c -o $@
 
 .S.o:
-	$(CC) $(CFLAGS) -c $*.S -o $@
+	$(CC-SILO) $(CFLAGS) -c $*.S -o $@
 
 # The ordering here is very significant. Please add new object files to OBJS5 only.
 OBJS1 = crt0.o
@@ -43,8 +43,8 @@
 OBJS4 = main.o
 OBJS4N = mainnet.o
 OBJS5 = cmdline.o disk.o file.o misc.o cfg.o strtol.o ranges.o timer.o \
-	memory.o fs/libfs.a mul.o ../common/rem.o ../common/sdiv.o umul.o \
-	../common/stringops2.o ls.o muldi3.o
+	memory.o fs/libfs.a ../common/rem.o ../common/sdiv.o umul.o \
+	../common/stringops2.o ls.o muldi3.o ../libext2fs/libext2fs.a
 OBJS = $(OBJS1) $(OBJS2) $(OBJS3) bmark.o $(OBJS4) $(OBJS5)
 OBJSNET = $(OBJS1) $(OBJS2N) $(OBJS3) bmark.o $(OBJS4N) $(OBJS5)
 
@@ -53,18 +53,21 @@
 # Should really switch to autoconf...
 all: second.b silotftp.b
 
+../libext2fs/libext2fs.a:
+	@make -C ../libext2fs
+
 fs/libfs.a: $(FS_OBJS)
 	$(RM) $@
 	$(AR) rc $@ $(FS_OBJS)
 
 second: $(OBJS) mark.o
-	$(LD) $(LDFLAGS_SMALL) -Bstatic -o second $(OBJS) -lext2fs mark.o
-	$(LD) $(LDFLAGS_LARGE) -Bstatic -o second2 $(OBJS) -lext2fs mark.o
+	$(LD) $(LDFLAGS_SMALL) -Bstatic -o second $(OBJS) mark.o
+	$(LD) $(LDFLAGS_LARGE) -Bstatic -o second2 $(OBJS) mark.o
 	$(NM) second | grep -v '*ABS*' | sort > second.map
 
 silotftp: $(OBJSNET) mark.o
-	$(LD) $(LDFLAGS_SMALL) -Bstatic -o silotftp $(OBJSNET) -lext2fs mark.o
-	$(LD) $(LDFLAGS_LARGE) -Bstatic -o silotftp2 $(OBJSNET) -lext2fs mark.o
+	$(LD) $(LDFLAGS_SMALL) -Bstatic -o silotftp $(OBJSNET) mark.o
+	$(LD) $(LDFLAGS_LARGE) -Bstatic -o silotftp2 $(OBJSNET) mark.o
 	$(NM) silotftp | grep -v '*ABS*' | sort > silotftp.map
 
 second.l: second
@@ -73,31 +76,31 @@
 file.o:	       file.c
 
 decompnet.o:   decomp.c
-	$(CC) $(CFLAGS) -DTFTP -DVERSION='"$(VERSION)"' -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -DTFTP -DVERSION='"$(VERSION)"' -c -o $@ $<
 
 decomp.o: decomp.c
-	$(CC) $(CFLAGS) -DVERSION='"$(VERSION)"' -c $<
+	$(CC-SILO) $(CFLAGS) -DVERSION='"$(VERSION)"' -c $<
 
 mainnet.o:   main.c
-	$(CC) $(CFLAGS) -DTFTP -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -DTFTP -c -o $@ $<
 
 malloc.o: ../common/malloc.c
-	$(CC) $(CFLAGS) -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -c -o $@ $<
 
 util:	util.c
-	$(CC) -DSMALL_RELOC=$(SMALL_RELOC) -DLARGE_RELOC=$(LARGE_RELOC) -o $@ $<
+	$(BUILD_CC) -DSMALL_RELOC=$(SMALL_RELOC) -DLARGE_RELOC=$(LARGE_RELOC) -o $@ $<
 
 clean:
 	$(RM) *.o fs/*.o second* silotftp* util fs/libfs.a
 
 crt0.o:	crt0.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9 -DIMGVERSION='"SILO$(IMGVERSION)"' crt0.S
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 -DIMGVERSION='"SILO$(IMGVERSION)"' crt0.S
 
 memory.o: memory.c
-	$(CC) $(CFLAGS) -c -Wa,-Av9 memory.c
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 memory.c
 
 timer.o: timer.c
-	$(CC) $(CFLAGS) -c -Wa,-Av9a timer.c
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9a timer.c
 
 second.b: second util
 	$(ELFTOAOUT) -o second.aout second
diff -Naur silo-1.4.11.orig/second/ls.c silo-1.4.11/second/ls.c
--- silo-1.4.11.orig/second/ls.c	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/second/ls.c	2006-03-09 21:34:57 +0000
@@ -19,10 +19,10 @@
    USA.  */
 
 #include <silo.h>
+#include <linux/types.h>
 #include <stringops.h>
 
 typedef int FILE;
-#include <linux/types.h>
 #include <ext2fs/ext2_fs.h>
 #include <ext2fs/ext2fs.h>
 
diff -Naur silo-1.4.11.orig/silo/silo.c silo-1.4.11/silo/silo.c
--- silo-1.4.11.orig/silo/silo.c	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/silo/silo.c	2006-03-09 21:34:57 +0000
@@ -128,8 +128,8 @@
     unsigned short nsect;	/* Sectors per track */
     unsigned char spare3[4];	/* Even more magic... */
     struct sun_partition {
-	unsigned long start_cylinder;
-	unsigned long num_sectors;
+	unsigned int start_cylinder;
+	unsigned int num_sectors;
     } partitions[8];
     unsigned short magic;	/* Magic number */
     unsigned short csum;	/* Label xor'd checksum */
diff -Naur silo-1.4.11.orig/silo/silocheck.c silo-1.4.11/silo/silocheck.c
--- silo-1.4.11.orig/silo/silocheck.c	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/silo/silocheck.c	2006-03-09 21:34:57 +0000
@@ -100,8 +100,8 @@
     unsigned short nsect;	/* Sectors per track */
     unsigned char spare3[4];	/* Even more magic... */
     struct sun_partition {
-	unsigned long start_cylinder;
-	unsigned long num_sectors;
+	unsigned int start_cylinder;
+	unsigned int num_sectors;
     } partitions[8];
     unsigned short magic;	/* Magic number */
     unsigned short csum;	/* Label xor'd checksum */
diff -Naur silo-1.4.11.orig/tilo/Makefile silo-1.4.11/tilo/Makefile
--- silo-1.4.11.orig/tilo/Makefile	2006-03-09 21:34:08 +0000
+++ silo-1.4.11/tilo/Makefile	2006-03-09 21:34:57 +0000
@@ -14,10 +14,10 @@
 all: maketilo
 
 .c.o:
-	$(CC) $(CFLAGS) -c $*.c
+	$(CC-SILO) $(CFLAGS) -c $*.c
 
 .S.o:
-	$(CC) $(CFLAGS) -c $*.S
+	$(CC-SILO) $(CFLAGS) -c $*.S
 
 OBJS_COMMON = ../common/printf.o ../common/jmp.o ../common/prom.o \
 	../common/tree.o ../common/console.o ../common/stringops1.o \
@@ -45,19 +45,19 @@
 
 
 mallocl.o: ../common/malloc.c
-	$(CC) $(CFLAGS) -DMALLOC_BASE=0x4D0000 -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -DMALLOC_BASE=0x4D0000 -c -o $@ $<
 
 malloc.o: ../common/malloc.c
-	$(CC) $(CFLAGS) -DMALLOC_BASE=0x3D0000 -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -DMALLOC_BASE=0x3D0000 -c -o $@ $<
 
 tilol.o: tilo.c
-	$(CC) $(CFLAGS) -DLARGETILO -c -o $@ $<
+	$(CC-SILO) $(CFLAGS) -DLARGETILO -c -o $@ $<
 
 crt0.o:	crt0.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9 -o $@ $<
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 -o $@ $<
 
 crt0l.o: crt0.S
-	$(CC) $(CFLAGS) -c -Wa,-Av9 -DLARGETILO -o $@ $<
+	$(CC-SILO) $(CFLAGS) -c -Wa,-Av9 -DLARGETILO -o $@ $<
 
 clean:
 	$(RM) *.o boot boot2 *.out b.h b2.h maketilo
