Many files:
  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.

diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index 865f1ef..70a19f3 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,8 +1,23 @@
 Sat Oct 25 00:06:58 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
+	* 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 and updates the filesystem accounting records
-		appropriately. 
+ 		block, zeros it, and updates the filesystem accounting
+ 		records appropriately.
 
 Wed Oct 22 16:47:27 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index a0249e1..eaba802 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -16,8 +16,9 @@
 	bitmaps.o \
 	bitops.o \
 	block.o \
+	bmap.o \
 	bmove.o \
-	brel_ma.o \
+#	brel_ma.o \
 	check_desc.o \
 	closefs.o \
 	cmp_bitmaps.o \
@@ -27,6 +28,7 @@
 	dir_iterate.o \
 	dupfs.o \
 	expanddir.o \
+	fileio.o \
 	freefs.o \
 	get_pathname.o \
 	getsize.o \
@@ -34,7 +36,7 @@
 	initialize.o \
 	inline.o \
 	inode.o \
-	irel_ma.o \
+#	irel_ma.o \
 	ismounted.o \
 	link.o \
 	llseek.o \
@@ -64,7 +66,8 @@
 	$(srcdir)/bitmaps.c \
 	$(srcdir)/bitops.c \
 	$(srcdir)/block.c \
-	$(srcdir)/brel_ma.c \
+#	$(srcdir)/brel_ma.c \
+	$(srcdir)/bmap.c \
 	$(srcdir)/bmove.c \
 	$(srcdir)/check_desc.c \
 	$(srcdir)/closefs.c \
@@ -75,6 +78,7 @@
 	$(srcdir)/dir_iterate.c \
 	$(srcdir)/dupfs.c \
 	$(srcdir)/expanddir.c \
+	$(srcdir)/fileio.c \
 	$(srcdir)/freefs.c \
 	$(srcdir)/get_pathname.c \
 	$(srcdir)/getsize.c \
@@ -82,7 +86,7 @@
 	$(srcdir)/initialize.c \
 	$(srcdir)/inline.c \
 	$(srcdir)/inode.c \
-	$(srcdir)/irel_ma.c \
+#	$(srcdir)/irel_ma.c \
 	$(srcdir)/ismounted.c \
 	$(srcdir)/link.c \
 	$(srcdir)/llseek.c \
diff --git a/lib/ext2fs/Makefile.pq b/lib/ext2fs/Makefile.pq
index 88dcf49..4569238 100644
--- a/lib/ext2fs/Makefile.pq
+++ b/lib/ext2fs/Makefile.pq
@@ -10,8 +10,8 @@
 	bitmaps.obj \
 	bitops.obj \
 	block.obj \
+	bmap.obj \
 	bmove.obj \
-	brel_ma.obj \
 	check_desc.obj \
 	closefs.obj \
 	cmp_bitmaps.obj \
@@ -21,6 +21,7 @@
 	dir_iterate.obj \
 	dupfs.obj \
 	expanddir.obj \
+	fileio.obj \
 	freefs.obj \
 	get_pathname.obj \
 	getsize.obj \
@@ -28,7 +29,6 @@
 	initialize.obj \
 	inline.obj \
 	inode.obj \
-	irel_ma.obj \
 	ismounted.obj \
 	link.obj \
 	lookup.obj \
diff --git a/lib/ext2fs/alloc.c b/lib/ext2fs/alloc.c
index 446184d..ecff171 100644
--- a/lib/ext2fs/alloc.c
+++ b/lib/ext2fs/alloc.c
@@ -16,6 +16,7 @@
 #endif
 #include <stdlib.h>
 #include <time.h>
+#include <string.h>
 #if HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -100,29 +101,52 @@
 }
 
 /*
- * This function uses fs->block_map, and updates the filesystem
- * accounting records appropriately.
+ * 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, blk_t *ret)
+errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+			     char *block_buf, blk_t *ret)
 {
 	errcode_t	retval;
+	blk_t		block;
 	int		group;
+	char		*buf = 0;
 
-	if (!fs->block_map)
-		ext2fs_read_block_bitmap(fs);
+	if (!block_buf) {
+		buf = malloc(fs->blocksize);
+		if (!buf)
+			return EXT2_NO_MEMORY;
+		block_buf = buf;
+	}
+	memset(block_buf, 0, fs->blocksize);
 
-	retval = ext2fs_new_block(fs, goal, 0, ret);
+	if (!fs->block_map) {
+		retval = ext2fs_read_block_bitmap(fs);
+		if (retval)
+			goto fail;
+	}
+
+	retval = ext2fs_new_block(fs, goal, 0, &block);
 	if (retval)
-		return retval;
+		goto fail;
+
+	retval = io_channel_write_blk(fs->io, block, 1, block_buf);
+	if (retval)
+		goto fail;
 	
 	fs->super->s_free_blocks_count--;
-	group = ((*ret - fs->super->s_first_data_block) /
-		 fs->super->s_blocks_per_group);
+	group = ext2fs_group_of_blk(fs, block);
 	fs->group_desc[group].bg_free_blocks_count--;
-	ext2fs_mark_block_bitmap(fs->block_map, *ret);
+	ext2fs_mark_block_bitmap(fs->block_map, block);
 	ext2fs_mark_super_dirty(fs);
 	ext2fs_mark_bb_dirty(fs);
+	*ret = block;
 	return 0;
+
+fail:
+	if (buf)
+		free(buf);
+	return retval;
 }
 
 errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
diff --git a/lib/ext2fs/bmap.c b/lib/ext2fs/bmap.c
new file mode 100644
index 0000000..3081926
--- /dev/null
+++ b/lib/ext2fs/bmap.c
@@ -0,0 +1,248 @@
+/*
+ * bmap.c --- logical to phiscal 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 <stdlib.h>
+
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+#ifdef NO_INLINE_FUNCS
+#define _BMAP_INLINE_	__inline__
+#else
+#define _BMAP_INLINE_
+#endif
+
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino,
+			     struct ext2_inode *inode, 
+			     char *block_buf, int bmap_flags,
+			     blk_t block, blk_t *phys_blk);
+
+#define BMAP_ALLOC	1
+
+#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
+
+static blk_t _BMAP_INLINE_ block_bmap(ext2_filsys fs, char *buf, blk_t nr)
+{
+	blk_t tmp;
+
+	tmp = ((blk_t *) buf)[nr];
+
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+		return ext2fs_swab32(tmp);
+
+	return tmp;
+}
+
+static errcode_t _BMAP_INLINE_ 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) {
+		*ret_blk = 0;
+		return 0;
+	}
+	retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
+	if (retval)
+		return retval;
+
+	b = ((blk_t *) block_buf)[nr];
+
+	if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+	    (fs->flags & EXT2_FLAG_SWAP_BYTES_READ))
+		b = ext2fs_swab32(b);
+
+	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;
+
+		if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
+		    (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE))
+			((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
+		else
+			((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 errcode_t _BMAP_INLINE_ 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;
+	int		addr_per_block;
+	
+	addr_per_block = fs->blocksize >> 2;
+
+	retval = block_ind_bmap(fs, flags, 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 errcode_t _BMAP_INLINE_ 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;
+	int		addr_per_block;
+	
+	addr_per_block = fs->blocksize >> 2;
+
+	retval = block_dind_bmap(fs, flags, 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, 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;
+	int addr_per_block;
+	blk_t	b;
+	char	*buf = 0;
+	errcode_t	retval = 0;
+	int		blocks_alloc = 0;
+
+	*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 = fs->blocksize >> 2;
+
+	if (!block_buf) {
+		buf = malloc(fs->blocksize * 2);
+		if (!buf)
+			return EXT2_NO_MEMORY;
+		block_buf = buf;
+	}
+
+	if (block < EXT2_NDIR_BLOCKS) {
+		*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))
+			    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))
+			    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))
+			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)
+		free(buf);
+	if ((retval == 0) && blocks_alloc) {
+		inode->i_blocks += (blocks_alloc * fs->blocksize) / 512;
+		retval = ext2fs_write_inode(fs, ino, inode);
+	}
+	return retval;
+}
+
+
+
diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in
index b8452ac..69ec87b 100644
--- a/lib/ext2fs/ext2_err.et.in
+++ b/lib/ext2fs/ext2_err.et.in
@@ -53,8 +53,8 @@
 ec	EXT2_ET_MAGIC_PQ_IO_CHANNEL,
 	"Wrong magic number for Powerquest io_channel structure"
 
-ec	EXT2_ET_MAGIC_RESERVED_6,
-	"Wrong magic number --- RESERVED_6"
+ec	EXT2_ET_MAGIC_EXT2_FILE,
+	"Wrong magic number for ext2 file structure"
 
 ec	EXT2_ET_MAGIC_RESERVED_7,
 	"Wrong magic number --- RESERVED_7"
@@ -248,4 +248,7 @@
 ec	EXT2_FILE_NOT_FOUND,
 	"File not found by ext2_lookup"
 
+ec	EXT2_FILE_RO,
+	"File open read-only"
+
 	end
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index f257a2b..5b30b12 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -40,6 +40,7 @@
 
 typedef __u32		blk_t;
 typedef unsigned int	dgrp_t;
+typedef __u32		ext2_off_t;
 
 #include "et/com_err.h"
 #include "ext2fs/ext2_io.h"
@@ -100,6 +101,24 @@
 #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
  */
 
@@ -293,6 +312,11 @@
 typedef struct ext2_icount *ext2_icount_t;
 
 /*
+ * Flags for ext2fs_bmap
+ */
+#define BMAP_ALLOC	1
+
+/*
  * For checking structure magic numbers...
  */
 
@@ -381,7 +405,8 @@
 					blk_t finish, int num,
 					ext2fs_block_bitmap map,
 					blk_t *ret);
-extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, blk_t *ret);
+extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
+				    char *block_buf, blk_t *ret);
 
 /* alloc_tables.c */
 extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
@@ -466,6 +491,13 @@
 					    void	*private),
 				void *private);
 
+/* bmap.c */
+extern errcode_t ext2fs_bmap(ext2_filsys fs, ino_t ino,
+			     struct ext2_inode *inode, 
+			     char *block_buf, int bmap_flags,
+			     blk_t block, blk_t *phys_blk);
+
+
 /* bmove.c */
 extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
 				    ext2fs_block_bitmap reserve,
@@ -545,6 +577,17 @@
 /* expanddir.c */
 extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ino_t dir);
 
+/* fileio.c */
+extern errcode_t ext2fs_file_open(ext2_filsys fs, ino_t ino,
+				  int flags, ext2_file_t *ret);
+extern errcode_t ext2fs_file_close(ext2_file_t file);
+extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+				  int wanted, int *got);
+extern errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
+				   int nbytes, int *written);
+extern errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset,
+				    int whence, ext2_off_t *ret_pos);
+
 /* freefs.c */
 extern void ext2fs_free(ext2_filsys fs);
 extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
diff --git a/lib/ext2fs/fileio.c b/lib/ext2fs/fileio.c
new file mode 100644
index 0000000..fa7acb0
--- /dev/null
+++ b/lib/ext2fs/fileio.c
@@ -0,0 +1,287 @@
+/*
+ * 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 <stdlib.h>
+
+#include <linux/ext2_fs.h>
+
+#include "ext2fs.h"
+
+struct ext2_file {
+	errcode_t		magic;
+	ext2_filsys 		fs;
+	ino_t			ino;
+	struct ext2_inode	inode;
+	int 			flags;
+	ext2_off_t		pos;
+	blk_t			blockno;
+	blk_t			physblock;
+	char 			*buf;
+};
+
+/*
+ * XXX Doesn't handle writing yet
+ */
+errcode_t ext2fs_file_open(ext2_filsys fs, ino_t ino,
+			   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;
+
+	file = (ext2_file_t) malloc(sizeof(struct ext2_file));
+	if (!file)
+		return EXT2_NO_MEMORY;
+	
+	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;
+
+	retval = ext2fs_read_inode(fs, ino, &file->inode);
+	if (retval)
+		goto fail;
+	
+	file->buf = malloc(fs->blocksize);
+	if (!file->buf) {
+		retval = EXT2_NO_MEMORY;
+		goto fail;
+	}
+
+	*ret = file;
+	return 0;
+	
+fail:
+	if (file->buf)
+		free(file->buf);
+	free(file);
+	return retval;
+}
+
+/*
+ * This function flushes the dirty block buffer out to disk if
+ * necessary.
+ */
+static errcode_t ext2fs_file_flush(ext2_file_t file)
+{
+	errcode_t	retval;
+	
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+
+	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(file->fs, file->ino, &file->inode,
+				     file->buf, BMAP_ALLOC,
+				     file->blockno, &file->physblock);
+		if (retval)
+			return retval;
+	}
+
+	retval = io_channel_write_blk(file->fs->io, file->physblock,
+				      1, file->buf);
+	if (retval)
+		return retval;
+
+	file->flags &= ~EXT2_FILE_BUF_DIRTY;
+
+	return retval;
+}
+
+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)
+		free(file->buf);
+	free(file);
+
+	return retval;
+}
+
+
+errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
+			   int wanted, int *got)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+	blk_t		b, pb;
+	int		start, left, c, count = 0;
+	char		*ptr = buf;
+
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	fs = file->fs;
+
+again:
+	if (file->pos >= file->inode.i_size)
+		goto done;
+
+	b = file->pos / fs->blocksize;
+	if (b != file->blockno) {
+		retval = ext2fs_file_flush(file);
+		if (retval)
+			goto fail;
+		file->flags &= ~EXT2_FILE_BUF_VALID;
+	}
+	file->blockno = b;
+	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
+		retval = ext2fs_bmap(fs, file->ino, &file->inode,
+				     file->buf, 0, b, &pb);
+		if (retval)
+			goto fail;
+		if (pb) {
+			file->physblock = pb;
+			retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
+			if (retval)
+				goto fail;
+		} else {
+			file->physblock = 0;
+			memset(file->buf, 0, fs->blocksize);
+		}
+		
+		file->flags |= EXT2_FILE_BUF_VALID;
+	}
+	start = file->pos % fs->blocksize;
+	c = fs->blocksize - start;
+	if (c > wanted)
+		c = wanted;
+	left = file->inode.i_size - file->pos ;
+	if (c > left)
+		c = left;
+	
+	memcpy(ptr, file->buf+start, c);
+	file->pos += c;
+	ptr += c;
+	count += c;
+	wanted -= c;
+
+	if (wanted > 0)
+		goto again;
+
+done:
+	if (got)
+		*got = count;
+	return 0;
+
+fail:
+	if (count)
+		goto done;
+	return retval;
+}
+
+
+errcode_t ext2fs_file_write(ext2_file_t file, void *buf,
+			    int nbytes, int *written)
+{
+	ext2_filsys	fs;
+	errcode_t	retval;
+	blk_t		b, pb;
+	int		start, c, count = 0;
+	char		*ptr = buf;
+
+	EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
+	fs = file->fs;
+
+	if (!(file->flags & EXT2_FILE_WRITE))
+		return EXT2_FILE_RO;
+
+again:
+	b = file->pos / fs->blocksize;
+	if (b != file->blockno) {
+		retval = ext2fs_file_flush(file);
+		if (retval)
+			goto fail;
+		file->flags &= ~EXT2_FILE_BUF_VALID;
+	}
+	file->blockno = b;
+	if (!(file->flags & EXT2_FILE_BUF_VALID)) {
+		retval = ext2fs_bmap(fs, file->ino, &file->inode,
+				     file->buf, BMAP_ALLOC, b, &pb);
+		if (retval)
+			goto fail;
+		file->physblock = pb;
+		
+		retval = io_channel_read_blk(fs->io, pb, 1, file->buf);
+		if (retval)
+			goto fail;
+		file->flags |= EXT2_FILE_BUF_VALID;
+	}
+	start = file->pos % fs->blocksize;
+	c = fs->blocksize - start;
+	if (c > nbytes)
+		c = nbytes;
+	
+	file->flags |= EXT2_FILE_BUF_DIRTY;
+	memcpy(file->buf+start, ptr, c);
+	file->pos += c;
+	ptr += c;
+	count += c;
+	nbytes -= c;
+
+	if (nbytes > 0)
+		goto again;
+
+done:
+	if (written)
+		*written = count;
+	return 0;
+
+fail:
+	if (count)
+		goto done;
+	return retval;
+}
+
+
+errcode_t ext2fs_file_llseek(ext2_file_t file, ext2_off_t offset,
+			     int whence, ext2_off_t *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 = file->inode.i_size + offset;
+	else
+		return EXT2_INVALID_ARGUMENT;
+
+	if (ret_pos)
+		*ret_pos = file->pos;
+
+	return 0;
+}
+
+