mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add extfs optimized symlink write support.
This commit is contained in:
parent
147aae31b1
commit
ac785d861e
2 changed files with 68 additions and 15 deletions
|
@ -313,14 +313,34 @@ bool Inode::FreeIndirect(uint64_t from, uint64_t offset, uint32_t block_id,
|
|||
|
||||
void Inode::Truncate(uint64_t new_size)
|
||||
{
|
||||
if ( 0 < Size() && Size() <= 60 && !data->i_blocks )
|
||||
{
|
||||
fprintf(stderr, "extfs: Truncating optimized symlinks is not implemented!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Enforce a filesize limit!
|
||||
uint64_t old_size = Size();
|
||||
bool could_be_embedded = old_size == 0 && EXT2_S_ISLNK(Mode()) && !data->i_blocks;
|
||||
bool is_embedded = 0 < old_size && old_size <= 60 && !data->i_blocks;
|
||||
if ( could_be_embedded || is_embedded )
|
||||
{
|
||||
if ( new_size <= 60 )
|
||||
{
|
||||
data_block->BeginWrite();
|
||||
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||
if ( old_size < new_size )
|
||||
memset(block_data + old_size, 0, new_size - old_size);
|
||||
if ( new_size < old_size )
|
||||
memset(block_data + new_size, 0, old_size - new_size);
|
||||
data->i_size = new_size;
|
||||
data_block->FinishWrite();
|
||||
return;
|
||||
}
|
||||
if ( is_embedded && !UnembedInInode() )
|
||||
{
|
||||
// Truncate() can't fail ATM so lose data instead of worse stuff.
|
||||
data_block->BeginWrite();
|
||||
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||
memset(block_data, 0, 60);
|
||||
data->i_size = 0;
|
||||
data_block->FinishWrite();
|
||||
}
|
||||
}
|
||||
// TODO: Enforce a filesize limit!
|
||||
SetSize(new_size);
|
||||
if ( old_size <= new_size )
|
||||
return;
|
||||
|
@ -701,8 +721,8 @@ ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
// and so on.
|
||||
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
||||
{
|
||||
assert(count <= 60);
|
||||
unsigned char* block_data = (unsigned char*) &(data->i_block[0]);
|
||||
assert(offset + count <= 60);
|
||||
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||
memcpy(buf, block_data + offset, count);
|
||||
return (ssize_t) count;
|
||||
}
|
||||
|
@ -739,13 +759,18 @@ ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
uint64_t end_at = offset + count;
|
||||
if ( offset < end_at )
|
||||
/* TODO: Overflow! off_t overflow? */{};
|
||||
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
||||
{
|
||||
fprintf(stderr, "extfs: Writing to optimized symlinks is not implemented!\n");
|
||||
return errno = EROFS, -1;
|
||||
}
|
||||
if ( file_size < end_at )
|
||||
Truncate(end_at);
|
||||
if ( 0 < end_at && end_at <= 60 && !data->i_blocks )
|
||||
{
|
||||
data_block->BeginWrite();
|
||||
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||
memcpy(block_data + offset, buf, count);
|
||||
if ( data->i_size < end_at )
|
||||
data->i_size = end_at;
|
||||
data_block->FinishWrite();
|
||||
return (ssize_t) count;
|
||||
}
|
||||
while ( sofar < count )
|
||||
{
|
||||
uint64_t block_id = offset / filesystem->block_size;
|
||||
|
@ -765,6 +790,30 @@ ssize_t Inode::WriteAt(const uint8_t* buf, size_t s_count, off_t o_offset)
|
|||
return (ssize_t) sofar;
|
||||
}
|
||||
|
||||
bool Inode::UnembedInInode()
|
||||
{
|
||||
assert(data->i_blocks == 0 && 0 < data->i_size && data->i_size <= 60);
|
||||
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||
size_t content_size = Size();
|
||||
unsigned char content[60];
|
||||
memcpy(content, block_data, content_size);
|
||||
data_block->BeginWrite();
|
||||
memset(block_data, 0, 60);
|
||||
data->i_size = 0;
|
||||
data_block->FinishWrite();
|
||||
if ( WriteAt(content, content_size, 0) != (ssize_t) content_size )
|
||||
{
|
||||
Truncate(0);
|
||||
data_block->BeginWrite();
|
||||
memcpy(block_data, content, content_size);
|
||||
data->i_size = content_size;
|
||||
data->i_blocks = 0;
|
||||
data_block->FinishWrite();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Inode::Rename(Inode* olddir, const char* oldname, const char* newname)
|
||||
{
|
||||
if ( !strcmp(oldname, ".") || !strcmp(oldname, "..") ||
|
||||
|
@ -823,7 +872,10 @@ bool Inode::Symlink(const char* elem, const char* dest)
|
|||
result->data->i_mtime = now.tv_sec;
|
||||
// TODO: Set all the other inode properties!
|
||||
|
||||
if ( result->WriteAt((const uint8_t*) dest, strlen(dest), 0) < 0 )
|
||||
size_t dest_length = strlen(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));
|
||||
|
|
|
@ -67,6 +67,7 @@ public:
|
|||
Inode* Unlink(const char* elem, bool directories, bool force=false);
|
||||
ssize_t ReadAt(uint8_t* buffer, size_t count, off_t offset);
|
||||
ssize_t WriteAt(const uint8_t* buffer, size_t count, off_t offset);
|
||||
bool UnembedInInode();
|
||||
bool Rename(Inode* olddir, const char* oldname, const char* newname);
|
||||
Inode* CreateDirectory(const char* path, mode_t mode);
|
||||
bool RemoveDirectory(const char* path);
|
||||
|
|
Loading…
Add table
Reference in a new issue