]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Many files:
authorTheodore Ts'o <tytso@mit.edu>
Sat, 25 Oct 1997 22:37:42 +0000 (22:37 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 25 Oct 1997 22:37:42 +0000 (22:37 +0000)
  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.

lib/ext2fs/ChangeLog
lib/ext2fs/Makefile.in
lib/ext2fs/Makefile.pq
lib/ext2fs/alloc.c
lib/ext2fs/bmap.c [new file with mode: 0644]
lib/ext2fs/ext2_err.et.in
lib/ext2fs/ext2fs.h
lib/ext2fs/fileio.c [new file with mode: 0644]

index 865f1efc23797f2f6b8a48035769103c593fa1d6..70a19f3205d06398b33bc3280ef4b6d95ded645e 100644 (file)
@@ -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>
 
index a0249e1365188f60f12ff39230d32ad27871513a..eaba802d9ed30cfd1bc9f861cb4e27d126dcd778 100644 (file)
@@ -16,8 +16,9 @@ OBJS= ext2_err.o \
        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 @@ OBJS= ext2_err.o \
        dir_iterate.o \
        dupfs.o \
        expanddir.o \
+       fileio.o \
        freefs.o \
        get_pathname.o \
        getsize.o \
@@ -34,7 +36,7 @@ OBJS= ext2_err.o \
        initialize.o \
        inline.o \
        inode.o \
-       irel_ma.o \
+#      irel_ma.o \
        ismounted.o \
        link.o \
        llseek.o \
@@ -64,7 +66,8 @@ SRCS= ext2_err.c \
        $(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 @@ SRCS= ext2_err.c \
        $(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 @@ SRCS= ext2_err.c \
        $(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 \
index 88dcf4919c27187d749b419b031f1968e50869f6..4569238e2aac86a1c068634c48c13eecb8d90138 100644 (file)
@@ -10,8 +10,8 @@ OBJS=         alloc.obj \
        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 @@ OBJS=         alloc.obj \
        dir_iterate.obj \
        dupfs.obj \
        expanddir.obj \
+       fileio.obj \
        freefs.obj \
        get_pathname.obj \
        getsize.obj \
@@ -28,7 +29,6 @@ OBJS=         alloc.obj \
        initialize.obj \
        inline.obj \
        inode.obj \
-       irel_ma.obj \
        ismounted.obj \
        link.obj \
        lookup.obj \
index 446184d8803118d97915503b70c9e5816f423c1e..ecff1711ce416f07d9c60c07f9a493ac82a17427 100644 (file)
@@ -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 @@ errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
 }
 
 /*
- * 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 (!block_buf) {
+               buf = malloc(fs->blocksize);
+               if (!buf)
+                       return EXT2_NO_MEMORY;
+               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;
 
-       if (!fs->block_map)
-               ext2fs_read_block_bitmap(fs);
-
-       retval = ext2fs_new_block(fs, goal, 0, ret);
+       retval = io_channel_write_blk(fs->io, block, 1, block_buf);
        if (retval)
-               return 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 (file)
index 0000000..3081926
--- /dev/null
@@ -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;
+}
+
+
+
index b8452ac101288ec85d83217d19b0e25aaf72d130..69ec87b8da9f976523b87552e6bfe811dcaa16c9 100644 (file)
@@ -53,8 +53,8 @@ ec    EXT2_ET_MAGIC_ICOUNT,
 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_TOO_MANY_REFS,
 ec     EXT2_FILE_NOT_FOUND,
        "File not found by ext2_lookup"
 
+ec     EXT2_FILE_RO,
+       "File open read-only"
+
        end
index f257a2b22ae752abc9cd6ab9ee600a9ca534fb74..5b30b12f94fe9b8a4d7bd574537e6c536180cd4c 100644 (file)
@@ -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"
@@ -99,6 +100,24 @@ 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
  */
@@ -292,6 +311,11 @@ typedef struct ext2_struct_inode_scan *ext2_inode_scan;
 
 typedef struct ext2_icount *ext2_icount_t;
 
+/*
+ * Flags for ext2fs_bmap
+ */
+#define BMAP_ALLOC     1
+
 /*
  * For checking structure magic numbers...
  */
@@ -381,7 +405,8 @@ 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, 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 @@ errcode_t ext2fs_block_iterate2(ext2_filsys fs,
                                            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 @@ extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest);
 /* 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 (file)
index 0000000..fa7acb0
--- /dev/null
@@ -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;
+}
+
+