From a83a0193a7b811927ece56d6b5e490b118efa5f9 Mon Sep 17 00:00:00 2001 From: antifallobst Date: Sun, 26 Feb 2023 16:14:37 +0100 Subject: [PATCH] feature (virtual file system): implemented mount points and a basic ramfs --- kernel/inc/drivers/fs/ramfs.h | 26 +++++ kernel/inc/drivers/fs/vfs.h | 38 +++++-- kernel/src/drivers/fs/ramfs.c | 40 +++++++ kernel/src/drivers/fs/vfs.c | 201 ++++++++++++++++++++++++++++++---- kernel/src/kmain.c | 33 +++--- 5 files changed, 293 insertions(+), 45 deletions(-) create mode 100644 kernel/inc/drivers/fs/ramfs.h create mode 100644 kernel/src/drivers/fs/ramfs.c diff --git a/kernel/inc/drivers/fs/ramfs.h b/kernel/inc/drivers/fs/ramfs.h new file mode 100644 index 0000000..700d08f --- /dev/null +++ b/kernel/inc/drivers/fs/ramfs.h @@ -0,0 +1,26 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#ifndef NOX_RAMFS_H +#define NOX_RAMFS_H + +#include "drivers/fs/vfs.h" + +void ramfs_file_delete (vfs_node_T* node); +void ramfs_file_write (vfs_node_T* node, uint64_t size, uint8_t* buffer_in); +void ramfs_file_read (vfs_node_T* node, uint64_t size, uint8_t* buffer_out); + + +#endif //NOX_RAMFS_H diff --git a/kernel/inc/drivers/fs/vfs.h b/kernel/inc/drivers/fs/vfs.h index 8f5cb49..618d141 100644 --- a/kernel/inc/drivers/fs/vfs.h +++ b/kernel/inc/drivers/fs/vfs.h @@ -24,6 +24,12 @@ typedef struct vfs_node_T vfs_node_T; +typedef enum { + FS_RAMFS, + + FS_ENUM_END +} fs_type_E; + typedef enum { VFS_NODE_DIRECTORY, VFS_NODE_FILE, @@ -33,6 +39,11 @@ typedef enum { VFS_NODE_ENUM_END } vfs_node_type_E; +typedef struct { + fs_type_E type; + vfs_node_T* root_node; +} fs_T; + typedef struct { void* buffer; uint64_t buffer_size; @@ -44,6 +55,9 @@ struct vfs_node_T{ char name[VFS_MAX_NAME_LENGTH]; vfs_node_type_E type; vfs_node_cache_T* cache; + uint64_t size; + void* specific; + fs_T* filesystem; vfs_node_T* prev; vfs_node_T* next; @@ -51,15 +65,23 @@ struct vfs_node_T{ vfs_node_T* childs; }; -extern vfs_node_T* g_vfs_root_node; +extern fs_T g_root_fs; -vfs_node_T* vfs_node_create (vfs_node_T* parent, string_t name, vfs_node_type_E type); -vfs_node_T* vfs_node_destruct (vfs_node_T* node); -void vfs_node_dump_info (vfs_node_T* node, uint64_t indent); -vfs_node_T* vfs_node_resolve_child (vfs_node_T* node, string_t child_name); +vfs_node_cache_T* vfs_node_cache_create (vfs_node_T* node, uint64_t size); +void vfs_node_cache_destruct (vfs_node_cache_T* node_cache); -void vfs_init (boot_info_T* boot_info); -vfs_node_T* vfs_resolve_path (string_t path); -void vfs_unpack_archive_ustar (); +vfs_node_T* vfs_node_create (vfs_node_T* parent, string_t name, vfs_node_type_E type, void* specific); +void vfs_node_destruct (vfs_node_T* node); +void vfs_node_dump_info (vfs_node_T* node, uint64_t indent); +vfs_node_T* vfs_node_resolve_child (vfs_node_T* node, string_t child_name); + +vfs_node_T* vfs_file_create (fs_T* filesystem, string_t path); +void vfs_file_delete (vfs_node_T* file); +void vfs_file_write (vfs_node_T* file, uint64_t position, uint64_t size, uint8_t* buffer_in); +void vfs_file_read (vfs_node_T* file, uint64_t position, uint64_t size, uint8_t* buffer_out); + +void vfs_init (boot_info_T* boot_info); +vfs_node_T* vfs_resolve_path (fs_T* filesystem, string_t path); +void vfs_unpack_archive_ustar (vfs_node_T* node, void* archive); #endif //NOX_VFS_H diff --git a/kernel/src/drivers/fs/ramfs.c b/kernel/src/drivers/fs/ramfs.c new file mode 100644 index 0000000..4c5ebbf --- /dev/null +++ b/kernel/src/drivers/fs/ramfs.c @@ -0,0 +1,40 @@ +/* Copyright (C) Antifallobst + * + * NoxOS is free software: + * you can redistribute it and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the License, + * or (at your option) any later version. + * + * NoxOS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ + +#include "drivers/fs/ramfs.h" +#include "utils/memory.h" +#include "utils/math.h" + +void ramfs_file_delete(vfs_node_T* node) { + if (node->cache == NULL) { return; } + + vfs_node_cache_destruct(node->cache); +} + +void ramfs_file_write(vfs_node_T* node, uint64_t size, uint8_t* buffer_in) { + if (node->cache != NULL) { + vfs_node_cache_destruct(node->cache); + } + + vfs_node_cache_create(node, size); + + memory_copy(buffer_in, node->cache->buffer, size); +} + +void ramfs_file_read(vfs_node_T* node, uint64_t size, uint8_t* buffer_out) { + if (node->cache == NULL) { return; } + + memory_copy(node->cache->buffer, buffer_out, MIN(size, node->cache->buffer_size)); +} \ No newline at end of file diff --git a/kernel/src/drivers/fs/vfs.c b/kernel/src/drivers/fs/vfs.c index 27babca..4b9ce94 100644 --- a/kernel/src/drivers/fs/vfs.c +++ b/kernel/src/drivers/fs/vfs.c @@ -14,10 +14,31 @@ */ #include "drivers/fs/vfs.h" +#include "drivers/fs/ramfs.h" #include "utils/memory.h" #include "utils/logger.h" -vfs_node_T* g_vfs_root_node; +fs_T g_root_fs; + +string_t g_fs_names[FS_ENUM_END] = { + "RAMFS" +}; + +vfs_node_cache_T* vfs_node_cache_create(vfs_node_T* node, uint64_t size) { + vfs_node_cache_T* node_cache = memory_allocate(sizeof(vfs_node_cache_T)); + node_cache->node = node; + node_cache->buffer_size = size; + node_cache->buffer = memory_allocate(size); + node_cache->reclaimable = false; + node->cache = node_cache; + return node_cache; +} + +void vfs_node_cache_destruct(vfs_node_cache_T* node_cache) { + node_cache->node->cache = NULL; + memory_free(node_cache->buffer); + memory_free(node_cache); +} void vfs_node_bring_to_parent_start(vfs_node_T* node) { if (node->parent == NULL) { return; } @@ -44,7 +65,36 @@ void vfs_node_bring_to_parent_start(vfs_node_T* node) { node->parent->childs = node; } -vfs_node_T* vfs_node_create(vfs_node_T* parent, string_t name, vfs_node_type_E type) { +vfs_node_T* vfs_node_create(vfs_node_T* parent, string_t name, vfs_node_type_E type, void* specific) { + fs_T* filesystem = NULL; + + if (parent != NULL) { + filesystem = parent->filesystem; + + switch (parent->type) { + case VFS_NODE_DIRECTORY: { + break; + } + case VFS_NODE_BLOCK_DEVICE: { + log(LOG_WARNING, " failed to create node (block device cannot have childs)"); + return NULL; + } + case VFS_NODE_FILE: { + log(LOG_WARNING, " failed to create node (file cannot have childs)"); + return NULL; + } + case VFS_NODE_MOUNT: { + parent = ((fs_T *) parent->specific)->root_node; + break; + } + default: { + // if this ever happens, something went really wrong + log(LOG_ERROR, " failed to create node (invalid parent type)"); + return NULL; + } + } + } + vfs_node_T* node = memory_allocate(sizeof(vfs_node_T)); uint64_t strlen = string_length(name); @@ -53,12 +103,14 @@ vfs_node_T* vfs_node_create(vfs_node_T* parent, string_t name, vfs_node_type_E t } memory_copy((void*)name, node->name, VFS_MAX_NAME_LENGTH-1); node->name[VFS_MAX_NAME_LENGTH-1] = '\0'; - node->parent = parent; - node->type = type; - node->cache = NULL; - node->childs = NULL; - node->prev = NULL; - node->next = NULL; + node->parent = parent; + node->type = type; + node->cache = NULL; + node->specific = specific; + node->filesystem = filesystem; + node->childs = NULL; + node->prev = NULL; + node->next = NULL; vfs_node_bring_to_parent_start(node); @@ -84,11 +136,32 @@ void vfs_node_dump_info(vfs_node_T* node, uint64_t indent) { log(LOG_NONE, "%s[file] %s", buf, node->name); break; } + case VFS_NODE_MOUNT: { + log(LOG_NONE, "%s[mount] %s -> %s", buf, node->name, g_fs_names[((fs_T*)node->specific)->type]); + } } } -vfs_node_T* vfs_node_destruct(vfs_node_T* node) { +void vfs_node_destruct(vfs_node_T* node) { + vfs_node_T* child = node->childs; + while (child != NULL) { + vfs_node_destruct(child); + child = child->next; + } + if (node->parent->childs == node) { + node->parent->childs = node->next; + } + + if (node->prev != NULL) { + node->prev->next = node->next; + } + + if (node->next != NULL) { + node->next->prev = node->prev; + } + + memory_free(node); } @@ -107,21 +180,86 @@ vfs_node_T* vfs_node_resolve_child(vfs_node_T* node, string_t child_name) { return NULL; } -void vfs_init(boot_info_T* boot_info) { - g_vfs_root_node = vfs_node_create(NULL, "root", VFS_NODE_DIRECTORY); -} +vfs_node_T* vfs_file_create(fs_T* filesystem, string_t path) { + // everything before index is the path and everything behind index is the name of the file that will be created + uint64_t index = string_find_last(path, '/') + 1; -vfs_node_T* vfs_resolve_path(string_t path) { - if (*path != '/') { - log(LOG_WARNING, " failed to resolve node from invalid path '%s' (no root prefix)"); + char dir_path[index]; + memory_copy(path, dir_path, index); dir_path[index] = '\0'; + + vfs_node_T* dir_node = vfs_resolve_path(filesystem, dir_path); + if (dir_node == NULL) { + log(LOG_WARNING, " failed to create file %s (invalid path)", path); return NULL; } + vfs_node_T* file = vfs_node_create(dir_node, &path[index], VFS_NODE_FILE, NULL); + + log(LOG_DEBUG, " created file %s", &path[index]); + + switch (file->filesystem->type) { + default: { + break; + } + } + + return file; +} + +void vfs_file_delete(vfs_node_T* file) { + switch (file->filesystem->type) { + case FS_RAMFS: { + ramfs_file_delete(file); + break; + } + default: { + break; + } + } +} + +void vfs_file_write(vfs_node_T* file, uint64_t position, uint64_t size, uint8_t* buffer_in) { + switch (file->filesystem->type) { + case FS_RAMFS: { + ramfs_file_write(file, size, buffer_in); + break; + } + default: { + break; + } + } +} + +void vfs_file_read(vfs_node_T* file, uint64_t position, uint64_t size, uint8_t* buffer_out) { + switch (file->filesystem->type) { + case FS_RAMFS: { + ramfs_file_read(file, size, buffer_out); + break; + } + default: { + break; + } + } +} + +void vfs_init(boot_info_T* boot_info) { + g_root_fs.type = FS_RAMFS; + g_root_fs.root_node = vfs_node_create(NULL, "root", VFS_NODE_DIRECTORY, NULL); + g_root_fs.root_node->filesystem = &g_root_fs; +} + +vfs_node_T* vfs_resolve_path(fs_T* filesystem, string_t path) { + log(LOG_DEBUG, " resolving path: %s", path); + if (*path != '/') { + log(LOG_WARNING, " failed to resolve node from invalid path '%s' (no root prefix)", path); + return NULL; + } + path++; uint32_t length; - vfs_node_T* node = g_vfs_root_node; + vfs_node_T* node = filesystem->root_node; + + while(*path != '\0') { - do { - path++; length = string_find_next(path, '/'); char name[length]; @@ -130,16 +268,35 @@ vfs_node_T* vfs_resolve_path(string_t path) { node = vfs_node_resolve_child(node, name); if (node == NULL) { - log(LOG_WARNING, " failed to resolve node from invalid path '%s' (node child resolve null)"); + log(LOG_WARNING, " failed to resolve node from invalid path '%s' (node child resolve null)", path); return NULL; } - path += length; - } while(*path != '\0'); + + switch (node->type) { + case VFS_NODE_DIRECTORY: { + path++; + log(LOG_DEBUG, " Node '%s' is a directory", node->name); + break; + } + case VFS_NODE_FILE: { + log(LOG_DEBUG, " Node '%s' is a file", node->name); + break; + } + case VFS_NODE_BLOCK_DEVICE: { + log(LOG_DEBUG, " Node '%s' is a block device", node->name); + break; + } + case VFS_NODE_MOUNT: { + log(LOG_DEBUG, " Node '%s' is a mount point to a %s filesystem", node->name, g_fs_names[((fs_T*)node->specific)->type]); + return vfs_resolve_path(node->specific, path); + } + } + } return node; } -void vfs_unpack_archive_ustar() { +void vfs_unpack_archive_ustar(vfs_node_T* node, void* archive) { } \ No newline at end of file diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index 56f5ecc..07fd41c 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -81,23 +81,26 @@ void kmain(boot_info_T boot_info) { limine_terminal_print(&boot_info, "Kernel initialized\n"); log(LOG_INFO, "!=====[ Kernel Initialized ]=====!\n"); - for (int i = 0; i < 150; i++) { - log(LOG_DEBUG, "test log %d", i); - } - -// vfs_node_T* node_temp = vfs_node_create(g_vfs_root_node, "temp", VFS_NODE_DIRECTORY); -// vfs_node_T* node_system = vfs_node_create(g_vfs_root_node, "system", VFS_NODE_DIRECTORY); -// vfs_node_T* node_config = vfs_node_create(node_system, "config", VFS_NODE_DIRECTORY); -// vfs_node_T* node_test = vfs_node_create(node_config, "test.conf", VFS_NODE_FILE); -// -// vfs_node_T* result = vfs_resolve_path("/system/config/test.conf"); -// if (result == node_test) { -// log(LOG_DEBUG, "resolve test passed"); -// } else { -// log(LOG_DEBUG, "resolve test failed 0x%x != 0x%x", result, node_test); +// for (int i = 0; i < 150; i++) { +// log(LOG_DEBUG, "test log %d", i); // } -// vfs_node_dump_info(g_vfs_root_node, 0); + vfs_node_T* node_temp = vfs_node_create(g_root_fs.root_node, "temp", VFS_NODE_DIRECTORY, NULL); + vfs_node_T* node_system = vfs_node_create(g_root_fs.root_node, "system", VFS_NODE_DIRECTORY, NULL); + vfs_node_T* node_test = vfs_file_create(&g_root_fs, "/system/test.txt"); + + char buffer[16] = "..............."; + + vfs_file_read(node_test, 0, 16, buffer); + log(LOG_DEBUG, "Buffer: \"%s\"", buffer); + + vfs_file_write(node_test, 0, 4, "test"); + log(LOG_DEBUG, "Writing data"); + + vfs_file_read(node_test, 0, 16, buffer); + log(LOG_DEBUG, "Buffer: \"%s\"", buffer); + + vfs_node_dump_info(g_root_fs.root_node, 0); CORE_HALT_FOREVER }