Fix extfs coding style and general issues.

This cleans up constructors so fields are initialized in the same order they
are declared in. This makes it trivial to spot accidentally uninitialized
fields.

This fixes a minor argument parsing bug when the mount path isn't set, but
fortunately argv[argc] is NULL and we wanted to set it to NULL anyway.

This prevents excessively large block sizes from being used.

This improves inode value range checks in the fsmarshall code. Inode 0 is
not a valid inode. The new code for this is also simpler.

This prevents creating links with names larger than 255 bytes.

This adds a check to ensure inodes don't overflow the hardlink count.

This ensures the dirent filetype is only set if supported.
This commit is contained in:
Jonas 'Sortie' Termansen 2015-07-09 17:14:37 +02:00
parent c88dadae8b
commit bc928e99a4
10 changed files with 197 additions and 218 deletions

View File

@ -98,6 +98,7 @@ uint32_t BlockGroup::AllocateBlock()
size_t num_bits = last ? num_blocks - chunk_offset : num_chunk_bits;
// TODO: This can be made faster by caching if previous bits were set.
for ( ; block_bitmap_chunk_i < num_bits; block_bitmap_chunk_i++ )
{
if ( !checkbit(chunk_bits, block_bitmap_chunk_i) )
{
block_bitmap_chunk->BeginWrite();
@ -113,6 +114,7 @@ uint32_t BlockGroup::AllocateBlock()
uint32_t block_id = first_block_id + group_block_id;
return block_id;
}
}
block_bitmap_chunk->Unref();
block_bitmap_chunk = NULL;
}
@ -143,6 +145,7 @@ uint32_t BlockGroup::AllocateInode()
size_t num_bits = last ? num_inodes - chunk_offset : num_chunk_bits;
// TODO: This can be made faster by caching if previous bits were set.
for ( ; inode_bitmap_chunk_i < num_bits; inode_bitmap_chunk_i++ )
{
if ( !checkbit(chunk_bits, inode_bitmap_chunk_i) )
{
inode_bitmap_chunk->BeginWrite();
@ -158,6 +161,7 @@ uint32_t BlockGroup::AllocateInode()
uint32_t inode_id = first_inode_id + group_inode_id;
return inode_id;
}
}
inode_bitmap_chunk->Unref();
inode_bitmap_chunk = NULL;
}

View File

@ -42,14 +42,14 @@ public:
uint32_t group_id;
uint32_t block_alloc_chunk;
uint32_t inode_alloc_chunk;
uint32_t num_block_bitmap_chunks;
uint32_t num_inode_bitmap_chunks;
uint32_t block_bitmap_chunk_i;
uint32_t inode_bitmap_chunk_i;
uint32_t num_blocks;
uint32_t num_inodes;
uint32_t first_block_id;
uint32_t first_inode_id;
uint32_t num_blocks;
uint32_t num_inodes;
uint32_t num_block_bitmap_chunks;
uint32_t num_inode_bitmap_chunks;
bool dirty;
public:

View File

@ -42,23 +42,25 @@ void* Device__SyncThread(void* ctx)
Device::Device(int fd, const char* path, uint32_t block_size, bool write)
{
this->write = write;
this->fd = fd;
this->path = path;
this->block_size = block_size;
struct stat st;
fstat(fd, &st);
this->device_size = st.st_size;
// sync_thread unset.
this->sync_thread_cond = PTHREAD_COND_INITIALIZER;
this->sync_thread_idle_cond = PTHREAD_COND_INITIALIZER;
this->sync_thread_lock = PTHREAD_MUTEX_INITIALIZER;
this->mru_block = NULL;
this->lru_block = NULL;
this->dirty_block = NULL;
for ( size_t i = 0; i < DEVICE_HASH_LENGTH; i++ )
hash_blocks[i] = NULL;
this->sync_thread_cond = PTHREAD_COND_INITIALIZER;
this->sync_thread_idle_cond = PTHREAD_COND_INITIALIZER;
this->sync_thread_lock = PTHREAD_MUTEX_INITIALIZER;
this->sync_in_transit = false;
struct stat st;
fstat(fd, &st);
this->device_size = st.st_size;
this->path = path;
this->block_size = block_size;
this->fd = fd;
this->write = write;
this->has_sync_thread = false;
this->sync_thread_should_exit = false;
this->sync_in_transit = false;
}
Device::~Device()

View File

@ -56,8 +56,6 @@ static const uint32_t EXT2_FEATURE_INCOMPAT_SUPPORTED = \
static const uint32_t EXT2_FEATURE_RO_COMPAT_SUPPORTED = \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
// TODO: Inode 0 is not valid, but a lot of functions here accept it!
mode_t HostModeFromExtMode(uint32_t extmode)
{
mode_t hostmode = extmode & 0777;
@ -169,7 +167,7 @@ static void uuid_from_string(uint8_t uuid[16], const char* string)
assert(string[i] == '\0');
}
void compact_arguments(int* argc, char*** argv)
static void compact_arguments(int* argc, char*** argv)
{
for ( int i = 0; i < *argc; i++ )
{
@ -182,12 +180,12 @@ void compact_arguments(int* argc, char*** argv)
}
}
void help(FILE* fp, const char* argv0)
static void help(FILE* fp, const char* argv0)
{
fprintf(fp, "Usage: %s [--probe] [--test-uuid UUID] DEVICE [MOUNT-POINT]\n", argv0);
fprintf(fp, "Usage: %s [OPTION]... DEVICE [MOUNT-POINT]\n", argv0);
}
void version(FILE* fp, const char* argv0)
static void version(FILE* fp, const char* argv0)
{
fprintf(fp, "%s (Sortix) %s\n", argv0, VERSIONSTR);
fprintf(fp, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n");
@ -206,7 +204,7 @@ int main(int argc, char* argv[])
for ( int i = 1; i < argc; i++ )
{
const char* arg = argv[i];
if ( arg[0] != '-' )
if ( arg[0] != '-' || !arg[1] )
continue;
argv[i] = NULL;
if ( !strcmp(arg, "--") )
@ -223,8 +221,12 @@ int main(int argc, char* argv[])
exit(1);
}
}
else if ( !strcmp(arg, "--help") ) { help(stdout, argv0); exit(0); }
else if ( !strcmp(arg, "--version") ) { version(stdout, argv0); exit(0); }
else if ( !strcmp(arg, "--help") )
help(stdout, argv0), exit(0);
else if ( !strcmp(arg, "--version") )
version(stdout, argv0), exit(0);
else if ( !strcmp(arg, "--background") )
foreground = false;
else if ( !strcmp(arg, "--foreground") )
foreground = true;
else if ( !strcmp(arg, "--probe") )
@ -265,7 +267,7 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv);
const char* device_path = 2 <= argc ? argv[1] : NULL;
const char* mount_path = 2 <= argc ? argv[2] : NULL;
const char* mount_path = 3 <= argc ? argv[2] : NULL;
if ( !device_path )
{
@ -318,31 +320,33 @@ int main(int argc, char* argv[])
}
// Test whether this revision of the extended filesystem is supported.
if ( probe && sb.s_rev_level == EXT2_GOOD_OLD_REV )
exit(1);
if ( !probe && sb.s_rev_level == EXT2_GOOD_OLD_REV )
if ( sb.s_rev_level == EXT2_GOOD_OLD_REV )
{
if ( probe )
exit(1);
error(1, 0, "`%s' is formatted with an obsolete filesystem revision",
device_path);
}
// Verify that no incompatible features are in use.
if ( probe && sb.s_feature_compat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED )
exit(1);
if ( !probe && sb.s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED )
if ( sb.s_feature_compat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED )
{
if ( probe )
exit(1);
error(1, 0, "`%s' uses unsupported and incompatible features",
device_path);
}
// Verify that no incompatible features are in use if opening for write.
if ( probe && default_access && write &&
if ( !default_access && write &&
sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED )
exit(1);
if ( !probe && default_access && write &&
sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED )
error(1, 0, "`%s uses unsupported and incompatible features, "
"read-only access is possible, but write-access was "
"requested", device_path);
{
if ( probe )
exit(1);
error(1, 0, "`%s' uses unsupported and incompatible features, "
"read-only access is possible, but write-access was "
"requested", device_path);
}
if ( write && sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED )
{
@ -359,13 +363,21 @@ int main(int argc, char* argv[])
fprintf(stderr, "Note: filesystem uses unsupported but compatible "
"features\n");
// Check the block size is sane. 64 KiB may have issues, 32 KiB then.
if ( sb.s_log_block_size > (15-10) /* 32 KiB blocks */ )
{
if ( probe )
exit(1);
error(1, 0, "`%s': excess block size", device_path);
}
// We have found no critical problems, so let the caller know that this
// filesystem satisfies the probe request.
if ( probe )
exit(0);
// Check whether the filesystem was unmounted cleanly.
if ( !probe && sb.s_state != EXT2_VALID_FS )
if ( sb.s_state != EXT2_VALID_FS )
fprintf(stderr, "Warning: `%s' wasn't unmounted cleanly\n",
device_path);

View File

@ -42,29 +42,29 @@ Filesystem::Filesystem(Device* device, const char* mount_path)
{
uint64_t sb_offset = 1024;
uint32_t sb_block_id = sb_offset / device->block_size;
sb_block = device->GetBlock(sb_block_id);
sb = (struct ext_superblock*)
(sb_block->block_data + sb_offset % device->block_size);
this->sb_block = device->GetBlock(sb_block_id);
this->sb = (struct ext_superblock*)
(sb_block->block_data + sb_offset % device->block_size);
this->device = device;
block_groups = NULL;
this->block_groups = NULL;
this->mount_path = mount_path;
block_size = device->block_size;
mru_inode = NULL;
lru_inode = NULL;
dirty_inode = NULL;
this->block_size = device->block_size;
this->inode_size = this->sb->s_inode_size;
this->num_blocks = this->sb->s_blocks_count;
this->num_groups = divup(this->sb->s_blocks_count, this->sb->s_blocks_per_group);
this->num_inodes = this->sb->s_inodes_count;
this->mru_inode = NULL;
this->lru_inode = NULL;
this->dirty_inode = NULL;
for ( size_t i = 0; i < INODE_HASH_LENGTH; i++ )
hash_inodes[i] = NULL;
inode_size = this->sb->s_inode_size;
num_blocks = sb->s_blocks_count;
num_groups = divup(this->sb->s_blocks_count, this->sb->s_blocks_per_group);
num_inodes = this->sb->s_inodes_count;
dirty = false;
this->hash_inodes[i] = NULL;
struct timespec now_realtime, now_monotonic;
clock_gettime(CLOCK_REALTIME, &now_realtime);
clock_gettime(CLOCK_MONOTONIC, &now_monotonic);
mtime_realtime = now_realtime.tv_sec;
mtime_monotonic = now_monotonic.tv_sec;
this->mtime_realtime = now_realtime.tv_sec;
this->mtime_monotonic = now_monotonic.tv_sec;
this->dirty = false;
BeginWrite();
sb->s_mtime = mtime_realtime;
sb->s_mnt_count++;
@ -133,7 +133,6 @@ BlockGroup* Filesystem::GetBlockGroup(uint32_t group_id)
assert(group_id < num_groups);
if ( block_groups[group_id] )
return block_groups[group_id]->Refer(), block_groups[group_id];
BlockGroup* group = new BlockGroup(this, group_id);
size_t group_size = sizeof(ext_blockgrpdesc);
uint32_t first_block_id = sb->s_first_data_block + 1 /* superblock */;
@ -141,6 +140,7 @@ BlockGroup* Filesystem::GetBlockGroup(uint32_t group_id)
uint32_t offset = (group_id * group_size) % block_size;
Block* block = device->GetBlock(block_id);
BlockGroup* group = new BlockGroup(this, group_id);
group->data_block = block;
uint8_t* buf = group->data_block->block_data + offset;
group->data = (struct ext_blockgrpdesc*) buf;
@ -149,16 +149,16 @@ BlockGroup* Filesystem::GetBlockGroup(uint32_t group_id)
Inode* Filesystem::GetInode(uint32_t inode_id)
{
assert(inode_id);
assert(inode_id < num_inodes);
if ( !inode_id || num_inodes <= inode_id )
return errno = EBADF, (Inode*) NULL;
if ( !inode_id )
return errno = EBADF, (Inode*) NULL;
size_t bin = inode_id % INODE_HASH_LENGTH;
for ( Inode* iter = hash_inodes[bin]; iter; iter = iter->next_hashed )
if ( iter->inode_id == inode_id )
return iter->Refer(), iter;
Inode* inode = new Inode(this, inode_id);
uint32_t group_id = (inode_id-1) / sb->s_inodes_per_group;
uint32_t tabel_index = (inode_id-1) % sb->s_inodes_per_group;
assert(group_id < num_groups);
@ -169,6 +169,7 @@ Inode* Filesystem::GetInode(uint32_t inode_id)
uint32_t offset = (tabel_index * inode_size) % block_size;
Block* block = device->GetBlock(block_id);
Inode* inode = new Inode(this, inode_id);
inode->data_block = block;
uint8_t* buf = inode->data_block->block_data + offset;
inode->data = (struct ext_inode*) buf;
@ -194,7 +195,7 @@ uint32_t Filesystem::AllocateBlock(BlockGroup* preferred)
// this can't happen. That also allows us to make the linked list
// requested above.
BeginWrite();
sb->s_free_blocks_count--;
sb->s_free_blocks_count = 0;
FinishWrite();
return errno = ENOSPC, 0;
}
@ -216,13 +217,14 @@ uint32_t Filesystem::AllocateInode(BlockGroup* preferred)
// this can't happen. That also allows us to make the linked list
// requested above.
BeginWrite();
sb->s_free_inodes_count--;
sb->s_free_inodes_count = 0;
FinishWrite();
return errno = ENOSPC, 0;
}
void Filesystem::FreeBlock(uint32_t block_id)
{
assert(block_id);
assert(block_id < num_blocks);
uint32_t group_id = (block_id - sb->s_first_data_block) / sb->s_blocks_per_group;
assert(group_id < num_groups);
@ -233,6 +235,7 @@ void Filesystem::FreeBlock(uint32_t block_id)
void Filesystem::FreeInode(uint32_t inode_id)
{
assert(inode_id);
assert(inode_id < num_inodes);
uint32_t group_id = (inode_id-1) / sb->s_inodes_per_group;
assert(group_id < num_groups);

View File

@ -36,8 +36,8 @@ public:
~Filesystem();
public:
struct ext_superblock* sb;
Block* sb_block;
struct ext_superblock* sb;
Device* device;
BlockGroup** block_groups;
const char* mount_path;

View File

@ -68,7 +68,7 @@ bool RespondHeader(int chl, size_t type, size_t size)
return RespondData(chl, &hdr, sizeof(hdr));
}
bool RespondMessage(int chl, unsigned int type, const void* ptr, size_t count)
bool RespondMessage(int chl, size_t type, const void* ptr, size_t count)
{
return RespondHeader(chl, type, count) &&
RespondData(chl, ptr, count);
@ -165,12 +165,18 @@ bool RespondTCGetBlob(int chl, const void* data, size_t data_size)
RespondData(chl, data, data_size);
}
Inode* SafeGetInode(Filesystem* fs, ino_t ino)
{
if ( (uint32_t) ino != ino )
return errno = EBADF, (Inode*) ino;
// TODO: Should check if the inode is not deleted.
return fs->GetInode((uint32_t) ino);
}
void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
{
(void) chl;
if ( fs->num_inodes <= msg->ino )
return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
if ( Inode* inode = SafeGetInode(fs, (uint32_t) msg->ino) )
{
inode->RemoteRefer();
inode->Unref();
@ -180,9 +186,7 @@ void HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs)
{
(void) chl;
if ( fs->num_inodes <= msg->ino )
return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
if ( Inode* inode = SafeGetInode(fs, (uint32_t) msg->ino) )
{
inode->RemoteUnref();
inode->Unref();
@ -191,8 +195,7 @@ void HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs)
void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
inode->Sync();
inode->Unref();
@ -201,8 +204,7 @@ void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs)
void HandleStat(int chl, struct fsm_req_stat* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
struct stat st;
StatInode(inode, &st);
@ -212,8 +214,7 @@ void HandleStat(int chl, struct fsm_req_stat* msg, Filesystem* fs)
void HandleChangeMode(int chl, struct fsm_req_chmod* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
uint32_t req_mode = ExtModeFromHostMode(msg->mode);
uint32_t old_mode = inode->Mode();
@ -225,8 +226,7 @@ void HandleChangeMode(int chl, struct fsm_req_chmod* msg, Filesystem* fs)
void HandleChangeOwner(int chl, struct fsm_req_chown* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
inode->SetUserId((uint32_t) msg->uid);
inode->SetGroupId((uint32_t) msg->gid);
@ -236,8 +236,7 @@ void HandleChangeOwner(int chl, struct fsm_req_chown* msg, Filesystem* fs)
void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
inode->BeginWrite();
inode->data->i_atime = msg->times[0].tv_sec;
@ -249,9 +248,8 @@ void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
void HandleTruncate(int chl, struct fsm_req_truncate* msg, Filesystem* fs)
{
if( msg->size < 0 ) { RespondError(chl, EINVAL); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( msg->size < 0 ) { RespondError(chl, EINVAL); return; }
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
inode->Truncate((uint64_t) msg->size);
inode->Unref();
@ -260,8 +258,7 @@ void HandleTruncate(int chl, struct fsm_req_truncate* msg, Filesystem* fs)
void HandleSeek(int chl, struct fsm_req_lseek* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
if ( msg->whence == SEEK_SET )
RespondSeek(chl, msg->offset);
@ -281,8 +278,7 @@ void HandleSeek(int chl, struct fsm_req_lseek* msg, Filesystem* fs)
void HandleReadAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
uint8_t* buf = (uint8_t*) malloc(msg->count);
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; }
@ -295,8 +291,7 @@ void HandleReadAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
void HandleWriteAt(int chl, struct fsm_req_pwrite* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
const uint8_t* buf = (const uint8_t*) &msg[1];
ssize_t amount = inode->WriteAt(buf, msg->count, msg->offset);
@ -307,8 +302,7 @@ void HandleWriteAt(int chl, struct fsm_req_pwrite* msg, Filesystem* fs)
void HandleOpen(int chl, struct fsm_req_open* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
@ -335,8 +329,7 @@ void HandleOpen(int chl, struct fsm_req_open* msg, Filesystem* fs)
void HandleMakeDir(int chl, struct fsm_req_mkdir* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
@ -363,8 +356,7 @@ void HandleMakeDir(int chl, struct fsm_req_mkdir* msg, Filesystem* fs)
void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
if ( !S_ISDIR(inode->Mode()) )
{
@ -426,8 +418,7 @@ void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
void HandleIsATTY(int chl, struct fsm_req_isatty* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
RespondError(chl, ENOTTY);
inode->Unref();
@ -435,8 +426,7 @@ void HandleIsATTY(int chl, struct fsm_req_isatty* msg, Filesystem* fs)
void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
@ -461,8 +451,7 @@ void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
void HandleRemoveDir(int chl, struct fsm_req_rmdir* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
@ -476,22 +465,20 @@ void HandleRemoveDir(int chl, struct fsm_req_rmdir* msg, Filesystem* fs)
memcpy(path, pathraw, msg->namelen);
path[msg->namelen] = '\0';
if ( inode->RemoveDirectory(path) )
RespondSuccess(chl);
else
RespondError(chl, errno);
bool result = inode->RemoveDirectory(path);
free(path);
inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
}
void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
if ( fs->num_inodes <= msg->linkino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
Inode* dest = fs->GetInode((uint32_t) msg->linkino);
Inode* dest = SafeGetInode(fs, msg->linkino);
if ( !dest ) { inode->Unref(); RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]);
@ -505,20 +492,20 @@ void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs)
memcpy(path, pathraw, msg->namelen);
path[msg->namelen] = '\0';
if ( inode->Link(path, dest, false) )
RespondSuccess(chl);
else
RespondError(chl, errno);
bool result = inode->Link(path, dest, false);
free(path);
dest->Unref();
inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
}
void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
Inode* inode = SafeGetInode(fs, msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; }
char* dest_raw = (char*) &(msg[1]);
@ -544,20 +531,20 @@ void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs)
memcpy(path, path_raw, msg->namelen);
path[msg->namelen] = '\0';
if ( inode->Symlink(path, dest) )
RespondSuccess(chl);
else
RespondError(chl, errno);
bool result = inode->Symlink(path, dest);
free(path);
free(dest);
inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
}
void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->ino);
Inode* inode = SafeGetInode(fs, msg->ino);
if ( !inode ) { RespondError(chl, errno); return; }
if ( !EXT2_S_ISLNK(inode->Mode()) ) { inode->Unref(); RespondError(chl, EINVAL); return; }
size_t count = inode->Size();
@ -572,9 +559,6 @@ void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs)
void HandleRename(int chl, struct fsm_req_rename* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->olddirino ) { RespondError(chl, EBADF); return; }
if ( fs->num_inodes <= msg->newdirino ) { RespondError(chl, EBADF); return; }
char* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->oldnamelen+1 + msg->newnamelen+1);
if ( !path ) { RespondError(chl, errno); return; }
@ -586,19 +570,20 @@ void HandleRename(int chl, struct fsm_req_rename* msg, Filesystem* fs)
const char* oldname = path;
const char* newname = path + msg->oldnamelen + 1;
Inode* olddir = fs->GetInode((uint32_t) msg->olddirino);
Inode* olddir = SafeGetInode(fs, msg->olddirino);
if ( !olddir ) { free(path); RespondError(chl, errno); return; }
Inode* newdir = fs->GetInode((uint32_t) msg->newdirino);
Inode* newdir = SafeGetInode(fs, msg->newdirino);
if ( !newdir ) { olddir->Unref(); free(path); RespondError(chl, errno); return; }
if ( newdir->Rename(olddir, oldname, newname) )
RespondSuccess(chl);
else
RespondError(chl, errno);
bool result = newdir->Rename(olddir, oldname, newname);
newdir->Unref();
olddir->Unref();
free(path);
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
}
void HandleStatVFS(int chl, struct fsm_req_statvfs* msg, Filesystem* fs)
@ -624,9 +609,6 @@ void HandleStatVFS(int chl, struct fsm_req_statvfs* msg, Filesystem* fs)
void HandleTCGetBlob(int chl, struct fsm_req_tcgetblob* msg, Filesystem* fs)
{
if ( fs->num_inodes <= msg->ino )
return (void) RespondError(chl, EBADF);
char* nameraw = (char*) &(msg[1]);
char* name = (char*) malloc(msg->namelen + 1);
if ( !name )
@ -765,14 +747,16 @@ int fsmarshall_main(const char* argv0,
HandleIncomingMessage(channel, &hdr, fs);
close(channel);
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if ( dev->write && !dev->has_sync_thread &&
5 <= timespec_sub(now, last_sync_at).tv_sec )
if ( dev->write && !dev->has_sync_thread )
{
fs->Sync();
last_sync_at = now;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
if ( 5 <= timespec_sub(now, last_sync_at).tv_sec )
{
fs->Sync();
last_sync_at = now;
}
}
}

View File

@ -30,6 +30,7 @@
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#define FUSE_USE_VERSION 26
@ -126,7 +127,7 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr)
delete[] elem;
inode->Unref();
if ( !next )
return NULL;
return (Inode*) NULL;
inode = next;
}
*path_ptr = *path ? path : ".";
@ -145,7 +146,7 @@ int ext2_fuse_getattr(const char* path, struct stat* st)
}
int ext2_fuse_fgetattr(const char* /*path*/, struct stat* st,
struct fuse_file_info* fi)
struct fuse_file_info* fi)
{
Filesystem* fs = FUSE_FS;
Inode* inode = fs->GetInode((uint32_t) fi->fh);
@ -199,11 +200,9 @@ int ext2_fuse_unlink(const char* path)
Inode* inode = ext2_fuse_parent_dir(&path);
if ( !inode )
return -errno;
bool result = inode->Unlink(path, false);
bool success = inode->Unlink(path, false);
inode->Unref();
if ( !result )
return -errno;
return 0;
return success ? 0 : -errno;
}
int ext2_fuse_rmdir(const char* path)

View File

@ -48,6 +48,9 @@
#ifndef S_SETABLE
#define S_SETABLE 02777
#endif
#ifndef O_WRITE
#define O_WRITE (O_WRONLY | O_RDWR)
#endif
Inode::Inode(Filesystem* filesystem, uint32_t inode_id)
{
@ -163,20 +166,6 @@ void Inode::SetSize(uint64_t new_size)
Modified();
}
void Inode::Linked()
{
BeginWrite();
data->i_links_count++;
FinishWrite();
}
void Inode::Unlinked()
{
BeginWrite();
data->i_links_count--;
FinishWrite();
}
Block* Inode::GetBlockFromTable(Block* table, uint32_t index)
{
if ( uint32_t block_id = ((uint32_t*) table->block_data)[index] )
@ -406,6 +395,8 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
if ( !EXT2_S_ISDIR(Mode()) )
return errno = ENOTDIR, (Inode*) NULL;
size_t elem_length = strlen(elem);
if ( elem_length == 0 )
return errno = ENOENT, (Inode*) NULL;
uint64_t filesize = Size();
uint64_t offset = 0;
Block* block = NULL;
@ -421,13 +412,12 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
return NULL;
const uint8_t* block_data = block->block_data + entry_block_offset;
const struct ext_dirent* entry = (const struct ext_dirent*) block_data;
if ( entry->name_len == elem_length &&
memcmp(elem, entry->name, elem_length) == 0 &&
entry->inode )
if ( entry->inode &&
entry->name_len == elem_length &&
memcmp(elem, entry->name, elem_length) == 0 )
{
uint8_t file_type = entry->file_type;
uint32_t inode_id = entry->inode;
assert(inode_id);
block->Unref();
if ( (flags & O_CREAT) && (flags & O_EXCL) )
return errno = EEXIST, (Inode*) NULL;
@ -444,7 +434,7 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
inode->Unref();
return errno = ENOTDIR, (Inode*) NULL;
}
if ( S_ISREG(inode->Mode()) && flags & O_TRUNC )
if ( S_ISREG(inode->Mode()) && flags & O_WRITE && flags & O_TRUNC )
inode->Truncate(0);
return inode;
}
@ -469,10 +459,7 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
// TODO: Set all the other inode properties!
if ( !Link(elem, result, false) )
{
memset(result->data, 0, sizeof(*result->data));
// TODO: dtime
result->Unref();
filesystem->FreeInode(result_inode_id);
return NULL;
}
return result;
@ -482,8 +469,6 @@ Inode* Inode::Open(const char* elem, int flags, mode_t mode)
bool Inode::Link(const char* elem, Inode* dest, bool directories)
{
// TODO: Check if dest has checked the link limit!
if ( !EXT2_S_ISDIR(Mode()) )
return errno = ENOTDIR, false;
if ( directories && !EXT2_S_ISDIR(dest->Mode()) )
@ -496,6 +481,8 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
// Search for a hole in which we can store the new directory entry and stop
// if we meet an existing link with the requested name.
size_t elem_length = strlen(elem);
if ( elem_length == 0 )
return errno = ENOENT, false;
size_t new_entry_size = roundup(sizeof(struct ext_dirent) + elem_length, (size_t) 4);
uint64_t filesize = Size();
uint64_t offset = 0;
@ -517,8 +504,7 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
const uint8_t* block_data = block->block_data + entry_block_offset;
const struct ext_dirent* entry = (const struct ext_dirent*) block_data;
if ( entry->name_len == elem_length &&
memcmp(elem, entry->name, elem_length) == 0 &&
entry->inode )
memcmp(elem, entry->name, elem_length) == 0 )
{
block->Unref();
return errno = EEXIST, false;
@ -526,7 +512,7 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
if ( !found_hole )
{
size_t entry_size = roundup(sizeof(struct ext_dirent) + entry->name_len, (size_t) 4);
if ( (!entry->name[0] || !entry->inode) && new_entry_size <= entry->reclen )
if ( (!entry->inode || !entry->name[0]) && new_entry_size <= entry->reclen )
{
hole_block_id = entry_block_id;
hole_block_offset = entry_block_offset;
@ -545,6 +531,12 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
offset += entry->reclen;
}
if ( UINT16_MAX <= dest->data->i_links_count )
return errno = EMLINK, false;
if ( 255 < elem_length )
return errno = ENAMETOOLONG, false;
// We'll append another block if we failed to find a suitable hole.
if ( !found_hole )
{
@ -576,23 +568,23 @@ bool Inode::Link(const char* elem, Inode* dest, bool directories)
// Write the new directory entry.
entry->inode = dest->inode_id;
entry->reclen = new_entry_size;
entry->name_len = elem_length;
// TODO: Only do this if the filetype feature is on!
entry->file_type = EXT2_FT_OF_MODE(dest->Mode());
if ( filesystem->sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE )
entry->file_type = EXT2_FT_OF_MODE(dest->Mode());
else
entry->file_type = 0;
strncpy(entry->name, elem, new_entry_size - sizeof(struct ext_dirent));
assert(entry->reclen);
block->FinishWrite();
block->Unref();
dest->Linked();
dest->BeginWrite();
dest->data->i_links_count++;
dest->FinishWrite();
if ( !found_hole )
SetSize(Size() + filesystem->block_size);
block->Unref();
return true;
}
@ -602,6 +594,8 @@ Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force)
return errno = ENOTDIR, (Inode*) NULL;
Modified();
size_t elem_length = strlen(elem);
if ( elem_length == 0 )
return errno = ENOENT, (Inode*) NULL;
uint32_t block_size = filesystem->block_size;
uint64_t filesize = Size();
uint64_t num_blocks = divup(filesize, (uint64_t) block_size);
@ -621,10 +615,9 @@ Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force)
return NULL;
uint8_t* block_data = block->block_data + entry_block_offset;
struct ext_dirent* entry = (struct ext_dirent*) block_data;
assert(entry->reclen);
if ( entry->name_len == elem_length &&
memcmp(elem, entry->name, elem_length) == 0 &&
entry->inode )
if ( entry->inode &&
entry->name_len == elem_length &&
memcmp(elem, entry->name, elem_length) == 0 )
{
Inode* inode = filesystem->GetInode(entry->inode);
@ -649,7 +642,9 @@ Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force)
return errno = EISDIR, (Inode*) NULL;
}
inode->Unlinked();
inode->BeginWrite();
inode->data->i_links_count--;
inode->FinishWrite();
block->BeginWrite();
@ -660,17 +655,13 @@ Inode* Inode::UnlinkKeep(const char* elem, bool directories, bool force)
// Merge the current entry with the previous if any.
if ( last_entry )
{
assert(entry->reclen);
last_entry->reclen += entry->reclen;
memset(entry, 0, entry->reclen);
entry = last_entry;
assert(last_entry->reclen);
}
assert(entry->reclen);
strncpy(entry->name + entry->name_len, "",
entry->reclen - sizeof(struct ext_dirent) - entry->name_len);
assert(entry->reclen);
// If the entire block is empty, we'll need to remove it.
if ( !entry->name[0] && entry->reclen == block_size )
@ -788,14 +779,14 @@ ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
uint32_t block_left = filesystem->block_size - block_offset;
Block* block = GetBlock(block_id);
if ( !block )
return sofar ? sofar : -1;
return sofar ? (ssize_t) sofar : -1;
size_t amount = count - sofar < block_left ? count - sofar : block_left;
block->BeginWrite();
memcpy(block->block_data + block_offset, buf + sofar, amount);
block->FinishWrite();
block->Unref();
sofar += amount;
offset += amount;
block->Unref();
}
return (ssize_t) sofar;
}
@ -886,20 +877,10 @@ bool Inode::Symlink(const char* elem, const char* dest)
if ( SSIZE_MAX < dest_length )
return errno = EFBIG, -1;
if ( result->WriteAt((const uint8_t*) dest, dest_length, 0) < (ssize_t) dest_length )
{
error:
memset(result->data, 0, sizeof(*result->data));
// TODO: dtime
result->Unref();
filesystem->FreeInode(result_inode_id);
return false;
}
return result->Unref(), false;
if ( !Link(elem, result, false) )
{
result->Truncate(0);
goto error;
}
return result->Truncate(0), result->Unref(), false;
result->Unref();
return true;
@ -933,23 +914,19 @@ Inode* Inode::CreateDirectory(const char* path, mode_t mode)
// TODO: Set all the other inode properties!
if ( !Link(path, result, true) )
{
error:
result->Unref();
return NULL;
}
return result->Unref(), (Inode*) NULL;
if ( !result->Link(".", result, true) )
{
Unlink(path, true, true);
goto error;
return result->Unref(), (Inode*) NULL;
}
if ( !result->Link("..", this, true) )
{
result->Unlink(".", true, true);
Unlink(path, true, true);
goto error;
return result->Unref(), (Inode*) NULL;
}
return result;

View File

@ -84,8 +84,6 @@ public:
void Use();
void Unlink();
void Prelink();
void Linked();
void Unlinked();
void Delete();
};