r1432 - in trunk: . silo

jim at linuxfromscratch.org jim at linuxfromscratch.org
Mon Mar 6 16:54:20 PST 2006


Author: jim
Date: 2006-03-06 17:54:13 -0700 (Mon, 06 Mar 2006)
New Revision: 1432

Added:
   trunk/silo/silo-1.4.10-fixes-2.patch
Modified:
   trunk/
Log:
 r1493 at server:  jim | 2006-03-06 16:53:05 -0800
 Added: silo-1.4.10-fixes-2.patch



Property changes on: trunk
___________________________________________________________________
Name: svk:merge
   - cc2644d5-6cf8-0310-b111-c40428001e49:/patches:1710
e59974df-c20a-0410-b7e1-d7eaf1be8828:/patches:1489
   + cc2644d5-6cf8-0310-b111-c40428001e49:/patches:1710
e59974df-c20a-0410-b7e1-d7eaf1be8828:/patches:1493

Added: trunk/silo/silo-1.4.10-fixes-2.patch
===================================================================
--- trunk/silo/silo-1.4.10-fixes-2.patch	                        (rev 0)
+++ trunk/silo/silo-1.4.10-fixes-2.patch	2006-03-07 00:54:13 UTC (rev 1432)
@@ -0,0 +1,24399 @@
+Submitted By: Joe Ciccone <joeciccone at crazyeyesoft dot com>
+Date: 2006-03-06
+Initial Package Version: 1.4.10
+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.10.orig/Makefile silo-1.4.10/Makefile
+--- silo-1.4.10.orig/Makefile	2004-05-13 16:53:50 +0000
++++ silo-1.4.10/Makefile	2006-03-07 00:42: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.10.orig/Rules.make silo-1.4.10/Rules.make
+--- silo-1.4.10.orig/Rules.make	2005-12-03 02:38:20 +0000
++++ silo-1.4.10/Rules.make	2006-03-07 00:27:16 +0000
+@@ -1,12 +1,16 @@
+ VERSION=1.4.10
+ IMGVERSION=0.99
+ RM=rm -f
+-# We want to force 32-bit builds
+-CC=gcc -m32
+-LD=ld
+-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
++AR=$(CROSS_COMPILE)ar
++RANLIB=$(CROSS_COMPILE)ranlib
++
+ ELFTOAOUT=elftoaout
+ BIN2H=../common/bin2h
+ 
+diff -Naur silo-1.4.10.orig/common/Makefile silo-1.4.10/common/Makefile
+--- silo-1.4.10.orig/common/Makefile	2004-06-20 17:16:32 +0000
++++ silo-1.4.10/common/Makefile	2006-03-06 23:18:06 +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.10.orig/first/Makefile silo-1.4.10/first/Makefile
+--- silo-1.4.10.orig/first/Makefile	2003-12-04 02:29:23 +0000
++++ silo-1.4.10/first/Makefile	2006-03-06 23:18:06 +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.10.orig/first-isofs/Makefile silo-1.4.10/first-isofs/Makefile
+--- silo-1.4.10.orig/first-isofs/Makefile	2003-04-14 13:21:41 +0000
++++ silo-1.4.10/first-isofs/Makefile	2006-03-06 23:18:06 +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.10.orig/include/emul_32/asm/elf.h silo-1.4.10/include/emul_32/asm/elf.h
+--- silo-1.4.10.orig/include/emul_32/asm/elf.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/include/emul_32/asm/elf.h	2006-03-07 00:17:35 +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.10.orig/include/emul_32/asm/posix_types.h silo-1.4.10/include/emul_32/asm/posix_types.h
+--- silo-1.4.10.orig/include/emul_32/asm/posix_types.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/include/emul_32/asm/posix_types.h	2006-03-07 00:17:35 +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.10.orig/include/emul_32/asm/types.h silo-1.4.10/include/emul_32/asm/types.h
+--- silo-1.4.10.orig/include/emul_32/asm/types.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/include/emul_32/asm/types.h	2006-03-07 00:17:35 +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.10.orig/include/ext2fs/ext2_err.h silo-1.4.10/include/ext2fs/ext2_err.h
+--- silo-1.4.10.orig/include/ext2fs/ext2_err.h	2001-06-16 06:35:24 +0000
++++ silo-1.4.10/include/ext2fs/ext2_err.h	2006-03-07 00:29:23 +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.10.orig/include/ext2fs/ext2_io.h silo-1.4.10/include/ext2fs/ext2_io.h
+--- silo-1.4.10.orig/include/ext2fs/ext2_io.h	2001-06-16 06:35:24 +0000
++++ silo-1.4.10/include/ext2fs/ext2_io.h	2006-03-07 00:30:04 +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.10.orig/libext2fs/ChangeLog silo-1.4.10/libext2fs/ChangeLog
+--- silo-1.4.10.orig/libext2fs/ChangeLog	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ChangeLog	2006-03-07 00:04:38 +0000
+@@ -0,0 +1,3311 @@
++2006-06-30  Theodore Ts'o  <tytso at mit.edu>
++
++	* Release of E2fsprogs 1.38
++
++2005-06-30  Theodore Ts'o  <tytso at 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 at 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 at mit.edu>
++
++	* getsectsize.c (BLKSSZGET): Clean up test for when to manually
++		define the BLKSSZGET ioctl.
++
++2005-05-29  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* test_io.c (safe_getenv): Fix bug so it would fetch the right
++		environment variable.
++
++2005-04-09  Theodore Ts'o  <tytso at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.37
++
++2005-03-21  Theodore Ts'o  <tytso at mit.edu>
++
++	* ext2_ext_attr.h (EXT2_XATTR_LEN, EXT2_XATTR_SIZE): Add new
++		convenience cpp macros.
++
++2005-03-20  Theodore Ts'o  <tytso at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.36
++
++2005-02-05  Theodore Ts'o  <tytso at mit.edu>
++
++	* Makefile.in: Remove ext2fs.pc on a "make distclean"
++
++2005-02-04  Theodore Ts'o  <tytso at mit.edu>
++
++	* Makefile.in (clean): Remove tst_getsize when doing a make clean
++
++2005-02-03  Theodore Ts'o  <tytso at 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 at 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 at mit.edu>
++
++	* ext2fs.pc.in: Add pkg-config files.
++
++2005-01-25  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* Makefile.in: Fix the kernel compile-time echo commands to be
++		consistent and portable
++
++2005-01-07  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at mit.edu>
++
++	* swapfs.c (ext2fs_swap_super): Byteswap the reserved_gdt_blocks
++		superblocks field.
++
++2004-12-15  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at mit.edu>
++
++	* getsize.c (ext2fs_get_device_size): Add support for Windows
++		9x/NT under Cygwin.  Thanks to Sam Robb
++		(samrobb at users.sourceforge.net) for pointing this and the
++		suggested code patch.
++
++2004-09-17  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at bergstrand.org>
++
++	* Makefile.in: Use $(BSDLIB_PIC_FLAG) to determine whether to use
++		-fpic or -fPIC
++
++2004-02-28  Theodore Ts'o  <tytso at mit.edu>
++
++	* Release of E2fsprogs 1.35
++
++2004-02-21  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.34
++
++2003-07-06  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at mit.edu>
++
++	* tst_badblocks.c (file_test): Use tmpfile() instead of mktemp().
++
++2003-04-29  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.33
++
++2003-04-21  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* unix_io.c: Use __CYGWIN__ instead of CYGWIN.
++
++2003-04-17  Theodore Ts'o  <tytso at mit.edu>
++
++	* getsize.c: Add Cygwin/Windows version of ext2fs_get_device_size()
++
++2003-04-12  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* ext2_fs.h (EXT2_FEATURE_RO_COMPAT_BTREE_DIR): Comment out unused
++		feature flag
++
++2003-03-30  Theodore Ts'o  <tytso at mit.edu>
++
++	* Makefile.in: Use the compile_et --build-tree option.
++
++2003-03-14  Theodore Ts'o  <tytso at 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 at 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 at 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 at mit.edu>
++
++	* dirhash.c: Fix gcc -Wall nits.
++
++2003-01-22  Theodore Ts'o  <tytso at mit.edu>
++
++	* unix_io.c (unix_write_blk): Fix up GCC -Wall nits.
++
++2003-01-21  Theodore Ts'o  <tytso at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.32
++
++2002-11-09  Theodore Ts'o  <tytso at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.31
++
++2002-11-08    <tytso at snap.thunk.org>
++
++	* Makefile.in (check): Skip trying to compile test_byteswap
++		if --disable-byteswaap had been given to configure.
++
++2002-11-07    <tytso at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.30
++
++2002-10-31  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at snap.thunk.org>
++
++	* ext2_fs.h: Add new field in superblock for default mount options.
++
++2002-10-13  Theodore Ts'o  <tytso at mit.edu>
++
++	* ext2fs.h: Add #include of header files necessary for ext2fs.h to
++		compile cleanly.
++
++2002-10-02  Theodore Y. Ts'o  <tytso at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.29
++
++2001-08-31  Theodore Tso  <tytso at thunk.org>
++
++	* Release of E2fsprogs 1.28
++
++2002-08-31  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at clusterfs.com>
++
++	* ext2_fs.h: Add superblock field for reserved group descriptors.
++
++2002-06-28  Theodore Ts'o  <tytso at 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 at 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 at 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 at mit.edu>
++
++	* ext2_fs.h (EXT2_DIRSYNC_FL): Add new file.
++
++2002-06-09  Andreas Dilger <adilger at 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 at 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 at 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 at mit.edu>
++
++	* ext2_ext_attr.h: Update to V2 version of the Bestbits format.
++
++2002-05-16  Andreas Dilger <adilger at 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 at 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 at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs 1.27
++
++2002-03-07  Theodore Tso  <tytso at 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 at suse.de>)
++
++2002-02-25  Theodore Tso  <tytso at mit.edu>
++
++	* ext2_fs.h: Add structure definitions for the directory indexing
++		extension.
++
++2002-02-23  Theodore Tso  <tytso at 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 at mit.edu>
++
++	* ismounted.c (is_swap_device): Fix file descriptor/memory leak;
++		we were missing an fclose().
++
++2002-02-20  Theodore Tso  <tytso at 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 at 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 at thunk.org>
++
++	* Release of E2fsprogs 1.26
++
++2002-02-03  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at thunk.org>
++
++	* Release of E2fsprogs 1.25
++
++2001-09-16  Theodore Tso  <tytso at 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 at 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 at thunk.org>
++
++	* Release of E2fsprogs 1.24a
++
++2001-08-30  Theodore Tso  <tytso at thunk.org>
++
++	* Release of E2fsprogs 1.24
++
++2001-08-30  Theodore Tso  <tytso at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.23
++
++2001-08-05  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at valinux.com>
++
++	* ext2_err.et.in (EXT2_ET_LOAD_EXT_JOURNAL): Add new error code
++
++2001-07-20  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.21
++
++2001-06-15  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.20
++
++2001-05-25  Theodore Tso  <tytso at 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 at 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 at valinux.com>
++
++	* ext2_err.et.in (EXT2_ET_JOURNAL_UNSUPP_VERSION): Added new error
++		code.
++
++2001-05-21  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at valinux.com>
++
++	* e2image.h (struct ext2_image_hdr): Fix type for fs_hostname
++
++2001-02-07  Theodore Tso  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at turbolinux.com>
++
++	* mkjournal.c: rename ext2fs_add_journal_fs() to the more descriptive
++		ext2fs_add_journal_inode()
++
++2001-01-01    <tytso at 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 at 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 at 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 at 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 at snap.thunk.org>
++
++	* test_io.c (test_write_blk, test_write_byte): Fix typos pointed
++		out by Andreas Dilger.
++
++2000-11-05    <tytso at 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 at 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 at 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 at 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 at 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 at valinux.com>
++
++	* ext2_err.et.in (EXT2_JOURNAL_NOT_BLOCK): Add new error code.
++
++2000-08-22    <tytso at 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 at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.19
++
++2000-07-07  Theodore Ts'o  <tytso at 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 at 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 at valinux.com>
++
++	* getsize.c (main): Add debugging code under #ifdef DEBUG
++
++2000-05-27  Theodore Ts'o  <tytso at 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 at 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 at valinux.com>
++
++	* ext2fs.h: Add appropriate ifdef's to support C++ compilation.
++
++2000-04-03  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at valinux.com>
++
++	* mkdir.c (ext2fs_mkdir): Only update the parent's inode link
++		counts if the link was successful.  Patch suggested by
++		jeremy at goop.org.
++
++	* Makefile.in (distclean): Remove TAGS and Makefile.in.old from
++		the source directory.
++
++1999-11-10    <tytso at valinux.com>
++
++	* Release of E2fsprogs 1.18
++
++1999-11-08    <tytso at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.17
++
++1999-10-26    <tytso at 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 at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.16
++
++1999-10-22    <tytso at 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 at valinux.com>
++
++	* nt_io.c: New file which supports I/O under Windows NT.
++
++1999-09-07    <tytso at 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 at valinux.com>
++
++	* Release of E2fsprogs 1.15
++
++1999-06-23    <tytso at 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 at sircus.demon.co.uk>.
++
++1999-06-21    <tytso at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs 1.14
++
++1999-01-07  Theodore Ts'o  <tytso at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs 1.13
++
++1998-12-03  Theodore Ts'o  <tytso at rsts-11.mit.edu>
++
++	* Makefile.in: Updated dependencies.
++
++1998-09-22  Theodore Ts'o  <tytso at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs 1.12
++
++1998-06-30  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at localhost.mit.edu>
++
++	* Release of E2fsprogs version 1.10
++
++Thu Apr 24 10:13:42 1997  Theodre Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.09
++
++Mon Apr 14 20:38:56 1997  Theodore Ts'o  <tytso at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.08
++
++Thu Apr 10 13:15:15 1997  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at mit.edu>
++
++	* Release of E2fsprogs version 1.07
++
++Sun Mar  2 16:46:18 1997  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* dirblock.c: Include string.h, since we use memcpy().
++
++Tue Dec  3 12:27:29 1996  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.06
++
++Mon Oct  7 00:44:17 1996  Theodore Ts'o  <tytso at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.05
++
++Sat Sep  7 07:36:03 1996  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at lab.sun.mcst.ru).
++
++Thu Aug 22 00:40:18 1996  Theodore Ts'o  <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.04
++
++Wed Mar 27 00:33:40 1996    <tytso at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.03
++
++Tue Mar 26 12:06:32 1996    <tytso at 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 at 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 at 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 at 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 at 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 at rsts-11.mit.edu>
++
++	* Release of E2fsprogs version 1.02
++
++Sat Dec  9 09:57:50 1995    <tytso at 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 at 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 at rsts-11.mit.edu>
++
++	* bitops.h: Added #ifdef's for Sparc.
++
++Wed Sep  6 22:14:46 1995    <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at lurch.mit.edu>
++
++	* Makefile.in (DLL_INSTALL_DIR, ELF_INSTALL_DIR): Set the
++		installation directories correctly.
++
++Tue Jul 18 09:27:38 1995    <tytso at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at 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 at bbj>
++
++	* Makefile: Added a dummy install target in case shared libraries
++		are not built.
++
++Mon Oct 24 14:11:44 1994    (tytso at 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 at 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 at 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 at 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 at 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.10.orig/libext2fs/Makefile silo-1.4.10/libext2fs/Makefile
+--- silo-1.4.10.orig/libext2fs/Makefile	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/Makefile	2006-03-07 00:43:45 +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.10.orig/libext2fs/alloc.c silo-1.4.10/libext2fs/alloc.c
+--- silo-1.4.10.orig/libext2fs/alloc.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/alloc.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/alloc_sb.c silo-1.4.10/libext2fs/alloc_sb.c
+--- silo-1.4.10.orig/libext2fs/alloc_sb.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/alloc_sb.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/alloc_stats.c silo-1.4.10/libext2fs/alloc_stats.c
+--- silo-1.4.10.orig/libext2fs/alloc_stats.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/alloc_stats.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/alloc_tables.c silo-1.4.10/libext2fs/alloc_tables.c
+--- silo-1.4.10.orig/libext2fs/alloc_tables.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/alloc_tables.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/badblocks.c silo-1.4.10/libext2fs/badblocks.c
+--- silo-1.4.10.orig/libext2fs/badblocks.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/badblocks.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bb_compat.c silo-1.4.10/libext2fs/bb_compat.c
+--- silo-1.4.10.orig/libext2fs/bb_compat.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bb_compat.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bb_inode.c silo-1.4.10/libext2fs/bb_inode.c
+--- silo-1.4.10.orig/libext2fs/bb_inode.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bb_inode.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bitmaps.c silo-1.4.10/libext2fs/bitmaps.c
+--- silo-1.4.10.orig/libext2fs/bitmaps.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bitmaps.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bitops.c silo-1.4.10/libext2fs/bitops.c
+--- silo-1.4.10.orig/libext2fs/bitops.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bitops.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bitops.h silo-1.4.10/libext2fs/bitops.h
+--- silo-1.4.10.orig/libext2fs/bitops.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bitops.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/block.c silo-1.4.10/libext2fs/block.c
+--- silo-1.4.10.orig/libext2fs/block.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/block.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bmap.c silo-1.4.10/libext2fs/bmap.c
+--- silo-1.4.10.orig/libext2fs/bmap.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bmap.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/bmove.c silo-1.4.10/libext2fs/bmove.c
+--- silo-1.4.10.orig/libext2fs/bmove.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/bmove.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/brel.h silo-1.4.10/libext2fs/brel.h
+--- silo-1.4.10.orig/libext2fs/brel.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/brel.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/brel_ma.c silo-1.4.10/libext2fs/brel_ma.c
+--- silo-1.4.10.orig/libext2fs/brel_ma.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/brel_ma.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/check_desc.c silo-1.4.10/libext2fs/check_desc.c
+--- silo-1.4.10.orig/libext2fs/check_desc.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/check_desc.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/closefs.c silo-1.4.10/libext2fs/closefs.c
+--- silo-1.4.10.orig/libext2fs/closefs.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/closefs.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/cmp_bitmaps.c silo-1.4.10/libext2fs/cmp_bitmaps.c
+--- silo-1.4.10.orig/libext2fs/cmp_bitmaps.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/cmp_bitmaps.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dblist.c silo-1.4.10/libext2fs/dblist.c
+--- silo-1.4.10.orig/libext2fs/dblist.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dblist.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dblist_dir.c silo-1.4.10/libext2fs/dblist_dir.c
+--- silo-1.4.10.orig/libext2fs/dblist_dir.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dblist_dir.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dir_iterate.c silo-1.4.10/libext2fs/dir_iterate.c
+--- silo-1.4.10.orig/libext2fs/dir_iterate.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dir_iterate.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dirblock.c silo-1.4.10/libext2fs/dirblock.c
+--- silo-1.4.10.orig/libext2fs/dirblock.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dirblock.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dirhash.c silo-1.4.10/libext2fs/dirhash.c
+--- silo-1.4.10.orig/libext2fs/dirhash.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dirhash.c	2006-03-07 00:04:38 +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 at 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.10.orig/libext2fs/dosio.c silo-1.4.10/libext2fs/dosio.c
+--- silo-1.4.10.orig/libext2fs/dosio.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dosio.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/dosio.h silo-1.4.10/libext2fs/dosio.h
+--- silo-1.4.10.orig/libext2fs/dosio.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dosio.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/dupfs.c silo-1.4.10/libext2fs/dupfs.c
+--- silo-1.4.10.orig/libext2fs/dupfs.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/dupfs.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/e2image.h silo-1.4.10/libext2fs/e2image.h
+--- silo-1.4.10.orig/libext2fs/e2image.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/e2image.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/expanddir.c silo-1.4.10/libext2fs/expanddir.c
+--- silo-1.4.10.orig/libext2fs/expanddir.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/expanddir.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/ext2_err.c silo-1.4.10/libext2fs/ext2_err.c
+--- silo-1.4.10.orig/libext2fs/ext2_err.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2_err.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/ext2_ext_attr.h silo-1.4.10/libext2fs/ext2_ext_attr.h
+--- silo-1.4.10.orig/libext2fs/ext2_ext_attr.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2_ext_attr.h	2006-03-07 00:04:38 +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 at 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.10.orig/libext2fs/ext2_fs.h silo-1.4.10/libext2fs/ext2_fs.h
+--- silo-1.4.10.orig/libext2fs/ext2_fs.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2_fs.h	2006-03-07 00:04:38 +0000
+@@ -0,0 +1,644 @@
++/*
++ *  linux/include/linux/ext2_fs.h
++ *
++ * Copyright (C) 1992, 1993, 1994, 1995
++ * Remy Card (card at 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.10.orig/libext2fs/ext2_io.h silo-1.4.10/libext2fs/ext2_io.h
+--- silo-1.4.10.orig/libext2fs/ext2_io.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2_io.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/ext2fs.h silo-1.4.10/libext2fs/ext2fs.h
+--- silo-1.4.10.orig/libext2fs/ext2fs.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2fs.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/ext2fsP.h silo-1.4.10/libext2fs/ext2fsP.h
+--- silo-1.4.10.orig/libext2fs/ext2fsP.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext2fsP.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/ext_attr.c silo-1.4.10/libext2fs/ext_attr.c
+--- silo-1.4.10.orig/libext2fs/ext_attr.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ext_attr.c	2006-03-07 00:04:38 +0000
+@@ -0,0 +1,105 @@
++/*
++ * ext_attr.c --- extended attribute blocks
++ * 
++ * Copyright (C) 2001 Andreas Gruenbacher, <a.gruenbacher at 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.10.orig/libext2fs/fileio.c silo-1.4.10/libext2fs/fileio.c
+--- silo-1.4.10.orig/libext2fs/fileio.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/fileio.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/finddev.c silo-1.4.10/libext2fs/finddev.c
+--- silo-1.4.10.orig/libext2fs/finddev.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/finddev.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/flushb.c silo-1.4.10/libext2fs/flushb.c
+--- silo-1.4.10.orig/libext2fs/flushb.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/flushb.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/freefs.c silo-1.4.10/libext2fs/freefs.c
+--- silo-1.4.10.orig/libext2fs/freefs.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/freefs.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/gen_bitmap.c silo-1.4.10/libext2fs/gen_bitmap.c
+--- silo-1.4.10.orig/libext2fs/gen_bitmap.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/gen_bitmap.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/get_pathname.c silo-1.4.10/libext2fs/get_pathname.c
+--- silo-1.4.10.orig/libext2fs/get_pathname.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/get_pathname.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/getsectsize.c silo-1.4.10/libext2fs/getsectsize.c
+--- silo-1.4.10.orig/libext2fs/getsectsize.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/getsectsize.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/getsize.c silo-1.4.10/libext2fs/getsize.c
+--- silo-1.4.10.orig/libext2fs/getsize.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/getsize.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/icount.c silo-1.4.10/libext2fs/icount.c
+--- silo-1.4.10.orig/libext2fs/icount.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/icount.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/imager.c silo-1.4.10/libext2fs/imager.c
+--- silo-1.4.10.orig/libext2fs/imager.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/imager.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/ind_block.c silo-1.4.10/libext2fs/ind_block.c
+--- silo-1.4.10.orig/libext2fs/ind_block.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ind_block.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/initialize.c silo-1.4.10/libext2fs/initialize.c
+--- silo-1.4.10.orig/libext2fs/initialize.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/initialize.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/inline.c silo-1.4.10/libext2fs/inline.c
+--- silo-1.4.10.orig/libext2fs/inline.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/inline.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/inode.c silo-1.4.10/libext2fs/inode.c
+--- silo-1.4.10.orig/libext2fs/inode.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/inode.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/inode_io.c silo-1.4.10/libext2fs/inode_io.c
+--- silo-1.4.10.orig/libext2fs/inode_io.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/inode_io.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/io_manager.c silo-1.4.10/libext2fs/io_manager.c
+--- silo-1.4.10.orig/libext2fs/io_manager.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/io_manager.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/irel.h silo-1.4.10/libext2fs/irel.h
+--- silo-1.4.10.orig/libext2fs/irel.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/irel.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/irel_ma.c silo-1.4.10/libext2fs/irel_ma.c
+--- silo-1.4.10.orig/libext2fs/irel_ma.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/irel_ma.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/ismounted.c silo-1.4.10/libext2fs/ismounted.c
+--- silo-1.4.10.orig/libext2fs/ismounted.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/ismounted.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/jfs_compat.h silo-1.4.10/libext2fs/jfs_compat.h
+--- silo-1.4.10.orig/libext2fs/jfs_compat.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/jfs_compat.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/jfs_dat.h silo-1.4.10/libext2fs/jfs_dat.h
+--- silo-1.4.10.orig/libext2fs/jfs_dat.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/jfs_dat.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/jfs_user.h silo-1.4.10/libext2fs/jfs_user.h
+--- silo-1.4.10.orig/libext2fs/jfs_user.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/jfs_user.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/kernel-jbd.h silo-1.4.10/libext2fs/kernel-jbd.h
+--- silo-1.4.10.orig/libext2fs/kernel-jbd.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/kernel-jbd.h	2006-03-07 00:04:38 +0000
+@@ -0,0 +1,910 @@
++/*
++ * linux/include/linux/jbd.h
++ * 
++ * Written by Stephen C. Tweedie <sct at 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.10.orig/libext2fs/kernel-list.h silo-1.4.10/libext2fs/kernel-list.h
+--- silo-1.4.10.orig/libext2fs/kernel-list.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/kernel-list.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/link.c silo-1.4.10/libext2fs/link.c
+--- silo-1.4.10.orig/libext2fs/link.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/link.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/llseek.c silo-1.4.10/libext2fs/llseek.c
+--- silo-1.4.10.orig/libext2fs/llseek.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/llseek.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/lookup.c silo-1.4.10/libext2fs/lookup.c
+--- silo-1.4.10.orig/libext2fs/lookup.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/lookup.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/mkdir.c silo-1.4.10/libext2fs/mkdir.c
+--- silo-1.4.10.orig/libext2fs/mkdir.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/mkdir.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/mkjournal.c silo-1.4.10/libext2fs/mkjournal.c
+--- silo-1.4.10.orig/libext2fs/mkjournal.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/mkjournal.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/namei.c silo-1.4.10/libext2fs/namei.c
+--- silo-1.4.10.orig/libext2fs/namei.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/namei.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/native.c silo-1.4.10/libext2fs/native.c
+--- silo-1.4.10.orig/libext2fs/native.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/native.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/newdir.c silo-1.4.10/libext2fs/newdir.c
+--- silo-1.4.10.orig/libext2fs/newdir.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/newdir.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/nt_io.c silo-1.4.10/libext2fs/nt_io.c
+--- silo-1.4.10.orig/libext2fs/nt_io.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/nt_io.c	2006-03-07 00:04:38 +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 at 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.10.orig/libext2fs/openfs.c silo-1.4.10/libext2fs/openfs.c
+--- silo-1.4.10.orig/libext2fs/openfs.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/openfs.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/read_bb.c silo-1.4.10/libext2fs/read_bb.c
+--- silo-1.4.10.orig/libext2fs/read_bb.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/read_bb.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/read_bb_file.c silo-1.4.10/libext2fs/read_bb_file.c
+--- silo-1.4.10.orig/libext2fs/read_bb_file.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/read_bb_file.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/res_gdt.c silo-1.4.10/libext2fs/res_gdt.c
+--- silo-1.4.10.orig/libext2fs/res_gdt.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/res_gdt.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/rs_bitmap.c silo-1.4.10/libext2fs/rs_bitmap.c
+--- silo-1.4.10.orig/libext2fs/rs_bitmap.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/rs_bitmap.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/rw_bitmaps.c silo-1.4.10/libext2fs/rw_bitmaps.c
+--- silo-1.4.10.orig/libext2fs/rw_bitmaps.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/rw_bitmaps.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/sparse.c silo-1.4.10/libext2fs/sparse.c
+--- silo-1.4.10.orig/libext2fs/sparse.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/sparse.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/swapfs.c silo-1.4.10/libext2fs/swapfs.c
+--- silo-1.4.10.orig/libext2fs/swapfs.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/swapfs.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/test_io.c silo-1.4.10/libext2fs/test_io.c
+--- silo-1.4.10.orig/libext2fs/test_io.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/test_io.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_badblocks.c silo-1.4.10/libext2fs/tst_badblocks.c
+--- silo-1.4.10.orig/libext2fs/tst_badblocks.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_badblocks.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_bitops.c silo-1.4.10/libext2fs/tst_bitops.c
+--- silo-1.4.10.orig/libext2fs/tst_bitops.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_bitops.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_byteswap.c silo-1.4.10/libext2fs/tst_byteswap.c
+--- silo-1.4.10.orig/libext2fs/tst_byteswap.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_byteswap.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_getsectsize.c silo-1.4.10/libext2fs/tst_getsectsize.c
+--- silo-1.4.10.orig/libext2fs/tst_getsectsize.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_getsectsize.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_getsize.c silo-1.4.10/libext2fs/tst_getsize.c
+--- silo-1.4.10.orig/libext2fs/tst_getsize.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_getsize.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/tst_iscan.c silo-1.4.10/libext2fs/tst_iscan.c
+--- silo-1.4.10.orig/libext2fs/tst_iscan.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/tst_iscan.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/unix_io.c silo-1.4.10/libext2fs/unix_io.c
+--- silo-1.4.10.orig/libext2fs/unix_io.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/unix_io.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/unlink.c silo-1.4.10/libext2fs/unlink.c
+--- silo-1.4.10.orig/libext2fs/unlink.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/unlink.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/valid_blk.c silo-1.4.10/libext2fs/valid_blk.c
+--- silo-1.4.10.orig/libext2fs/valid_blk.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/valid_blk.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/version.c silo-1.4.10/libext2fs/version.c
+--- silo-1.4.10.orig/libext2fs/version.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/version.c	2006-03-07 00:04:38 +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.10.orig/libext2fs/version.h silo-1.4.10/libext2fs/version.h
+--- silo-1.4.10.orig/libext2fs/version.h	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/version.h	2006-03-07 00:04:38 +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.10.orig/libext2fs/write_bb_file.c silo-1.4.10/libext2fs/write_bb_file.c
+--- silo-1.4.10.orig/libext2fs/write_bb_file.c	1970-01-01 00:00:00 +0000
++++ silo-1.4.10/libext2fs/write_bb_file.c	2006-03-07 00:04:38 +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.10.orig/second/Makefile silo-1.4.10/second/Makefile
+--- silo-1.4.10.orig/second/Makefile	2004-06-20 17:16:32 +0000
++++ silo-1.4.10/second/Makefile	2006-03-07 00:44:10 +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.10.orig/second/ls.c silo-1.4.10/second/ls.c
+--- silo-1.4.10.orig/second/ls.c	2004-01-10 23:36:34 +0000
++++ silo-1.4.10/second/ls.c	2006-03-06 23:18:06 +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.10.orig/silo/silo.c silo-1.4.10/silo/silo.c
+--- silo-1.4.10.orig/silo/silo.c	2005-12-03 02:37:05 +0000
++++ silo-1.4.10/silo/silo.c	2006-03-07 00:16:32 +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.10.orig/silo/silocheck.c silo-1.4.10/silo/silocheck.c
+--- silo-1.4.10.orig/silo/silocheck.c	2005-12-03 02:37:05 +0000
++++ silo-1.4.10/silo/silocheck.c	2006-03-07 00:17:17 +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.10.orig/tilo/Makefile silo-1.4.10/tilo/Makefile
+--- silo-1.4.10.orig/tilo/Makefile	2004-06-20 17:20:37 +0000
++++ silo-1.4.10/tilo/Makefile	2006-03-06 23:18:06 +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




More information about the patches mailing list