feature (virtual file system): implemented mount points and a basic ramfs
This commit is contained in:
parent
a0015018db
commit
a83a0193a7
|
@ -0,0 +1,26 @@
|
||||||
|
/* Copyright (C) Antifallobst <antifallobst@systemausfall.org>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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
|
|
@ -24,6 +24,12 @@
|
||||||
|
|
||||||
typedef struct vfs_node_T vfs_node_T;
|
typedef struct vfs_node_T vfs_node_T;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FS_RAMFS,
|
||||||
|
|
||||||
|
FS_ENUM_END
|
||||||
|
} fs_type_E;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VFS_NODE_DIRECTORY,
|
VFS_NODE_DIRECTORY,
|
||||||
VFS_NODE_FILE,
|
VFS_NODE_FILE,
|
||||||
|
@ -33,6 +39,11 @@ typedef enum {
|
||||||
VFS_NODE_ENUM_END
|
VFS_NODE_ENUM_END
|
||||||
} vfs_node_type_E;
|
} vfs_node_type_E;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
fs_type_E type;
|
||||||
|
vfs_node_T* root_node;
|
||||||
|
} fs_T;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void* buffer;
|
void* buffer;
|
||||||
uint64_t buffer_size;
|
uint64_t buffer_size;
|
||||||
|
@ -44,6 +55,9 @@ struct vfs_node_T{
|
||||||
char name[VFS_MAX_NAME_LENGTH];
|
char name[VFS_MAX_NAME_LENGTH];
|
||||||
vfs_node_type_E type;
|
vfs_node_type_E type;
|
||||||
vfs_node_cache_T* cache;
|
vfs_node_cache_T* cache;
|
||||||
|
uint64_t size;
|
||||||
|
void* specific;
|
||||||
|
fs_T* filesystem;
|
||||||
|
|
||||||
vfs_node_T* prev;
|
vfs_node_T* prev;
|
||||||
vfs_node_T* next;
|
vfs_node_T* next;
|
||||||
|
@ -51,15 +65,23 @@ struct vfs_node_T{
|
||||||
vfs_node_T* childs;
|
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_cache_T* vfs_node_cache_create (vfs_node_T* node, uint64_t size);
|
||||||
vfs_node_T* vfs_node_destruct (vfs_node_T* node);
|
void vfs_node_cache_destruct (vfs_node_cache_T* node_cache);
|
||||||
|
|
||||||
|
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);
|
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_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);
|
void vfs_init (boot_info_T* boot_info);
|
||||||
vfs_node_T* vfs_resolve_path (string_t path);
|
vfs_node_T* vfs_resolve_path (fs_T* filesystem, string_t path);
|
||||||
void vfs_unpack_archive_ustar ();
|
void vfs_unpack_archive_ustar (vfs_node_T* node, void* archive);
|
||||||
|
|
||||||
#endif //NOX_VFS_H
|
#endif //NOX_VFS_H
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* Copyright (C) Antifallobst <antifallobst@systemausfall.org>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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));
|
||||||
|
}
|
|
@ -14,10 +14,31 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "drivers/fs/vfs.h"
|
#include "drivers/fs/vfs.h"
|
||||||
|
#include "drivers/fs/ramfs.h"
|
||||||
#include "utils/memory.h"
|
#include "utils/memory.h"
|
||||||
#include "utils/logger.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) {
|
void vfs_node_bring_to_parent_start(vfs_node_T* node) {
|
||||||
if (node->parent == NULL) { return; }
|
if (node->parent == NULL) { return; }
|
||||||
|
@ -44,7 +65,36 @@ void vfs_node_bring_to_parent_start(vfs_node_T* node) {
|
||||||
node->parent->childs = 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, "<VFS> failed to create node (block device cannot have childs)");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
case VFS_NODE_FILE: {
|
||||||
|
log(LOG_WARNING, "<VFS> 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, "<VFS> failed to create node (invalid parent type)");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
vfs_node_T* node = memory_allocate(sizeof(vfs_node_T));
|
vfs_node_T* node = memory_allocate(sizeof(vfs_node_T));
|
||||||
|
|
||||||
uint64_t strlen = string_length(name);
|
uint64_t strlen = string_length(name);
|
||||||
|
@ -56,6 +106,8 @@ vfs_node_T* vfs_node_create(vfs_node_T* parent, string_t name, vfs_node_type_E t
|
||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
node->type = type;
|
node->type = type;
|
||||||
node->cache = NULL;
|
node->cache = NULL;
|
||||||
|
node->specific = specific;
|
||||||
|
node->filesystem = filesystem;
|
||||||
node->childs = NULL;
|
node->childs = NULL;
|
||||||
node->prev = NULL;
|
node->prev = NULL;
|
||||||
node->next = NULL;
|
node->next = NULL;
|
||||||
|
@ -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);
|
log(LOG_NONE, "%s[file] %s", buf, node->name);
|
||||||
break;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs_init(boot_info_T* boot_info) {
|
vfs_node_T* vfs_file_create(fs_T* filesystem, string_t path) {
|
||||||
g_vfs_root_node = vfs_node_create(NULL, "root", VFS_NODE_DIRECTORY);
|
// 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) {
|
char dir_path[index];
|
||||||
if (*path != '/') {
|
memory_copy(path, dir_path, index); dir_path[index] = '\0';
|
||||||
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (no root prefix)");
|
|
||||||
|
vfs_node_T* dir_node = vfs_resolve_path(filesystem, dir_path);
|
||||||
|
if (dir_node == NULL) {
|
||||||
|
log(LOG_WARNING, "<VFS> failed to create file %s (invalid path)", path);
|
||||||
return NULL;
|
return 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) {
|
||||||
|
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, "<VFS> resolving path: %s", path);
|
||||||
|
if (*path != '/') {
|
||||||
|
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (no root prefix)", path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
path++;
|
||||||
|
|
||||||
uint32_t length;
|
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, '/');
|
length = string_find_next(path, '/');
|
||||||
|
|
||||||
char name[length];
|
char name[length];
|
||||||
|
@ -130,16 +268,35 @@ vfs_node_T* vfs_resolve_path(string_t path) {
|
||||||
|
|
||||||
node = vfs_node_resolve_child(node, name);
|
node = vfs_node_resolve_child(node, name);
|
||||||
if (node == NULL) {
|
if (node == NULL) {
|
||||||
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (node child resolve null)");
|
log(LOG_WARNING, "<VFS> failed to resolve node from invalid path '%s' (node child resolve null)", path);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
path += length;
|
path += length;
|
||||||
} while(*path != '\0');
|
|
||||||
|
switch (node->type) {
|
||||||
|
case VFS_NODE_DIRECTORY: {
|
||||||
|
path++;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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 node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vfs_unpack_archive_ustar() {
|
void vfs_unpack_archive_ustar(vfs_node_T* node, void* archive) {
|
||||||
|
|
||||||
}
|
}
|
|
@ -81,23 +81,26 @@ 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++) {
|
// for (int i = 0; i < 150; i++) {
|
||||||
log(LOG_DEBUG, "test log %d", 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);
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 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
|
CORE_HALT_FOREVER
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue