358 lines
9.8 KiB
C++
358 lines
9.8 KiB
C++
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "boot/answer_code.hpp"
|
|
#include "drivers/fs/handlers.hpp"
|
|
#include "drivers/fs/fs.hpp"
|
|
|
|
Handler_vfs boot_handler("/boot");
|
|
|
|
void parse_and_fill_arg_c(const char* start, size_t len, arg* out_arg) {
|
|
if (len == 0) {
|
|
out_arg->type = argNONE_t;
|
|
return;
|
|
}
|
|
size_t copy_len = (len > 31) ? 31 : len;
|
|
char tmp[33];
|
|
memcpy(tmp, start, copy_len);
|
|
tmp[copy_len] = '\0';
|
|
|
|
char* endptr;
|
|
|
|
long int_val = strtol(tmp, &endptr, 10);
|
|
if (*endptr == '\0') {
|
|
out_arg->type = argINT_t;
|
|
out_arg->value.valueINT = (int)int_val;
|
|
return;
|
|
}
|
|
|
|
float float_val = strtof(tmp, &endptr);
|
|
if (*endptr == '\0') {
|
|
out_arg->type = argFLOAT_t;
|
|
out_arg->value.valueFLOAT = float_val;
|
|
return;
|
|
}
|
|
|
|
out_arg->type = argSTRING_t;
|
|
memcpy(out_arg->value.valueSTRING, tmp, copy_len + 1);
|
|
}
|
|
|
|
void parse_args_c_style(const char* input, arg* args_array) {
|
|
for (int i = 0; i < 8; i++) {
|
|
args_array[i].type = argNONE_t;
|
|
}
|
|
|
|
if (input == nullptr) return;
|
|
|
|
const char* token_start = input;
|
|
|
|
if (input[0] == '\\' && input[1] == '$') {
|
|
input += 2;
|
|
token_start = input;
|
|
}
|
|
|
|
int arg_index = 0;
|
|
|
|
while (*input != '\0') {
|
|
if (*input == '\\' && *(input + 1) == '$') {
|
|
if (input != token_start && *(input - 1) == '\\') {
|
|
input += 2;
|
|
continue;
|
|
}
|
|
|
|
size_t token_len = input - token_start;
|
|
|
|
if (arg_index < 8) {
|
|
parse_and_fill_arg_c(token_start, token_len, &args_array[arg_index]);
|
|
arg_index++;
|
|
}
|
|
|
|
input += 2;
|
|
token_start = input;
|
|
continue;
|
|
}
|
|
|
|
input++;
|
|
}
|
|
|
|
size_t last_len = input - token_start;
|
|
if (last_len > 0 && arg_index < 8) {
|
|
parse_and_fill_arg_c(token_start, last_len, &args_array[arg_index]);
|
|
}
|
|
}
|
|
|
|
Handler_vfs::Handler_vfs(const char *path) {
|
|
strcpy(this->path, path);
|
|
count_fn = 0;
|
|
count_ds = 0;
|
|
capacity_fn = 10;
|
|
capacity_ds = 10;
|
|
functions = (function_file*)malloc(capacity_fn * sizeof(function_file));
|
|
descriptors = (descriptor*)malloc(capacity_ds * sizeof(descriptor));
|
|
};
|
|
|
|
Handler_vfs::~Handler_vfs() {
|
|
if (functions != nullptr) free(functions);
|
|
if (descriptors != nullptr) free(descriptors);
|
|
}
|
|
|
|
int Handler_vfs::link_function(const char *name, func_t func) {
|
|
if (count_fn + 1 > capacity_fn) {
|
|
int new_capacity = capacity_fn + 10;
|
|
size_t new_size = new_capacity * sizeof(function_file);
|
|
|
|
function_file* temp = (function_file*)realloc(functions, new_size);
|
|
if (temp != nullptr) {
|
|
functions = temp;
|
|
capacity_fn = new_capacity;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
strncpy(functions[count_fn].name, name, 31);
|
|
functions[count_fn].name[31] = '\0';
|
|
functions[count_fn].handler = func;
|
|
count_fn++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Handler_vfs::unlink_function(const char *name) {
|
|
int index = -1;
|
|
for (int i = 0; i < count_fn; i++) {
|
|
if (strcmp(functions[i].name, name) == 0) {
|
|
index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (index == -1) return -1;
|
|
|
|
for (int i = index; i < count_fn - 1; i++) {
|
|
functions[i] = functions[i + 1];
|
|
}
|
|
count_fn--;
|
|
|
|
if (capacity_fn - count_fn >= 15 && capacity_fn > 10) {
|
|
int new_capacity = capacity_fn - 10;
|
|
size_t new_size = new_capacity * sizeof(function_file);
|
|
|
|
function_file* temp = (function_file*)realloc(functions, new_size);
|
|
if (temp != nullptr || new_size == 0) {
|
|
functions = temp;
|
|
capacity_fn = new_capacity;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Handler_vfs::open(const char *name, int flags, int mode) {
|
|
int fn_idx = -1;
|
|
for (int i = 0; i < count_fn; i++) {
|
|
if (strcmp(functions[i].name, name) == 0) {
|
|
fn_idx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (fn_idx == -1) return OS_ERR_NOT_FOUND;
|
|
|
|
int target_fd = -1;
|
|
for (int i = 0; i < count_ds; i++) {
|
|
if (descriptors[i].handler == nullptr) {
|
|
target_fd = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (target_fd == -1) {
|
|
if (count_ds + 1 > capacity_ds) {
|
|
int new_capacity = capacity_ds + 10;
|
|
descriptor* temp = (descriptor*)realloc(descriptors, new_capacity * sizeof(descriptor));
|
|
if (temp == nullptr) return OS_ERR_NO_MEMORY;
|
|
descriptors = temp;
|
|
capacity_ds = new_capacity;
|
|
}
|
|
target_fd = count_ds;
|
|
count_ds++;
|
|
}
|
|
|
|
memset(descriptors[target_fd].name, 0, 32);
|
|
strncpy(descriptors[target_fd].name, name, 31);
|
|
descriptors[target_fd].handler = functions[fn_idx].handler;
|
|
|
|
for(int i=0; i<8; ++i) descriptors[target_fd].args[i].type = argNONE_t;
|
|
|
|
return target_fd;
|
|
}
|
|
|
|
int Handler_vfs::open_vfs(void* ctx, const char *path, int flags, int mode) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->open(path, flags, mode);
|
|
}
|
|
|
|
ssize_t Handler_vfs::read(int fd, void *dst, size_t size) {
|
|
if (fd < 0 || fd >= count_ds || descriptors[fd].handler == nullptr) return OS_ERR_NOT_FOUND;
|
|
if (dst == nullptr) {
|
|
descriptors[fd].handler(&descriptors[fd]);
|
|
return 0;
|
|
}
|
|
|
|
if (size < sizeof(Result)) return OS_ERR_NO_MEMORY;
|
|
|
|
Result res = descriptors[fd].handler(&descriptors[fd]);
|
|
memcpy(dst, &res, sizeof(res));
|
|
|
|
return sizeof(res);
|
|
}
|
|
|
|
ssize_t Handler_vfs::read_vfs(void* ctx, int fd, void *dst, size_t size) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->read(fd, dst, size);
|
|
}
|
|
|
|
ssize_t Handler_vfs::write(int fd, const void *src, size_t size) {
|
|
if (fd < 0 || fd >= count_ds || descriptors[fd].handler == nullptr) {
|
|
return OS_ERR_NOT_FOUND;
|
|
}
|
|
if (src == nullptr || size == 0) {
|
|
return OS_ERR_INVALID_ARG;
|
|
}
|
|
char tmp_input[128];
|
|
size_t copy_size = (size > 127) ? 127 : size;
|
|
|
|
memcpy(tmp_input, src, copy_size);
|
|
tmp_input[copy_size] = '\0';
|
|
parse_args_c_style(tmp_input, descriptors[fd].args);
|
|
|
|
return (ssize_t)size;
|
|
}
|
|
|
|
ssize_t Handler_vfs::write_vfs(void* ctx, int fd, const void *src, size_t size) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->write(fd, src, size);
|
|
}
|
|
|
|
int Handler_vfs::close(int fd) {
|
|
if (fd < 0 || fd >= count_ds) return OS_ERR_INVALID_ARG;
|
|
descriptors[fd].handler = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
int Handler_vfs::close_vfs(void* ctx, int fd) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->close(fd);
|
|
}
|
|
|
|
int Handler_vfs::rename(const char *src, const char *dst) {
|
|
int fn_idx = -1;
|
|
for (int i = 0; i < count_fn; i++) {
|
|
if (strcmp(functions[i].name, src) == 0) {
|
|
fn_idx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (fn_idx == -1) return OS_ERR_NOT_FOUND;
|
|
|
|
strncpy(functions[fn_idx].name, dst, 31);
|
|
functions[fn_idx].name[31] = '\0';
|
|
return 0;
|
|
}
|
|
|
|
int Handler_vfs::rename_vfs(void* ctx, const char *src, const char *dst) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->rename(src, dst);
|
|
}
|
|
|
|
// --- РЕАЛИЗАЦИЯ РАБОТЫ С ДИРЕКТОРИЯМИ И STAT ---
|
|
|
|
DIR* Handler_vfs::opendir(const char* name) {
|
|
// Выделяем память для состояния директории
|
|
descriptor_dir* dd = new descriptor_dir();
|
|
strncpy(dd->path, name, 127);
|
|
dd->path[127] = '\0';
|
|
dd->current_index = 0;
|
|
dd->handler = this;
|
|
|
|
// Cast в DIR*, так как для VFS это просто непрозрачный указатель
|
|
return (DIR*)dd;
|
|
}
|
|
|
|
DIR* Handler_vfs::opendir_vfs(void* ctx, const char* name) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->opendir(name);
|
|
}
|
|
|
|
struct dirent* Handler_vfs::readdir(DIR* pdir) {
|
|
if (!pdir) return nullptr;
|
|
|
|
descriptor_dir* dd = (descriptor_dir*)pdir;
|
|
Handler_vfs* self = dd->handler;
|
|
|
|
if (dd->current_index >= self->count_fn) {
|
|
return nullptr;
|
|
}
|
|
|
|
static struct dirent entry;
|
|
memset(&entry, 0, sizeof(entry));
|
|
|
|
const char* fn_name = self->functions[dd->current_index].name;
|
|
|
|
if (fn_name[0] == '/') {
|
|
fn_name++;
|
|
}
|
|
|
|
strncpy(entry.d_name, fn_name, sizeof(entry.d_name) - 1);
|
|
entry.d_name[sizeof(entry.d_name) - 1] = '\0';
|
|
|
|
dd->current_index++;
|
|
|
|
return &entry;
|
|
}
|
|
|
|
|
|
struct dirent* Handler_vfs::readdir_vfs(void* ctx, DIR* pdir) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->readdir(pdir);
|
|
}
|
|
|
|
int Handler_vfs::closedir(DIR* pdir) {
|
|
if (!pdir) return -1;
|
|
descriptor_dir* dd = (descriptor_dir*)pdir;
|
|
delete dd; // Освобождаем память, выделенную в opendir
|
|
return 0;
|
|
}
|
|
|
|
int Handler_vfs::closedir_vfs(void* ctx, DIR* pdir) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->closedir(pdir);
|
|
}
|
|
|
|
int Handler_vfs::stat(const char * path, struct stat * st) {
|
|
if (!st) return -1;
|
|
memset(st, 0, sizeof(struct stat));
|
|
|
|
// Ищем, является ли путь именем зарегистрированной функции (файлом)
|
|
for (int i = 0; i < count_fn; i++) {
|
|
if (strcmp(functions[i].name, path) == 0) {
|
|
st->st_mode = S_IFREG | 0666; // Обычный файл
|
|
st->st_size = sizeof(Result);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Проверяем, является ли путь самой директорией (точкой монтирования)
|
|
if (strcmp(path, this->path) == 0 || strcmp(path, "/") == 0) {
|
|
st->st_mode = S_IFDIR | 0777; // Директория
|
|
return 0;
|
|
}
|
|
|
|
return -1; // Не найдено
|
|
}
|
|
|
|
int Handler_vfs::stat_vfs(void* ctx, const char * path, struct stat * st) {
|
|
Handler_vfs* self = (Handler_vfs*)ctx;
|
|
return self->stat(path, st);
|
|
} |