Fsutil: allow truncate to arbitrary length.

This commit is contained in:
Serge Vakulenko
2014-07-17 21:31:49 -07:00
parent 08c79d7fec
commit 847e2bff77
5 changed files with 64 additions and 30 deletions

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

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