metal-cos/sys/kern/vfs.c
2023-09-10 16:12:25 -04:00

221 lines
3.8 KiB
C

/*
* Copyright (c) 2013-2023 Ali Mashtizadeh
* All rights reserved.
*/
#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);
/**
* VFS_MountRoot --
*
* Mount the root file system from a specific disk.
*/
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;
}
/**
* VFS_Lookup --
*
* Lookup a VNode by a path. This function recursively searches the directory
* heirarchy until the given path is found otherwise returns NULL if not found.
*/
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') {
Log(vfs, "%s %lx\n", path, curNode);
return curNode;
}
start = end + 1;
end = end + 1;
}
}
/**
* VFS_Stat --
*
* Return the struct stat that contains the file and directory information for
* a given VNode.
*/
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;
}
/**
* VFS_Open --
*
* Open a vnode for reading and writing.
*
* @param [in] fn VNode to open.
*
* @return Return status
*/
int
VFS_Open(VNode *fn)
{
return fn->op->open(fn);
}
/**
* VFS_Close --
*
* Close a vnode.
*
* @param [in] fn VNode to close.
*
* @return Return status
*/
int
VFS_Close(VNode *fn)
{
return fn->op->close(fn);
}
/**
* VFS_Read --
*
* Read from a vnode.
*
* @param [in] fn VNode to read from.
* @param [in] buf Buffer to write the data to.
* @param [in] off File offset in bytes.
* @param [in] len Length to read in bytes.
*
* @return Return status
*/
int
VFS_Read(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
return fn->op->read(fn, buf, off, len);
}
/**
* VFS_Write --
*
* Write from a vnode.
*
* @param [in] fn VNode to write to.
* @param [in] buf Buffer to read the data from.
* @param [in] off File offset in bytes.
* @param [in] len Length to read in bytes.
*
* @return Return status
*/
int
VFS_Write(VNode *fn, void *buf, uint64_t off, uint64_t len)
{
return fn->op->write(fn, buf, off, len);
}
/**
* VFS_ReadDir --
*
* Read a directory entry from a vnode.
*
* @param [in] fn VNode to read from.
* @param [in] buf Buffer to write the data to.
* @param [in] off Directory offset in bytes.
* @param [in] len Length to read in bytes.
*
* @return Return status
*/
int
VFS_ReadDir(VNode *fn, void *buf, uint64_t len, uint64_t *off)
{
return fn->op->readdir(fn, buf, len, off);
}