From 30fab293065b7fc6d7d138e8e9eea533a3560873 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 25 Oct 1997 22:37:42 +0000 Subject: [PATCH] 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. --- lib/ext2fs/ChangeLog | 19 ++- lib/ext2fs/Makefile.in | 12 +- lib/ext2fs/Makefile.pq | 4 +- lib/ext2fs/alloc.c | 46 ++++++-- lib/ext2fs/bmap.c | 248 +++++++++++++++++++++++++++++++++++++++ lib/ext2fs/ext2_err.et.in | 7 +- lib/ext2fs/ext2fs.h | 45 +++++++- lib/ext2fs/fileio.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 646 insertions(+), 22 deletions(-) create mode 100644 lib/ext2fs/bmap.c create mode 100644 lib/ext2fs/fileio.c 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 + * 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 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 @@ 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 \ 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 @@ 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 \ 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 #include +#include #if HAVE_SYS_STAT_H #include #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 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include + +#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_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 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 @@ 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 */ @@ -293,6 +312,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 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 +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include + +#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; +} + + -- 1.8.3.1