diff --git a/kernel/include/fs/TmpFS.h b/kernel/include/fs/TmpFS.h new file mode 100644 index 00000000..4411389e --- /dev/null +++ b/kernel/include/fs/TmpFS.h @@ -0,0 +1,59 @@ +#pragma once +#include "fs/VFS.h" + +namespace TmpFSImpl +{ + ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); + ssize_t write(VFS::Node* node, size_t offset, size_t size, char* buffer); + VFS::Node* find(VFS::Node* node, const char* filename); + VFS::Node* readdir(VFS::Node* node, long index); + int mkdir(VFS::Node* node, const char* filename, mode_t mode); +} + +class TmpFS +{ + public: + VFS::Node* root() + { + return m_root; + } + + static TmpFS* create(const char* name); + static void release(TmpFS* fs); + + ssize_t read(VFS::Node* node, size_t offset, size_t size, char* buffer); + ssize_t write(VFS::Node* node, size_t offset, size_t size, char* buffer); + + VFS::Node* find(VFS::Node* node, const char* filename); + VFS::Node* readdir(VFS::Node* node, long index); + + int mkdir(VFS::Node* node, const char* filename, mode_t mode); + + void purge(); + + private: + struct File + { + char* buf; + size_t len; + int valid; + }; + + struct Directory + { + VFS::Node* buf; + size_t len; + int valid; + }; + + template struct Array + { + T* buf; + size_t len; + }; + + TmpFS(const char* name); + Array m_files; + Array m_dirs; + VFS::Node* m_root; +}; \ No newline at end of file diff --git a/kernel/src/fs/TmpFS.cpp b/kernel/src/fs/TmpFS.cpp new file mode 100644 index 00000000..f1ff2802 --- /dev/null +++ b/kernel/src/fs/TmpFS.cpp @@ -0,0 +1,208 @@ +#define MODULE "tmpfs" + +#include "fs/TmpFS.h" +#include "log/Log.h" +#include "std/errno.h" +#include "std/stdlib.h" +#include "std/string.h" + +ssize_t TmpFSImpl::read(VFS::Node* node, size_t offset, size_t size, char* buffer) +{ + if (!node) return -1; + if (!node->impl) return -1; + return ((TmpFS*)node->impl)->read(node, offset, size, buffer); +} + +ssize_t TmpFSImpl::write(VFS::Node* node, size_t offset, size_t size, char* buffer) +{ + if (!node) return -1; + if (!node->impl) return -1; + return ((TmpFS*)node->impl)->write(node, offset, size, buffer); +} + +VFS::Node* TmpFSImpl::find(VFS::Node* node, const char* filename) +{ + if (!node) return 0; + if (!node->impl) return 0; + return ((TmpFS*)node->impl)->find(node, filename); +} + +VFS::Node* TmpFSImpl::readdir(VFS::Node* node, long index) +{ + if (!node) return 0; + if (!node->impl) return 0; + return ((TmpFS*)node->impl)->readdir(node, index); +} + +int TmpFSImpl::mkdir(VFS::Node* node, const char* filename, mode_t mode) +{ + if (!node) return -1; + if (!node->impl) return -1; + return ((TmpFS*)node->impl)->mkdir(node, filename, mode); +} + +TmpFS* TmpFS::create(const char* name) +{ + return new TmpFS(name); +} + +void TmpFS::release(TmpFS* fs) +{ + fs->purge(); + kfree(fs->m_dirs.buf); + delete fs->root(); + delete fs; +} + +extern uint64_t clock_now(); + +TmpFS::TmpFS(const char* name) +{ + m_root = new VFS::Node; + memset(m_root, 0, sizeof(VFS::Node)); + m_root->atime = m_root->ctime = m_root->mtime = clock_now(); + m_root->impl = (uint64_t)this; + m_root->inode = 0; + m_root->gid = m_root->uid = 0; + m_root->mode = 0755; + m_root->length = 0; + m_root->type = VFS_DIRECTORY; + m_root->tty = 0; + m_root->readdir_func = TmpFSImpl::readdir; + m_root->find_func = TmpFSImpl::find; + m_root->mkdir_func = TmpFSImpl::mkdir; + m_root->flags = 0; + strlcpy(m_root->name, name, sizeof(m_root->name)); + m_dirs.buf = (Directory*)krealloc(nullptr, sizeof(Directory)); + m_dirs.len = 1; + m_dirs.buf[0] = {nullptr, 0, 1}; +} + +void TmpFS::purge() +{ + for (size_t i = 0; i < m_dirs.len; i++) + { + if (m_dirs.buf[i].valid && m_dirs.buf[i].len) kfree(m_dirs.buf[i].buf); + } + + m_dirs.buf = (Directory*)krealloc(m_dirs.buf, sizeof(Directory)); // leave space for the root directory + + for (size_t i = 0; i < m_files.len; i++) + { + if (m_files.buf[i].valid && m_files.buf[i].len) kfree(m_files.buf[i].buf); + } + + kfree(m_files.buf); +} + +ssize_t TmpFS::read(VFS::Node* node, size_t offset, size_t size, char* buffer) +{ + if (!node) return -1; + if (node->inode >= m_files.len) return -1; + File& file = m_files.buf[node->inode]; + if (!file.valid) return -1; + if (offset > file.len) return 0; + if (offset + size > file.len) { size = file.len - offset; } + memcpy(buffer, (void*)(file.buf + offset), size); + return size; +} + +ssize_t TmpFS::write(VFS::Node* node, size_t offset, size_t size, char* buffer) +{ + if (!node) return -1; + if (node->inode >= m_files.len) return -1; + File& file = m_files.buf[node->inode]; + if (!file.valid) return -1; + if (offset + size > file.len) + { + char* newbuf = (char*)krealloc(file.buf, offset + size); + if (!newbuf) { size = file.len - offset; } + else + { + file.buf = newbuf; + file.len = offset + size; + node->length = file.len; + } + } + memcpy((void*)(file.buf + offset), buffer, size); + return size; +} + +VFS::Node* TmpFS::find(VFS::Node* node, const char* filename) +{ + if (!node) return 0; + if (node->inode >= m_dirs.len) return 0; + Directory& dir = m_dirs.buf[node->inode]; + if (!dir.valid) return 0; + for (size_t i = 0; i < dir.len; i++) + { + if (!strncmp(dir.buf[i].name, filename, sizeof(dir.buf[i].name))) { return &dir.buf[i]; } + } + return 0; +} + +VFS::Node* TmpFS::readdir(VFS::Node* node, long index) +{ + if (!node) return 0; + if (node->inode >= m_dirs.len) return 0; + Directory& dir = m_dirs.buf[node->inode]; + if (!dir.valid) return 0; + if (index >= (long)dir.len) return 0; + return &dir.buf[index]; +} + +int TmpFS::mkdir(VFS::Node* node, const char* filename, mode_t mode) +{ + if (!node) return 0; + if (node->inode >= m_dirs.len) return 0; + Directory& dir = m_dirs.buf[node->inode]; + if (!dir.valid) return 0; + + kinfoln("creating directory %s in %s", filename, node->name); + + size_t new_len = m_dirs.len + 1; + Directory* new_buf = (Directory*)krealloc(m_dirs.buf, new_len); + if (!new_buf) return -ENOMEM; + + m_dirs.len = new_len; + m_dirs.buf = new_buf; + + uint64_t new_inode = m_dirs.len - 1; + + m_dirs.buf[new_inode].valid = 0; + + size_t new_dir_len = dir.len + 1; + VFS::Node* new_dir_buf = (VFS::Node*)krealloc(dir.buf, new_dir_len); + if (!new_dir_buf) return -ENOMEM; + + m_dirs.buf[new_inode].valid = 1; + m_dirs.buf[new_inode].len = 0; + m_dirs.buf[new_inode].buf = nullptr; + + dir.buf = new_dir_buf; + dir.len = new_dir_len; + + node->mtime = clock_now(); + node->ctime = clock_now(); + node->length++; + + VFS::Node* new_node = &dir.buf[dir.len - 1]; + + memset(new_node, 0, sizeof(VFS::Node)); + + new_node->inode = new_inode; + new_node->atime = new_node->ctime = new_node->mtime = clock_now(); + new_node->impl = (uint64_t)this; + new_node->gid = new_node->uid = 0; + new_node->mode = mode; + new_node->length = 0; + new_node->type = VFS_DIRECTORY; + new_node->tty = 0; + new_node->readdir_func = TmpFSImpl::readdir; + new_node->find_func = TmpFSImpl::find; + new_node->mkdir_func = TmpFSImpl::mkdir; + new_node->flags = 0; + strlcpy(new_node->name, filename, sizeof(new_node->name)); + + return 0; +} \ No newline at end of file diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp index ef0deae2..0a61980a 100644 --- a/kernel/src/fs/VFS.cpp +++ b/kernel/src/fs/VFS.cpp @@ -25,12 +25,12 @@ ssize_t VFS::read(Node* node, size_t offset, size_t length, char* buffer) } if (node->type == VFS_DIRECTORY) { - kwarnln("read() failed: is a directory"); + kwarnln("read() failed for %s: is a directory", node->name); return -EISDIR; } if (!node->read_func) { - kwarnln("read() failed: the chosen node doesn't support reading"); + kwarnln("read() failed for %s: the chosen node doesn't support reading", node->name); return -1; } @@ -46,12 +46,12 @@ ssize_t VFS::write(Node* node, size_t offset, size_t length, const char* buffer) } if (node->type == VFS_DIRECTORY) { - kwarnln("write() failed: is a directory"); + kwarnln("write() failed for %s: is a directory", node->name); return -EISDIR; } if (!node->write_func) { - kwarnln("write() failed: the chosen node doesn't support writing"); + kwarnln("write() failed for %s: the chosen node doesn't support writing", node->name); return -1; } @@ -107,7 +107,7 @@ VFS::Node* VFS::resolve_path(const char* filename, Node* root) buffer[path_section_size] = 0; if (!current_node->find_func) { - kwarnln("Current node has no way to find child nodes"); + kwarnln("Current node %s has no way to find child nodes", current_node->name); return 0; } Node* child = current_node->find_func(current_node, buffer); @@ -239,8 +239,16 @@ bool VFS::exists(const char* pathname) void VFS::mount(Node* mountpoint, Node* mounted) { - if (!mountpoint || !mounted) return; - if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) return; + if (!mountpoint || !mounted) + { + kinfoln("mount failed: invalid pointers"); + return; + } + if (mountpoint->flags & VFS_MOUNTPOINT || mounted->flags & VFS_MOUNTPOINT) + { + kinfoln("mount failed: already a mountpoint"); + return; + } mountpoint->link = mounted; mountpoint->flags |= VFS_MOUNTPOINT; } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index ab5c3751..131b7ab8 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -2,6 +2,7 @@ #include "config.h" #include "cpu/CPU.h" +#include "fs/TmpFS.h" #include "fs/devices/DeviceFS.h" #include "gdt/GDT.h" #include "init/Init.h" @@ -69,6 +70,8 @@ extern "C" void _start() ASSERT(VFS::mkdir("/dev") == 0); VFS::mount("/dev", DeviceFS::get()); + ASSERT(VFS::mkdir("/tmp") == 0); + VFS::mount("/tmp", TmpFS::create("tmp")->root()); Init::finish_kernel_boot(); diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 8248095d..edcce627 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -43,6 +43,7 @@ template void sched_for_each_task(Callback callback) bool will_continue = callback(task); if (!will_continue) break; task = task->next_task; + if (!task) break; } while (task != base_task); } @@ -369,6 +370,7 @@ void Scheduler::reap_tasks() static void sched_decrement_sleep_times() { sched_for_each_task([](Task* task) { + if (!task) return false; if (task->task_sleep > 0) { task->task_sleep -= frequency;