diff options
Diffstat (limited to 'src/fs/fs.cc')
| -rw-r--r-- | src/fs/fs.cc | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/fs/fs.cc b/src/fs/fs.cc new file mode 100644 index 0000000..b2b91c2 --- /dev/null +++ b/src/fs/fs.cc @@ -0,0 +1,190 @@ +#include "fs/fs.h" +#include "kernel/riscv.h" +#include "drivers/uart.h" +#include "kernel/spinlock.h" +#include "kernel/proc.h" +#include "fs/fat32.h" +#include "lib/string.h" + +static Inode *global_root_inode = nullptr; + +static const char *skipelem(const char *path, char *name) +{ + const char *s; + int len; + + while (*path == '/') + path++; + if (*path == 0) + return nullptr; + + s = path; + while (*path != '/' && *path != 0) + path++; + + len = path - s; + if (len >= 128) + len = 127; + + memmove(name, s, len); + name[len] = 0; + + while (*path == '/') + path++; + return path; +} + +void Inode::getattr(struct kstat *st) +{ + st->dev = dev; + st->ino = inum; + st->type = type; + st->nlink = nlink; + st->size = size; + + st->uid = 0; + st->gid = 0; + st->mode = 0; +} + +namespace VFS +{ + void init() + { + Drivers::uart_puts("[VFS] Inode subsystem initialized.\n"); + } + + void iput(Inode *ip) + { + if (ip == nullptr) + return; + + ip->lock.acquire(); + if(ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: iput ref\n"); + while (1) + ; + } + ip->ref_cnt--; + int ref = ip->ref_cnt; + ip->lock.release(); + + if (ref == 0) + { + delete ip; + } + } + + Inode* idup(Inode *ip) + { + if (ip == nullptr) + return nullptr; + + ip->lock.acquire(); + ip->ref_cnt++; + ip->lock.release(); + return ip; + } + + void ilock(Inode *ip) + { + if (ip == 0 || ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: ilock\n"); + while (1) + ; + } + + ip->lock.acquire(); + + } + + void iunlock(Inode *ip) + { + if (ip == 0 || !ip->lock.holding() || ip->ref_cnt < 1) + { + Drivers::uart_puts("panic: iunlock\n"); + while (1) + ; + } + ip->lock.release(); + } + + static void iunlockput(Inode *ip) + { + iunlock(ip); + iput(ip); + } + + void mount_root(Inode *root) + { + if (global_root_inode) + { + Drivers::uart_puts("VFS: Root already mounted!\n"); + return; + } + global_root_inode = root; + Drivers::uart_puts("[VFS] Root filesystem mounted.\n"); + } + + Inode *get_root() + { + if (global_root_inode == nullptr) + { + Drivers::uart_puts("[VFS] Lazy init: Mounting FAT32...\n"); + fat32_fs.init(); + mount_root(fat32_fs.root()); + } + if (!global_root_inode) + return nullptr; + return idup(global_root_inode); + } + + Inode *namei(const char *path) + { + char name[128]; + Inode *ip, *next; + struct Proc *p = myproc(); + + if (*path == '/') + { + ip = get_root(); + } + else + { + if (p->cwd == nullptr) + { + ip = get_root(); + } + else + { + ip = idup(p->cwd); + } + } + + if (ip == nullptr) + return nullptr; + + while ((path = skipelem(path, name)) != nullptr) + { + ilock(ip); + + if (ip->type != T_DIR) + { + iunlockput(ip); + return nullptr; + } + + next = ip->lookup(name); + iunlockput(ip); + + ip = next; + if (ip == nullptr) + return nullptr; + } + + return ip; + } + +} // namespace VFS |
