diff --git a/kernel/include/fs/VFS.h b/kernel/include/fs/VFS.h index 943604da..b250bed8 100644 --- a/kernel/include/fs/VFS.h +++ b/kernel/include/fs/VFS.h @@ -7,12 +7,15 @@ typedef long ssize_t; #define VFS_FILE 0x0 #define VFS_DIRECTORY 0x1 +#define VFS_MOUNTPOINT 0x1 + namespace VFS { struct Node; typedef ssize_t (*node_read)(Node*, size_t, size_t, char*); typedef Node* (*node_finddir)(Node*, const char*); + typedef int (*node_mkdir)(Node*, const char*); struct Node { @@ -20,15 +23,23 @@ namespace VFS uint64_t inode; uint64_t length; int type; + int flags; node_read read_func; node_finddir find_func; + node_mkdir mkdir_func; + Node* link; }; ssize_t read(Node* node, size_t offset, size_t length, char* buffer); + int mkdir(const char* path, const char* name); void mount_root(Node* root); Node* resolve_path(const char* filename, Node* root = nullptr); + void mount(Node* mountpoint, Node* mounted); + + void unmount(Node* mountpoint); + Node* root(); } \ No newline at end of file diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp index c5646e4a..6be9314c 100644 --- a/kernel/src/fs/VFS.cpp +++ b/kernel/src/fs/VFS.cpp @@ -90,10 +90,53 @@ VFS::Node* VFS::resolve_path(const char* filename, Node* root) kwarnln("Current node did not find our target node"); return 0; } + if (child->flags & VFS_MOUNTPOINT) + { + kdbgln("Current node (%s, inode=%ld) is a mountpoint, resolving actual node", child->name, + child->inode); + if (!child->link) + { + kwarnln("Current node's link is null"); + return 0; + } + child = child->link; + kdbgln("Resolved to %s (inode %ld)", child->name, child->inode); + } current_node = child; kfree(buffer); } filename += path_section_size; } +} + +int VFS::mkdir(const char* path, const char* name) +{ + Node* node = resolve_path(path, vfs_root); + if (!node) + { + kwarnln("Attempting to mkdir in %s, which does not exist", path); + return -1; + } + if (!node->mkdir_func) + { + kwarnln("Chosen node does not support mkdir()"); + return -1; + } + return node->mkdir_func(node, name); +} + +void VFS::mount(Node* mountpoint, Node* mounted) +{ + if (!mountpoint || !mounted) return; + if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) return; + mountpoint->link = mounted; + mountpoint->flags |= VFS_MOUNTPOINT; +} + +void VFS::unmount(Node* mountpoint) +{ + if (!mountpoint) return; + if (!(mountpoint->flags & VFS_MOUNTPOINT)) return; + mountpoint->flags &= ~VFS_MOUNTPOINT; } \ No newline at end of file diff --git a/kernel/src/init/InitRD.cpp b/kernel/src/init/InitRD.cpp index c8bce851..db4abc7e 100644 --- a/kernel/src/init/InitRD.cpp +++ b/kernel/src/init/InitRD.cpp @@ -185,6 +185,46 @@ VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename) return 0; } +int initrd_mkdir(VFS::Node* node, const char* name) // FIXME: Return proper error numbers. +{ + if (total_dirs >= 32) + { + kwarnln("mkdir() failed: too many directories"); + return -1; + } + if (node->inode > total_dirs) + { + kwarnln("mkdir() failed: invalid node"); + return -1; + } + if (!(node->type & VFS_DIRECTORY)) + { + kwarnln("mkdir() failed: not a directory"); + return -1; + } + InitRD::Directory& parent = dirs[node->inode]; + if (parent.entries == INITRD_MAX_FILES_IN_DIR) + { + kwarnln("mkdir() failed: parent is null"); + return -1; + } + uint64_t inode = total_dirs; + VFS::Node& new_node = nodes[total_nodes++]; + new_node.inode = inode; + new_node.find_func = initrd_scan_dir; + new_node.mkdir_func = initrd_mkdir; + new_node.length = 0; + new_node.type = VFS_DIRECTORY; + strncpy(new_node.name, name, sizeof(new_node.name)); + InitRD::Directory dir; + strncpy(dir.name, name, sizeof(dir.name)); + dir.entries = 0; + dirs[total_dirs++] = dir; // FIXME: Right now this isn't of worry, but there is a possibility for a TOCTOU bug here. + // Should use a spinlock or something. + parent.files[parent.entries++] = &new_node; + return 0; +} + static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode) { const char* filename = dir.name; @@ -318,11 +358,13 @@ static void initrd_initialize_root() { initrd_root.length = 0; initrd_root.inode = 0; + initrd_root.type |= VFS_DIRECTORY; InitRD::Directory& root = dirs[0]; total_dirs++; strncpy(initrd_root.name, "initrd", sizeof(initrd_root.name)); strncpy(root.name, "initrd", sizeof(root.name)); initrd_root.find_func = initrd_scan_dir; + initrd_root.mkdir_func = initrd_mkdir; } void InitRD::init() diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index daebe4b2..b209e0c9 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -164,12 +164,11 @@ extern "C" void _start() kinfoln("Trying VFS"); - VFS::Node* node = VFS::resolve_path("/sys/"); - if (!node) { kerrorln("Unable to find /sys in VFS"); } + if (VFS::mkdir("/", "rootfs") < 0) { kerrorln("Unable to create directory rootfs"); } else { - kinfoln("Found '%s'", node->name); - node = VFS::resolve_path("config", node); + VFS::mount(VFS::resolve_path("/rootfs"), VFS::root()); + VFS::Node* node = VFS::resolve_path("/rootfs/sys/config"); if (!node) kerrorln("unable to find /sys/config in VFS"); else {