summaryrefslogtreecommitdiff
path: root/kernel/src/generic/tmpfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/src/generic/tmpfs.cpp')
-rw-r--r--kernel/src/generic/tmpfs.cpp306
1 files changed, 306 insertions, 0 deletions
diff --git a/kernel/src/generic/tmpfs.cpp b/kernel/src/generic/tmpfs.cpp
new file mode 100644
index 0000000..650fda3
--- /dev/null
+++ b/kernel/src/generic/tmpfs.cpp
@@ -0,0 +1,306 @@
+#include <cstdint>
+#include <generic/tmpfs.hpp>
+#include <generic/pmm.hpp>
+#include <generic/hhdm.hpp>
+#include <generic/vfs.hpp>
+#include <klibc/string.hpp>
+#include <utils/errno.hpp>
+#include <utils/assert.hpp>
+#include <atomic>
+
+tmpfs::tmpfs_node root_node = {};
+std::atomic<std::uint64_t> tmpfs_id_ptr = 1;
+
+bool tmpfs_find_child(tmpfs::tmpfs_node* node, char* name, tmpfs::tmpfs_node** out) {
+ if(node->type != vfs_file_type::directory)
+ return false;
+
+ for(std::uint64_t i = 0;i < node->size / sizeof(std::uint64_t);i++ ) {
+
+ if(node->directory_content[i] == nullptr)
+ continue;
+
+ if(klibc::strcmp(node->directory_content[i]->name, name) == 0) {
+ *out = node->directory_content[i];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+tmpfs::tmpfs_node* tmpfs_lookup(char* path) {
+ if(klibc::strcmp(path,"/\0") == 0)
+ return &root_node;
+
+ tmpfs::tmpfs_node* current_node = &root_node;
+
+ char path_copy[4096];
+ klibc::memcpy(path_copy, path, klibc::strlen(path) + 1);
+
+ char* saveptr;
+ char* token = klibc::strtok(&saveptr, path_copy, "/");
+
+ while (token != nullptr) {
+ bool status = tmpfs_find_child(current_node, token, &current_node);
+ if(status == false)
+ return nullptr;
+ token = klibc::strtok(&saveptr, nullptr, "/");
+ }
+ return current_node;
+}
+
+tmpfs::tmpfs_node* tmpfs_get_parent(char* path) {
+ if (klibc::strcmp(path, "/") == 0 || klibc::strlen(path) == 0) {
+ return nullptr;
+ }
+
+ char path_copy[4096];
+ klibc::memcpy(path_copy, path, klibc::strlen(path) + 1);
+
+ char* last_slash = nullptr;
+ for (int i = 0; path_copy[i] != '\0'; i++) {
+ if (path_copy[i] == '/') {
+ last_slash = &path_copy[i];
+ }
+ }
+
+ if (last_slash == nullptr)
+ return &root_node;
+
+ if (last_slash == path_copy)
+ return &root_node;
+
+ *last_slash = '\0';
+ return tmpfs_lookup(path_copy);
+}
+
+char* tmpfs_get_name_from_path(char* path) {
+ if (path[0] == '\0') return path;
+ if (klibc::strcmp(path, "/") == 0) return path;
+
+ char* last_slash = nullptr;
+ int i = 0;
+
+ while (path[i] != '\0') {
+ if (path[i] == '/') {
+ last_slash = &path[i];
+ }
+ i++;
+ }
+
+ if (last_slash == nullptr)
+ return path;
+
+ return last_slash + 1;
+}
+
+std::int32_t tmpfs_readlink(filesystem* fs, char* path, char* buffer) {
+ fs->lock.lock();
+ tmpfs::tmpfs_node* node = tmpfs_lookup(path);
+ if(node == nullptr) { fs->lock.unlock();
+ return -ENOENT; }
+
+ if(node->type != vfs_file_type::symlink) { fs->lock.unlock();
+ return -EINVAL; }
+
+ assert(node->content,"meeeow meeeeeow :3");
+
+ klibc::memcpy(buffer, node->content, 4096);
+
+ fs->lock.unlock();
+ return 0;
+}
+
+signed long tmpfs_ls(file_descriptor* file, char* out, std::size_t count) {
+ file->vnode.fs->lock.lock();
+ auto node = (tmpfs::tmpfs_node*)file->fs_specific.tmpfs_pointer;
+
+ std::size_t current_offset = 0;
+ dirent file_ls = {};
+
+ if(node->type != vfs_file_type::directory)
+ return -ENOTDIR;
+
+again:
+
+ if(file->offset >= node->size) {
+ file->vnode.fs->lock.unlock();
+ return 0;
+ }
+
+ while(true) {
+ auto current_node = node->directory_content[file->offset];
+ if(sizeof(dirent) + klibc::strlen(current_node->name) + 1 > count - current_offset) {
+ file->vnode.fs->lock.unlock();
+ return current_offset;
+ }
+
+ file->offset += sizeof(tmpfs::tmpfs_node**);
+
+ if(current_node == nullptr)
+ goto again;
+
+ dirent* current_dir = (dirent*)(out + current_offset);
+ current_dir->d_ino = current_node->ino;
+ current_dir->d_type = vfs_to_dt_type(current_node->type);
+ current_dir->d_reclen = sizeof(dirent) + klibc::strlen(current_node->name) + 1;
+ current_dir->d_off = 0;
+ current_offset += current_dir->d_reclen;
+
+ }
+
+ file->vnode.fs->lock.unlock();
+ return 0;
+}
+
+std::int32_t tmpfs_create(filesystem* fs, char* path, vfs_file_type type, std::uint32_t mode) {
+ fs->lock.lock();
+ tmpfs::tmpfs_node* parent = tmpfs_get_parent(path);
+
+ if(parent == nullptr) { fs->lock.unlock();
+ return -ENOENT; }
+
+ parent->size += sizeof(tmpfs::tmpfs_node*);
+
+ if(parent->physical_size < parent->size) {
+ alloc_t res = pmm::buddy::alloc(parent->size * sizeof(tmpfs::tmpfs_node*));
+ tmpfs::tmpfs_node** new_dir = (tmpfs::tmpfs_node**)(res.phys + etc::hhdm());
+ klibc::memcpy(new_dir, parent->directory_content, parent->size);
+ pmm::buddy::free((std::uint64_t)parent->directory_content - etc::hhdm());
+ parent->directory_content = new_dir;
+ parent->physical_size = res.real_size;
+ }
+
+ tmpfs::tmpfs_node* new_node = (tmpfs::tmpfs_node*)(pmm::freelist::alloc_4k() + etc::hhdm());
+
+ new_node->type = type;
+ new_node->ino = tmpfs_id_ptr++;
+ new_node->mode = mode;
+ klibc::memcpy(new_node->name, tmpfs_get_name_from_path(path), klibc::strlen(tmpfs_get_name_from_path(path)) + 1);
+
+ parent->directory_content[(parent->size / sizeof(tmpfs::tmpfs_node**)) - 1] = new_node;
+
+ fs->lock.unlock();
+ return 0;
+}
+
+signed long tmpfs_read(file_descriptor* file, void* buffer, std::size_t count) {
+ file->vnode.fs->lock.lock();
+ tmpfs::tmpfs_node* node = (tmpfs::tmpfs_node*)(file->fs_specific.tmpfs_pointer);
+ if(node->type == vfs_file_type::directory) { file->vnode.fs->lock.unlock();
+ return -EISDIR; }
+
+ if(file->offset >= node->size || node->content == nullptr) {
+ file->vnode.fs->lock.unlock();
+ return 0;
+ }
+
+ std::size_t available = node->size - file->offset;
+ std::size_t to_read = (count > available) ? available : count;
+ klibc::memcpy(buffer, node->content + file->offset, to_read);
+ file->offset += to_read;
+
+ file->vnode.fs->lock.unlock();
+ return to_read;
+}
+
+signed long tmpfs_write(file_descriptor* file, void* buffer, std::size_t count) {
+ file->vnode.fs->lock.lock();
+ tmpfs::tmpfs_node* node = (tmpfs::tmpfs_node*)(file->fs_specific.tmpfs_pointer);
+ if(node->type == vfs_file_type::directory) { file->vnode.fs->lock.unlock();
+ return -EISDIR; }
+
+ if(file->offset + count > node->physical_size || node->content == nullptr) {
+ alloc_t new_content = pmm::buddy::alloc(file->offset + count);
+ char* new_cont = (char*)(new_content.phys + etc::hhdm());
+ if(node->content) {
+ klibc::memcpy(new_cont, node->content, node->size);
+ pmm::buddy::free((std::uint64_t)node->content - etc::hhdm());
+ }
+ node->content = new_cont;
+ node->physical_size = new_content.real_size;
+ }
+
+ if(file->offset + count > node->size)
+ node->size = file->offset + count;
+
+ klibc::memcpy(node->content + file->offset, buffer, count);
+
+ file->offset += count;
+ file->vnode.fs->lock.unlock();
+ return count;
+}
+
+inline static std::int32_t type_to_mode(vfs_file_type type) {
+ switch (type)
+ {
+
+ case vfs_file_type::directory:
+ return S_IFDIR;
+
+ case vfs_file_type::file:
+ return S_IFREG;
+
+ case vfs_file_type::symlink:
+ return S_IFLNK;
+
+ default:
+ assert(0,"say gex");
+ }
+}
+
+std::int32_t tmpfs_stat(file_descriptor* file, stat* out) {
+ file->vnode.fs->lock.lock();
+ tmpfs::tmpfs_node* node = (tmpfs::tmpfs_node*)file->fs_specific.tmpfs_pointer;
+ out->st_gid = 0;
+ out->st_uid = 0;
+ out->st_rdev = 0;
+ out->st_blksize = PAGE_SIZE;
+ out->st_blocks = node->physical_size / PAGE_SIZE;
+ out->st_mode = type_to_mode(node->type) | node->mode;
+ out->st_size = node->size;
+ out->st_ino = node->ino;
+ file->vnode.fs->lock.unlock();
+ return 0;
+}
+
+std::int32_t tmpfs_open(filesystem* fs, void* file_desc, char* path, bool is_directory) {
+ fs->lock.lock();
+ tmpfs::tmpfs_node* node = tmpfs_lookup(path);
+ if(node == nullptr) { fs->lock.unlock();
+ return -ENOENT; }
+
+ if(is_directory && node->type != vfs_file_type::directory) { fs->lock.unlock();
+ return -ENOTDIR; }
+
+ file_descriptor* fd = (file_descriptor*)file_desc;
+
+ fd->vnode.fs = fs;
+ fd->vnode.stat = tmpfs_stat;
+ fd->vnode.read = tmpfs_read;
+ fd->vnode.write = tmpfs_write;
+ fd->vnode.ls = tmpfs_ls;
+ fd->fs_specific.tmpfs_pointer = (std::uint64_t)node;
+
+ fs->lock.unlock();
+ return 0;
+}
+
+void tmpfs::init_default(vfs::node* node) {
+ filesystem* new_fs = new filesystem;
+ node->fs = new_fs;
+ node->fs->open = tmpfs_open;
+ node->fs->create = tmpfs_create;
+ node->fs->readlink = tmpfs_readlink;
+ klibc::memcpy(node->path, "/tmp/\0\0", sizeof("/tmp/\0\0") + 1);
+
+ alloc_t root_alloc = pmm::buddy::alloc(PAGE_SIZE);
+
+ root_node.size = 0;
+ root_node.physical_size = root_alloc.real_size;
+ klibc::memcpy(root_node.name, "/\0", sizeof("/\0") + 1);
+ root_node.directory_content = (tmpfs::tmpfs_node**)(root_alloc.phys + etc::hhdm());
+ log("tmpfs", "root_node is 0x%p",&root_node);
+
+} \ No newline at end of file