#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; 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) { kinfoln("starting to create directory %s in %s", filename, node->name); 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]; 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; }