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

View File

@ -42,14 +42,14 @@ public:
uint32_t group_id; uint32_t group_id;
uint32_t block_alloc_chunk; uint32_t block_alloc_chunk;
uint32_t inode_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 block_bitmap_chunk_i;
uint32_t inode_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_block_id;
uint32_t first_inode_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; bool dirty;
public: 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) Device::Device(int fd, const char* path, uint32_t block_size, bool write)
{ {
this->write = write; // sync_thread unset.
this->fd = fd; this->sync_thread_cond = PTHREAD_COND_INITIALIZER;
this->path = path; this->sync_thread_idle_cond = PTHREAD_COND_INITIALIZER;
this->block_size = block_size; this->sync_thread_lock = PTHREAD_MUTEX_INITIALIZER;
struct stat st;
fstat(fd, &st);
this->device_size = st.st_size;
this->mru_block = NULL; this->mru_block = NULL;
this->lru_block = NULL; this->lru_block = NULL;
this->dirty_block = NULL; this->dirty_block = NULL;
for ( size_t i = 0; i < DEVICE_HASH_LENGTH; i++ ) for ( size_t i = 0; i < DEVICE_HASH_LENGTH; i++ )
hash_blocks[i] = NULL; hash_blocks[i] = NULL;
this->sync_thread_cond = PTHREAD_COND_INITIALIZER; struct stat st;
this->sync_thread_idle_cond = PTHREAD_COND_INITIALIZER; fstat(fd, &st);
this->sync_thread_lock = PTHREAD_MUTEX_INITIALIZER; this->device_size = st.st_size;
this->sync_in_transit = false; this->path = path;
this->block_size = block_size;
this->fd = fd;
this->write = write;
this->has_sync_thread = false; this->has_sync_thread = false;
this->sync_thread_should_exit = false;
this->sync_in_transit = false;
} }
Device::~Device() 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 = \ static const uint32_t EXT2_FEATURE_RO_COMPAT_SUPPORTED = \
EXT2_FEATURE_RO_COMPAT_LARGE_FILE; 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 HostModeFromExtMode(uint32_t extmode)
{ {
mode_t hostmode = extmode & 0777; 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'); 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++ ) 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, "%s (Sortix) %s\n", argv0, VERSIONSTR);
fprintf(fp, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"); 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++ ) for ( int i = 1; i < argc; i++ )
{ {
const char* arg = argv[i]; const char* arg = argv[i];
if ( arg[0] != '-' ) if ( arg[0] != '-' || !arg[1] )
continue; continue;
argv[i] = NULL; argv[i] = NULL;
if ( !strcmp(arg, "--") ) if ( !strcmp(arg, "--") )
@ -223,8 +221,12 @@ int main(int argc, char* argv[])
exit(1); exit(1);
} }
} }
else if ( !strcmp(arg, "--help") ) { help(stdout, argv0); exit(0); } else if ( !strcmp(arg, "--help") )
else if ( !strcmp(arg, "--version") ) { version(stdout, argv0); exit(0); } 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") ) else if ( !strcmp(arg, "--foreground") )
foreground = true; foreground = true;
else if ( !strcmp(arg, "--probe") ) else if ( !strcmp(arg, "--probe") )
@ -265,7 +267,7 @@ int main(int argc, char* argv[])
compact_arguments(&argc, &argv); compact_arguments(&argc, &argv);
const char* device_path = 2 <= argc ? argv[1] : NULL; 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 ) if ( !device_path )
{ {
@ -318,31 +320,33 @@ int main(int argc, char* argv[])
} }
// Test whether this revision of the extended filesystem is supported. // Test whether this revision of the extended filesystem is supported.
if ( probe && sb.s_rev_level == EXT2_GOOD_OLD_REV ) if ( sb.s_rev_level == EXT2_GOOD_OLD_REV )
exit(1); {
if ( probe )
if ( !probe && sb.s_rev_level == EXT2_GOOD_OLD_REV ) exit(1);
error(1, 0, "`%s' is formatted with an obsolete filesystem revision", error(1, 0, "`%s' is formatted with an obsolete filesystem revision",
device_path); device_path);
}
// Verify that no incompatible features are in use. // Verify that no incompatible features are in use.
if ( probe && sb.s_feature_compat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED ) if ( sb.s_feature_compat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED )
exit(1); {
if ( probe )
if ( !probe && sb.s_feature_incompat & ~EXT2_FEATURE_INCOMPAT_SUPPORTED ) exit(1);
error(1, 0, "`%s' uses unsupported and incompatible features", error(1, 0, "`%s' uses unsupported and incompatible features",
device_path); device_path);
}
// Verify that no incompatible features are in use if opening for write. // 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 ) sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED )
exit(1); {
if ( probe )
if ( !probe && default_access && write && exit(1);
sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED ) error(1, 0, "`%s' uses unsupported and incompatible features, "
error(1, 0, "`%s uses unsupported and incompatible features, " "read-only access is possible, but write-access was "
"read-only access is possible, but write-access was " "requested", device_path);
"requested", device_path); }
if ( write && sb.s_feature_ro_compat & ~EXT2_FEATURE_RO_COMPAT_SUPPORTED ) 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 " fprintf(stderr, "Note: filesystem uses unsupported but compatible "
"features\n"); "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 // We have found no critical problems, so let the caller know that this
// filesystem satisfies the probe request. // filesystem satisfies the probe request.
if ( probe ) if ( probe )
exit(0); exit(0);
// Check whether the filesystem was unmounted cleanly. // 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", fprintf(stderr, "Warning: `%s' wasn't unmounted cleanly\n",
device_path); device_path);

View File

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

View File

@ -36,8 +36,8 @@ public:
~Filesystem(); ~Filesystem();
public: public:
struct ext_superblock* sb;
Block* sb_block; Block* sb_block;
struct ext_superblock* sb;
Device* device; Device* device;
BlockGroup** block_groups; BlockGroup** block_groups;
const char* mount_path; 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)); 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) && return RespondHeader(chl, type, count) &&
RespondData(chl, ptr, 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); 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 HandleRefer(int chl, struct fsm_req_refer* msg, Filesystem* fs)
{ {
(void) chl; (void) chl;
if ( fs->num_inodes <= msg->ino ) if ( Inode* inode = SafeGetInode(fs, (uint32_t) msg->ino) )
return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
{ {
inode->RemoteRefer(); inode->RemoteRefer();
inode->Unref(); 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 HandleUnref(int chl, struct fsm_req_unref* msg, Filesystem* fs)
{ {
(void) chl; (void) chl;
if ( fs->num_inodes <= msg->ino ) if ( Inode* inode = SafeGetInode(fs, (uint32_t) msg->ino) )
return;
if ( Inode* inode = fs->GetInode((uint32_t) msg->ino) )
{ {
inode->RemoteUnref(); inode->RemoteUnref();
inode->Unref(); 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) void HandleSync(int chl, struct fsm_req_sync* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
inode->Sync(); inode->Sync();
inode->Unref(); 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) void HandleStat(int chl, struct fsm_req_stat* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
struct stat st; struct stat st;
StatInode(inode, &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) void HandleChangeMode(int chl, struct fsm_req_chmod* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
uint32_t req_mode = ExtModeFromHostMode(msg->mode); uint32_t req_mode = ExtModeFromHostMode(msg->mode);
uint32_t old_mode = inode->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) void HandleChangeOwner(int chl, struct fsm_req_chown* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
inode->SetUserId((uint32_t) msg->uid); inode->SetUserId((uint32_t) msg->uid);
inode->SetGroupId((uint32_t) msg->gid); 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) void HandleUTimens(int chl, struct fsm_req_utimens* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
inode->BeginWrite(); inode->BeginWrite();
inode->data->i_atime = msg->times[0].tv_sec; 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) void HandleTruncate(int chl, struct fsm_req_truncate* msg, Filesystem* fs)
{ {
if( msg->size < 0 ) { RespondError(chl, EINVAL); return; } if ( msg->size < 0 ) { RespondError(chl, EINVAL); return; }
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
inode->Truncate((uint64_t) msg->size); inode->Truncate((uint64_t) msg->size);
inode->Unref(); 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) void HandleSeek(int chl, struct fsm_req_lseek* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
if ( msg->whence == SEEK_SET ) if ( msg->whence == SEEK_SET )
RespondSeek(chl, msg->offset); 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) void HandleReadAt(int chl, struct fsm_req_pread* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
uint8_t* buf = (uint8_t*) malloc(msg->count); uint8_t* buf = (uint8_t*) malloc(msg->count);
if ( !buf ) { inode->Unref(); RespondError(chl, errno); return; } 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) void HandleWriteAt(int chl, struct fsm_req_pwrite* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
const uint8_t* buf = (const uint8_t*) &msg[1]; const uint8_t* buf = (const uint8_t*) &msg[1];
ssize_t amount = inode->WriteAt(buf, msg->count, msg->offset); 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) void HandleOpen(int chl, struct fsm_req_open* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]); 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) void HandleMakeDir(int chl, struct fsm_req_mkdir* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]); 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) void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
if ( !S_ISDIR(inode->Mode()) ) 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) void HandleIsATTY(int chl, struct fsm_req_isatty* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
RespondError(chl, ENOTTY); RespondError(chl, ENOTTY);
inode->Unref(); 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) void HandleUnlink(int chl, struct fsm_req_unlink* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]); 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) void HandleRemoveDir(int chl, struct fsm_req_rmdir* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]); 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); memcpy(path, pathraw, msg->namelen);
path[msg->namelen] = '\0'; path[msg->namelen] = '\0';
if ( inode->RemoveDirectory(path) ) bool result = inode->RemoveDirectory(path);
RespondSuccess(chl);
else
RespondError(chl, errno);
free(path); free(path);
inode->Unref(); inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
} }
void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs) void HandleLink(int chl, struct fsm_req_link* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
if ( fs->num_inodes <= msg->linkino ) { RespondError(chl, EBADF); return; }
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } 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; } if ( !dest ) { inode->Unref(); RespondError(chl, errno); return; }
char* pathraw = (char*) &(msg[1]); 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); memcpy(path, pathraw, msg->namelen);
path[msg->namelen] = '\0'; path[msg->namelen] = '\0';
if ( inode->Link(path, dest, false) ) bool result = inode->Link(path, dest, false);
RespondSuccess(chl);
else
RespondError(chl, errno);
free(path); free(path);
dest->Unref(); dest->Unref();
inode->Unref(); inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
} }
void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs) void HandleSymlink(int chl, struct fsm_req_symlink* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->dirino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->dirino);
Inode* inode = fs->GetInode((uint32_t) msg->dirino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
char* dest_raw = (char*) &(msg[1]); 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); memcpy(path, path_raw, msg->namelen);
path[msg->namelen] = '\0'; path[msg->namelen] = '\0';
if ( inode->Symlink(path, dest) ) bool result = inode->Symlink(path, dest);
RespondSuccess(chl);
else
RespondError(chl, errno);
free(path); free(path);
free(dest); free(dest);
inode->Unref(); inode->Unref();
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
} }
void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs) void HandleReadlink(int chl, struct fsm_req_readlink* msg, Filesystem* fs)
{ {
if ( fs->num_inodes <= msg->ino ) { RespondError(chl, EBADF); return; } Inode* inode = SafeGetInode(fs, msg->ino);
Inode* inode = fs->GetInode((uint32_t) msg->ino);
if ( !inode ) { RespondError(chl, errno); return; } if ( !inode ) { RespondError(chl, errno); return; }
if ( !EXT2_S_ISLNK(inode->Mode()) ) { inode->Unref(); RespondError(chl, EINVAL); return; } if ( !EXT2_S_ISLNK(inode->Mode()) ) { inode->Unref(); RespondError(chl, EINVAL); return; }
size_t count = inode->Size(); 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) 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* pathraw = (char*) &(msg[1]);
char* path = (char*) malloc(msg->oldnamelen+1 + msg->newnamelen+1); char* path = (char*) malloc(msg->oldnamelen+1 + msg->newnamelen+1);
if ( !path ) { RespondError(chl, errno); return; } 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* oldname = path;
const char* newname = path + msg->oldnamelen + 1; 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; } 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 ) { olddir->Unref(); free(path); RespondError(chl, errno); return; }
if ( newdir->Rename(olddir, oldname, newname) ) bool result = newdir->Rename(olddir, oldname, newname);
RespondSuccess(chl);
else
RespondError(chl, errno);
newdir->Unref(); newdir->Unref();
olddir->Unref(); olddir->Unref();
free(path); free(path);
if ( !result ) { RespondError(chl, errno); return; }
RespondSuccess(chl);
} }
void HandleStatVFS(int chl, struct fsm_req_statvfs* msg, Filesystem* fs) 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) 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* nameraw = (char*) &(msg[1]);
char* name = (char*) malloc(msg->namelen + 1); char* name = (char*) malloc(msg->namelen + 1);
if ( !name ) if ( !name )
@ -765,14 +747,16 @@ int fsmarshall_main(const char* argv0,
HandleIncomingMessage(channel, &hdr, fs); HandleIncomingMessage(channel, &hdr, fs);
close(channel); close(channel);
struct timespec now; if ( dev->write && !dev->has_sync_thread )
clock_gettime(CLOCK_MONOTONIC, &now);
if ( dev->write && !dev->has_sync_thread &&
5 <= timespec_sub(now, last_sync_at).tv_sec )
{ {
fs->Sync(); struct timespec now;
last_sync_at = 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 <limits.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#define FUSE_USE_VERSION 26 #define FUSE_USE_VERSION 26
@ -126,7 +127,7 @@ Inode* ext2_fuse_parent_dir(const char** path_ptr)
delete[] elem; delete[] elem;
inode->Unref(); inode->Unref();
if ( !next ) if ( !next )
return NULL; return (Inode*) NULL;
inode = next; inode = next;
} }
*path_ptr = *path ? path : "."; *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, int ext2_fuse_fgetattr(const char* /*path*/, struct stat* st,
struct fuse_file_info* fi) struct fuse_file_info* fi)
{ {
Filesystem* fs = FUSE_FS; Filesystem* fs = FUSE_FS;
Inode* inode = fs->GetInode((uint32_t) fi->fh); 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); Inode* inode = ext2_fuse_parent_dir(&path);
if ( !inode ) if ( !inode )
return -errno; return -errno;
bool result = inode->Unlink(path, false); bool success = inode->Unlink(path, false);
inode->Unref(); inode->Unref();
if ( !result ) return success ? 0 : -errno;
return -errno;
return 0;
} }
int ext2_fuse_rmdir(const char* path) int ext2_fuse_rmdir(const char* path)

View File

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

View File

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