[wip] add read and write

This commit is contained in:
ІО-23 Шмуляр Олег 2025-04-26 19:03:39 +03:00
parent 4f610340f5
commit 87f3239c52
2 changed files with 310 additions and 0 deletions

View File

@ -3,6 +3,8 @@
#include <stdio.h>
#include <unistd.h>
#include "config.h"
#include "color.h"
@ -15,8 +17,10 @@
#if ENABLE_STDOUT == 1
#define pr_stdout(...) { printf(__VA_ARGS__); }
#define write_stdout(data, size) { write(1, (data), (size)); }
#else
#define pr_stdout(...) {}
#define write_stdout(data, size) {}
#endif

306
src/fs.c
View File

@ -587,6 +587,312 @@ int fs_open(void *d)
return 0;
}
int fs_seek(void *d)
{
int fd = ((int *) d)[0];
int offset = ((int *) d)[1];
if (!fs_file_descriptions[fd].inode) {
pr_err("fd %d is not open\n", fd);
return 0;
}
struct fs_inode f;
read_block(fs_file_descriptions[fd].inode, (void *) &f);
if (offset > f.size) {
pr_err("offset is larger than file (%d > %d)\n", offset, f.size);
return 0;
}
pr("Moving rw_offset of fd %d: %d -> %d\n",
fd, fs_file_descriptions[fd].rw_offset, offset);
fs_file_descriptions[fd].rw_offset = offset;
return 0;
}
static void read_fd_block(unsigned int fd, unsigned int block_index, unsigned char *buf)
{
struct fs_inode f;
read_block(fs_file_descriptions[fd].inode, (void *) &f);
if (block_index < BLOCK_ADDRESSES_PER_INODE) {
if (f.blocks[block_index])
read_block(f.blocks[block_index], (void *) buf);
else
memset(buf, 0, FS_BLOCK_SIZE);
} else {
int ext_no = (block_index - BLOCK_ADDRESSES_PER_INODE) / BLOCK_ADDRESSES_PER_INODE_EXTENSION;
int ext_offset = (block_index - BLOCK_ADDRESSES_PER_INODE) % BLOCK_ADDRESSES_PER_INODE_EXTENSION;
unsigned int target_extension_address;
unsigned int i;
// seek to target extension address
for (
target_extension_address = f.next_extension, i = 0;
(i < ext_no) && target_extension_address;
i++
) {
struct fs_inode_extension ext;
read_block(target_extension_address, (void *) &ext);
target_extension_address = ext.next_extension;
}
if (!target_extension_address) {
memset(buf, 0, FS_BLOCK_SIZE);
} else {
struct fs_inode_extension ext;
read_block(target_extension_address, (void *) &ext);
if (!ext.blocks[ext_offset])
memset(buf, 0, FS_BLOCK_SIZE);
else
read_block(ext.blocks[ext_offset], (void *) buf);
}
}
}
static int write_fd_block(unsigned int fd, unsigned int block_index, unsigned char *buf)
{
struct fs_inode f;
read_block(fs_file_descriptions[fd].inode, (void *) &f);
if (block_index < BLOCK_ADDRESSES_PER_INODE) {
if (!f.blocks[block_index]) {
int new_block = find_free_block();
if (!new_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for writing file data\n",
fd, block_index);
return -1;
}
mark_used(new_block);
f.blocks[block_index] = new_block;
write_block(fs_file_descriptions[fd].inode, (void *) &f);
}
write_block(f.blocks[block_index], (void *) buf);
} else {
int ext_no = (block_index - BLOCK_ADDRESSES_PER_INODE) / BLOCK_ADDRESSES_PER_INODE_EXTENSION;
int ext_offset = (block_index - BLOCK_ADDRESSES_PER_INODE) % BLOCK_ADDRESSES_PER_INODE_EXTENSION;
// treat switch from base inode to inode extension as special case
if (!f.next_extension) {
int new_block = find_free_block();
if (!new_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for inode extension\n",
fd, block_index);
return -1;
}
mark_used(new_block);
struct fs_inode_extension ext;
memset(&ext, 0, sizeof(struct fs_inode_extension));
f.next_extension = new_block;
write_block(fs_file_descriptions[fd].inode, (void *) &f);
}
unsigned int target_extension_address;
unsigned int previous_extension_address = f.next_extension;
unsigned int i;
// seek to target extension address
for (
target_extension_address = previous_extension_address, i = 0;
(i < ext_no);
i++
) {
if (!target_extension_address) {
int new_block = find_free_block();
if (!new_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for inode extension\n",
fd, block_index);
return -1;
}
mark_used(new_block);
// updating previous inode extension
struct fs_inode_extension prev_ext;
read_block(previous_extension_address, (void *) &prev_ext); // read
prev_ext.next_extension = new_block; // modify
write_block(previous_extension_address, (void *) &prev_ext); // write
// writing new inode extension
struct fs_inode_extension ext;
memset(&ext, 0, sizeof(struct fs_inode_extension));
write_block(target_extension_address, (void *) &ext);
}
struct fs_inode_extension ext;
read_block(target_extension_address, (void *) &ext);
previous_extension_address = target_extension_address;
target_extension_address = ext.next_extension;
}
if (!target_extension_address) {
int new_block = find_free_block();
if (!new_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for inode extension\n",
fd, block_index);
return -1;
}
struct fs_inode_extension prev_ext;
read_block(previous_extension_address, (void *) &prev_ext); // read
prev_ext.next_extension = new_block; // modify
write_block(previous_extension_address, (void *) &prev_ext); // write
int new_data_block = find_free_block();
if (!new_data_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for data\n",
fd, block_index);
return -1;
}
mark_used(new_block);
mark_used(new_data_block);
// writing new inode extension
struct fs_inode_extension ext;
memset(&ext, 0, sizeof(struct fs_inode_extension));
ext.blocks[ext_offset] = new_data_block;
write_block(target_extension_address, (void *) &ext);
// writing new data block
write_block(new_data_block, (void *) buf);
} else {
struct fs_inode_extension ext;
read_block(target_extension_address, (void *) &ext);
if (!ext.blocks[ext_offset]) {
int new_data_block = find_free_block();
if (!new_data_block) {
pr_err("failed to write to fd=%d block=%d: can't allocate block for data\n",
fd, block_index);
return -1;
}
mark_used(new_data_block);
ext.blocks[ext_offset] = new_data_block;
write_block(target_extension_address, (void *) &ext);
}
write_block(ext.blocks[ext_offset], (void *) buf);
}
}
}
int fs_read(void *d)
{
int fd = ((int *) d)[0];
int amount = ((int *) d)[1];
if (!fs_file_descriptions[fd].inode) {
pr_err("fd %d is not open\n", fd);
return 0;
}
if (amount <= 0)
return 0;
struct fs_inode f;
read_block(fs_file_descriptions[fd].inode, (void *) &f);
if (fs_file_descriptions[fd].rw_offset + amount > f.size) {
pr_err("can not read outside of a file (offset %d + amount %d > f.size %d)\n",
fs_file_descriptions[fd].rw_offset, amount, f.size);
return 0;
}
pr("Reading %d bytes from fd %d (offset %d)\n",
amount, fd, fs_file_descriptions[fd].rw_offset);
unsigned char *read_data = malloc(amount);
unsigned int total_read_data_amount = 0;
// read from first block
unsigned char block_buffer[FS_BLOCK_SIZE];
int block_index = fs_file_descriptions[fd].rw_offset / FS_BLOCK_SIZE;
int block_offset = fs_file_descriptions[fd].rw_offset % FS_BLOCK_SIZE;
read_fd_block(fd, block_index, block_buffer);
if (block_offset + amount <= FS_BLOCK_SIZE) {
memcpy(read_data, &(block_buffer[block_offset]), amount);
goto print_read_data;
} else {
memcpy(read_data, &(block_buffer[block_offset]), FS_BLOCK_SIZE - block_offset);
total_read_data_amount += FS_BLOCK_SIZE - block_offset;
}
// read from all next blocks
while (amount - total_read_data_amount > 0) {
block_index++;
read_fd_block(fd, block_index, block_buffer);
int bytes_to_read = (amount - total_read_data_amount > FS_BLOCK_SIZE)
? FS_BLOCK_SIZE : amount - total_read_data_amount;
memcpy(&(read_data[total_read_data_amount]), block_buffer, bytes_to_read);
total_read_data_amount += bytes_to_read;
}
print_read_data:
pr("Updating fd %d offset: %d -> %d\n",
fd, fs_file_descriptions[fd].rw_offset, fs_file_descriptions[fd].rw_offset+amount);
fs_file_descriptions[fd].rw_offset += amount;
write_stdout(read_data, amount);
pr_stdout("\n");
free(read_data);
return 0;
}
int fs_write(void *d)
{
int fd = ((int *) d)[0];
char *str = *((char **) d+4);
int str_len = strlen(str);
if (!fs_file_descriptions[fd].inode) {
pr_err("fd %d is not open\n", fd);
return 0;
}
if (str_len == 0)
return 0;
int block_index = fs_file_descriptions[fd].rw_offset / FS_BLOCK_SIZE;
int block_offset = fs_file_descriptions[fd].rw_offset % FS_BLOCK_SIZE;
unsigned char data_buffer[FS_BLOCK_SIZE];
if (block_offset + str_len <= FS_BLOCK_SIZE) {
read_fd_block(fd, block_index, data_buffer);
memcpy(&(data_buffer[block_offset]), str, str_len);
write_fd_block(fd, block_index, data_buffer);
} else {
read_fd_block(fd, block_index, data_buffer);
memcpy(&(data_buffer[block_offset]), str, FS_BLOCK_SIZE - block_offset);
write_fd_block(fd, block_index, data_buffer);
read_fd_block(fd, block_index+1, data_buffer);
memcpy(data_buffer, &(str[FS_BLOCK_SIZE - block_offset]), str_len - block_offset);
write_fd_block(fd, block_index+1, data_buffer);
}
pr("Moving fd %d offset: %d -> %d\n",
fd, fs_file_descriptions[fd].rw_offset, fs_file_descriptions[fd].rw_offset + str_len);
fs_file_descriptions[fd].rw_offset += str_len;
return 0;
}
int fs_close(void *d)
{
int fd = *((int *) d);