216 lines
5.0 KiB
C
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;
|
||
|
}
|