Luna/kernel/src/fs/TmpFS.cpp

207 lines
5.6 KiB
C++

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