Fix extfs unhandled allocation failures.

This is not sufficient. The operator new calls are dangerous right now
because they throw exceptions (not handled) on error instead of returning
NULL. This needs to be changed to operator new nothrow instead.
This commit is contained in:
Jonas 'Sortie' Termansen 2015-07-09 18:06:45 +02:00
parent bc928e99a4
commit e2202b2ddb
6 changed files with 80 additions and 22 deletions

View File

@ -91,6 +91,8 @@ uint32_t BlockGroup::AllocateBlock()
{
uint32_t block_id = data->bg_block_bitmap + block_alloc_chunk;
block_bitmap_chunk = filesystem->device->GetBlock(block_id);
if ( !block_bitmap_chunk )
return 0;
block_bitmap_chunk_i = 0;
}
uint32_t chunk_offset = block_alloc_chunk * num_chunk_bits;
@ -138,6 +140,8 @@ uint32_t BlockGroup::AllocateInode()
{
uint32_t block_id = data->bg_inode_bitmap + inode_alloc_chunk;
inode_bitmap_chunk = filesystem->device->GetBlock(block_id);
if ( !inode_bitmap_chunk )
return 0;
inode_bitmap_chunk_i = 0;
}
uint32_t chunk_offset = inode_alloc_chunk * num_chunk_bits;

View File

@ -92,8 +92,13 @@ Block* Device::GetBlock(uint32_t block_id)
{
if ( Block* block = GetCachedBlock(block_id) )
return block;
uint8_t* data = new uint8_t[block_size];
if ( !data ) // TODO: Use operator new nothrow!
return NULL;
Block* block = new Block(this, block_id);
block->block_data = new uint8_t[block_size];
if ( !block ) // TODO: Use operator new nothrow!
return delete[] data, (Block*) NULL;
block->block_data = data;
off_t file_offset = (off_t) block_size * (off_t) block_id;
preadall(fd, block->block_data, block_size, file_offset);
block->Prelink();
@ -109,8 +114,13 @@ Block* Device::GetBlockZeroed(uint32_t block_id)
block->FinishWrite();
return block;
}
uint8_t* data = new uint8_t[block_size];
if ( !data ) // TODO: Use operator new nothrow!
return NULL;
Block* block = new Block(this, block_id);
block->block_data = new uint8_t[block_size];
if ( !block ) // TODO: Use operator new nothrow!
return delete[] data, (Block*) NULL;
block->block_data = data;
memset(block->block_data, 0, block_size);
block->Prelink();
block->BeginWrite();

View File

@ -384,9 +384,15 @@ int main(int argc, char* argv[])
uint32_t block_size = 1024U << sb.s_log_block_size;
Device* dev = new Device(fd, device_path, block_size, write);
if ( !dev ) // TODO: Use operator new nothrow!
error(1, errno, "malloc");
Filesystem* fs = new Filesystem(dev, mount_path);
if ( !fs ) // TODO: Use operator new nothrow!
error(1, errno, "malloc");
fs->block_groups = new BlockGroup*[fs->num_groups];
if ( !fs->block_groups ) // TODO: Use operator new nothrow!
error(1, errno, "malloc");
for ( size_t i = 0; i < fs->num_groups; i++ )
fs->block_groups[i] = NULL;

View File

@ -43,6 +43,7 @@ Filesystem::Filesystem(Device* device, const char* mount_path)
uint64_t sb_offset = 1024;
uint32_t sb_block_id = sb_offset / device->block_size;
this->sb_block = device->GetBlock(sb_block_id);
assert(sb_block); // TODO: This can fail.
this->sb = (struct ext_superblock*)
(sb_block->block_data + sb_offset % device->block_size);
this->device = device;
@ -140,7 +141,11 @@ BlockGroup* Filesystem::GetBlockGroup(uint32_t group_id)
uint32_t offset = (group_id * group_size) % block_size;
Block* block = device->GetBlock(block_id);
if ( !block )
return (BlockGroup*) NULL;
BlockGroup* group = new BlockGroup(this, group_id);
if ( !group ) // TODO: Use operator new nothrow!
return block->Unref(), (BlockGroup*) NULL;
group->data_block = block;
uint8_t* buf = group->data_block->block_data + offset;
group->data = (struct ext_blockgrpdesc*) buf;
@ -163,13 +168,19 @@ Inode* Filesystem::GetInode(uint32_t inode_id)
uint32_t tabel_index = (inode_id-1) % sb->s_inodes_per_group;
assert(group_id < num_groups);
BlockGroup* group = GetBlockGroup(group_id);
if ( !group )
return (Inode*) NULL;
uint32_t tabel_block = group->data->bg_inode_table;
group->Unref();
uint32_t block_id = tabel_block + (tabel_index * inode_size) / block_size;
uint32_t offset = (tabel_index * inode_size) % block_size;
Block* block = device->GetBlock(block_id);
if ( !block )
return (Inode*) NULL;
Inode* inode = new Inode(this, inode_id);
if ( !inode )
return block->Unref(), (Inode*) NULL;
inode->data_block = block;
uint8_t* buf = inode->data_block->block_data + offset;
inode->data = (struct ext_inode*) buf;
@ -229,6 +240,8 @@ void Filesystem::FreeBlock(uint32_t block_id)
uint32_t group_id = (block_id - sb->s_first_data_block) / sb->s_blocks_per_group;
assert(group_id < num_groups);
BlockGroup* group = GetBlockGroup(group_id);
if ( !group )
return;
group->FreeBlock(block_id);
group->Unref();
}
@ -240,6 +253,8 @@ void Filesystem::FreeInode(uint32_t inode_id)
uint32_t group_id = (inode_id-1) / sb->s_inodes_per_group;
assert(group_id < num_groups);
BlockGroup* group = GetBlockGroup(group_id);
if ( !group )
return;
group->FreeInode(inode_id);
group->Unref();
}

View File

@ -77,7 +77,8 @@ Inode* ext2_fuse_resolve_path(const char* path)
{
Filesystem* fs = FUSE_FS;
Inode* inode = fs->GetInode(EXT2_ROOT_INO);
assert(inode);
if ( !inode )
return (Inode*) NULL;
while ( path[0] )
{
if ( *path == '/' )
@ -88,12 +89,12 @@ Inode* ext2_fuse_resolve_path(const char* path)
continue;
}
size_t elem_len = strcspn(path, "/");
char* elem = new char[elem_len+1];
memcpy(elem, path, elem_len);
elem[elem_len] = '\0';
char* elem = strndup(path, elem_len);
if ( !elem )
return inode->Unref(), errno = ENOTDIR, (Inode*) NULL;
path += elem_len;
Inode* next = inode->Open(elem, O_RDONLY, 0);
delete[] elem;
free(elem);
inode->Unref();
if ( !next )
return NULL;
@ -108,7 +109,8 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr)
const char* path = *path_ptr;
Filesystem* fs = FUSE_FS;
Inode* inode = fs->GetInode(EXT2_ROOT_INO);
assert(inode);
if ( !inode )
return (Inode*) NULL;
while ( strchr(path, '/') )
{
if ( *path == '/' )
@ -119,12 +121,12 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr)
continue;
}
size_t elem_len = strcspn(path, "/");
char* elem = new char[elem_len+1];
memcpy(elem, path, elem_len);
elem[elem_len] = '\0';
char* elem = strndup(path, elem_len);
if ( !elem )
return inode->Unref(), errno = ENOTDIR, (Inode*) NULL;
path += elem_len;
Inode* next = inode->Open(elem, O_RDONLY, 0);
delete[] elem;
free(elem);
inode->Unref();
if ( !next )
return (Inode*) NULL;
@ -492,11 +494,12 @@ int ext2_fuse_readdir(const char* /*path*/, void* buf, fuse_fill_dir_t filler,
const struct ext_dirent* entry = (const struct ext_dirent*) block_data;
if ( entry->inode && entry->name_len && (!rec_num || !rec_num--) )
{
char* entry_name = new char[entry->name_len+1];
char* entry_name = strndup(entry->name, entry->name_len);
if ( !entry_name )
return block->Unref(), inode->Unref(), -errno;
memcpy(entry_name, entry->name, entry->name_len);
entry_name[entry->name_len] = '\0';
bool full = filler(buf, entry_name, NULL, 0);
delete[] entry_name;
free(entry_name);
if ( full )
{
block->Unref();

View File

@ -427,6 +427,8 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
file_type != EXT2_FT_SYMLINK )
return errno = ENOTDIR, (Inode*) NULL;
Inode* inode = filesystem->GetInode(inode_id);
if ( !inode )
return (Inode*) NULL;
if ( flags & O_DIRECTORY &&
!EXT2_S_ISDIR(inode->Mode()) &&
!EXT2_S_ISLNK(inode->Mode()) )
@ -449,6 +451,8 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
if ( !result_inode_id )
return NULL;
Inode* result = filesystem->GetInode(result_inode_id);
if ( !result )
return filesystem->FreeInode(result_inode_id), (Inode*) NULL;
memset(result->data, 0, sizeof(*result->data));
result->SetMode((mode & S_SETABLE) | S_IFREG);
struct timespec now;
@ -673,10 +677,17 @@ Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force)
if ( entry_block_id + 1 != num_blocks )
{
Block* last_block = GetBlock(num_blocks-1);
memcpy(block->block_data, last_block->block_data, block_size);
last_block->Unref();
if ( last_block )
{
memcpy(block->block_data, last_block->block_data, block_size);
last_block->Unref();
Truncate(filesize - block_size);
}
}
else
{
Truncate(filesize - block_size);
}
Truncate(filesize - block_size);
}
block->FinishWrite();
@ -863,6 +874,8 @@ bool Inode::Symlink(const char* elem, const char* dest)
return NULL;
Inode* result = filesystem->GetInode(result_inode_id);
if ( !result )
return filesystem->FreeInode(result_inode_id), false;
memset(result->data, 0, sizeof(*result->data));
result->SetMode((0777 & S_SETABLE) | EXT2_S_IFLNK);
@ -894,6 +907,8 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
return NULL;
Inode* result = filesystem->GetInode(result_inode_id);
if ( !result )
return filesystem->FreeInode(result_inode_id), (Inode*) NULL;
memset(result->data, 0, sizeof(*result->data));
result->SetMode((mode & S_SETABLE) | EXT2_S_IFDIR);
@ -901,6 +916,8 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
uint32_t group_id = (result->inode_id - 1) / filesystem->sb->s_inodes_per_group;
assert(group_id < filesystem->num_groups);
BlockGroup* block_group = filesystem->GetBlockGroup(group_id);
if ( !block_group )
return result->Unref(), (Inode*) NULL;
block_group->BeginWrite();
block_group->data->bg_used_dirs_count++;
block_group->FinishWrite();
@ -945,10 +962,13 @@ bool Inode::RemoveDirectory(const char* path)
uint32_t group_id = (result->inode_id - 1) / filesystem->sb->s_inodes_per_group;
assert(group_id < filesystem->num_groups);
BlockGroup* block_group = filesystem->GetBlockGroup(group_id);
block_group->BeginWrite();
block_group->data->bg_used_dirs_count--;
block_group->FinishWrite();
block_group->Unref();
if ( block_group )
{
block_group->BeginWrite();
block_group->data->bg_used_dirs_count--;
block_group->FinishWrite();
block_group->Unref();
}
result->Unref();