summaryrefslogtreecommitdiff
path: root/src/kernel/vfs
diff options
context:
space:
mode:
authorAlex AUVOLAT <alexis211@gmail.com>2012-05-17 13:30:09 +0200
committerAlex AUVOLAT <alexis211@gmail.com>2012-05-17 13:30:09 +0200
commit7c9a48b4e6d66cf4f62e7bad9e22ab06923e47ef (patch)
treedf44a926f105c913c77525d35441d20a632f1440 /src/kernel/vfs
parentc6d35a5f4fdda6ae2e98498f19a4adaee6d95692 (diff)
downloadTCE-7c9a48b4e6d66cf4f62e7bad9e22ab06923e47ef.tar.gz
TCE-7c9a48b4e6d66cf4f62e7bad9e22ab06923e47ef.zip
Beginning of a VFS implemented. C++ is great.
Diffstat (limited to 'src/kernel/vfs')
-rw-r--r--src/kernel/vfs/node.cpp122
-rw-r--r--src/kernel/vfs/node.h41
-rw-r--r--src/kernel/vfs/vdir.cpp55
-rw-r--r--src/kernel/vfs/vdir.h32
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
+