From 7c9a48b4e6d66cf4f62e7bad9e22ab06923e47ef Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Thu, 17 May 2012 13:30:09 +0200 Subject: Beginning of a VFS implemented. C++ is great. --- doc/syscalls.txt | 33 ++++++++-- doc/vfs.txt | 3 + src/common/include/string.h | 2 +- src/common/include/tce/syscalls.h | 27 ++++++-- src/common/include/tce/vfs.h | 42 +++++++++++++ src/common/string.c | 4 +- src/kernel/Makefile | 5 +- src/kernel/config.h | 4 +- src/kernel/core/kmain.cpp | 3 + src/kernel/lib/earray.cpp | 6 +- src/kernel/lib/earray.h | 2 +- src/kernel/mem/_dlmalloc.h | 2 +- src/kernel/mem/mem.h | 4 +- src/kernel/task/syscall.cpp | 71 ++++++++++++++++++--- src/kernel/task/task.cpp | 19 +++--- src/kernel/task/task.h | 8 ++- src/kernel/vfs/node.cpp | 122 +++++++++++++++++++++++++++++++++++++ src/kernel/vfs/node.h | 41 +++++++++++++ src/kernel/vfs/vdir.cpp | 55 +++++++++++++++++ src/kernel/vfs/vdir.h | 32 ++++++++++ src/user/lib/include/tce/syscall.h | 11 ++++ src/user/lib/std/stdio.c | 1 - src/user/lib/tce/syscall.c | 41 +++++++++++++ src/user/test/main.c | 65 +++++++++++++++++++- 24 files changed, 559 insertions(+), 44 deletions(-) create mode 100644 src/common/include/tce/vfs.h create mode 100644 src/kernel/vfs/node.cpp create mode 100644 src/kernel/vfs/node.h create mode 100644 src/kernel/vfs/vdir.cpp create mode 100644 src/kernel/vfs/vdir.h diff --git a/doc/syscalls.txt b/doc/syscalls.txt index 952b95e..39982c0 100644 --- a/doc/syscalls.txt +++ b/doc/syscalls.txt @@ -15,11 +15,36 @@ id=eax Name Parameters Description 7 irq_wait ebx: irq number Waits for an IRQ (requires privilege PL_DRIVER) 8 proc_priv none Returns current process privilege level - 9 sbrk ebx: size Allocates some memory - 10 brk ebx: new_end Allocates/frees some memory + 10 sbrk ebx: size Allocates some memory + 11 brk ebx: new_end Allocates/frees some memory - 11 mmap (see linux specs) not implemented - 12 munmap (see linux specs) not implemented + 12 mmap (see linux specs) not implemented + 13 munmap (see linux specs) not implemented + + 20 open ebx: char* filename open a file, returns a descriptor + ecx: mode + 21 open_relative ebx: root open a file, returns a descriptor + ecx: char* filename + edx: mode + 22 stat ebx: char* filename get file info + ecx: struct* info + 23 stat_relative ebx: root get file info + ecx: char* filename + edx: struct* info + 24 statf ebx: file descriptor get file info + ecx: struct* info + 25 close ebx: file descriptor close file + 26 read ebx: file descriptor read from file + ecx: offset + edx: length + esi: pointer to data + 27 write ebx: file descriptor write to file + ecx: offset + edx: length + esi: pointer to data + 28 link ebx: char* from symlink/hardlink/mount/... + ecx: char* to + edx: mode If a processes wishes to exit with an error code, it HAS to use process_exit. thread_exit will do nothing. diff --git a/doc/vfs.txt b/doc/vfs.txt index 255ddb0..5a6a0b2 100644 --- a/doc/vfs.txt +++ b/doc/vfs.txt @@ -8,11 +8,13 @@ File are objects that implement an abstract file class in the kernel. Its method - int stat(struct file_info *info) - file* get_child(char* name) - int add_child(char* name, file *child) +- int get_size() The following syscall interface is given to the process (fd_t is a file descriptor, an int) : - fd_t open(char* filename, int mode) - fd_t open_relative(fd_t root, char* filename, int mode) - int stat(char* filename, struct file_info *info) +- int stat_relative(fd_t root, char* filename, struct file_info *info) - int statf(fd_t file, struct file_info *info) - void close(fd_t file) - int read(fd_t file, size_t offset, size_t len, char *buffer) @@ -33,6 +35,7 @@ File open modes flags : - FM_APPEND append data - FM_TRUNC truncate existing file - FM_CREATE create file if it doesn't exist +- FM_DELETE delete the file - incompatible with everything else note : if mode contains neither FM_READ nor FM_WRITE, then the file will be created/truncated according to the flags given, but will not be actually oppenned, so the return value of open will be 0. diff --git a/src/common/include/string.h b/src/common/include/string.h index e6aa86e..19e87c1 100644 --- a/src/common/include/string.h +++ b/src/common/include/string.h @@ -10,7 +10,7 @@ extern "C" { int strlen(const char *str); char *strcpy(char *dest, const char *src); -// char *strdup(const char *src); // uses malloc, that's bad +char *strdup(const char *src); // uses malloc, that's bad char *strchr(const char *str, char c); char *strcat(char *dest, const char *src); int strcmp(const char *s1, const char *s2); diff --git a/src/common/include/tce/syscalls.h b/src/common/include/tce/syscalls.h index 3b5b68f..6c67523 100644 --- a/src/common/include/tce/syscalls.h +++ b/src/common/include/tce/syscalls.h @@ -9,11 +9,30 @@ #define SC_THREAD_NEW 6 #define SC_IRQ_WAIT 7 #define SC_PROC_PRIV 8 -#define SC_SBRK 9 -#define SC_BRK 10 +#define SC_SBRK 10 +#define SC_BRK 11 // NOT YET IMPLEMENTED -#define SC_MMAP 11 -#define SC_MUNMAP 12 +#define SC_MMAP 12 +#define SC_MUNMAP 13 + +#define SC_OPEN 20 +#define SC_OPEN_RELATIVE 21 +#define SC_STAT 22 +#define SC_STAT_RELATIVE 23 +#define SC_STATF 24 +#define SC_CLOSE 25 +#define SC_READ 26 +#define SC_WRITE 27 +#define SC_LINK 28 + + +// ERRORS +#define E_NOT_IMPLEMENTED -1 +#define E_NOT_FOUND -2 +#define E_INVALID_FD -3 +#define E_TOO_SHORT -4 // not enough space for data to be copied to +#define E_INVALID_RANGE -5 +#define E_INVALID -6 // anything went wrong - invalid parameter, usually #endif diff --git a/src/common/include/tce/vfs.h b/src/common/include/tce/vfs.h new file mode 100644 index 0000000..20ea03b --- /dev/null +++ b/src/common/include/tce/vfs.h @@ -0,0 +1,42 @@ +#ifndef DEF_TCE_VFS_H +#define DEF_TCE_VFS_H + +#include + +typedef size_t FILE; + +typedef struct _file_info { + uint32_t type; + uint32_t dev_type; + uint32_t mode; + uint32_t uid, gid; + size_t size; +} file_info; + +// file open flags +#define FM_READ 0x00000001 +#define FM_WRITE 0x00000002 +#define FM_APPEND 0x00000004 +#define FM_TRUNC 0x00000008 +#define FM_CREATE 0x00000010 +#define FM_DELETE 0x00000020 + +// link modes +#define LM_SYMLINK 1 +#define LM_HARDLINK 2 +#define LM_MOUNT 3 +#define LM_OUTPUT_TO 4 + +// file type flags +#define FT_FILE 0x00000001 +#define FT_DIR 0x00000002 +#define FT_SYMLINK 0x00000004 +#define FT_DEV 0x00000008 +#define FT_TERMINAL 0x00000010 + +// device types +#define DT_BLOCK 1 +#define DT_KEYBOARD 2 +#define DT_DISPLAY 3 + +#endif diff --git a/src/common/string.c b/src/common/string.c index 120fd5d..3825e47 100644 --- a/src/common/string.c +++ b/src/common/string.c @@ -20,12 +20,12 @@ char *strcpy(char *dest, const char *src) { return (char*)src; } -/*char *strdup(const char *src) { +char *strdup(const char *src) { char* ret = malloc(strlen(src) + 1); if (ret == NULL) return ret; strcpy(ret, src); return ret; -}*/ +} char *strcat(char *dest, const char *src) { char *dest2 = dest; diff --git a/src/kernel/Makefile b/src/kernel/Makefile index 2a18bc8..0537388 100644 --- a/src/kernel/Makefile +++ b/src/kernel/Makefile @@ -2,9 +2,10 @@ Out = kernel.elf Obj = core/loader_.o core/kmain.o core/sys.o \ core/monitor.o task/timer.o \ task/idt.o task/idt_.o task/task.o task/task_.o task/syscall.o task/sched.o \ - lib/bitset.o lib/std.o lib/cpp.o lib/earray.o \ + lib/bitset.o lib/std.o lib/cpp.o \ mem/mem.o mem/paging.o mem/gdt.o mem/_dlmalloc.o mem/seg.o \ - linker/elf.o + linker/elf.o \ + vfs/node.o vfs/vdir.o ExtObj = $(SrcPath)/common/_common.o diff --git a/src/kernel/config.h b/src/kernel/config.h index 0fb4697..ffb56d2 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -2,8 +2,8 @@ #define DEF_CONFIG_H #define K_OS_NAME "T/CE" -#define K_OS_VER "0.0.5" -#define K_OS_CODENAME "CPLUSPLUS==\\o/" +#define K_OS_VER "0.1.0" +#define K_OS_CODENAME "Mind Your VFS" #endif diff --git a/src/kernel/core/kmain.cpp b/src/kernel/core/kmain.cpp index 8b77bcf..eb2c3ec 100644 --- a/src/kernel/core/kmain.cpp +++ b/src/kernel/core/kmain.cpp @@ -11,6 +11,7 @@ #include #include #include +#include /* The kernel's main procedure. This function is called in loader_.asm. This function calls the initializer functions for all system parts. @@ -55,6 +56,8 @@ extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) { //kheap_init(); timer_init(30); tasking_init(); + + vfs_setup(); monitor_write("\nLoading modules :\n"); for (i = 0; i < mbd->mods_count; i++) { diff --git a/src/kernel/lib/earray.cpp b/src/kernel/lib/earray.cpp index 5760822..3a41f18 100644 --- a/src/kernel/lib/earray.cpp +++ b/src/kernel/lib/earray.cpp @@ -1,5 +1,3 @@ -#include "earray.h" - #include #include #include @@ -101,7 +99,7 @@ T *earray::at(int num) { mutex_unlock(&mutex); return 0; } - void* ret = data[i][j]; + T* ret = data[i][j]; mutex_unlock(&mutex); return ret; } @@ -145,7 +143,7 @@ void earray::set(int num, T* ptr) { } } } else { - if (data[a] = 0) { + if (data[a] == 0) { data[a] = (T**)kmalloc(vect_len * sizeof(T*)); for (i = 0; i < vect_len; i++) data[a][i] = 0; } diff --git a/src/kernel/lib/earray.h b/src/kernel/lib/earray.h index d3d7a9b..9a43612 100644 --- a/src/kernel/lib/earray.h +++ b/src/kernel/lib/earray.h @@ -32,6 +32,6 @@ struct earray { int count() { return elements; } }; - +#include #endif diff --git a/src/kernel/mem/_dlmalloc.h b/src/kernel/mem/_dlmalloc.h index a80273c..23682be 100644 --- a/src/kernel/mem/_dlmalloc.h +++ b/src/kernel/mem/_dlmalloc.h @@ -12,7 +12,7 @@ #define LACKS_SYS_PARAM_H #define LACKS_STDLIB_H -#define USE_DL_PREFIX +// #define USE_DL_PREFIX #define USE_LOCKS 2 diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h index 085d9ce..4201983 100644 --- a/src/kernel/mem/mem.h +++ b/src/kernel/mem/mem.h @@ -14,8 +14,8 @@ void kfree_page(void* page); extern "C" void* ksbrk(size_t size); extern "C" void kbrk(void* ptr); -#define kmalloc dlmalloc -#define kfree dlfree +#define kmalloc malloc +#define kfree free extern bool _no_more_ksbrk; extern size_t mem_placementAddr; diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp index 678677d..797c5db 100644 --- a/src/kernel/task/syscall.cpp +++ b/src/kernel/task/syscall.cpp @@ -3,6 +3,7 @@ #include "timer.h" #include #include +#include #define CALL0(name, scname) static void scname(registers* r) { r->eax = name(); } #define CALL1(name, scname) static void scname(registers* r) { \ @@ -11,6 +12,8 @@ r->eax = name(r->ebx, r->ecx); } #define CALL3(name, scname) static void scname(registers* r) { \ r->eax = name(r->ebx, r->ecx, r->edx); } +#define CALL4(name, scname) static void scname(registers* r) { \ + r->eax = name(r->ebx, r->ecx, r->edx, r->esi); } #define CALL0V(name, scname) static void scname(registers* r) { name(); } #define CALL1V(name, scname) static void scname(registers* r) { name(r->ebx); } #define CALL2V(name, scname) static void scname(registers* r) { name(r->ebx, r->ecx); } @@ -26,29 +29,83 @@ CALL0(proc_priv, proc_priv_sc); CALL1(process_sbrk, proc_sbrk_sc); CALL1V(process_brk, proc_brk_sc); +CALL1V(close, close_sc); + static void printk_sc(registers *r) { monitor_write((char*)r->ebx); } static void thread_new_sc(registers* r) { cli(); - new thread(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx); + new thread(current_process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx); sti(); } +static void open_sc(registers *r) { + r->eax = open((char*)r->ebx, r->ecx); +} + +static void open_relative_sc(registers *r) { + r->eax = open_relative(r->ebx, (char*)r->ecx, r->edx); +} + +static void stat_sc(registers *r) { + r->eax = stat((char*)r->ebx, (file_info*)r->ecx); +} + +static void stat_relative_sc(registers *r) { + r->eax = stat_relative(r->ebx, (char*)r->ecx, (file_info*)r->edx); +} + +static void statf_sc(registers *r) { + r->eax = statf(r->ebx, (file_info*)r->ecx); +} + +static void read_sc(registers *r) { + r->eax = read(r->ebx, r->ecx, r->edx, (char*)r->esi); +} + +static void write_sc(registers *r) { + r->eax = write(r->ebx, r->ecx, r->edx, (char*)r->esi); +} + +static void link_sc(registers *r) { + r->eax = link((char*)r->ebx, (char*)r->ecx, r->edx); +} + + int_callback syscalls[NUMBER_OF_SYSCALLS] = { // This must correspond to common/include/tce/syscalls.h - 0, - thread_exit_sc, //0 + 0, // 0 + thread_exit_sc, schedule_sc, thread_sleep_sc, process_exit_sc, - printk_sc, - thread_new_sc, //5 + printk_sc, //5 + thread_new_sc, irq_wait_sc, proc_priv_sc, - proc_sbrk_sc, + 0, + proc_sbrk_sc, //10 proc_brk_sc, - 0 }; + 0, + 0, + 0, + 0, //15 + 0, + 0, + 0, + 0, + open_sc, //20 + open_relative_sc, + stat_sc, + stat_relative_sc, + statf_sc, + close_sc, //25 + read_sc, + write_sc, + link_sc, + 0 + }; /* Called in idt_.asm on a system call (interrupt 64). diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp index 92820f9..3998bfe 100644 --- a/src/kernel/task/task.cpp +++ b/src/kernel/task/task.cpp @@ -20,7 +20,7 @@ extern "C" uint32_t read_eip(); extern "C" void task_idle(void*); static uint32_t nextpid = 1; -process *processes = 0, *kernel_process; +process *processes = 0, *kernel_process = 0, *current_process = 0; thread *current_thread = 0, *idle_thread = 0; uint32_t tasking_tmpStack[KSTACKSIZE]; @@ -78,8 +78,9 @@ void schedule() { current_thread = sched_dequeue(); ASSERT(current_thread != 0); + current_process = current_thread->process; - pagedir_switch(current_thread->process->pagedir); + pagedir_switch(current_process->pagedir); gdt_setKernelStack(((uint32_t)current_thread->kernelStack_addr) + current_thread->kernelStack_size); @@ -135,8 +136,8 @@ void thread::wakeUp() { /* Returns the privilege level of the current process. */ int proc_priv() { - if (current_thread == 0 || current_thread->process == 0) return PL_UNKNOWN; - return current_thread->process->privilege; + if (current_thread == 0 || current_process == 0) return PL_UNKNOWN; + return current_process->privilege; } /* For internal use only. Called by thread_exit_stackJmp on a stack that will not be deleted. @@ -272,7 +273,7 @@ thread::thread(class process *proc, thread_entry entry_point, void *data, void * } /* Creates a new process. Creates a struct process and fills it up. */ -process::process(process* _parent, uint32_t _uid, uint32_t _privilege) { +process::process(process* _parent, uint32_t _uid, uint32_t _privilege) : fd(12, 64) { pid = (nextpid++); uid = _uid; thread_count = 0; @@ -284,6 +285,8 @@ process::process(process* _parent, uint32_t _uid, uint32_t _privilege) { data = 0; dataseg = 0; + fd.add((node*)-1); // descriptor #0 must not be used + stack = 0; if (privilege >= PL_USER) { //We are running in user mode size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; @@ -338,7 +341,7 @@ static void process_delete(process *pr) { } size_t process_sbrk(size_t size) { - process *p = current_thread->process; + process *p = current_process; if (p->data == 0) return -1; ASSERT(p->data < K_HIGHHALF_ADDR); if (p->data + size >= K_HIGHHALF_ADDR) return -1; @@ -378,9 +381,7 @@ size_t process_sbrk(size_t size) { } void process_brk(size_t ptr) { - process *p = current_thread->process; - ASSERT(ptr < K_HIGHHALF_ADDR); - process_sbrk(ptr - p->data); + process_sbrk(ptr - current_process->data); } diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 301f8be..1c32657 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -5,6 +5,8 @@ #include #include "idt.h" +#include + #define TS_RUNNING 0 #define TS_WAKEWAIT 2 //Waiting to be waked up by something precise (thread currently blocked) @@ -21,6 +23,7 @@ typedef void (*thread_entry)(void*); class thread; +class node; class process { public: @@ -34,7 +37,9 @@ class process { process *next; //Forms a linked list thread *threads; - process() {} // must not be used directly + earray fd; // file descriptors + + process() : fd(4, 4) {} // must not be used directly process(process *parent, uint32_t uid, uint32_t privilege); }; @@ -55,6 +60,7 @@ class thread { }; extern thread *current_thread; +extern process *current_process; void tasking_init(); #ifdef __cplusplus 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 + +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 +#include + +#include + +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 +#include + +struct vdir_child { + char* name; + node *el; + + vdir_child(char* na, node* nd) : el(nd) { + name = strdup(na); + } +}; + +class vdir : public node { + earray 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 + diff --git a/src/user/lib/include/tce/syscall.h b/src/user/lib/include/tce/syscall.h index 7bcdd2b..028b544 100644 --- a/src/user/lib/include/tce/syscall.h +++ b/src/user/lib/include/tce/syscall.h @@ -3,6 +3,7 @@ #include #include +#include #define NEW_STACK_SIZE 0x8000 @@ -18,4 +19,14 @@ int proc_priv(); void* sbrk(size_t size); void brk(void* ptr); +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/user/lib/std/stdio.c b/src/user/lib/std/stdio.c index 63ad357..c11dd05 100644 --- a/src/user/lib/std/stdio.c +++ b/src/user/lib/std/stdio.c @@ -32,7 +32,6 @@ void printk_int(int number) { } r[order] = 0; printk(s); - free(s); } void printk_hex(unsigned v) { diff --git a/src/user/lib/tce/syscall.c b/src/user/lib/tce/syscall.c index c7965a9..4e81475 100644 --- a/src/user/lib/tce/syscall.c +++ b/src/user/lib/tce/syscall.c @@ -1,6 +1,7 @@ #include #include #include +#include static size_t call(size_t a, size_t b, size_t c, size_t d, size_t e, size_t f) { size_t ret; @@ -62,6 +63,8 @@ int proc_priv() { return call(SC_PROC_PRIV, 0, 0, 0, 0, 0); } +// ******** memory + void* sbrk(size_t s) { return (void*)call(SC_SBRK, s, 0, 0, 0, 0); } @@ -69,3 +72,41 @@ void* sbrk(size_t s) { void brk(void* ptr) { return call (SC_BRK, ptr, 0, 0, 0, 0); } + +// ********** file + +FILE open(char* filename, int mode) { + return call(SC_OPEN, (unsigned)filename, mode, 0, 0, 0); +} + +FILE open_relative(FILE root, char* filename, int mode) { + return call(SC_OPEN_RELATIVE, root, (unsigned) filename, mode, 0, 0); +} + +int stat(char* filename, file_info *info) { + return call(SC_STAT, (unsigned) filename, (unsigned) info, 0, 0, 0); +} + +int stat_relative(FILE root, char* filename, file_info *info) { + return call(SC_STAT_RELATIVE, root, (unsigned) filename, (unsigned) info, 0, 0); +} + +int statf(FILE file, file_info *info) { + return call(SC_STATF, file, (unsigned)info, 0, 0, 0); +} + +void close(FILE file) { + call(SC_CLOSE, file, 0, 0, 0, 0); +} + +int read(FILE file, size_t offset, size_t len, char *buffer) { + return call(SC_READ, file, offset, len, (unsigned) buffer, 0); +} + +int write(FILE file, size_t offset, size_t len, char* buffer) { + return call(SC_WRITE, file, offset, len, (unsigned) buffer, 0); +} + +int link(char* from, char* to, int mode) { + return call(SC_LINK, (unsigned) from, (unsigned)to, mode, 0, 0); +} diff --git a/src/user/test/main.c b/src/user/test/main.c index ec14c21..a7df667 100644 --- a/src/user/test/main.c +++ b/src/user/test/main.c @@ -1,9 +1,14 @@ #include #include +#include + +int threads = 0; void thread_cascade(void* d) { int n = (int)d; + threads ++; + if (d == 0) { //printk("{#} 0 cascade element started => end\n"); printk("*"); @@ -25,6 +30,41 @@ void thread_cascade(void* d) { //printk("{#} Thread cascade element finished.\n"); printk("."); } + + threads--; +} + +void list_dir(FILE f, int lv) { + char buf[256]; + int i = 0, k; + int r; + file_info info; + + while ((r = read(f, i, 256, buf)) > 0) { + for (k = 0; k < lv; k++) printk(" "); + printk(buf); printk("\t\t"); + + stat_relative(f, buf, &info); + printk_hex(info.type); + if (info.type & FT_DIR) { + printk("\t"); + if (strcmp(buf, ".") != 0 && strcmp(buf, "..") != 0) { + FILE ff = open_relative(f, buf, 0); + if (ff <= 0) { + printk("error: "); printk_int(ff); printk("\n"); + } else { + printk("fd: "); printk_int(ff); printk("\n"); + list_dir(ff, lv+1); + close(ff); + } + } else { + printk("\n"); + } + } else { + printk("\n"); + } + i++; + } } int main() { @@ -32,12 +72,31 @@ int main() { printk_hex((uint32_t)malloc(42)); printk("\n"); - printk("(test app) Creating thread cascade (total 2**8 = 256 threads)\n"); - thread_new(thread_cascade, (void*)8); + printk(" -> Creating thread cascade (total 2**4 = 16 threads)\n"); + thread_new(thread_cascade, (void*)4); - printk("(test app) Main thread now sleeping... forever...\n"); + printk(" -> Main thread now sleeping...\n"); while (1) { + thread_sleep(100); + if (threads == 0) break; + } + printk("\n -> Ok, let's try something else.\n"); + + FILE f = open("/", 0); + if (f <= 0) { + printk(" -> Could not open '/', error #"); + printk_int(f); + printk("...\n"); + } else { + printk("Now enumerating '/' (fd "); printk_int(f); printk(") :\n"); + list_dir(f, 1); + close(f); + } + + printk(" -> Now sleeping, forever and ever...\n"); + while(1) { thread_sleep(1000); } + return 0; } -- cgit v1.2.3