matos/core/fsEntry.c
2024-05-23 16:27:20 +02:00

216 lines
5.0 KiB
C

#include "alloc.h"
#include "assert.h"
#include "fsEntry.h"
#include "errno.h"
#include "list.h"
#include "mem.h"
bool_t pstringSplipPath(struct pstr *path, struct pstr *upper, struct pstr *lower)
{
typeof(path->name) curPos = path->name;
typeof(path->len) curLen = path->len;
typeof(path->len) upperLen = 0;
// Skip leading /
while (curLen > 0 && curPos[0] == '/') {
curPos++;
curLen--;
}
upper->name = curPos;
// Find first non /
while (curLen > 0 && curPos[0] != '/') {
upperLen++;
curLen--;
curPos++;
}
upper->len = upperLen;
while (curLen > 0 && curPos[0] == '/') {
curPos++;
curLen--;
}
lower->name = curPos;
lower->len = path->len - (lower->name - path->name);
return lower->len > 0;
}
bool_t pstringIsEq(const struct pstr *p1, const struct pstr *p2)
{
return p1->len == p2->len && (memcmp(p1->name, p2->name, p1->len) == 0);
}
bool_t pstringIsStr(const struct pstr *p, char *s)
{
size_t slen = strlen(s);
return p->len == slen && (memcmp(p->name, s, slen) == 0);
}
int fsEntryRef(struct fs_entry *entry)
{
entry->ref++;
return 0;
}
int fsEntryUnref(struct fs_entry **entry)
{
struct fs_entry *toDelete = NULL, *entryTmp;
entryTmp = *entry;
while (entryTmp) {
assert(entryTmp->ref > 0);
entryTmp->ref--;
if (entryTmp->ref > 0)
break;
if (entryTmp == *entry)
*entry = NULL;
if (entryTmp->parent) {
struct fs_entry *parent = entryTmp->parent;
assert(entryTmp->parent->ref >= 1);
list_delete_named(parent->childs, entryTmp, prevSiblings, nextSiblings);
// At next iteration we will decrement parent's ref cnt
}
// Avoid recursivity in kernel by using a list of entry to suppress
list_add_tail_named(toDelete, entryTmp, prevSiblings, nextSiblings);
// now, unref parent
entryTmp = entryTmp->parent;
}
// free 0 ref entries
while (!list_is_empty_named(toDelete, prevSiblings, nextSiblings)) {
entryTmp = list_pop_head_named(toDelete, prevSiblings, nextSiblings);
fsInodeUnref(entryTmp->node);
free(entryTmp);
}
return 0;
}
struct fs_entry *fsEntryAlloc(struct fs_entry *parent, const struct pstr *name, struct inode *inode)
{
struct fs_entry *entry = zalloc(sizeof(struct fs_entry));
if (!entry)
return NULL;
if (name && name->len > 0) {
char *allocName = malloc(name->len);
if (!allocName) {
free(entry);
return NULL;
}
memcpy(allocName, name->name, name->len);
entry->name.len = name->len;
entry->name.name = allocName;
}
entry->ref = 1;
entry->node = inode;
entry->parent = parent;
fsInodeRef(inode);
if (parent) {
fsEntryRef(parent);
list_add_head_named(parent->childs, entry, prevSiblings, nextSiblings);
}
return entry;
}
int fsEntryLookup(struct fs_entry *entry, const struct pstr *name, const struct fs_entry *root, struct fs_entry **result)
{
if (pstringIsStr(name, ".")) {
*result = entry;
} else if (pstringIsStr(name, "..")) {
if (entry == root) {
*result = entry;
} else {
// If this entry is mounted, get the mountpoint
for (; entry->mountpoint; entry = entry->mountpoint) {
// No-op
}
assert(NULL != entry->parent);
*result = entry->parent;
}
fsEntryRef(*result);
return 0;
} else {
struct fs_entry *child;
int childIdx;
list_foreach_forward_named(entry->childs, child, childIdx, prevSiblings, nextSiblings)
{
if (pstringIsEq(&child->name, name)) {
break;
}
}
if (!list_foreach_early_break(entry->childs, child, childIdx))
return -ENOENT;
*result = child;
}
// Follow the mount chain
for (; (*result)->mountedFs; *result = (*result)->mountedFs)
;
fsEntryRef(*result);
return 0;
}
int fsEntrySetup(void)
{
return allocBookSlab(sizeof(struct fs_entry), PAGE_SIZE, 0, 0);
}
int fsEntryMount(struct fs_entry *mountpoint, struct fs_entry *mounted)
{
if (mountpoint->mountedFs != NULL || mounted->mountpoint != NULL) {
return -EBUSY;
}
mountpoint->mountedFs = mounted;
mounted->mountpoint = mountpoint;
fsEntryRef(mounted);
fsEntryRef(mountpoint);
return 0;
}
int fsEntryUmount(struct fs_entry *mounted)
{
if (!mounted->mountpoint || !mounted->mountpoint->mountedFs || mounted->mountpoint->mountedFs != mounted)
return -ENOENT;
if (mounted->mountedFs)
return -EBUSY;
// self + mounted
if (mounted->ref != 2)
return -EBUSY;
mounted->mountpoint->mountedFs = NULL;
fsEntryUnref(&mounted->mountpoint);
mounted->mountpoint = NULL;
fsEntryUnref(&mounted);
return 0;
}