Many files:
  Checkin of e2fsprogs 0.5b

diff --git a/lib/ext2fs/block.c b/lib/ext2fs/block.c
new file mode 100644
index 0000000..d2c87ce
--- /dev/null
+++ b/lib/ext2fs/block.c
@@ -0,0 +1,223 @@
+/*
+ * block.c --- iterate over all blocks in an inode
+ * 
+ * Copyright (C) 1993 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <linux/fs.h>
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct block_context {
+	ext2_filsys	fs;
+	int (*func)(ext2_filsys	fs,
+		    blk_t	*blocknr,
+		    int		bcount,
+		    void	*private);
+	int		bcount;
+	int		bsize;
+	int		flags;
+	errcode_t	errcode;
+	char	*ind_buf;
+	char	*dind_buf;
+	char	*tind_buf;
+	void	*private;
+};
+
+static int block_iterate_ind(blk_t *ind_block, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags;
+	blk_t	*block_nr;
+
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+		ret = (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+	if (!*ind_block || (ret & BLOCK_ABORT))
+		return ret;
+	ctx->errcode = io_channel_read_blk(ctx->fs->io, *ind_block,
+					   1, ctx->ind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	for (i = 0; i < (ctx->fs->blocksize >> 2); i++, ctx->bcount++) {
+		block_nr = (blk_t *) ctx->ind_buf + i;
+		if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+			flags = (*ctx->func)(ctx->fs, block_nr, ctx->bcount,
+					     ctx->private);
+			changed	|= flags & BLOCK_CHANGED;
+			if (flags & BLOCK_ABORT) {
+				ret |= BLOCK_ABORT;
+				break;
+			}
+		}
+	}
+	if (changed) {
+		ctx->errcode = io_channel_write_blk(ctx->fs->io, *ind_block,
+						    1, ctx->ind_buf);
+		if (ctx->errcode)
+			ret |= BLOCK_ERROR | BLOCK_ABORT;
+	}
+	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ret & BLOCK_ABORT))
+		ret |= (*ctx->func)(ctx->fs, ind_block, -1, ctx->private);
+	return ret;
+}
+	
+static int block_iterate_dind(blk_t *dind_block, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags;
+	blk_t	*block_nr;
+
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+		ret = (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+	if (!*dind_block || (ret & BLOCK_ABORT))
+		return ret;
+	ctx->errcode = io_channel_read_blk(ctx->fs->io, *dind_block,
+					   1, ctx->dind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	for (i = 0; i < (ctx->fs->blocksize >> 2); i++) {
+		block_nr = (blk_t *) ctx->dind_buf + i;
+		if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+			flags = block_iterate_ind(block_nr, ctx);
+			changed |= flags & BLOCK_CHANGED;
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+		}
+	}
+	if (changed) {
+		ctx->errcode = io_channel_write_blk(ctx->fs->io, *dind_block,
+						    1, ctx->dind_buf);
+		if (ctx->errcode)
+			ret |= BLOCK_ERROR | BLOCK_ABORT;
+	}
+	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ret & BLOCK_ABORT))
+		ret |= (*ctx->func)(ctx->fs, dind_block, -2, ctx->private);
+	return ret;
+}
+	
+static int block_iterate_tind(blk_t *tind_block, struct block_context *ctx)
+{
+	int	ret = 0, changed = 0;
+	int	i, flags;
+	blk_t	*block_nr;
+
+	if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE))
+		ret = (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+	if (!*tind_block || (ret & BLOCK_ABORT))
+		return ret;
+	ctx->errcode = io_channel_read_blk(ctx->fs->io, *tind_block,
+					   1, ctx->tind_buf);
+	if (ctx->errcode) {
+		ret |= BLOCK_ERROR;
+		return ret;
+	}
+	for (i = 0; i < (ctx->fs->blocksize >> 2); i++) {
+		block_nr = (blk_t *) ctx->tind_buf + i;
+		if (*block_nr || (ctx->flags & BLOCK_FLAG_APPEND)) {
+			flags = block_iterate_dind(block_nr, ctx);
+			if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
+				ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
+				break;
+			}
+		}
+	}
+	if (changed) {
+		ctx->errcode = io_channel_write_blk(ctx->fs->io, *tind_block,
+						    1, ctx->tind_buf);
+		if (ctx->errcode)
+			ret |= BLOCK_ERROR | BLOCK_ABORT;
+	}
+	if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
+	    !(ret & BLOCK_ABORT))
+		ret |= (*ctx->func)(ctx->fs, tind_block, -3, ctx->private);
+	
+	return ret;
+}
+	
+errcode_t ext2fs_block_iterate(ext2_filsys fs,
+			       ino_t	ino,
+			       int	flags,
+			       char *block_buf,
+			       int (*func)(ext2_filsys fs,
+					   blk_t	*blocknr,
+					   int	blockcnt,
+					   void	*private),
+			       void *private)
+{
+	int	i;
+	int	ret = 0;
+	struct block_context ctx;
+	blk_t	blocks[EXT2_N_BLOCKS];	/* directory data blocks */
+	struct ext2_inode inode;
+	errcode_t	retval;
+	
+	ret = ext2fs_get_blocks(fs, ino, blocks);
+	if (ret)
+		return ret;
+
+	ctx.fs = fs;
+	ctx.func = func;
+	ctx.private = private;
+	ctx.bcount = 0;
+	ctx.flags = flags;
+	if (block_buf) {
+		ctx.ind_buf = block_buf;
+	} else {
+		ctx.ind_buf = malloc(fs->blocksize * 3);
+		if (!ctx.ind_buf)
+			return ENOMEM;
+	}
+	ctx.dind_buf = ctx.ind_buf + fs->blocksize;
+	ctx.tind_buf = ctx.dind_buf + fs->blocksize;
+	
+	for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
+		if (blocks[i] || (flags & BLOCK_FLAG_APPEND)) {
+			ret |= (*func)(fs, &blocks[i], ctx.bcount, private);
+			if (ret & BLOCK_ABORT)
+				goto abort;
+		}
+	}
+	if (*(blocks + EXT2_IND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_ind(blocks + EXT2_IND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort;
+	}
+	if (*(blocks + EXT2_DIND_BLOCK) || (flags & BLOCK_FLAG_APPEND)) {
+		ret |= block_iterate_dind(blocks + EXT2_DIND_BLOCK, &ctx);
+		if (ret & BLOCK_ABORT)
+			goto abort;
+	}
+	if (*(blocks + EXT2_TIND_BLOCK) || (flags & BLOCK_FLAG_APPEND))
+		ret |= block_iterate_tind(blocks + EXT2_TIND_BLOCK, &ctx);
+
+abort:
+	if (ret & BLOCK_CHANGED) {
+		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)
+		free(ctx.ind_buf);
+
+	return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
+}