270 lines
7.1 KiB
C++

#include "fstree.h"
bool operator==(const PathEntry& lhs, const PathEntry& rhs) {
if (lhs.length == rhs.length)
if (lhs.length == 0)
return true;
else if (lhs.length < rhs.length)
return strcmp(lhs.path, rhs.path, lhs.length);
else
return strcmp(lhs.path, rhs.path, lhs.length);
return false;
}
bool operator!=(const PathEntry& lhs, const PathEntry& rhs) {
return !(lhs == rhs);
}
// FS Tree Skeleton
bool FSTree::exists(Path p){}
FSType FSTree::type(Path p){}
ReadWriter* FSTree::open(Path p){}
uint32_t FSTree::getDentsSize(Path p){}
void FSTree::getDents(Path p, FSDirectoryListing* buffer){}
// RootFSTree
RootFSTree::RootFSTree() {
this->node = new FSTreeNode{
PathEntry{0,0},
xnoe::linkedlist<FSTreeNode*>(),
0
};
}
bool pathEntryInFSTreeNode(PathEntry p, FSTreeNode* n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
if (current->elem->self == p)
return true;
current = current->next;
}
return false;
}
FSTreeNode* getNodeFromPathEntry(PathEntry p, FSTreeNode* n) {
if (!n)
return 0;
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
if (current->elem->self == p)
return current->elem;
current = current->next;
}
return 0;
}
FSTreeNode* RootFSTree::makeNodeIfNotExist(Path p) {
PathElement* currentPathElement = p.start;
FSTreeNode* currentNode = this->node;
if (!currentPathElement || currentPathElement == p.end)
return currentNode;
nextPE:
while (currentPathElement) {
xnoe::linkedlistelem<FSTreeNode*>* currentChild = currentNode->children.start;
while (currentChild) {
if (currentChild->elem->self == currentPathElement->elem) {
currentNode = currentChild->elem;
currentPathElement = currentPathElement->next;
goto nextPE;
}
currentChild = currentChild->next;
}
currentNode->children.append(new FSTreeNode{currentPathElement->elem, xnoe::linkedlist<FSTreeNode*>(), 0});
currentNode = currentNode->children.end->elem;
currentPathElement = currentPathElement->next;
}
return currentNode;
}
FSTree* RootFSTree::getLongestMatchingUnder(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
FSTree* lastMountpoint = 0;
while (currentPath && currentNode) {
if ((currentPath->elem == currentNode->self) && currentNode->mountpoint)
lastMountpoint = currentNode->mountpoint;
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
if (currentNode && currentNode->mountpoint)
lastMountpoint = currentNode->mountpoint;
currentPath = currentPath->next;
}
return lastMountpoint;
}
Path* RootFSTree::getRemainingPath(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
PathElement* lastMountpoint = 0;
while (currentPath && currentNode) {
if (currentPath->elem == currentNode->self && currentNode->mountpoint)
lastMountpoint = currentPath;
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
if (currentNode && currentNode->mountpoint)
lastMountpoint = currentPath;
currentPath = currentPath->next;
}
lastMountpoint = lastMountpoint->next;
if (lastMountpoint) {
Path* np = new Path;
PathElement* current = lastMountpoint;
while (current) {
np->append(current->elem);
current = current->next;
}
return np;
}
return 0;
}
FSTreeNode* RootFSTree::getExhaustive(Path p) {
PathElement* currentPath = p.start;
FSTreeNode* currentNode = this->node;
if (!currentPath)
return 0;
if (currentPath->elem != currentNode->self)
return 0;
while (currentPath && currentNode) {
currentNode = getNodeFromPathEntry(currentPath->elem, currentNode);
currentPath = currentPath->next;
}
if (currentPath)
return 0;
else
return currentNode;
}
template<typename T>
T RootFSTree::attempt(T(FSTree::*fn)(Path), Path p, T fallback) {
FSTree* mp = getLongestMatchingUnder(p);
if (mp) {
Path* rp = getRemainingPath(p);
T r;
if (rp) {
r = (mp->*fn)(*rp);
rp->destroy();
} else {
r = (mp->*fn)(Path());
}
return r;
}
return fallback;
}
void RootFSTree::attempt(void(FSTree::*fn)(Path, FSDirectoryListing*), Path p, FSDirectoryListing* b) {
FSTree* mp = getLongestMatchingUnder(p);
if (mp) {
Path* rp = getRemainingPath(p);
if (rp) {
(mp->*fn)(*rp, b);
rp->destroy();
} else {
(mp->*fn)(Path(), b);
}
}
}
bool RootFSTree::exists(Path p) {
return attempt<bool>(&FSTree::exists, p, false);
}
FSType RootFSTree::type(Path p){
return attempt<FSType>(&FSTree::type, p, Directory);
}
ReadWriter* RootFSTree::open(Path p){
return attempt<ReadWriter*>(&FSTree::open, p, 0);
}
uint32_t RootFSTree::getDentsSize(Path p){
uint32_t size = attempt<uint32_t>(&FSTree::getDentsSize, p, 0);
FSTreeNode* n = getExhaustive(p);
if (n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
size += sizeof(FSDirectoryEntry);
size += current->elem->self.length;
current = current->next;
}
}
return size;
}
void RootFSTree::getDents(Path p, FSDirectoryListing* buffer){
attempt(&FSTree::getDents, p, buffer);
uint32_t oldCount = buffer->count;
uint32_t stringsOffset = buffer->count * sizeof(FSDirectoryEntry) + sizeof(FSDirectoryListing);
uint32_t addCount = 0;
char* strings = ((uint32_t)buffer) + stringsOffset;
FSTreeNode* n = getExhaustive(p);
if (n) {
xnoe::linkedlistelem<FSTreeNode*>* current = n->children.start;
while (current) {
addCount++;
current = current->next;
}
if (addCount) {
current = n->children.start;
for (int i=buffer->stringsLength; i>=0; i--)
strings[i+addCount*sizeof(FSDirectoryEntry)] = strings[i];
for (int i=0; i < buffer->count; i++)
buffer->entries[i].path.path += addCount*sizeof(FSDirectoryEntry);
while (current) {
strings += addCount*sizeof(FSDirectoryEntry) + buffer->stringsLength;
memcpy(strings, current->elem->self.path, current->elem->self.length);
buffer->entries[buffer->count++] = FSDirectoryEntry {
PathEntry{
current->elem->self.length,
strings
},
Directory,
0
};
strings += current->elem->self.length;
current = current->next;
}
}
}
}
bool RootFSTree::isMountpoint(Path p) {
Path* mp = getRemainingPath(p);
if (mp->start->next)
return false;
else
return true;
}
void RootFSTree::mount(Path p, FSTree* f) {
FSTreeNode* fstn = makeNodeIfNotExist(p);
fstn->mountpoint = f;
}
void RootFSTree::unmount(Path p) {
}
Path createPathFromString(char* s) {
Path p;
p.start = 0;
p.end = 0;
char* lastPtr = s;
uint32_t length = 0;
char c;
while (c=*(s++)) {
if (c == '/') {
if (length == 0)
p.append(PathEntry{length, 0});
else
p.append(PathEntry{length, lastPtr});
lastPtr = s;
length = 0;
continue;
}
length += 1;
}
if (length)
p.append(PathEntry{length, lastPtr});
return p;
}