diff options
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r-- | src/kernel/vfs/node.cpp | 122 | ||||
-rw-r--r-- | src/kernel/vfs/node.h | 41 | ||||
-rw-r--r-- | src/kernel/vfs/vdir.cpp | 55 | ||||
-rw-r--r-- | src/kernel/vfs/vdir.h | 32 |
4 files changed, 250 insertions, 0 deletions
diff --git a/src/kernel/vfs/node.cpp b/src/kernel/vfs/node.cpp new file mode 100644 index 0000000..9900a3c --- /dev/null +++ b/src/kernel/vfs/node.cpp @@ -0,0 +1,122 @@ +#include "node.h" +#include "vdir.h" +#include <core/monitor.h> + +int node::open(process *proc, int mode) { + //TODO : permission checks + return 0; // ok +} + +int node::stat(file_info *info) { + info->type = type; + info->dev_type = dev_type; + info->mode = mode; + info->uid = uid; + info->gid = gid; + info->size = this->get_size(); + return 0; +} + +node *root = 0; + +void vfs_setup() { + root = new vdir(0); + root->add_child(".dev", new vdir(root)); + + monitor_write("[VFS] "); +} + +node* vfs_find(node* root, char* path) { + node* el = root; + char *member = path; + + while (*path != 0 && el != 0) { + if (*path == '/') { + if (member == path) { + member++; + path++; + } else { + *path = 0; + el = el->get_child(member); + path++; + member = path; + } + } else { + path++; + } + } + if (el != 0 && member != path) { + el = el->get_child(member); + } + + return el; +} + +node* vfs_read_fd(FILE d) { + return current_process->fd.at(d); +} + +// Syscalls + +static FILE i_open(node* r, char* filename, int mode) { + node* f = vfs_find(r, filename); + if (f == 0) return E_NOT_FOUND; + //TODO : different actions depending on open mode + int e = f->open(current_process, mode); + if (e != 0) return e; + return current_process->fd.add(f); +} + +FILE open(char* filename, int mode) { + return i_open(root, filename, mode); +} + +FILE open_relative(FILE root, char* filename, int mode) { + node* n = vfs_read_fd(root); + if (n == 0) return E_INVALID_FD; + return i_open(n, filename, mode); +} + +int stat(char* filename, file_info *info) { + node *f = vfs_find(root, filename); + if (f == 0) return E_NOT_FOUND; + return f->stat(info); +} + +int stat_relative(FILE root, char* filename, file_info *info) { + node *r = vfs_read_fd(root); + if (r == 0) return E_INVALID_FD; + node *f = vfs_find(r, filename); + if (f == 0) return E_NOT_FOUND; + return f->stat(info); +} + +int statf(FILE file, file_info *info) { + node *f = vfs_read_fd(file); + if (f == 0) return E_INVALID_FD; + return f->stat(info); +} + +void close(FILE file) { + node *f = vfs_read_fd(file); + if (f != 0) { + f->close(current_process); + current_process->fd.set(file, 0); + } +} + +int read(FILE file, size_t offset, size_t len, char* buffer) { + node *f = vfs_read_fd(file); + if (f == 0) return E_INVALID_FD; + return f->read(offset, len, buffer); +} + +int write(FILE file, size_t offset, size_t len, char* buffer) { + node *f = vfs_read_fd(file); + if (f == 0) return E_INVALID_FD; + return f->write(offset, len, buffer); +} + +int link(char* from, char* to, int mode) { + return E_NOT_IMPLEMENTED; +} diff --git a/src/kernel/vfs/node.h b/src/kernel/vfs/node.h new file mode 100644 index 0000000..2d16dab --- /dev/null +++ b/src/kernel/vfs/node.h @@ -0,0 +1,41 @@ +#ifndef DEF_VFS_NODE_H +#define DEF_VFS_NODE_H + +#include <tce/vfs.h> +#include <tce/syscalls.h> + +#include <task/task.h> + +class node { + public: + node* parent; + int type, dev_type; + int mode, uid, gid; + + node(node* p, int t) : parent(p), type(t) {} + + virtual int open(process *proc, int mode); + virtual void close(process *proc) {} + virtual int read(size_t offset, size_t len, char *buffer) { return E_NOT_IMPLEMENTED; } + virtual int write(size_t offset, size_t len, char* buffer) { return E_NOT_IMPLEMENTED; } + int stat(file_info *info); + virtual node* get_child(char* name) { return 0; } + virtual int add_child(char* name, node *child) { return E_NOT_IMPLEMENTED; } + virtual size_t get_size() { return 0; } +}; + +void vfs_setup(); +node* vfs_find(node* root, char* filename); + +// syscall interface +FILE open(char* filename, int mode); +FILE open_relative(FILE root, char* filename, int mode); +int stat(char* filename, file_info *info); +int stat_relative(FILE root, char* filename, file_info *info); +int statf(FILE file, file_info *info); +void close(FILE file); +int read(FILE file, size_t offset, size_t len, char *buffer); +int write(FILE file, size_t offset, size_t len, char *buffer); +int link(char* from, char* to, int mode); + +#endif diff --git a/src/kernel/vfs/vdir.cpp b/src/kernel/vfs/vdir.cpp new file mode 100644 index 0000000..299c0e7 --- /dev/null +++ b/src/kernel/vfs/vdir.cpp @@ -0,0 +1,55 @@ +#include "vdir.h" + +vdir::vdir(node* parent) : node(parent, FT_DIR), children(8, 64) { + children.add(new vdir_child(".", this)); + child_count = 1; + + if (parent != 0) { + children.add(new vdir_child("..", parent)); + child_count++; + } +} + +node* vdir::get_child(char* name) { + for (unsigned i = 0; i < child_count; i++) { + vdir_child *c = children.at(i); + ASSERT(c != 0); + if (strcmp(c->name, name) == 0) return c->el; + } + return 0; +} + +int vdir::read(size_t offset, size_t len, char* buffer) { + if (offset >= child_count) return 0; + vdir_child *c = children.at(offset); + ASSERT(c != 0); + size_t nlen = strlen(c->name); + if (len <= nlen) { + return E_TOO_SHORT; + } + strcpy(buffer, c->name); + return nlen; +} + +int vdir::write(size_t offset, size_t len, char* buffer) { + // rename file + if (offset >= child_count) return E_INVALID_RANGE; + vdir_child *c = children.at(offset); + ASSERT(c != 0); + if (len == 0) return E_INVALID; + kfree(c->name); + c->name = (char*)kmalloc(len + 1); + for (unsigned i = 0; i < len; i++) c->name[i] = buffer[i]; + c->name[len] = 0; + return len; +} + +size_t vdir::get_size() { + return child_count; +} + +int vdir::add_child(char* name, node *child) { + ASSERT((int)child_count == children.add(new vdir_child(name, child))); + child_count++; + return 0; +} diff --git a/src/kernel/vfs/vdir.h b/src/kernel/vfs/vdir.h new file mode 100644 index 0000000..9595409 --- /dev/null +++ b/src/kernel/vfs/vdir.h @@ -0,0 +1,32 @@ +#ifndef DEF_VFS_VDIR_H +#define DEF_VFS_VDIR_H + +#include "node.h" +#include <lib/earray.h> +#include <string.h> + +struct vdir_child { + char* name; + node *el; + + vdir_child(char* na, node* nd) : el(nd) { + name = strdup(na); + } +}; + +class vdir : public node { + earray<vdir_child> children; + size_t child_count; + + public: + vdir(node* parent); + + virtual int read(size_t offset, size_t len, char* buffer); + virtual int write(size_t offset, size_t len, char* buffer); // rename file + virtual node* get_child(char* name); + virtual int add_child(char* name, node *child); + virtual size_t get_size(); +}; + +#endif + |