VFS: Implement resolve_path and form the initial ramdisk's VFS properly
Finally, resolve_path: a function which takes a path (/etc/fstab for example), and walks the VFS: In this case, it would start with the root FS node, and ask it: "do you have a directory/file named etc?" The node could say 'yes', 'no', or 'i'm not a directory, I'm a file' (should not be the case for the VFS root, but for the other ones it could be) If it says yes, we continue and ask the child if it has a file named fstab. Etc...
This commit is contained in:
parent
2be70d0bc1
commit
bbe7c6e658
@ -21,9 +21,10 @@ namespace VFS
|
||||
};
|
||||
|
||||
ssize_t read(Node* node, size_t offset, size_t length, char* buffer);
|
||||
Node* open(const char* filename);
|
||||
|
||||
void mount_root(Node* root);
|
||||
|
||||
Node* resolve_path(const char* filename, Node* root = nullptr);
|
||||
|
||||
Node* root();
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "fs/VFS.h"
|
||||
#include "log/Log.h"
|
||||
#include "std/stdlib.h"
|
||||
#include "std/string.h"
|
||||
|
||||
static VFS::Node* vfs_root;
|
||||
@ -25,24 +26,6 @@ ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer)
|
||||
return node->read_func(node, offset, length, buffer);
|
||||
}
|
||||
|
||||
VFS::Node* VFS::open(const char* filename)
|
||||
{
|
||||
if (!vfs_root)
|
||||
{
|
||||
kwarnln("open() failed: root not mounted");
|
||||
return 0;
|
||||
}
|
||||
if (!vfs_root->find_func)
|
||||
{
|
||||
kwarnln("open() failed: root doesn't support finding files");
|
||||
return 0;
|
||||
}
|
||||
|
||||
kinfoln("open(): opening %s", filename);
|
||||
|
||||
return vfs_root->find_func(vfs_root, filename);
|
||||
}
|
||||
|
||||
void VFS::mount_root(Node* root)
|
||||
{
|
||||
if (!root)
|
||||
@ -63,3 +46,48 @@ VFS::Node* VFS::root()
|
||||
{
|
||||
return vfs_root;
|
||||
}
|
||||
|
||||
VFS::Node* VFS::resolve_path(const char* filename, Node* root)
|
||||
{
|
||||
if (!root) root = vfs_root;
|
||||
|
||||
if (strlen(filename) == 0) return 0;
|
||||
if (*filename == '/') // Absolute path.
|
||||
{
|
||||
filename++;
|
||||
root = vfs_root;
|
||||
}
|
||||
|
||||
Node* current_node = root;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return current_node; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func)
|
||||
{
|
||||
kwarnln("Current node has no way to find child nodes");
|
||||
return 0;
|
||||
}
|
||||
Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child)
|
||||
{
|
||||
kwarnln("Current node did not find our target node");
|
||||
return 0;
|
||||
}
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
@ -115,10 +115,52 @@ void InitRD::for_each(void (*callback)(File& f))
|
||||
}
|
||||
}
|
||||
|
||||
#define INITRD_MAX_FILES_IN_DIR 8
|
||||
#define INITRD_MAX_FILES 32
|
||||
|
||||
namespace InitRD
|
||||
{
|
||||
struct Directory
|
||||
{
|
||||
char name[64];
|
||||
int entries = 0;
|
||||
VFS::Node* files[INITRD_MAX_FILES_IN_DIR];
|
||||
};
|
||||
}
|
||||
|
||||
void initrd_for_each_dir(void (*callback)(InitRD::Directory& f))
|
||||
{
|
||||
uint64_t block = 0;
|
||||
uint64_t total_blocks = InitRD::get_total_blocks();
|
||||
while (block < total_blocks)
|
||||
{
|
||||
InitRD::TarHeader* hdr = (InitRD::TarHeader*)InitRD::get_block(block);
|
||||
if (!InitRD::is_valid_header(hdr))
|
||||
{
|
||||
block++;
|
||||
continue;
|
||||
}
|
||||
if (hdr->typeflag == 53)
|
||||
{
|
||||
InitRD::Directory dir;
|
||||
strncpy(dir.name, hdr->name, sizeof(dir.name));
|
||||
callback(dir);
|
||||
block++;
|
||||
continue;
|
||||
}
|
||||
auto f = get_file(hdr);
|
||||
block += get_file_size_in_blocks(f) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static InitRD::File files[32];
|
||||
static uint32_t total_files = 0;
|
||||
|
||||
static VFS::Node nodes[32];
|
||||
static InitRD::Directory dirs[32];
|
||||
static uint32_t total_dirs = 0;
|
||||
|
||||
static VFS::Node nodes[63]; // One of the dirs is the initrd_root
|
||||
static uint32_t total_nodes = 0;
|
||||
|
||||
ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
|
||||
{
|
||||
@ -131,30 +173,154 @@ ssize_t initrd_read(VFS::Node* node, size_t offset, size_t length, char* buffer)
|
||||
return length;
|
||||
}
|
||||
|
||||
VFS::Node* initrd_scan_root(VFS::Node*, const char* filename)
|
||||
VFS::Node* initrd_scan_dir(VFS::Node* node, const char* filename)
|
||||
{
|
||||
for (uint32_t i = 0; i < total_files; i++)
|
||||
if (!node) return 0;
|
||||
if (node->inode >= total_dirs) return 0;
|
||||
InitRD::Directory dir = dirs[node->inode];
|
||||
for (int i = 0; i < dir.entries; i++)
|
||||
{
|
||||
if (strncmp(nodes[i].name, filename, sizeof(VFS::Node::name)) == 0) { return &nodes[i]; }
|
||||
if (strncmp(dir.files[i]->name, filename, sizeof(VFS::Node::name)) == 0) { return dir.files[i]; }
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initrd_scan()
|
||||
static bool initrd_register_dir(InitRD::Directory& dir, uint64_t inode)
|
||||
{
|
||||
const char* filename = dir.name;
|
||||
VFS::Node* current_node = &initrd_root;
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return false; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (filename[path_section_size]) // We are in a '/'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func) { return false; }
|
||||
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child) { return false; }
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||
|
||||
if (!current_node->find_func) { return false; }
|
||||
|
||||
InitRD::Directory& parent = dirs[current_node->inode];
|
||||
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
|
||||
VFS::Node& node = nodes[total_nodes++];
|
||||
node.inode = inode;
|
||||
node.find_func = initrd_scan_dir;
|
||||
node.length = 0;
|
||||
strncpy(node.name, buffer, sizeof(node.name));
|
||||
strncpy(dir.name, buffer, sizeof(dir.name));
|
||||
|
||||
parent.files[parent.entries++] = &node;
|
||||
|
||||
kfree(buffer);
|
||||
return true;
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
||||
|
||||
static bool initrd_register_file(InitRD::File& f, uint64_t inode)
|
||||
{
|
||||
const char* filename = f.name;
|
||||
VFS::Node* current_node = &initrd_root;
|
||||
while (true)
|
||||
{
|
||||
while (*filename == '/') { filename++; }
|
||||
if (*filename == 0) { return false; }
|
||||
|
||||
size_t path_section_size = 0;
|
||||
while (filename[path_section_size] && filename[path_section_size] != '/') { path_section_size++; }
|
||||
|
||||
if (filename[path_section_size]) // We are in a '/'
|
||||
{
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
if (!current_node->find_func) { return false; }
|
||||
VFS::Node* child = current_node->find_func(current_node, buffer);
|
||||
if (!child) { return false; }
|
||||
current_node = child;
|
||||
kfree(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(filename, ".", path_section_size) != 0) // The current path section is not '.'
|
||||
{
|
||||
if (strncmp(filename, "..", path_section_size) == 0) { return false; }
|
||||
|
||||
if (!current_node->find_func) { return false; }
|
||||
|
||||
InitRD::Directory& parent = dirs[current_node->inode];
|
||||
if (parent.entries == INITRD_MAX_FILES_IN_DIR) { return false; }
|
||||
|
||||
char* buffer = (char*)kmalloc(path_section_size + 1);
|
||||
memcpy(buffer, filename, path_section_size);
|
||||
buffer[path_section_size] = 0;
|
||||
|
||||
VFS::Node& node = nodes[total_nodes++];
|
||||
node.inode = inode;
|
||||
node.read_func = initrd_read;
|
||||
node.length = f.size;
|
||||
strncpy(node.name, buffer, sizeof(node.name));
|
||||
strncpy(f.name, buffer, sizeof(f.name));
|
||||
|
||||
parent.files[parent.entries++] = &node;
|
||||
kfree(buffer);
|
||||
return true;
|
||||
}
|
||||
else { return false; }
|
||||
}
|
||||
|
||||
filename += path_section_size;
|
||||
}
|
||||
}
|
||||
|
||||
static void initrd_scan()
|
||||
{
|
||||
initrd_for_each_dir([](InitRD::Directory& dir) {
|
||||
if (total_dirs >= 32) return;
|
||||
uint64_t inode = total_dirs;
|
||||
if (initrd_register_dir(dir, inode)) dirs[total_dirs++] = dir;
|
||||
});
|
||||
InitRD::for_each([](InitRD::File& f) {
|
||||
if (total_files >= 32) return;
|
||||
kdbgln("registering file %s", f.name);
|
||||
files[total_files++] = f;
|
||||
uint64_t inode = total_files;
|
||||
if (initrd_register_file(f, inode)) files[total_files++] = f;
|
||||
});
|
||||
for (uint32_t i = 0; i < total_files; i++)
|
||||
{
|
||||
VFS::Node& node = nodes[i];
|
||||
node.inode = i;
|
||||
node.read_func = initrd_read;
|
||||
node.length = files[i].size;
|
||||
strncpy(node.name, files[i].name, sizeof(node.name));
|
||||
}
|
||||
}
|
||||
|
||||
static void initrd_initialize_root()
|
||||
{
|
||||
initrd_root.length = 0;
|
||||
initrd_root.inode = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
void InitRD::init()
|
||||
@ -163,12 +329,8 @@ void InitRD::init()
|
||||
MemoryManager::get_unaligned_mappings((void*)bootboot.initrd_ptr, bootboot.initrd_size / PAGE_SIZE + 1);
|
||||
kdbgln("physical base at %lx, size %lx, mapped to %p", bootboot.initrd_ptr, bootboot.initrd_size, initrd_base);
|
||||
kdbgln("total blocks: %ld", get_total_blocks());
|
||||
initrd_initialize_root();
|
||||
initrd_scan();
|
||||
initrd_root.length = 0;
|
||||
initrd_root.inode = (uint64_t)-1;
|
||||
strncpy(initrd_root.name, "initrd", 7);
|
||||
initrd_root.find_func = initrd_scan_root;
|
||||
VFS::mount_root(&initrd_root);
|
||||
kdbgln("mounted initrd at VFS root, total files: %d", total_files);
|
||||
initrd_initialized = true;
|
||||
}
|
@ -162,8 +162,13 @@ extern "C" void _start()
|
||||
|
||||
kinfoln("Trying VFS");
|
||||
|
||||
VFS::Node* node = VFS::open("sys/config");
|
||||
if (!node) { kerrorln("Unable to find file in VFS"); }
|
||||
VFS::Node* node = VFS::resolve_path("/sys/");
|
||||
if (!node) { kerrorln("Unable to find /sys in VFS"); }
|
||||
else
|
||||
{
|
||||
kinfoln("Found '%s'", node->name);
|
||||
node = VFS::resolve_path("config", node);
|
||||
if (!node) kerrorln("unable to find /sys/config in VFS");
|
||||
else
|
||||
{
|
||||
kinfoln("Found '%s'", node->name);
|
||||
@ -174,6 +179,7 @@ extern "C" void _start()
|
||||
kinfoln("Read: %s", buffer);
|
||||
kfree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
PCI::scan([](PCI::Device& dev) {
|
||||
kinfoln("Found PCI device %x:%x, %s", dev.id().vendor, dev.id().device, pci_type_name(dev.type()));
|
||||
|
Loading…
Reference in New Issue
Block a user