|
@@ -1,16 +1,18 @@
|
|
|
#include <kernel/errno.h>
|
|
|
#include <kernel/mem.h>
|
|
|
#include <kernel/stdio.h>
|
|
|
+#include <kernel/syscall.hpp>
|
|
|
#include <kernel/tty.h>
|
|
|
-#include <kernel/vfs.h>
|
|
|
+#include <kernel/vfs.hpp>
|
|
|
#include <types/allocator.hpp>
|
|
|
#include <types/list.hpp>
|
|
|
+#include <types/status.h>
|
|
|
+#include <types/stdint.h>
|
|
|
#include <types/string.hpp>
|
|
|
#include <types/vector.hpp>
|
|
|
|
|
|
using types::allocator_traits;
|
|
|
using types::kernel_allocator;
|
|
|
-using types::list;
|
|
|
using types::string;
|
|
|
using types::vector;
|
|
|
|
|
@@ -19,328 +21,369 @@ struct tmpfs_file_entry {
|
|
|
char filename[128];
|
|
|
};
|
|
|
|
|
|
-class tmpfs {
|
|
|
-private:
|
|
|
- using inode_list_type = list<struct inode, kernel_allocator>;
|
|
|
-
|
|
|
-private:
|
|
|
- size_t m_limit;
|
|
|
- // TODO: hashtable etc.
|
|
|
- inode_list_type m_inodes;
|
|
|
- struct fs_info m_fs;
|
|
|
- size_t m_last_inode_no;
|
|
|
-
|
|
|
-protected:
|
|
|
- inline vector<struct tmpfs_file_entry>* mk_fe_vector(void)
|
|
|
- {
|
|
|
- return allocator_traits<kernel_allocator<vector<struct tmpfs_file_entry>>>::allocate_and_construct();
|
|
|
- }
|
|
|
-
|
|
|
- inline vector<char>* mk_data_vector(void)
|
|
|
- {
|
|
|
- return allocator_traits<kernel_allocator<vector<char>>>::allocate_and_construct();
|
|
|
- }
|
|
|
-
|
|
|
- inline struct inode mk_inode(unsigned int dir, unsigned int file, unsigned int mnt, void* data)
|
|
|
- {
|
|
|
- struct inode i { };
|
|
|
- i.flags.directory = dir;
|
|
|
- i.flags.file = file;
|
|
|
- i.flags.mount_point = mnt;
|
|
|
- i.fs = &m_fs;
|
|
|
- i.impl = data;
|
|
|
- i.ino = m_last_inode_no++;
|
|
|
- i.perm = 0777;
|
|
|
- return i;
|
|
|
- }
|
|
|
+fs::vfs::dentry::dentry(dentry* _parent, inode* _ind, const name_type& _name)
|
|
|
+ : parent(_parent)
|
|
|
+ , ind(_ind)
|
|
|
+ , flags { 0 }
|
|
|
+ , name(_name)
|
|
|
+{
|
|
|
+}
|
|
|
+fs::vfs::dentry::dentry(dentry* _parent, inode* _ind, name_type&& _name)
|
|
|
+ : parent(_parent)
|
|
|
+ , ind(_ind)
|
|
|
+ , flags { 0 }
|
|
|
+ , name(types::move(_name))
|
|
|
+{
|
|
|
+}
|
|
|
+fs::vfs::dentry::dentry(dentry&& val)
|
|
|
+ : children(types::move(val.children))
|
|
|
+ , idx_children(types::move(val.idx_children))
|
|
|
+ , parent(val.parent)
|
|
|
+ , ind(val.ind)
|
|
|
+ , flags { val.flags }
|
|
|
+ , name(types::move(val.name))
|
|
|
+{
|
|
|
+ for (auto& item : children)
|
|
|
+ item.parent = this;
|
|
|
+}
|
|
|
+fs::vfs::dentry* fs::vfs::dentry::append(inode* ind, const name_type& name)
|
|
|
+{
|
|
|
+ auto iter = children.emplace_back(this, ind, name);
|
|
|
+ idx_children.insert(iter->name, iter.ptr());
|
|
|
+ return iter.ptr();
|
|
|
+}
|
|
|
+fs::vfs::dentry* fs::vfs::dentry::append(inode* ind, name_type&& name)
|
|
|
+{
|
|
|
+ auto iter = children.emplace_back(this, ind, types::move(name));
|
|
|
+ idx_children.insert(iter->name, iter.ptr());
|
|
|
+ return iter.ptr();
|
|
|
+}
|
|
|
+fs::vfs::dentry* fs::vfs::dentry::find(const name_type& name)
|
|
|
+{
|
|
|
+ if (ind->flags.in.directory && !flags.in.present)
|
|
|
+ ind->fs->load_dentry(this);
|
|
|
|
|
|
-public:
|
|
|
- explicit tmpfs(size_t limit);
|
|
|
- void mklink(struct inode* dir, struct inode* inode, const char* filename);
|
|
|
- void mkfile(struct inode* dir, const char* filename);
|
|
|
- void mkdir(struct inode* dir, const char* dirname);
|
|
|
- size_t read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
|
|
|
- size_t write(struct inode* file, const char* buf, size_t offset, size_t n);
|
|
|
- int readdir(struct inode* dir, struct dirent* entry, size_t i);
|
|
|
- struct inode* findinode(struct inode* dir, const char* filename);
|
|
|
- int stat(struct inode* dir, struct stat* stat, const char* filename);
|
|
|
-
|
|
|
- struct inode* root_inode(void)
|
|
|
- {
|
|
|
- return &*m_inodes.begin();
|
|
|
+ auto iter = idx_children.find(name);
|
|
|
+ if (!iter) {
|
|
|
+ errno = ENOTFOUND;
|
|
|
+ return nullptr;
|
|
|
}
|
|
|
-};
|
|
|
|
|
|
-size_t tmpfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
|
|
|
+ return iter->value;
|
|
|
+}
|
|
|
+fs::vfs::dentry* fs::vfs::dentry::replace(dentry* val)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(file->fs->impl);
|
|
|
- return fs->read(file, buf, buf_size, offset, n);
|
|
|
+ // TODO: prevent the dirent to be swapped out of memory
|
|
|
+ parent->idx_children.find(this->name)->value = val;
|
|
|
+ return this;
|
|
|
}
|
|
|
-size_t tmpfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
|
|
|
+void fs::vfs::dentry::invalidate(void)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(file->fs->impl);
|
|
|
- return fs->write(file, buf, offset, n);
|
|
|
+ // TODO: write back
|
|
|
+ flags.in.dirty = 0;
|
|
|
+ children.clear();
|
|
|
+ idx_children.clear();
|
|
|
+ flags.in.present = 0;
|
|
|
}
|
|
|
-int tmpfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
|
|
|
+fs::vfs::vfs(void)
|
|
|
+ : _last_inode_no(0)
|
|
|
+ , _root(nullptr, nullptr, "/")
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
- return fs->readdir(dir, entry, i);
|
|
|
}
|
|
|
-struct inode* tmpfs_findinode(struct inode* dir, const char* filename)
|
|
|
+fs::ino_t fs::vfs::_assign_inode_id(void)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
- return fs->findinode(dir, filename);
|
|
|
+ return ++_last_inode_no;
|
|
|
}
|
|
|
-int tmpfs_mkfile(struct inode* dir, const char* filename)
|
|
|
+fs::inode* fs::vfs::cache_inode(inode_flags flags, uint32_t perm, size_t size, void* impl_data)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
- fs->mkfile(dir, filename);
|
|
|
- return GB_OK;
|
|
|
+ auto iter = _inodes.emplace_back(inode { flags, perm, impl_data, _assign_inode_id(), this, size });
|
|
|
+ _idx_inodes.insert(iter->ino, iter.ptr());
|
|
|
+ return iter.ptr();
|
|
|
}
|
|
|
-// int tmpfs_rmfile(struct inode* dir, const char* filename)
|
|
|
-// {
|
|
|
-// auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
-// fs->rmfile(dir, filename);
|
|
|
-// return GB_OK;
|
|
|
-// }
|
|
|
-int tmpfs_mkdir(struct inode* dir, const char* dirname)
|
|
|
+fs::inode* fs::vfs::get_inode(ino_t ino)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
- fs->mkdir(dir, dirname);
|
|
|
- return GB_OK;
|
|
|
+ auto iter = _idx_inodes.find(ino);
|
|
|
+ // TODO: load inode from disk if not found
|
|
|
+ if (!iter)
|
|
|
+ return nullptr;
|
|
|
+ else
|
|
|
+ return iter->value;
|
|
|
}
|
|
|
-int tmpfs_stat(struct inode* dir, struct stat* stat, const char* filename)
|
|
|
+void fs::vfs::register_root_node(inode* root)
|
|
|
{
|
|
|
- auto* fs = static_cast<tmpfs*>(dir->fs->impl);
|
|
|
- return fs->stat(dir, stat, filename);
|
|
|
+ if (!_root.ind)
|
|
|
+ _root.ind = root;
|
|
|
}
|
|
|
-
|
|
|
-static const struct inode_ops tmpfs_inode_ops = {
|
|
|
- .read = tmpfs_read,
|
|
|
- .write = tmpfs_write,
|
|
|
- .readdir = tmpfs_readdir,
|
|
|
- .findinode = tmpfs_findinode,
|
|
|
- .mkfile = tmpfs_mkfile,
|
|
|
- .rmfile = 0,
|
|
|
- .mkdir = tmpfs_mkdir,
|
|
|
- .stat = tmpfs_stat,
|
|
|
-};
|
|
|
-
|
|
|
-tmpfs::tmpfs(size_t limit)
|
|
|
- : m_limit(limit)
|
|
|
- , m_fs { .ops = &tmpfs_inode_ops, .impl = this }
|
|
|
- , m_last_inode_no(0)
|
|
|
+int fs::vfs::load_dentry(dentry*)
|
|
|
+{
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
+}
|
|
|
+int fs::vfs::mount(dentry* mnt, vfs* new_fs)
|
|
|
{
|
|
|
- struct inode in = mk_inode(1, 0, 1, mk_fe_vector());
|
|
|
+ if (!mnt->ind->flags.in.directory) {
|
|
|
+ errno = ENOTDIR;
|
|
|
+ return GB_FAILED;
|
|
|
+ }
|
|
|
|
|
|
- mklink(&in, &in, ".");
|
|
|
- mklink(&in, &in, "..");
|
|
|
+ auto* new_ent = new_fs->root();
|
|
|
|
|
|
- m_inodes.push_back(in);
|
|
|
-}
|
|
|
+ new_ent->parent = mnt->parent;
|
|
|
+ new_ent->name = mnt->name;
|
|
|
|
|
|
-void tmpfs::mklink(struct inode* dir, struct inode* inode, const char* filename)
|
|
|
+ auto* orig_ent = mnt->replace(new_ent);
|
|
|
+ _mount_recover_list.insert(new_ent, orig_ent);
|
|
|
+ return GB_OK;
|
|
|
+}
|
|
|
+size_t fs::vfs::inode_read(inode*, char*, size_t, size_t, size_t)
|
|
|
{
|
|
|
- auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
|
|
|
- struct tmpfs_file_entry ent = {
|
|
|
- .ino = inode->ino,
|
|
|
- .filename = { 0 },
|
|
|
- };
|
|
|
- snprintf(ent.filename, sizeof(ent.filename), filename);
|
|
|
- fes->push_back(ent);
|
|
|
+ syscall(0x03);
|
|
|
+ return 0xffffffff;
|
|
|
}
|
|
|
-
|
|
|
-void tmpfs::mkfile(struct inode* dir, const char* filename)
|
|
|
+size_t fs::vfs::inode_write(inode*, const char*, size_t, size_t)
|
|
|
{
|
|
|
- struct inode file = mk_inode(0, 1, 0, mk_data_vector());
|
|
|
- m_inodes.push_back(file);
|
|
|
- mklink(dir, &file, filename);
|
|
|
+ syscall(0x03);
|
|
|
+ return 0xffffffff;
|
|
|
}
|
|
|
-
|
|
|
-void tmpfs::mkdir(struct inode* dir, const char* dirname)
|
|
|
+int fs::vfs::inode_mkfile(dentry*, const char*)
|
|
|
{
|
|
|
- struct inode new_dir = mk_inode(1, 0, 0, mk_fe_vector());
|
|
|
- m_inodes.push_back(new_dir);
|
|
|
- mklink(&new_dir, &new_dir, ".");
|
|
|
-
|
|
|
- mklink(dir, &new_dir, dirname);
|
|
|
- mklink(&new_dir, dir, "..");
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
}
|
|
|
-
|
|
|
-size_t tmpfs::read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
|
|
|
+int fs::vfs::inode_mknode(dentry*, const char*, node_t)
|
|
|
{
|
|
|
- if (file->flags.file != 1)
|
|
|
- return 0;
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
+}
|
|
|
+int fs::vfs::inode_rmfile(dentry*, const char*)
|
|
|
+{
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
+}
|
|
|
+int fs::vfs::inode_mkdir(dentry*, const char*)
|
|
|
+{
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
+}
|
|
|
+int fs::vfs::inode_stat(dentry*, stat*)
|
|
|
+{
|
|
|
+ syscall(0x03);
|
|
|
+ return GB_FAILED;
|
|
|
+}
|
|
|
|
|
|
- auto* data = static_cast<vector<char>*>(file->impl);
|
|
|
- size_t fsize = data->size();
|
|
|
+class tmpfs : public virtual fs::vfs {
|
|
|
+protected:
|
|
|
+ inline vector<tmpfs_file_entry>* mk_fe_vector(void)
|
|
|
+ {
|
|
|
+ return allocator_traits<kernel_allocator<vector<tmpfs_file_entry>>>::allocate_and_construct();
|
|
|
+ }
|
|
|
|
|
|
- if (offset + n > fsize)
|
|
|
- n = fsize - offset;
|
|
|
+ inline vector<char>* mk_data_vector(void)
|
|
|
+ {
|
|
|
+ return allocator_traits<kernel_allocator<vector<char>>>::allocate_and_construct();
|
|
|
+ }
|
|
|
|
|
|
- if (buf_size < n) {
|
|
|
- n = buf_size;
|
|
|
+ void mklink(fs::inode* dir, fs::inode* inode, const char* filename)
|
|
|
+ {
|
|
|
+ auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
|
|
|
+ struct tmpfs_file_entry ent = {
|
|
|
+ .ino = inode->ino,
|
|
|
+ .filename = { 0 },
|
|
|
+ };
|
|
|
+ snprintf(ent.filename, sizeof(ent.filename), filename);
|
|
|
+ fes->push_back(ent);
|
|
|
+ dir->size += sizeof(tmpfs_file_entry);
|
|
|
}
|
|
|
|
|
|
- memcpy(buf, data->data() + offset, n);
|
|
|
+ virtual int load_dentry(dentry* ent) override
|
|
|
+ {
|
|
|
+ if (!ent->ind->flags.in.directory) {
|
|
|
+ errno = ENOTDIR;
|
|
|
+ return GB_FAILED;
|
|
|
+ }
|
|
|
|
|
|
- return n;
|
|
|
-}
|
|
|
+ auto& entries = *static_cast<vector<tmpfs_file_entry>*>(ent->ind->impl);
|
|
|
+ for (const auto& entry : entries)
|
|
|
+ ent->append(get_inode(entry.ino), entry.filename);
|
|
|
|
|
|
-size_t tmpfs::write(struct inode* file, const char* buf, size_t offset, size_t n)
|
|
|
-{
|
|
|
- if (file->flags.file != 1)
|
|
|
- return 0;
|
|
|
+ ent->flags.in.present = 1;
|
|
|
+ return GB_OK;
|
|
|
+ }
|
|
|
|
|
|
- auto* data = static_cast<vector<char>*>(file->impl);
|
|
|
+public:
|
|
|
+ explicit tmpfs(void)
|
|
|
+ {
|
|
|
+ auto& in = *cache_inode({ INODE_DIR | INODE_MNT }, 0777, 0, mk_fe_vector());
|
|
|
|
|
|
- for (size_t i = data->size(); i < offset + n; ++i) {
|
|
|
- data->push_back(0);
|
|
|
+ mklink(&in, &in, ".");
|
|
|
+ mklink(&in, &in, "..");
|
|
|
+
|
|
|
+ register_root_node(&in);
|
|
|
}
|
|
|
- memcpy(data->data() + offset, buf, n);
|
|
|
|
|
|
- return n;
|
|
|
-}
|
|
|
+ virtual int inode_mkfile(dentry* dir, const char* filename) override
|
|
|
+ {
|
|
|
+ auto& file = *cache_inode({ .v = INODE_FILE }, 0777, 0, mk_data_vector());
|
|
|
+ mklink(dir->ind, &file, filename);
|
|
|
+ dir->invalidate();
|
|
|
+ return GB_OK;
|
|
|
+ }
|
|
|
|
|
|
-int tmpfs::readdir(struct inode* dir, struct dirent* entry, size_t i)
|
|
|
-{
|
|
|
- if (dir->flags.directory != 1) {
|
|
|
- errno = ENOTDIR;
|
|
|
- return GB_FAILED;
|
|
|
+ virtual int inode_mknode(dentry* dir, const char* filename, fs::node_t sn) override
|
|
|
+ {
|
|
|
+ auto& node = *cache_inode({ .v = INODE_NODE }, 0777, 0, (void*)sn.v);
|
|
|
+ mklink(dir->ind, &node, filename);
|
|
|
+ dir->invalidate();
|
|
|
+ return GB_OK;
|
|
|
}
|
|
|
|
|
|
- auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
|
|
|
+ virtual int inode_mkdir(dentry* dir, const char* dirname) override
|
|
|
+ {
|
|
|
+ auto& new_dir = *cache_inode({ .v = INODE_DIR }, 0777, 0, mk_fe_vector());
|
|
|
+ mklink(&new_dir, &new_dir, ".");
|
|
|
|
|
|
- if (i >= fes->size()) {
|
|
|
- errno = ENOENT;
|
|
|
- return GB_FAILED;
|
|
|
+ mklink(dir->ind, &new_dir, dirname);
|
|
|
+ mklink(&new_dir, dir->ind, "..");
|
|
|
+
|
|
|
+ dir->invalidate();
|
|
|
+ return GB_OK;
|
|
|
}
|
|
|
|
|
|
- entry->ino = fes->at(i).ino;
|
|
|
- snprintf(entry->name, sizeof(entry->name), fes->at(i).filename);
|
|
|
+ virtual size_t inode_read(fs::inode* file, char* buf, size_t buf_size, size_t offset, size_t n) override
|
|
|
+ {
|
|
|
+ if (file->flags.in.file != 1)
|
|
|
+ return 0;
|
|
|
|
|
|
- return GB_OK;
|
|
|
-}
|
|
|
+ auto* data = static_cast<vector<char>*>(file->impl);
|
|
|
+ size_t fsize = data->size();
|
|
|
|
|
|
-struct inode* tmpfs::findinode(struct inode* dir, const char* filename)
|
|
|
-{
|
|
|
- struct dirent ent { };
|
|
|
- size_t i = 0;
|
|
|
- while (readdir(dir, &ent, i) == GB_OK) {
|
|
|
- if (strcmp(ent.name, filename) == 0) {
|
|
|
- // optimize: use hash table to build an index
|
|
|
- auto& inodes = static_cast<tmpfs*>(dir->fs->impl)->m_inodes;
|
|
|
- for (auto iter = inodes.begin(); iter != inodes.end(); ++iter)
|
|
|
- if (iter->ino == ent.ino)
|
|
|
- return iter.ptr();
|
|
|
+ if (offset + n > fsize)
|
|
|
+ n = fsize - offset;
|
|
|
+
|
|
|
+ if (buf_size < n) {
|
|
|
+ n = buf_size;
|
|
|
}
|
|
|
- ++i;
|
|
|
+
|
|
|
+ memcpy(buf, data->data() + offset, n);
|
|
|
+
|
|
|
+ return n;
|
|
|
}
|
|
|
- return nullptr;
|
|
|
-}
|
|
|
|
|
|
-int tmpfs::stat(struct inode* dir, struct stat* stat, const char* filename)
|
|
|
-{
|
|
|
- // for later use
|
|
|
- // auto* fes = static_cast<vector<struct tmpfs_file_entry>*>(dir->impl);
|
|
|
+ virtual size_t inode_write(fs::inode* file, const char* buf, size_t offset, size_t n) override
|
|
|
+ {
|
|
|
+ if (file->flags.in.file != 1)
|
|
|
+ return 0;
|
|
|
|
|
|
- auto* file_inode = vfs_findinode(dir, filename);
|
|
|
+ auto* data = static_cast<vector<char>*>(file->impl);
|
|
|
|
|
|
- if (!file_inode) {
|
|
|
- errno = ENOENT;
|
|
|
- return GB_FAILED;
|
|
|
- }
|
|
|
+ for (size_t i = data->size(); i < offset + n; ++i) {
|
|
|
+ data->push_back(0);
|
|
|
+ }
|
|
|
+ memcpy(data->data() + offset, buf, n);
|
|
|
|
|
|
- stat->st_ino = file_inode->ino;
|
|
|
- if (file_inode->flags.file) {
|
|
|
- stat->st_blksize = 1;
|
|
|
- stat->st_blocks = static_cast<vector<char>*>(file_inode->impl)->size();
|
|
|
- }
|
|
|
- if (file_inode->flags.directory) {
|
|
|
- stat->st_blksize = sizeof(struct tmpfs_file_entry);
|
|
|
- stat->st_blocks = static_cast<vector<struct tmpfs_file_entry>*>(file_inode->impl)->size();
|
|
|
+ return n;
|
|
|
}
|
|
|
|
|
|
- return GB_OK;
|
|
|
-}
|
|
|
+ virtual int inode_stat(dentry* dir, fs::stat* stat) override
|
|
|
+ {
|
|
|
+ auto* file_inode = dir->ind;
|
|
|
+
|
|
|
+ stat->st_ino = file_inode->ino;
|
|
|
+ stat->st_size = file_inode->size;
|
|
|
+ if (file_inode->flags.in.file) {
|
|
|
+ stat->st_rdev.v = 0;
|
|
|
+ stat->st_blksize = 1;
|
|
|
+ stat->st_blocks = file_inode->size;
|
|
|
+ }
|
|
|
+ if (file_inode->flags.in.directory) {
|
|
|
+ stat->st_rdev.v = 0;
|
|
|
+ stat->st_blksize = sizeof(tmpfs_file_entry);
|
|
|
+ stat->st_blocks = file_inode->size;
|
|
|
+ }
|
|
|
+ if (file_inode->flags.in.special_node) {
|
|
|
+ stat->st_rdev.v = (uint32_t)file_inode->impl;
|
|
|
+ stat->st_blksize = 0;
|
|
|
+ stat->st_blocks = 0;
|
|
|
+ }
|
|
|
|
|
|
-size_t vfs_read(struct inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
|
|
|
-{
|
|
|
- if (file->fs->ops->read) {
|
|
|
- return file->fs->ops->read(file, buf, buf_size, offset, n);
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
+ return GB_OK;
|
|
|
}
|
|
|
-}
|
|
|
-size_t vfs_write(struct inode* file, const char* buf, size_t offset, size_t n)
|
|
|
+};
|
|
|
+
|
|
|
+// 8 * 8 for now
|
|
|
+static fs::special_node sns[8][8];
|
|
|
+
|
|
|
+size_t fs::vfs_read(fs::inode* file, char* buf, size_t buf_size, size_t offset, size_t n)
|
|
|
{
|
|
|
- if (file->fs->ops->write) {
|
|
|
- return file->fs->ops->write(file, buf, offset, n);
|
|
|
+ if (file->flags.in.special_node) {
|
|
|
+ fs::node_t sn {
|
|
|
+ .v = (uint32_t)file->impl
|
|
|
+ };
|
|
|
+ auto* ptr = &sns[sn.in.major][sn.in.minor];
|
|
|
+ auto* ops = &ptr->ops;
|
|
|
+ if (ops && ops->read)
|
|
|
+ return ops->read(ptr, buf, buf_size, offset, n);
|
|
|
+ else {
|
|
|
+ errno = EINVAL;
|
|
|
+ return 0xffffffff;
|
|
|
+ }
|
|
|
} else {
|
|
|
- return 0;
|
|
|
+ return file->fs->inode_read(file, buf, buf_size, offset, n);
|
|
|
}
|
|
|
}
|
|
|
-int vfs_readdir(struct inode* dir, struct dirent* entry, size_t i)
|
|
|
+size_t fs::vfs_write(fs::inode* file, const char* buf, size_t offset, size_t n)
|
|
|
{
|
|
|
- if (dir->fs->ops->readdir) {
|
|
|
- return dir->fs->ops->readdir(dir, entry, i);
|
|
|
+ if (file->flags.in.special_node) {
|
|
|
+ fs::node_t sn {
|
|
|
+ .v = (uint32_t)file->impl
|
|
|
+ };
|
|
|
+ auto* ptr = &sns[sn.in.major][sn.in.minor];
|
|
|
+ auto* ops = &ptr->ops;
|
|
|
+ if (ops && ops->write)
|
|
|
+ return ops->write(ptr, buf, offset, n);
|
|
|
+ else {
|
|
|
+ errno = EINVAL;
|
|
|
+ return 0xffffffff;
|
|
|
+ }
|
|
|
} else {
|
|
|
- return 0;
|
|
|
+ return file->fs->inode_write(file, buf, offset, n);
|
|
|
}
|
|
|
}
|
|
|
-struct inode* vfs_findinode(struct inode* dir, const char* filename)
|
|
|
+int fs::vfs_mkfile(fs::vfs::dentry* dir, const char* filename)
|
|
|
{
|
|
|
- if (dir->fs->ops->findinode) {
|
|
|
- return dir->fs->ops->findinode(dir, filename);
|
|
|
- } else {
|
|
|
- return nullptr;
|
|
|
- }
|
|
|
+ return dir->ind->fs->inode_mkfile(dir, filename);
|
|
|
}
|
|
|
-int vfs_mkfile(struct inode* dir, const char* filename)
|
|
|
+int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, fs::node_t sn)
|
|
|
{
|
|
|
- if (dir->fs->ops->mkfile) {
|
|
|
- return dir->fs->ops->mkfile(dir, filename);
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return dir->ind->fs->inode_mknode(dir, filename, sn);
|
|
|
}
|
|
|
-int vfs_rmfile(struct inode* dir, const char* filename)
|
|
|
+int fs::vfs_rmfile(fs::vfs::dentry* dir, const char* filename)
|
|
|
{
|
|
|
- if (dir->fs->ops->rmfile) {
|
|
|
- return dir->fs->ops->rmfile(dir, filename);
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return dir->ind->fs->inode_rmfile(dir, filename);
|
|
|
}
|
|
|
-int vfs_mkdir(struct inode* dir, const char* dirname)
|
|
|
+int fs::vfs_mkdir(fs::vfs::dentry* dir, const char* dirname)
|
|
|
{
|
|
|
- if (dir->fs->ops->mkdir) {
|
|
|
- return dir->fs->ops->mkdir(dir, dirname);
|
|
|
- } else {
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ return dir->ind->fs->inode_mkdir(dir, dirname);
|
|
|
}
|
|
|
|
|
|
-struct inode* vfs_open(const char* path)
|
|
|
+fs::vfs::dentry* fs::vfs_open(const char* path)
|
|
|
{
|
|
|
if (path[0] == '/' && path[1] == 0x00) {
|
|
|
- return fs_root;
|
|
|
+ return fs::fs_root;
|
|
|
}
|
|
|
|
|
|
- struct inode* cur = fs_root;
|
|
|
+ auto* cur = fs::fs_root;
|
|
|
size_t n = 0;
|
|
|
switch (*(path++)) {
|
|
|
// absolute path
|
|
|
case '/':
|
|
|
while (true) {
|
|
|
if (path[n] == 0x00) {
|
|
|
- string fname(path, n);
|
|
|
- cur = vfs_findinode(cur, fname.c_str());
|
|
|
+ cur = cur->find(string(path, n));
|
|
|
return cur;
|
|
|
}
|
|
|
if (path[n] == '/') {
|
|
|
- string fname(path, n);
|
|
|
- cur = vfs_findinode(cur, fname.c_str());
|
|
|
+ cur = cur->find(string(path, n));
|
|
|
if (path[n + 1] == 0x00) {
|
|
|
return cur;
|
|
|
} else {
|
|
@@ -363,47 +406,63 @@ struct inode* vfs_open(const char* path)
|
|
|
}
|
|
|
return nullptr;
|
|
|
}
|
|
|
-
|
|
|
-int vfs_stat(struct stat* stat, const char* _path)
|
|
|
+int fs::vfs_stat(const char* filename, stat* stat)
|
|
|
{
|
|
|
- if (_path[0] == '/' && _path[1] == 0x00) {
|
|
|
- if (fs_root->fs->ops->stat) {
|
|
|
- return fs_root->fs->ops->stat(fs_root, stat, ".");
|
|
|
- } else {
|
|
|
- errno = EINVAL;
|
|
|
- return GB_FAILED;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- string path(_path);
|
|
|
- auto iter = path.back();
|
|
|
- while (*(iter - 1) != '/')
|
|
|
- --iter;
|
|
|
- string filename(&*iter);
|
|
|
- string parent_path = path.substr(0, &*iter - path.data());
|
|
|
+ auto ent = vfs_open(filename);
|
|
|
+ return vfs_stat(ent, stat);
|
|
|
+}
|
|
|
+int fs::vfs_stat(fs::vfs::dentry* ent, stat* stat)
|
|
|
+{
|
|
|
+ return ent->ind->fs->inode_stat(ent, stat);
|
|
|
+}
|
|
|
|
|
|
- auto* dir_inode = vfs_open(parent_path.c_str());
|
|
|
+fs::vfs::dentry* fs::fs_root;
|
|
|
+static types::list<fs::vfs*>* fs_es;
|
|
|
|
|
|
- if (!dir_inode) {
|
|
|
- errno = ENOENT;
|
|
|
- return GB_FAILED;
|
|
|
- }
|
|
|
+void fs::register_special_block(
|
|
|
+ uint16_t major,
|
|
|
+ uint16_t minor,
|
|
|
+ fs::special_node_read read,
|
|
|
+ fs::special_node_write write,
|
|
|
+ uint32_t data1,
|
|
|
+ uint32_t data2)
|
|
|
+{
|
|
|
+ fs::special_node& sn = sns[major][minor];
|
|
|
+ sn.ops.read = read;
|
|
|
+ sn.ops.write = write;
|
|
|
+ sn.data1 = data1;
|
|
|
+ sn.data2 = data2;
|
|
|
+}
|
|
|
|
|
|
- if (dir_inode->fs->ops->stat) {
|
|
|
- return dir_inode->fs->ops->stat(dir_inode, stat, filename.c_str());
|
|
|
- } else {
|
|
|
- errno = EINVAL;
|
|
|
- return GB_FAILED;
|
|
|
- }
|
|
|
+fs::vfs* fs::register_fs(vfs* fs)
|
|
|
+{
|
|
|
+ fs_es->push_back(fs);
|
|
|
+ return fs;
|
|
|
}
|
|
|
|
|
|
-struct inode* fs_root;
|
|
|
-static tmpfs* rootfs;
|
|
|
+size_t b_null_read(fs::special_node*, char* buf, size_t buf_size, size_t, size_t n)
|
|
|
+{
|
|
|
+ if (n >= buf_size)
|
|
|
+ n = buf_size;
|
|
|
+ memset(buf, 0x00, n);
|
|
|
+ return n;
|
|
|
+}
|
|
|
+size_t b_null_write(fs::special_node*, const char*, size_t, size_t n)
|
|
|
+{
|
|
|
+ return n;
|
|
|
+}
|
|
|
|
|
|
void init_vfs(void)
|
|
|
{
|
|
|
- rootfs = allocator_traits<kernel_allocator<tmpfs>>::allocate_and_construct(4096 * 1024);
|
|
|
- fs_root = rootfs->root_inode();
|
|
|
+ using namespace fs;
|
|
|
+ // null
|
|
|
+ register_special_block(0, 0, b_null_read, b_null_write, 0, 0);
|
|
|
+
|
|
|
+ fs_es = types::kernel_allocator_new<types::list<vfs*>>();
|
|
|
+
|
|
|
+ auto* rootfs = types::kernel_allocator_new<tmpfs>();
|
|
|
+ fs_es->push_back(rootfs);
|
|
|
+ fs_root = rootfs->root();
|
|
|
|
|
|
vfs_mkdir(fs_root, "dev");
|
|
|
vfs_mkdir(fs_root, "root");
|
|
@@ -411,11 +470,19 @@ void init_vfs(void)
|
|
|
|
|
|
auto* init = vfs_open("/init");
|
|
|
const char* str = "#/bin/sh\nexec /bin/sh\n";
|
|
|
- vfs_write(init, str, 0, strlen(str));
|
|
|
+ vfs_write(init->ind, str, 0, strlen(str));
|
|
|
+
|
|
|
+ auto* dev = vfs_open("/dev");
|
|
|
+ vfs_mknode(dev, "null", { .in { .major = 0, .minor = 0 } });
|
|
|
+ vfs_mknode(dev, "console", { .in { .major = 1, .minor = 0 } });
|
|
|
+ vfs_mknode(dev, "hda", { .in { .major = 2, .minor = 0 } });
|
|
|
|
|
|
- struct stat _stat { };
|
|
|
+ stat _stat {};
|
|
|
|
|
|
- vfs_stat(&_stat, "/init");
|
|
|
- vfs_stat(&_stat, "/");
|
|
|
- vfs_stat(&_stat, "/dev");
|
|
|
+ vfs_stat("/init", &_stat);
|
|
|
+ vfs_stat("/", &_stat);
|
|
|
+ vfs_stat("/dev", &_stat);
|
|
|
+ vfs_stat("/dev/null", &_stat);
|
|
|
+ vfs_stat("/dev/console", &_stat);
|
|
|
+ vfs_stat("/dev/hda", &_stat);
|
|
|
}
|