From 847e2bff771dc881839f3d82aa43cb324b286e89 Mon Sep 17 00:00:00 2001 From: Serge Vakulenko Date: Thu, 17 Jul 2014 21:31:49 -0700 Subject: [PATCH] Fsutil: allow truncate to arbitrary length. --- tools/fsutil/block.c | 39 ++++++++++++++++++++++++++++----------- tools/fsutil/bsdfs.h | 8 ++++---- tools/fsutil/file.c | 2 +- tools/fsutil/inode.c | 39 +++++++++++++++++++++++++-------------- tools/fsutil/mount.c | 6 ++++++ 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/tools/fsutil/block.c b/tools/fsutil/block.c index 5aa53ba..c1a880f 100644 --- a/tools/fsutil/block.c +++ b/tools/fsutil/block.c @@ -84,7 +84,7 @@ int fs_block_free (fs_t *fs, unsigned int bno) /* * Free an indirect block. */ -int fs_indirect_block_free (fs_t *fs, unsigned int bno) +int fs_indirect_block_free (fs_t *fs, unsigned int bno, int nblk) { unsigned nb; unsigned char data [BSDFS_BSIZE]; @@ -94,8 +94,13 @@ int fs_indirect_block_free (fs_t *fs, unsigned int bno) fprintf (stderr, "inode_clear: read error at block %d\n", bno); return 0; } - for (i=BSDFS_BSIZE-2; i>=0; i-=2) { - nb = data [i+1] << 8 | data [i]; + for (i=BSDFS_BSIZE-4; i>=0; i-=4) { + if (i/4 < nblk) { + /* Truncate up to required size. */ + return 0; + } + nb = data [i+3] << 24 | data [i+2] << 16 | + data [i+1] << 8 | data [i]; if (nb) fs_block_free (fs, nb); } @@ -106,7 +111,7 @@ int fs_indirect_block_free (fs_t *fs, unsigned int bno) /* * Free a double indirect block. */ -int fs_double_indirect_block_free (fs_t *fs, unsigned int bno) +int fs_double_indirect_block_free (fs_t *fs, unsigned int bno, int nblk) { unsigned nb; unsigned char data [BSDFS_BSIZE]; @@ -116,10 +121,16 @@ int fs_double_indirect_block_free (fs_t *fs, unsigned int bno) fprintf (stderr, "inode_clear: read error at block %d\n", bno); return 0; } - for (i=BSDFS_BSIZE-2; i>=0; i-=2) { - nb = data [i+1] << 8 | data [i]; + for (i=BSDFS_BSIZE-4; i>=0; i-=4) { + if (i/4 * BSDFS_BSIZE/4 < nblk) { + /* Truncate up to required size. */ + return 0; + } + nb = data [i+3] << 24 | data [i+2] << 16 | + data [i+1] << 8 | data [i]; if (nb) - fs_indirect_block_free (fs, nb); + fs_indirect_block_free (fs, nb, + nblk - i/4 * BSDFS_BSIZE/4); } fs_block_free (fs, bno); return 1; @@ -128,7 +139,7 @@ int fs_double_indirect_block_free (fs_t *fs, unsigned int bno) /* * Free a triple indirect block. */ -int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno) +int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno, int nblk) { unsigned nb; unsigned char data [BSDFS_BSIZE]; @@ -138,10 +149,16 @@ int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno) fprintf (stderr, "inode_clear: read error at block %d\n", bno); return 0; } - for (i=BSDFS_BSIZE-2; i>=0; i-=2) { - nb = data [i+1] << 8 | data [i]; + for (i=BSDFS_BSIZE-4; i>=0; i-=4) { + if (i/4 * BSDFS_BSIZE/4 * BSDFS_BSIZE/4 < nblk) { + /* Truncate up to required size. */ + return 0; + } + nb = data [i+3] << 24 | data [i+2] << 16 | + data [i+1] << 8 | data [i]; if (nb) - fs_double_indirect_block_free (fs, nb); + fs_double_indirect_block_free (fs, nb, + nblk - i/4 * BSDFS_BSIZE/4 * BSDFS_BSIZE/4); } fs_block_free (fs, bno); return 1; diff --git a/tools/fsutil/bsdfs.h b/tools/fsutil/bsdfs.h index 831a67d..7b5954d 100644 --- a/tools/fsutil/bsdfs.h +++ b/tools/fsutil/bsdfs.h @@ -169,7 +169,7 @@ int fs_mount(fs_t *fs, char *dirname); int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum); int fs_inode_save (fs_inode_t *inode, int force); void fs_inode_clear (fs_inode_t *inode); -void fs_inode_truncate (fs_inode_t *inode); +void fs_inode_truncate (fs_inode_t *inode, unsigned long size); void fs_inode_print (fs_inode_t *inode, FILE *out); int fs_inode_read (fs_inode_t *inode, unsigned long offset, unsigned char *data, unsigned long bytes); @@ -184,9 +184,9 @@ int fs_write_block (fs_t *fs, unsigned bnum, unsigned char *data); int fs_read_block (fs_t *fs, unsigned bnum, unsigned char *data); int fs_block_free (fs_t *fs, unsigned int bno); int fs_block_alloc (fs_t *fs, unsigned int *bno); -int fs_indirect_block_free (fs_t *fs, unsigned int bno); -int fs_double_indirect_block_free (fs_t *fs, unsigned int bno); -int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno); +int fs_indirect_block_free (fs_t *fs, unsigned int bno, int nblk); +int fs_double_indirect_block_free (fs_t *fs, unsigned int bno, int nblk); +int fs_triple_indirect_block_free (fs_t *fs, unsigned int bno, int nblk); void fs_directory_scan (fs_inode_t *inode, char *dirname, fs_directory_scanner_t scanner, void *arg); diff --git a/tools/fsutil/file.c b/tools/fsutil/file.c index 4fea8fa..3d0275e 100644 --- a/tools/fsutil/file.c +++ b/tools/fsutil/file.c @@ -37,7 +37,7 @@ int fs_file_create (fs_t *fs, fs_file_t *file, const char *name, int mode) /* Cannot open directory on write. */ return 0; } - fs_inode_truncate (&file->inode); + fs_inode_truncate (&file->inode, 0); fs_inode_save (&file->inode, 0); file->writable = 1; file->offset = 0; diff --git a/tools/fsutil/inode.c b/tools/fsutil/inode.c index a2c567c..418f953 100644 --- a/tools/fsutil/inode.c +++ b/tools/fsutil/inode.c @@ -90,35 +90,46 @@ int fs_inode_get (fs_t *fs, fs_inode_t *inode, unsigned inum) * a contiguous free list much longer * than FIFO. */ -void fs_inode_truncate (fs_inode_t *inode) +void fs_inode_truncate (fs_inode_t *inode, unsigned long size) { + int i, nblk; unsigned *blk; if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR || (inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK) return; -#define SINGLE 4 /* index of single indirect block */ -#define DOUBLE 5 /* index of double indirect block */ -#define TRIPLE 6 /* index of triple indirect block */ +#define SINGLE NDADDR /* index of single indirect block */ +#define DOUBLE (SINGLE+1) /* index of double indirect block */ +#define TRIPLE (DOUBLE+1) /* index of triple indirect block */ - for (blk = &inode->addr[TRIPLE]; blk >= &inode->addr[0]; --blk) { + nblk = (size + BSDFS_BSIZE - 1) / BSDFS_BSIZE; + for (i=TRIPLE; i>=0; --i) { + blk = &inode->addr[i]; if (*blk == 0) continue; - if (blk == &inode->addr [TRIPLE]) - fs_triple_indirect_block_free (inode->fs, *blk); - else if (blk == &inode->addr [DOUBLE]) - fs_double_indirect_block_free (inode->fs, *blk); - else if (blk == &inode->addr [SINGLE]) - fs_indirect_block_free (inode->fs, *blk); - else + if (i == TRIPLE) { + if (! fs_triple_indirect_block_free (inode->fs, *blk, + nblk - (NDADDR + BSDFS_BSIZE/4 + BSDFS_BSIZE/4*BSDFS_BSIZE/4))) + break; + } else if (i == DOUBLE) { + if (! fs_double_indirect_block_free (inode->fs, *blk, + nblk - (NDADDR + BSDFS_BSIZE/4))) + break; + } else if (i == SINGLE) { + if (! fs_indirect_block_free (inode->fs, *blk, nblk - NDADDR)) + break; + } else { + if (i * BSDFS_BSIZE < size) + break; fs_block_free (inode->fs, *blk); + } *blk = 0; } - inode->size = 0; + inode->size = size; inode->dirty = 1; } @@ -743,7 +754,7 @@ delete_file: inode->dirty = 1; inode->nlink--; if (inode->nlink <= 0) { - fs_inode_truncate (inode); + fs_inode_truncate (inode, 0); fs_inode_clear (inode); if (inode->fs->ninode < NICINOD) { inode->fs->inode [inode->fs->ninode++] = dirent.inum; diff --git a/tools/fsutil/mount.c b/tools/fsutil/mount.c index 1d05a9b..8471ede 100644 --- a/tools/fsutil/mount.c +++ b/tools/fsutil/mount.c @@ -173,6 +173,12 @@ int op_open(const char *path, struct fuse_file_info *fi) return -ENOENT; } + if ((file.inode.mode & INODE_MODE_FMT) != INODE_MODE_FREG) { + /* Cannot open special files. */ + file.inode.mode = 0; + return -ENXIO; + } + if (fi->flags & O_APPEND) { file.offset = file.inode.size; }