From 21e8730f41123b55257b359201954fed6e6bbbe2 Mon Sep 17 00:00:00 2001 From: IlyaShurupov Date: Thu, 28 Mar 2024 15:52:07 +0300 Subject: [PATCH] link initial unstable --- inc/DirectoryTree.hpp | 6 ++++-- inc/FileSystem.hpp | 3 ++- src/DirectoryTree.cpp | 44 +++++++++++++++++++++++++++++++++++++++---- src/FileSystem.cpp | 42 +++++++++++++++++++++++++++++++++++++++++ src/Interpreter.cpp | 18 +++++++++++++++++- 5 files changed, 105 insertions(+), 8 deletions(-) diff --git a/inc/DirectoryTree.hpp b/inc/DirectoryTree.hpp index 77d39ec..d1b8e23 100644 --- a/inc/DirectoryTree.hpp +++ b/inc/DirectoryTree.hpp @@ -63,12 +63,14 @@ public: class Link : public Node { public: - Link(); + Link(Node* target, bool isHard); Link(const Link& node); [[nodiscard]] Link* clone() const override; [[nodiscard]] Node* getLink() const; + [[nodiscard]] bool isHard() const; + void setHard(bool); private: Node* mLink = nullptr; @@ -103,7 +105,7 @@ public: } void getNodePath(Node* node, std::vector& path) const; - ui64 size() const; + [[nodiscard]] ui64 size() const; private: void updateTreeLinkCount(Node* node); diff --git a/inc/FileSystem.hpp b/inc/FileSystem.hpp index ac1a541..df5f508 100644 --- a/inc/FileSystem.hpp +++ b/inc/FileSystem.hpp @@ -29,10 +29,11 @@ public: bool removeFileOrLink(const Path& path); bool copyNode(const Path& source, const Path& to); bool moveNode(const Path& source, const Path& to); + bool makeLink(const Path& source, const Path& to, bool isDynamic); void log() const; - const std::string& getLastError(); + static const std::string& getLastError(); private: bool isPathContainsCurrent(Node* node); diff --git a/src/DirectoryTree.cpp b/src/DirectoryTree.cpp index cd29309..0cafb75 100644 --- a/src/DirectoryTree.cpp +++ b/src/DirectoryTree.cpp @@ -4,6 +4,7 @@ #include std::string gError; +bool gDebug = true; Node::~Node() = default; @@ -27,14 +28,25 @@ File *File::clone() const { return new File(*this); } -Link::Link() { +Link::Link(Node* target, bool isHard) { mType = LINK; + mIsHard = isHard; + mLink = target; } Node *Link::getLink() const { return mLink; } +bool Link::isHard() const { + return mIsHard; +} + +void Link::setHard(bool val) { + mIsHard = val; + // TODO : do we need to update cache here? +} + Link::Link(const Link &node) : Node(node) { mLink = node.mLink; mIsHard = node.mIsHard; @@ -133,6 +145,7 @@ Node* Directory::findNode(const std::vector& path, ui32 currentDepth) { return ((Directory*)node)->findNode(path, ++currentDepth); case Node::LINK: + if (currentDepth == path.size() - 1) return node; node = ((Link*)node)->getLink(); break; @@ -186,15 +199,34 @@ void Directory::dumpUtil(std::stringstream& ss, ui32 currentDepth, std::vectorkey.val << "\n"; switch (node->data->mType) { case Node::DIRECTORY: + ss << node->key.val; + if (gDebug) ss << " [" << node->key.incomingLinksHard << ":" << node->key.incomingLinksDynamic << "]"; + ss << "\n"; ((Directory*) node->data)->dumpUtil(ss, currentDepth, indents); return; + case Node::LINK: { + auto linkNode = ((Link*)node->data); + ss << node->key.val << (linkNode->isHard() ? " hlink[/" : " dlink[/"); + std::vector path; + getNodePath(linkNode->getLink(), path); + std::reverse(path.begin(), path.end()); + for (auto key : path) ss << *key << "/"; + ss << "]\n"; + return; + } + + case Node::FILE: + ss << node->key.val; + if (gDebug) ss << " [file]"; + ss << "\n"; + return; + default: - // do nothing for now + ss << " ERROR \n"; return; } }); @@ -212,8 +244,12 @@ ui64 Directory::size() const { Directory::Directory(const Directory &node) : Node(node) { node.traverseInorder([&](const DirectoryTree::Node* node){ - mMembers.insert(node->key, node->data->clone()); + auto newNode = node->data->clone(); + mMembers.insert(node->key, newNode); + newNode->mParent = this; }); + + updateTreeLinkCount(this); } Directory *Directory::clone() const { diff --git a/src/FileSystem.cpp b/src/FileSystem.cpp index 9d4e561..bd50808 100644 --- a/src/FileSystem.cpp +++ b/src/FileSystem.cpp @@ -176,6 +176,48 @@ bool FileSystem::moveNode(const Path &source, const Path &target) { return true; } +bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic) { + if (source.getDepth() < 1 || source.isInvalid()) { + gError = "Invalid source path"; + return false; + } + + // TODO : remove code duplication + Directory* workingDirectorySource = source.isAbsolute() ? root : currentDirectory; + Directory* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory; + + auto sourceNode = workingDirectorySource->findNode(source.getChain()); + if (!sourceNode) { + gError = "Invalid source path"; + return false; + } + + if (sourceNode->mType == Node::LINK) { + gError = "Link on link is not allowed"; + return false; + } + + auto targetNode = workingDirectoryTarget->findNode(target.getChain()); + if (!targetNode || targetNode->mType != Node::DIRECTORY) { + gError = "Invalid target directory"; + return false; + } + + const Key& key = sourceNode->mTreeNode->key.val; + auto targetDirectory = (Directory*)targetNode; + + if (targetDirectory->findNode(key)) { + gError = "Node with such name already exists in the target directory"; + return false; + } + + auto newLink = new Link(sourceNode, !isDynamic); + + assert(targetDirectory->attachNode(key, newLink)); + + return true; +} + bool FileSystem::removeFileOrLink(const Path &path) { if (path.getDepth() < 1 || path.isInvalid()) { gError = "Invalid path"; diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 271da1f..62a8d26 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -73,6 +73,22 @@ Interpreter::Interpreter() { return filesystem.moveNode(args[1], args[2]); } }; + + mCommands["mhl"] = { + "make hard link", + 2, + [](FileSystem& filesystem, const std::vector& args){ + return filesystem.makeLink(args[1], args[2], false); + } + }; + + mCommands["mdl"] = { + "make dynamic link", + 2, + [](FileSystem& filesystem, const std::vector& args){ + return filesystem.makeLink(args[1], args[2], true); + } + }; } void Interpreter::reportError(const std::string& description) { @@ -116,7 +132,7 @@ void Interpreter::interpret(const std::string& command) { bool success = iter->second.callback(mFileSystem, words); if (!success) { - reportError(mFileSystem.getLastError()); + reportError(FileSystem::getLastError()); return; }