VFS: Add basic mount(), unmount() and mkdir() functions (not accessible to userspace yet)

This commit is contained in:
apio 2022-10-11 18:23:00 +02:00
parent 1278cec065
commit 4aa3da8c12
4 changed files with 99 additions and 4 deletions

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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()

View File

@ -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
{