#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; }