Fsutil: allow truncate to arbitrary length.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user