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;
+}
+
+