feature (virtual file system): implemented USTAR-archive unpacking and using this for the initrd archive as part of the VFS initialization.
This commit is contained in:
parent
8bcf895726
commit
0de9f843ba
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023 Antifallobst <antifallobst@systemausfall.org>
|
||||||
|
*
|
||||||
|
* 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
|
|
@ -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_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_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);
|
void vfs_init (boot_info_T* boot_info);
|
||||||
vfs_node_T* vfs_resolve_path (fs_T* filesystem, string_t path);
|
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
|
#endif //NOX_VFS_H
|
||||||
|
|
|
@ -23,10 +23,13 @@
|
||||||
|
|
||||||
#include "drivers/fs/vfs.h"
|
#include "drivers/fs/vfs.h"
|
||||||
#include "drivers/fs/ramfs.h"
|
#include "drivers/fs/ramfs.h"
|
||||||
|
#include "drivers/fs/ustar.h"
|
||||||
#include "utils/memory.h"
|
#include "utils/memory.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include "utils/math.h"
|
||||||
|
|
||||||
fs_T g_root_fs;
|
fs_T g_root_fs;
|
||||||
|
fs_T g_ramdisk_fs;
|
||||||
|
|
||||||
string_t g_fs_names[FS_ENUM_END] = {
|
string_t g_fs_names[FS_ENUM_END] = {
|
||||||
"RAMFS"
|
"RAMFS"
|
||||||
|
@ -146,6 +149,8 @@ void vfs_node_dump_info(vfs_node_T* node, uint64_t indent) {
|
||||||
}
|
}
|
||||||
case VFS_NODE_MOUNT: {
|
case VFS_NODE_MOUNT: {
|
||||||
log(LOG_NONE, "%s[mount] %s -> %s", buf, node->name, g_fs_names[((fs_T*)node->specific)->type]);
|
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);
|
vfs_node_T* file = vfs_node_create(dir_node, &path[index], VFS_NODE_FILE, NULL);
|
||||||
|
|
||||||
log(LOG_DEBUG, "<VFS> created file %s", &path[index]);
|
|
||||||
|
|
||||||
switch (file->filesystem->type) {
|
switch (file->filesystem->type) {
|
||||||
default: {
|
default: {
|
||||||
break;
|
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, "<VFS> 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) {
|
void vfs_init(boot_info_T* boot_info) {
|
||||||
g_root_fs.type = FS_RAMFS;
|
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 = vfs_node_create(NULL, "root", VFS_NODE_DIRECTORY, NULL);
|
||||||
g_root_fs.root_node->filesystem = &g_root_fs;
|
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) {
|
vfs_node_T* vfs_resolve_path(fs_T* filesystem, string_t path) {
|
||||||
log(LOG_DEBUG, "<VFS> resolving path: %s", path);
|
|
||||||
if (*path != '/') {
|
if (*path != '/') {
|
||||||
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (no root prefix)", path);
|
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (no root prefix)", path);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -283,28 +319,51 @@ vfs_node_T* vfs_resolve_path(fs_T* filesystem, string_t path) {
|
||||||
|
|
||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case VFS_NODE_DIRECTORY: {
|
case VFS_NODE_DIRECTORY: {
|
||||||
path++;
|
path++; // remove the '/'
|
||||||
log(LOG_DEBUG, "<VFS> Node '%s' is a directory", node->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VFS_NODE_FILE: {
|
|
||||||
log(LOG_DEBUG, "<VFS> Node '%s' is a file", node->name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case VFS_NODE_BLOCK_DEVICE: {
|
|
||||||
log(LOG_DEBUG, "<VFS> Node '%s' is a block device", node->name);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VFS_NODE_MOUNT: {
|
case VFS_NODE_MOUNT: {
|
||||||
log(LOG_DEBUG, "<VFS> 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 vfs_resolve_path(node->specific, path);
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
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, "<VFS> 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];
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -89,26 +89,13 @@ void kmain(boot_info_T boot_info) {
|
||||||
limine_terminal_print(&boot_info, "Kernel initialized\n");
|
limine_terminal_print(&boot_info, "Kernel initialized\n");
|
||||||
log(LOG_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);
|
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
|
CORE_HALT_FOREVER
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue