mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-02 07:28:21 +00:00
ext2: support creation of sparse files
This commit is contained in:
+52
-13
@@ -485,6 +485,10 @@ static int getinodeblock(ext2fs_t *fs, ext2node_t *node, uintmax_t index, blockp
|
|||||||
|
|
||||||
// first singly indirect block
|
// first singly indirect block
|
||||||
if (singly == 0) {
|
if (singly == 0) {
|
||||||
|
if (node->inode.singlypointer == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
size_t readc;
|
size_t readc;
|
||||||
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.singlypointer) + singlyoffset, &readc, 0);
|
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.singlypointer) + singlyoffset, &readc, 0);
|
||||||
}
|
}
|
||||||
@@ -496,11 +500,20 @@ static int getinodeblock(ext2fs_t *fs, ext2node_t *node, uintmax_t index, blockp
|
|||||||
|
|
||||||
// first doubly indirect block
|
// first doubly indirect block
|
||||||
if (doubly == 0) {
|
if (doubly == 0) {
|
||||||
|
if (node->inode.doublypointer == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
size_t readc;
|
size_t readc;
|
||||||
blockptr_t singlyptr;
|
blockptr_t singlyptr;
|
||||||
int e = vfs_read(fs->backing, &singlyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.doublypointer) + doublyoffset, &readc, 0);
|
int e = vfs_read(fs->backing, &singlyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.doublypointer) + doublyoffset, &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
|
if (singlyptr == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, singlyptr) + singlyoffset, &readc, 0);
|
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, singlyptr) + singlyoffset, &readc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,14 +525,30 @@ static int getinodeblock(ext2fs_t *fs, ext2node_t *node, uintmax_t index, blockp
|
|||||||
size_t readc;
|
size_t readc;
|
||||||
blockptr_t doublyptr;
|
blockptr_t doublyptr;
|
||||||
blockptr_t singlyptr;
|
blockptr_t singlyptr;
|
||||||
|
|
||||||
|
if (node->inode.triplypointer == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int e = vfs_read(fs->backing, &doublyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.triplypointer) + triplyoffset, &readc, 0);
|
int e = vfs_read(fs->backing, &doublyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, node->inode.triplypointer) + triplyoffset, &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
|
if (doublyptr == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
e = vfs_read(fs->backing, &singlyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, doublyptr) + doublyoffset, &readc, 0);
|
e = vfs_read(fs->backing, &singlyptr, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, doublyptr) + doublyoffset, &readc, 0);
|
||||||
if (e)
|
if (e)
|
||||||
return e;
|
return e;
|
||||||
|
|
||||||
|
if (singlyptr == 0) {
|
||||||
|
*block = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, singlyptr) + singlyoffset, &readc, 0);
|
return vfs_read(fs->backing, block, sizeof(blockptr_t), BLOCK_GETDISKOFFSET(fs, singlyptr) + singlyoffset, &readc, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,17 +753,28 @@ static int resizeinode(ext2fs_t *fs, ext2node_t *node, size_t newsize) {
|
|||||||
size_t currentblockcount = ROUND_UP(INODE_SIZE(&node->inode), fs->blocksize) / fs->blocksize;
|
size_t currentblockcount = ROUND_UP(INODE_SIZE(&node->inode), fs->blocksize) / fs->blocksize;
|
||||||
|
|
||||||
if (newblockcount > currentblockcount) {
|
if (newblockcount > currentblockcount) {
|
||||||
// grow
|
// when growing, we do not allocate any new blocks to use the sparse file feature
|
||||||
for (int i = currentblockcount; i < newblockcount; ++i) {
|
// instead, we set specific objects to zero
|
||||||
uintmax_t newblock;
|
size_t blocks_in_indirect = BLOCKS_IN_INDIRECT(fs);
|
||||||
int e = allocatestructure(fs, &newblock, false);
|
size_t doubly_start = blocks_in_indirect + 12 ;
|
||||||
if (e)
|
size_t triply_start = blocks_in_indirect * blocks_in_indirect + doubly_start;
|
||||||
return e;
|
// direct?
|
||||||
e = setinodeblock(fs, node, i, newblock);
|
if (currentblockcount < 12) {
|
||||||
ASSERT_UNCLEAN(fs, e == 0);
|
for (int i = currentblockcount; i < min(newblockcount, 12); ++i)
|
||||||
if (e)
|
node->inode.directpointer[i] = 0;
|
||||||
return e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// singly?
|
||||||
|
if (currentblockcount <= 12 && newblockcount > 12)
|
||||||
|
node->inode.singlypointer = 0;
|
||||||
|
|
||||||
|
// doubly?
|
||||||
|
if (newblockcount <= doubly_start && newblockcount > doubly_start)
|
||||||
|
node->inode.doublypointer = 0;
|
||||||
|
|
||||||
|
// triply?
|
||||||
|
if (newblockcount <= triply_start && newblockcount > triply_start)
|
||||||
|
node->inode.triplypointer = 0;
|
||||||
} else if (newblockcount < currentblockcount) {
|
} else if (newblockcount < currentblockcount) {
|
||||||
// shrink
|
// shrink
|
||||||
for (int i = newblockcount; i < currentblockcount; ++i) {
|
for (int i = newblockcount; i < currentblockcount; ++i) {
|
||||||
@@ -902,7 +942,7 @@ static int findindir(ext2fs_t *fs, ext2node_t *node, char *name, int *inode, ext
|
|||||||
|
|
||||||
ext2dent_t *dent = (ext2dent_t *)((uintptr_t)dirbuffer + block_offset);
|
ext2dent_t *dent = (ext2dent_t *)((uintptr_t)dirbuffer + block_offset);
|
||||||
|
|
||||||
if (namelen == dent->namelen && dent->inode && strncmp(name, dent->name, dent->namelen) == 0) {
|
if (namelen == dent->namelen && dent->inode && memcmp(name, dent->name, dent->namelen) == 0) {
|
||||||
inodefound = dent->inode;
|
inodefound = dent->inode;
|
||||||
if (switchnode) {
|
if (switchnode) {
|
||||||
dent->inode = switchnode->id;
|
dent->inode = switchnode->id;
|
||||||
@@ -1014,7 +1054,7 @@ static int removedent(ext2fs_t *fs, ext2node_t *node, char *name, int *inode) {
|
|||||||
|
|
||||||
dent = (ext2dent_t *)((uintptr_t)dirbuffer + block_offset);
|
dent = (ext2dent_t *)((uintptr_t)dirbuffer + block_offset);
|
||||||
|
|
||||||
if (namelen == dent->namelen && dent->inode && strncmp(name, dent->name, dent->namelen) == 0) {
|
if (namelen == dent->namelen && dent->inode && memcmp(name, dent->name, dent->namelen) == 0) {
|
||||||
inodefound = dent->inode;
|
inodefound = dent->inode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1262,7 +1302,6 @@ static int ext2_getdents(vnode_t *vnode, dent_t *buffer, size_t count, uintmax_t
|
|||||||
return ENOTDIR;
|
return ENOTDIR;
|
||||||
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
// XXX loading the whole dir into memory at once isn't the best idea but works for now
|
|
||||||
void *dirbuffer = alloc(fs->blocksize);
|
void *dirbuffer = alloc(fs->blocksize);
|
||||||
if (dirbuffer == NULL)
|
if (dirbuffer == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|||||||
Reference in New Issue
Block a user