Add extfs optimized symlink write support.
This commit is contained in:
parent
147aae31b1
commit
ac785d861e
|
@ -313,14 +313,34 @@ bool Inode::FreeIndirect(uint64_t from, uint64_t offset, uint32_t block_id,
|
||||||
|
|
||||||
void Inode::Truncate(uint64_t new_size)
|
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();
|
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);
|
SetSize(new_size);
|
||||||
if ( old_size <= new_size )
|
if ( old_size <= new_size )
|
||||||
return;
|
return;
|
||||||
|
@ -701,8 +721,8 @@ ssize_t Inode::ReadAt(uint8_t* buf, size_t s_count, off_t o_offset)
|
||||||
// and so on.
|
// and so on.
|
||||||
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
if ( 0 < file_size && file_size <= 60 && !data->i_blocks )
|
||||||
{
|
{
|
||||||
assert(count <= 60);
|
assert(offset + count <= 60);
|
||||||
unsigned char* block_data = (unsigned char*) &(data->i_block[0]);
|
unsigned char* block_data = (unsigned char*) &data->i_block[0];
|
||||||
memcpy(buf, block_data + offset, count);
|
memcpy(buf, block_data + offset, count);
|
||||||
return (ssize_t) 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;
|
uint64_t end_at = offset + count;
|
||||||
if ( offset < end_at )
|
if ( offset < end_at )
|
||||||
/* TODO: Overflow! off_t overflow? */{};
|
/* 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 )
|
if ( file_size < end_at )
|
||||||
Truncate(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 )
|
while ( sofar < count )
|
||||||
{
|
{
|
||||||
uint64_t block_id = offset / filesystem->block_size;
|
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;
|
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)
|
bool Inode::Rename(Inode* olddir, const char* oldname, const char* newname)
|
||||||
{
|
{
|
||||||
if ( !strcmp(oldname, ".") || !strcmp(oldname, "..") ||
|
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;
|
result->data->i_mtime = now.tv_sec;
|
||||||
// TODO: Set all the other inode properties!
|
// 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:
|
error:
|
||||||
memset(result->data, 0, sizeof(*result->data));
|
memset(result->data, 0, sizeof(*result->data));
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
Inode* Unlink(const char* elem, bool directories, bool force=false);
|
Inode* Unlink(const char* elem, bool directories, bool force=false);
|
||||||
ssize_t ReadAt(uint8_t* buffer, size_t count, off_t offset);
|
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);
|
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);
|
bool Rename(Inode* olddir, const char* oldname, const char* newname);
|
||||||
Inode* CreateDirectory(const char* path, mode_t mode);
|
Inode* CreateDirectory(const char* path, mode_t mode);
|
||||||
bool RemoveDirectory(const char* path);
|
bool RemoveDirectory(const char* path);
|
||||||
|
|
Loading…
Reference in New Issue