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. * 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 nb;
unsigned char data [BSDFS_BSIZE]; 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); fprintf (stderr, "inode_clear: read error at block %d\n", bno);
return 0; return 0;
} }
for (i=BSDFS_BSIZE-2; i>=0; i-=2) { for (i=BSDFS_BSIZE-4; i>=0; i-=4) {
nb = data [i+1] << 8 | data [i]; 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) if (nb)
fs_block_free (fs, 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. * 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 nb;
unsigned char data [BSDFS_BSIZE]; 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); fprintf (stderr, "inode_clear: read error at block %d\n", bno);
return 0; return 0;
} }
for (i=BSDFS_BSIZE-2; i>=0; i-=2) { for (i=BSDFS_BSIZE-4; i>=0; i-=4) {
nb = data [i+1] << 8 | data [i]; 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) 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); fs_block_free (fs, bno);
return 1; return 1;
@@ -128,7 +139,7 @@ int fs_double_indirect_block_free (fs_t *fs, unsigned int bno)
/* /*
* Free a triple indirect block. * 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 nb;
unsigned char data [BSDFS_BSIZE]; 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); fprintf (stderr, "inode_clear: read error at block %d\n", bno);
return 0; return 0;
} }
for (i=BSDFS_BSIZE-2; i>=0; i-=2) { for (i=BSDFS_BSIZE-4; i>=0; i-=4) {
nb = data [i+1] << 8 | data [i]; 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) 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); fs_block_free (fs, bno);
return 1; 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_get (fs_t *fs, fs_inode_t *inode, unsigned inum);
int fs_inode_save (fs_inode_t *inode, int force); int fs_inode_save (fs_inode_t *inode, int force);
void fs_inode_clear (fs_inode_t *inode); 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); void fs_inode_print (fs_inode_t *inode, FILE *out);
int fs_inode_read (fs_inode_t *inode, unsigned long offset, int fs_inode_read (fs_inode_t *inode, unsigned long offset,
unsigned char *data, unsigned long bytes); 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_read_block (fs_t *fs, unsigned bnum, unsigned char *data);
int fs_block_free (fs_t *fs, unsigned int bno); int fs_block_free (fs_t *fs, unsigned int bno);
int fs_block_alloc (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_indirect_block_free (fs_t *fs, unsigned int bno, int nblk);
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);
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);
void fs_directory_scan (fs_inode_t *inode, char *dirname, void fs_directory_scan (fs_inode_t *inode, char *dirname,
fs_directory_scanner_t scanner, void *arg); 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. */ /* Cannot open directory on write. */
return 0; return 0;
} }
fs_inode_truncate (&file->inode); fs_inode_truncate (&file->inode, 0);
fs_inode_save (&file->inode, 0); fs_inode_save (&file->inode, 0);
file->writable = 1; file->writable = 1;
file->offset = 0; 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 * a contiguous free list much longer
* than FIFO. * 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; unsigned *blk;
if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR || if ((inode->mode & INODE_MODE_FMT) == INODE_MODE_FCHR ||
(inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK) (inode->mode & INODE_MODE_FMT) == INODE_MODE_FBLK)
return; return;
#define SINGLE 4 /* index of single indirect block */ #define SINGLE NDADDR /* index of single indirect block */
#define DOUBLE 5 /* index of double indirect block */ #define DOUBLE (SINGLE+1) /* index of double indirect block */
#define TRIPLE 6 /* index of triple 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) if (*blk == 0)
continue; continue;
if (blk == &inode->addr [TRIPLE]) if (i == TRIPLE) {
fs_triple_indirect_block_free (inode->fs, *blk); if (! fs_triple_indirect_block_free (inode->fs, *blk,
else if (blk == &inode->addr [DOUBLE]) nblk - (NDADDR + BSDFS_BSIZE/4 + BSDFS_BSIZE/4*BSDFS_BSIZE/4)))
fs_double_indirect_block_free (inode->fs, *blk); break;
else if (blk == &inode->addr [SINGLE]) } else if (i == DOUBLE) {
fs_indirect_block_free (inode->fs, *blk); if (! fs_double_indirect_block_free (inode->fs, *blk,
else 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); fs_block_free (inode->fs, *blk);
}
*blk = 0; *blk = 0;
} }
inode->size = 0; inode->size = size;
inode->dirty = 1; inode->dirty = 1;
} }
@@ -743,7 +754,7 @@ delete_file:
inode->dirty = 1; inode->dirty = 1;
inode->nlink--; inode->nlink--;
if (inode->nlink <= 0) { if (inode->nlink <= 0) {
fs_inode_truncate (inode); fs_inode_truncate (inode, 0);
fs_inode_clear (inode); fs_inode_clear (inode);
if (inode->fs->ninode < NICINOD) { if (inode->fs->ninode < NICINOD) {
inode->fs->inode [inode->fs->ninode++] = dirent.inum; 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; 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) { if (fi->flags & O_APPEND) {
file.offset = file.inode.size; file.offset = file.inode.size;
} }