metal-cos/sys/kern/vfs.c
2015-01-23 12:16:20 -08:00

144 lines
2.3 KiB
C

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/kassert.h>
#include <sys/kdebug.h>
#include <sys/spinlock.h>
#include <sys/disk.h>
#include <sys/vfs.h>
#include <sys/handle.h>
extern VFS *O2FS_Mount(Disk *root);
static Spinlock vfsLock;
static VFS *rootFS;
static VNode *rootNode;
static Slab vfsSlab;
static Slab vnodeSlab;
DEFINE_SLAB(VFS, &vfsSlab);
DEFINE_SLAB(VNode, &vnodeSlab);
int
VFS_MountRoot(Disk *rootDisk)
{
int status;
Spinlock_Init(&vfsLock, "VFS Lock", SPINLOCK_TYPE_NORMAL);
Slab_Init(&vfsSlab, "VFS Slab", sizeof(VFS), 16);
Slab_Init(&vnodeSlab, "VNode Slab", sizeof(VNode), 16);
rootFS = O2FS_Mount(rootDisk);
if (!rootFS)
return -1;
status = rootFS->op->getroot(rootFS, &rootNode);
if (status < 0)
Panic("Failed to get root VNode\n");
return 0;
}
VNode *
VFS_Lookup(const char *path)
{
int status;
const char *start = path + 1;
const char *end = path + 1;
uint64_t len;
VNode *curNode;
VNode *oldNode;
char curName[256];
if (path[0] != '/')
return NULL;
status = rootFS->op->getroot(rootFS, &curNode);
if (status < 0)
Panic("Failed to get root VNode\n");
while (1) {
while (*end != '\0' && *end != '/')
end++;
len = (size_t)(end - start);
if (len == 0) {
// Handle root and trailing slash
return curNode;
}
if (len > 256) {
// Release
return NULL;
}
memcpy(curName, start, len);
curName[len] = '\0';
oldNode = curNode;
curNode = NULL;
status = oldNode->op->lookup(oldNode, &curNode, curName);
if (status < 0) {
// Release
return NULL;
}
// Release oldNode
if (*end == '\0')
return curNode;
start = end + 1;
end = end + 1;
}
}
int
VFS_Stat(const char *path, struct stat *sb)
{
VNode *vn = VFS_Lookup(path);
if (vn == NULL)
return -ENOENT;
vn->op->stat(vn, sb);
// Release
return 0;
}
int
VFS_Open(VNode *fn)
{
return fn->op->open(fn);
}
int
VFS_Close(VNode *fn)
{
return fn->op->close(fn);
}
int
VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
return fn->op->read(fn, buf, off, len);
}
int
VFS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
return fn->op->write(fn, buf, off, len);
}
int
VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off)
{
return fn->op->readdir(fn, buf, len, off);
}