From 0de9f843bad669972eb2a18f52a1eed79ded2479 Mon Sep 17 00:00:00 2001 From: antifallobst Date: Mon, 27 Feb 2023 22:50:05 +0100 Subject: [PATCH] feature (virtual file system): implemented USTAR-archive unpacking and using this for the initrd archive as part of the VFS initialization. --- kernel/inc/drivers/fs/ustar.h | 58 +++++++++++++++++++++ kernel/inc/drivers/fs/vfs.h | 5 +- kernel/src/drivers/fs/vfs.c | 95 ++++++++++++++++++++++++++++------- kernel/src/kmain.c | 25 +++------ 4 files changed, 145 insertions(+), 38 deletions(-) create mode 100644 kernel/inc/drivers/fs/ustar.h diff --git a/kernel/inc/drivers/fs/ustar.h b/kernel/inc/drivers/fs/ustar.h new file mode 100644 index 0000000..8620896 --- /dev/null +++ b/kernel/inc/drivers/fs/ustar.h @@ -0,0 +1,58 @@ +/* + * Copyright 2023 Antifallobst + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the “Software”), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef NOX_USTAR_H +#define NOX_USTAR_H + +#include "utils/stdtypes.h" + +typedef enum { + USTAR_FILE, + USTAR_LINK_HARD, + USTAR_LINK_SYM, + USTAR_CHAR_DEVICE, + USTAR_BLOCK_DEVICE, + USTAR_DIRECTORY, + USTAR_PIPE +} ustar_type_E; + +typedef struct { + char name [100]; + uint64_t mode; + uint64_t owner_id; + uint64_t group_id; + char size [12]; // octal based string (don't ask me why, the ustar standard is weird) + char last_modification [12]; // unix timestamp (octal) + uint64_t checksum; + uint8_t type; + char name_linked [100]; + char indicator [6]; + uint16_t version; + char owner_user_name [32]; + char owner_group_name [32]; + uint64_t device_major; + uint64_t device_minor; + char name_prefix [155]; +}__attribute__((packed)) __attribute__((aligned(512))) ustar_header_T; + +#endif //NOX_USTAR_H diff --git a/kernel/inc/drivers/fs/vfs.h b/kernel/inc/drivers/fs/vfs.h index ef14c60..38cbc8e 100644 --- a/kernel/inc/drivers/fs/vfs.h +++ b/kernel/inc/drivers/fs/vfs.h @@ -88,8 +88,11 @@ 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); +vfs_node_T* vfs_directory_create (fs_T* filesystem, string_t path); +void vfs_directory_delete (vfs_node_T* directory); + 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); +void vfs_unpack_archive_ustar (fs_T* filesystem, void* archive); #endif //NOX_VFS_H diff --git a/kernel/src/drivers/fs/vfs.c b/kernel/src/drivers/fs/vfs.c index 69fd0ad..92bbd4b 100644 --- a/kernel/src/drivers/fs/vfs.c +++ b/kernel/src/drivers/fs/vfs.c @@ -23,10 +23,13 @@ #include "drivers/fs/vfs.h" #include "drivers/fs/ramfs.h" +#include "drivers/fs/ustar.h" #include "utils/memory.h" #include "utils/logger.h" +#include "utils/math.h" fs_T g_root_fs; +fs_T g_ramdisk_fs; string_t g_fs_names[FS_ENUM_END] = { "RAMFS" @@ -146,6 +149,8 @@ void vfs_node_dump_info(vfs_node_T* node, uint64_t indent) { } case VFS_NODE_MOUNT: { log(LOG_NONE, "%s[mount] %s -> %s", buf, node->name, g_fs_names[((fs_T*)node->specific)->type]); + vfs_node_dump_info(((fs_T*)node->specific)->root_node, indent+6); + break; } } } @@ -202,8 +207,6 @@ vfs_node_T* vfs_file_create(fs_T* filesystem, string_t path) { } 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; @@ -249,14 +252,47 @@ void vfs_file_read(vfs_node_T* file, uint64_t position, uint64_t size, uint8_t* } } +vfs_node_T* vfs_directory_create(fs_T* filesystem, string_t path) { + // everything before index is the path and everything behind index is the name of the dir that will be created + uint64_t index = string_find_last(path, '/') + 1; + + 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 directory %s (invalid path)", path); + return NULL; + } + vfs_node_T* dir = vfs_node_create(dir_node, &path[index], VFS_NODE_DIRECTORY, NULL); + + switch (dir->filesystem->type) { + default: { + break; + } + } + + return dir; +} + +void vfs_directory_delete(vfs_node_T* directory) { + +} + 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; + 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; + g_ramdisk_fs.type = FS_RAMFS; + g_ramdisk_fs.root_node = vfs_node_create(NULL, "root", VFS_NODE_DIRECTORY, NULL); + g_ramdisk_fs.root_node->filesystem = &g_ramdisk_fs; + + // unpacking initial ramdisk to '/initrd/' + vfs_node_create(g_root_fs.root_node, "initrd", VFS_NODE_MOUNT, &g_ramdisk_fs); + vfs_unpack_archive_ustar(&g_ramdisk_fs, boot_info->ramdisk_file->address); } 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; @@ -283,28 +319,51 @@ vfs_node_T* vfs_resolve_path(fs_T* filesystem, string_t path) { 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); + path++; // remove the '/' 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); } + default: { + break; + } } } return node; } -void vfs_unpack_archive_ustar(vfs_node_T* node, void* archive) { +void vfs_unpack_archive_ustar(fs_T* filesystem , void* archive) { + // skip the first header, that specifies the root directory + ustar_header_T* header = archive + sizeof(ustar_header_T); + log(LOG_INFO, " unpacking initrd"); + + while (memory_compare(header->indicator, "ustar", 5)) { + uint64_t size = octal_string_to_int(header->size, 11); + uint32_t blocks = 1 + (size > 0 ? (size / 512) + 1 : 0); + if (header->type > 0) { + header->type -= '0'; + } + + log(LOG_INFO, " extracting: %s", header->name); + + switch (header->type) { + case USTAR_FILE: { + vfs_node_T* file = vfs_file_create(filesystem, &header->name[1]); + vfs_file_write(file, 0, size, (uint8_t*)&header[1]); + break; + } + case USTAR_DIRECTORY: { + // get rid of the '/' at the end + header->name[string_length(header->name)-1] = '\0'; + + vfs_directory_create(filesystem, &header->name[1]); + break; + } + } + + header = &header[blocks]; + } } \ No newline at end of file diff --git a/kernel/src/kmain.c b/kernel/src/kmain.c index a7b7133..5159d5e 100644 --- a/kernel/src/kmain.c +++ b/kernel/src/kmain.c @@ -89,26 +89,13 @@ 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_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); + char buffer [129]; buffer[128] = 0; + + vfs_file_read(vfs_resolve_path(&g_root_fs, "/initrd/test.txt"), 0, 128, (uint8_t*)buffer); + + log(LOG_DEBUG, "Reading 128 bytes from '/initrd/test.txt':\n%s", buffer); + CORE_HALT_FOREVER }