/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include #include namespace vfs { int Node::open(int Flags, mode_t Mode) { debug("Operation not handled"); return -ENXIO; } int Node::close() { debug("Operation not handled"); return -ENXIO; } size_t Node::read(uint8_t *Buffer, size_t Size, off_t Offset) { debug("Operation not handled"); return -ENXIO; } size_t Node::write(uint8_t *Buffer, size_t Size, off_t Offset) { debug("Operation not handled"); return -ENXIO; } int Node::ioctl(unsigned long Request, void *Argp) { debug("Operation not handled"); return -ENODEV; } RefNode *Node::CreateReference() { SmartLock(NodeLock); RefNode *ref = new RefNode(this); References.push_back(ref); debug("Created reference %#lx for node %#lx", ref, this); return ref; } void Node::RemoveReference(RefNode *Reference) { SmartLock(NodeLock); debug("Removing reference %#lx for node %#lx", Reference, this); References.erase(std::find(References.begin(), References.end(), Reference)); } Node::Node(Node *Parent, const char *Name, NodeType Type, bool NoParent, Virtual *fs, int *Err) { assert(Name != nullptr); assert(strlen(Name) != 0); assert((NoParent == false && fs == nullptr) || (NoParent == true && fs != nullptr)); if (Err != nullptr) *Err = 0; this->Type = Type; auto GetChild = [](const char *Name, Node *Parent) { if (!Parent) return (Node *)nullptr; foreach (auto Child in Parent->Children) { if (strcmp(Child->Name, Name) == 0) return Child; } return (Node *)nullptr; }; auto CreateWithParent = [this](const char *Name, Node *Parent) { assert(Parent->vFS != nullptr); assert(Parent->Type == DIRECTORY || Parent->Type == MOUNTPOINT); this->vFS = Parent->vFS; this->Parent = Parent; this->Name = new char[strlen(Name) + 1]; strcpy((char *)this->Name, Name); this->FullPath = new char[strlen(Parent->FullPath) + strlen(this->Name) + 2]; strcpy((char *)this->FullPath, Parent->FullPath); if (strcmp(this->FullPath, "/") != 0) strcat((char *)this->FullPath, "/"); strcat((char *)this->FullPath, this->Name); this->Parent->Children.push_back(this); }; if (Parent) CreateWithParent(Name, Parent); else if (NoParent) { const char *Path = Name; Node *RootNode = fs->FileSystemRoot->Children[0]; Node *CurrentParent = fs->GetParent(Path, Parent); if (fs->PathExists(Path, CurrentParent)) { debug("Path \"%s\" already exists.", Path); delete[] Path; if (Err != nullptr) *Err = -EEXIST; delete this; return; } const char *CleanPath = fs->NormalizePath(Path, CurrentParent); cwk_segment segment; if (!cwk_path_get_first_segment(CleanPath, &segment)) { debug("Path doesn't have any segments."); delete[] CleanPath; if (Err != nullptr) *Err = -EINVAL; delete this; return; } cwk_segment last_segment; cwk_path_get_last_segment(CleanPath, &last_segment); do { char *SegmentName = new char[segment.end - segment.begin + 1]; memcpy(SegmentName, segment.begin, segment.end - segment.begin); if (Parent) { if (GetChild(SegmentName, RootNode) != nullptr) { RootNode = GetChild(SegmentName, RootNode); delete[] SegmentName; continue; } } if (GetChild(SegmentName, CurrentParent) == nullptr) { if (segment.begin == last_segment.begin) { CreateWithParent(SegmentName, CurrentParent); delete[] SegmentName; break; /* This is the last segment anyway... */ } CurrentParent = new Node(CurrentParent, SegmentName, Type); } else { CurrentParent = GetChild(SegmentName, CurrentParent); } delete[] SegmentName; } while (cwk_path_get_next_segment(&segment)); } else { this->Name = new char[strlen(Name) + 1]; strcpy((char *)this->Name, Name); this->FullPath = Name; trace("Node %s(%#lx) has no parent", this->Name, this); } } int Node::Delete(bool Recursive) { if (this->References.size() != 0) { debug("Node %s(%#lx) has %ld references", this->FullPath, this, this->References.size()); return -EBUSY; } if (this->Type == MOUNTPOINT || this->Type == DIRECTORY) { if (this->Children.size() != 0) { if (!Recursive) { debug("Node %s(%#lx) has %ld children", this->FullPath, this, this->Children.size()); return -ENOTEMPTY; } for (auto Child : this->Children) { int ret = Child->Delete(Recursive); if (ret < 0) { debug("Failed to delete child %s(%#lx)", Child->FullPath, Child); return ret; } } } } delete this; return 0; } Node::~Node() { debug("Destroyed node %#lx", this); assert(this->Children.size() == 0); if (this->Parent) { this->Parent->Children.erase(std::find(this->Parent->Children.begin(), this->Parent->Children.end(), this)); } delete[] this->Name; if (this->Parent) delete[] this->FullPath; if (this->Symlink) delete[] this->Symlink; } }