This commit is contained in:
IlyaShurupov 2024-03-29 12:27:21 +03:00
parent 7655a7f5f0
commit cd593ab024
13 changed files with 467 additions and 459 deletions

35
inc/Directory.hpp Normal file
View file

@ -0,0 +1,35 @@
#pragma once
#include "Node.hpp"
class Directory : public Node {
typedef std::map<Key, Node*> DirectoryTree;
public:
Directory();
Directory(const Directory& node);
~Directory() override;
[[nodiscard]] Directory* clone() const override;
bool attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode) override;
bool detachNode(const std::vector<Key>& directoryPath, const Key& key) override;
bool detachNode(const Key& key) override;
bool attachNode(const Key &newKey, Node *newNode) override;
Node* findNode(const std::vector<Key>& path, ui32 currentDepth = 0) override;
Node* findNode(const Key& path) override;
[[nodiscard]] ui64 size() const override;
bool isDirectory() const override { return true; }
private:
void getMaxDepthUtil(ui32 depth, ui32& maxDepth) const;
void dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) override;
public:
DirectoryTree mMembers;
};

View file

@ -1,93 +0,0 @@
#pragma once
typedef unsigned long long ui64;
typedef unsigned long ui32;
typedef long long i64;
typedef long i32;
#include <map>
#include <utility>
#include <vector>
#include <string>
class Link;
extern std::string gError;
typedef std::string Key;
class Node {
public:
Node() = default;
Node(const Node& node);
virtual ~Node();
[[nodiscard]] virtual Node* clone() const;
public:
enum Type : ui32 { NONE, DIRECTORY, FILE, LINK } ;
Type mType = NONE; // TODO : remove
class Directory* mParent = nullptr;
std::vector<Link*> mIncomingHardLinks;
std::vector<Link*> mIncomingDynamicLinks;
};
typedef std::map<Key, Node*> DirectoryTree;
class File : public Node {
public:
File();
File(const File& node);
[[nodiscard]] File* clone() const override;
};
class Link : public Node {
public:
Link(Node* target, bool isHard);
Link(const Link& node);
~Link() override;
[[nodiscard]] Link* clone() const override;
[[nodiscard]] Node* getLink() const;
[[nodiscard]] bool isHard() const;
private:
Node* mLink = nullptr;
bool mIsHard = false;
};
class Directory : public Node {
public:
Directory();
Directory(const Directory& node);
~Directory() override;
[[nodiscard]] Directory* clone() const override;
void dump(std::stringstream& ss);
bool attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode);
bool detachNode(const std::vector<Key>& directoryPath, const Key& key);
bool detachNode(const Key& key);
bool attachNode(const Key &newKey, Node *newNode);
Node* findNode(const std::vector<Key>& path, ui32 currentDepth = 0);
Node* findNode(const Key& path);
[[nodiscard]] ui32 getMaxDepth() const;
void getNodeStraightPath(Node* node, std::vector<const Node*>& path) const;
[[nodiscard]] ui64 size() const;
private:
void getMaxDepthUtil(ui32 depth, ui32& maxDepth) const;
void dumpUtil(std::stringstream& ss, ui32 currentDepth, std::vector<bool>& indents);
public:
DirectoryTree mMembers;
};

View file

@ -1,21 +1,20 @@
#pragma once
#include "Node.hpp"
#include "Path.hpp"
#include "DirectoryTree.hpp"
#include <sstream>
// FIX MEMORY VIOLATIONS WITH LINKS
// restore path unwindingk
// RESTORE LINKS
// COPY operator update link targets
// Improve error logs
// use smart pointers
// DONT STORE CACHE
// DO O(N) deletion and moving
// in-tree node links will report false to those operations and hard nodes deletion
// use in node 'is_delete' flag and travers all nodes with link checks
// remove mParent mTreeNode links
// Key (is copied on each tree access) !!!
// Functionality:
// deleting directory - mark all nodes as deleted
// traverse and check for links
@ -51,6 +50,6 @@ private:
bool isPathContainsCurrent(Node* node);
private:
Directory* root = nullptr;
Directory* currentDirectory = nullptr;
Node* root = nullptr;
Node* currentDirectory = nullptr;
};

28
inc/Link.hpp Normal file
View file

@ -0,0 +1,28 @@
#pragma once
#include "Node.hpp"
class Link : public Node {
public:
Link(Node* target, bool isHard);
Link(const Link& node);
~Link() override;
[[nodiscard]] Link* clone() const override;
[[nodiscard]] Node* getLink() const;
[[nodiscard]] bool isHard() const;
Node* getTarget() override;
// link on link is not allowed, so no inf looping here
Node* findNode(const std::vector<Key>& path, ui32 currentDepth) override;
void dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) override;
bool isLink() const override { return true; }
private:
Node* mLink = nullptr;
bool mIsHard = false;
};

64
inc/Node.hpp Normal file
View file

@ -0,0 +1,64 @@
#pragma once
typedef unsigned long long ui64;
typedef unsigned long ui32;
typedef long long i64;
typedef long i32;
#include <map>
#include <utility>
#include <vector>
#include <string>
#include <cassert>
class Link;
extern std::string gError;
typedef std::string Key;
class Node {
public:
Node() = default;
Node(const Node& node);
virtual ~Node();
[[nodiscard]] virtual Node* clone() const;
virtual bool attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode) { return false; }
virtual bool detachNode(const std::vector<Key>& directoryPath, const Key& key) { return false; }
virtual bool detachNode(const Key& key) { return false; }
virtual bool attachNode(const Key &newKey, Node *newNode) { return false; }
virtual void getMaxDepthUtil(ui32 depth, ui32& maxDepth) const {}
virtual void dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents);
ui32 getMaxDepth() const;
void dump(std::stringstream& ss);
void getNodeStraightPath(Node* node, std::vector<const Node*>& path) const;
virtual ui64 size() const { return 0; }
virtual Node* getTarget() { return this; }
virtual Node* findNode(const std::vector<Key>& path, ui32 currentDepth = 0);
virtual Node* findNode(const Key& path) { return nullptr; }
bool empty() const { return !size(); }
static void indent(std::stringstream & ss, ui32 depth, std::vector<bool>& indents);
virtual bool isDirectory() const { return false; }
virtual bool isLink() const { return false; }
virtual bool isHard() const { return false; }
public:
Node* mParent = nullptr;
std::vector<Link*> mIncomingHardLinks;
std::vector<Link*> mIncomingDynamicLinks;
};

130
src/Directory.cpp Normal file
View file

@ -0,0 +1,130 @@
#include "Directory.hpp"
#include <sstream>
#include <cassert>
#include <algorithm>
Directory::Directory() {
}
bool Directory::attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode) {
Node* node = findNode(directoryPath);
if (!node) {
gError = "Invalid path";
return false;
}
while (node->getTarget() != node) node = node->getTarget();
return node->attachNode(newKey, newNode);
}
bool Directory::attachNode(const Key &newKey, Node *newNode) {
auto iterNode = mMembers.find(newKey);
if (iterNode != mMembers.end()) {
Node* existingNode = iterNode->second;
if (!(typeid(*existingNode) == typeid(*newNode) && newNode->empty() && existingNode->empty())) {
gError = "Such node already exists";
return false;
}
return false; // exit silently
}
mMembers.insert({ newKey, newNode });
newNode->mParent = this;
return true;
}
bool Directory::detachNode(const std::vector<Key>& directoryPath, const Key& key) {
Node* node = findNode(directoryPath);
return node->detachNode(key);
}
bool Directory::detachNode(const Key& key) {
auto removeNode = mMembers.find(key);
if (removeNode == mMembers.end()) {
gError = "Invalid path";
return false;
}
//if (removeNode->key.incomingLinksHard || removeNode->key.incomingLinksDynamic) {
// gError = "Cannot modify node with incoming hard links";
// return false;
//}
removeNode->second->mParent = nullptr;
mMembers.erase(key);
return true;
}
Node* Directory::findNode(const Key& key) {
auto iterNode = mMembers.find(key);
return iterNode != mMembers.end() ? iterNode->second : nullptr;
}
Node* Directory::findNode(const std::vector<Key>& path, ui32 currentDepth) {
if (path.size() == currentDepth) {
return this;
}
const Key& key = path[currentDepth];
auto nextNode = mMembers.find(key);
if (nextNode == mMembers.end()) {
return nullptr;
}
return nextNode->second->findNode(path, currentDepth + 1);
}
void Directory::getMaxDepthUtil(ui32 depth, ui32& maxDepth) const {
if (mMembers.empty()) return;
maxDepth = std::max(depth, maxDepth);
for (auto& node : mMembers) {
node.second->getMaxDepthUtil(++depth, maxDepth);
}
}
void Directory::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indents[currentDepth] = true;
indent(ss, currentDepth, indents);
ss << key;
ss << " [" << mIncomingHardLinks.size() << ":" << mIncomingDynamicLinks.size() << "]";
ss << "\n";
currentDepth++;
if (mMembers.empty()) return;
const auto& lastNode = mMembers.rbegin()->first;
for (auto & member : mMembers) {
if (lastNode == member.first) indents[currentDepth - 1] = false;
member.second->dumpUtil(ss, member.first, currentDepth, indents);
}
}
ui64 Directory::size() const {
return mMembers.size();
}
Directory::Directory(const Directory &node) : Node(node) {
for (auto & member : node.mMembers) {
auto newNode = member.second->clone();
mMembers.insert({ member.first, newNode });
newNode->mParent = this;
}
}
Directory::~Directory() {
for (const auto& node : mMembers) {
delete node.second;
}
}
Directory *Directory::clone() const {
return new Directory(*this);
}

View file

@ -1,286 +0,0 @@
#include "DirectoryTree.hpp"
#include <sstream>
#include <cassert>
#include <algorithm>
std::string gError;
bool gDebug = true;
Node::~Node() {
// assert(mIncomingHardLinks.empty());
// for (auto dynamicLink : mIncomingDynamicLinks) {
// dynamicLink->mParent->detachNode(dynamicLink->mTreeNode->key.val);
// delete dynamicLink;
//
}
Node::Node(const Node &node) {
mType = node.mType;
}
Node *Node::clone() const {
return new Node(*this);
}
File::File() {
mType = Type::FILE;
}
File::File(const File& node) : Node(node) {
// nothing to do
}
File *File::clone() const {
return new File(*this);
}
Link::Link(Node* target, bool isHard) {
mType = LINK;
mIsHard = isHard;
mLink = target;
if (mIsHard) {
target->mIncomingHardLinks.push_back(this);
} else {
target->mIncomingDynamicLinks.push_back(this);
}
}
Node *Link::getLink() const {
return mLink;
}
bool Link::isHard() const {
return mIsHard;
}
Link::Link(const Link &node) : Node(node) {
mLink = node.mLink;
mIsHard = node.mIsHard;
assert(mLink);
if (mIsHard) {
mLink->mIncomingHardLinks.push_back(this);
} else {
mLink->mIncomingDynamicLinks.push_back(this);
}
}
Link *Link::clone() const {
return new Link(*this);
}
Link::~Link() {
// assert(mLink);
// auto& links = mIsHard ? mLink->mIncomingHardLinks : mLink->mIncomingDynamicLinks;
// links.erase(std::remove(links.begin(), links.end(), this), links.end());
// Directory::updateTreeLinkCount(mLink);
// mLink = nullptr;
}
Directory::Directory() {
mType = DIRECTORY;
}
bool Directory::attachNode(const std::vector<Key>& directoryPath, const Key& newKey, Node* newNode) {
Node* node = findNode(directoryPath, 0);
while (node && node->mType == LINK) node = ((Link*)node)->getLink();
if (!node || node->mType != DIRECTORY) {
gError = "Invalid path";
return false;
}
return ((Directory*) node)->attachNode(newKey, newNode);
}
bool Directory::attachNode(const Key &newKey, Node *newNode) {
auto iterNode = mMembers.find(newKey);
if (iterNode != mMembers.end()) {
if (iterNode->second->mType == newNode->mType) return false; // exit silently
gError = "Can not add node";
return false;
}
mMembers.insert({ newKey, newNode });
newNode->mParent = this;
return true;
}
bool Directory::detachNode(const std::vector<Key>& directoryPath, const Key& key) {
Node* node = findNode(directoryPath, 0);
if (!node || node->mType != DIRECTORY) {
gError = "Invalid path";
return false;
}
return ((Directory*) node)->detachNode(key);
}
bool Directory::detachNode(const Key& key) {
auto removeNode = mMembers.find(key);
if (removeNode == mMembers.end()) {
gError = "Invalid path";
return false;
}
//if (removeNode->key.incomingLinksHard || removeNode->key.incomingLinksDynamic) {
// gError = "Cannot modify node with incoming hard links";
// return false;
//}
removeNode->second->mParent = nullptr;
mMembers.erase(key);
return true;
}
Node* Directory::findNode(const Key& key) {
auto iterNode = mMembers.find(key);
return iterNode != mMembers.end() ? iterNode->second : nullptr;
}
Node* Directory::findNode(const std::vector<Key>& path, ui32 currentDepth) {
if (path.size() == currentDepth) {
return this;
}
const Key& key = path[currentDepth];
auto iterNode = mMembers.find(key);
if (iterNode == mMembers.end()) {
return nullptr;
}
Node* node = iterNode->second;
// link on link is not allowed
while (true) {
switch (node->mType) {
case Node::FILE:
if (currentDepth == path.size() - 1) return node;
return nullptr;
case Node::DIRECTORY:
return ((Directory*)node)->findNode(path, ++currentDepth);
case Node::LINK:
if (currentDepth == path.size() - 1) return node;
node = ((Link*)node)->getLink();
break;
default:
return nullptr;
}
}
}
void Directory::getMaxDepthUtil(ui32 depth, ui32& maxDepth) const {
if (mMembers.empty()) return;
maxDepth = std::max(depth, maxDepth);
for (auto& node : mMembers) {
if (node.second->mType == DIRECTORY) {
((Directory*)node.second)->getMaxDepthUtil(++depth, maxDepth);
}
}
}
ui32 Directory::getMaxDepth() const {
ui32 maxDepth = 1;
getMaxDepthUtil(1, maxDepth);
return maxDepth;
}
void Directory::dump(std::stringstream& ss) {
std::vector<bool> indents;
indents.resize(getMaxDepth());
dumpUtil(ss, 0, indents);
ss << "\n";
}
static void indent(std::stringstream & ss, ui32 depth, std::vector<bool>& indents) {
if (!depth) return;
for (auto i = 0; i < depth - 1; i++) {
ss << (indents[i] ? " |" : " ");
}
ss << " |_ ";
}
void Directory::dumpUtil(std::stringstream& ss, ui32 currentDepth, std::vector<bool>& indents) {
if (mMembers.empty())
return;
indents[currentDepth] = true;
currentDepth++;
const auto& lastNode = mMembers.rbegin()->first;
for (auto & member : mMembers) {
if (lastNode == member.first)
indents[currentDepth - 1] = false;
indent(ss, currentDepth, indents);
switch (member.second->mType) {
case Node::DIRECTORY:
ss << member.first;
if (gDebug) ss << " [" << member.second->mIncomingHardLinks.size() << ":" << member.second->mIncomingDynamicLinks.size() << "]";
ss << "\n";
((Directory*) member.second)->dumpUtil(ss, currentDepth, indents);
break;
case Node::LINK: {
auto linkNode = ((Link*)member.second);
ss << member.first << (linkNode->isHard() ? " hlink[/" : " dlink[/");
std::vector<const Node*> path;
getNodeStraightPath(linkNode->getLink(), path);
std::reverse(path.begin(), path.end());
for (auto key : path)
ss << "X" << "/";
ss << "]\n";
break;
}
case Node::FILE:
ss << member.first;
if (gDebug) ss << " [file]";
ss << "\n";
break;
default:
ss << " ERROR \n";
break;
}
}
}
void Directory::getNodeStraightPath(Node* node, std::vector<const Node*>& path) const {
if (!node) return;
path.push_back(node);
getNodeStraightPath(node->mParent, path);
}
ui64 Directory::size() const {
return mMembers.size();
}
Directory::Directory(const Directory &node) : Node(node) {
for (auto & member : node.mMembers) {
auto newNode = member.second->clone();
mMembers.insert({ member.first, newNode });
newNode->mParent = this;
}
}
Directory::~Directory() {
for (auto node : mMembers) {
delete node.second;
}
}
Directory *Directory::clone() const {
return new Directory(*this);
}

View file

@ -1,6 +1,9 @@
#include "FileSystem.hpp"
#include "Directory.hpp"
#include "Link.hpp"
#include <iostream>
#include <cassert>
#include <algorithm>
@ -21,19 +24,12 @@ bool FileSystem::makeDirectory(const Path& path) {
return false;
}
Directory* parentDirectory = path.isAbsolute() ? root : currentDirectory;
auto existingNode = parentDirectory->findNode(path.getChain());
if (existingNode) {
if (existingNode->mType == Node::DIRECTORY) return true;
gError = "Can not create directory, such node exists";
return false;
}
Node* parentNode = path.isAbsolute() ? root : currentDirectory;
auto newDirectory = new Directory();
if (!parentDirectory->attachNode(path.getParentChain(), path.getFilename(), newDirectory)) {
if (!parentNode->attachNode(path.getParentChain(), path.getFilename(), newDirectory)) {
delete newDirectory;
gError = "Invalid path";
gError = "Invalid path or node exists";
return false;
}
@ -46,17 +42,10 @@ bool FileSystem::makeFile(const Path& path) {
return false;
}
Directory* parentDirectory = path.isAbsolute() ? root : currentDirectory;
Node* parentNode = path.isAbsolute() ? root : currentDirectory;
auto existingNode = parentDirectory->findNode(path.getChain());
if (existingNode) {
if (existingNode->mType == Node::FILE) return true;
gError = "Can not create file, such node exists";
return false;
}
auto newFile = new File();
if (!parentDirectory->attachNode(path.getParentChain(), path.getFilename(), newFile)) {
auto newFile = new Node();
if (!parentNode->attachNode(path.getParentChain(), path.getFilename(), newFile)) {
delete newFile;
gError = "Invalid path";
return false;
@ -71,20 +60,20 @@ bool FileSystem::removeDirectory(const Path& path, bool recursively) {
return false;
}
Directory* parentDirectory = path.isAbsolute() ? root : currentDirectory;
Node* parentNode = path.isAbsolute() ? root : currentDirectory;
auto existingNode = parentDirectory->findNode(path.getChain());
auto existingNode = parentNode->findNode(path.getChain());
if (!existingNode) {
gError = "Cant remove, such node doesnt exists";
return false;
}
if (existingNode->mType != Node::DIRECTORY) {
if (!existingNode->isDirectory()) {
gError = "Path is not a directory";
return false;
}
if (!recursively && existingNode->mType == Node::DIRECTORY && ((Directory*)existingNode)->size()) {
if (!recursively && !existingNode->empty()) {
gError = "Directory is not empty";
return false;
}
@ -94,7 +83,10 @@ bool FileSystem::removeDirectory(const Path& path, bool recursively) {
return false;
}
assert(parentDirectory->detachNode(path.getParentChain(), path.getFilename()));
if (!parentNode->detachNode(path.getParentChain(), path.getFilename())) {
gError = "Can not detach node";
return false;
}
delete existingNode;
return true;
@ -106,9 +98,8 @@ bool FileSystem::copyNode(const Path& source, const Path& target) {
return false;
}
// TODO : remove code duplication
Directory* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Directory* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
Node* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Node* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
auto sourceNode = workingDirectorySource->findNode(source.getChain());
if (!sourceNode) {
@ -117,23 +108,25 @@ bool FileSystem::copyNode(const Path& source, const Path& target) {
}
auto targetNode = workingDirectoryTarget->findNode(target.getChain());
if (!targetNode || targetNode->mType != Node::DIRECTORY) {
if (!targetNode) {
gError = "Invalid target directory";
return false;
}
auto targetDirectory = (Directory*)targetNode;
Key key = source.getFilename();
if (targetDirectory->findNode(key)) {
if (targetNode->findNode(key)) {
// gError = "Node with such name already exists in the target directory";
// return false;
key += "-copy";
key += "_copy";
}
Node* clonedNode = sourceNode->clone();
assert(targetDirectory->attachNode(key, clonedNode));
if (!targetNode->attachNode(key, clonedNode)) {
delete clonedNode;
return false;
}
return true;
}
@ -144,39 +137,39 @@ bool FileSystem::moveNode(const Path &source, const Path &target) {
return false;
}
// TODO : remove code duplication
Directory* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Directory* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
Node* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Node* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
auto sourceParentNode = workingDirectorySource->findNode(source.getParentChain());
assert(sourceParentNode->mType == Node::DIRECTORY);
auto sourceNode = workingDirectorySource->findNode(source.getChain());
if (!sourceParentNode) {
gError = "Invalid source path";
return false;
}
auto sourceNode = sourceParentNode->findNode(source.getFilename());
if (!sourceNode) {
gError = "Invalid source path";
return false;
}
auto targetNode = workingDirectoryTarget->findNode(target.getChain());
if (!targetNode || targetNode->mType != Node::DIRECTORY) {
if (!targetNode) {
gError = "Invalid target directory";
return false;
}
auto sourceParentDirectory = (Directory*)sourceParentNode;
auto targetDirectory = (Directory*)targetNode;
const Key& key = source.getFilename();
Key key = source.getFilename();
if (targetDirectory->findNode(key)) {
gError = "Node with such name already exists in the target directory";
if (sourceParentNode->isHard()) {
gError = "Node contains incoming hard links";
return false;
}
if (!sourceParentDirectory->detachNode(key)) {
if (!targetNode->attachNode(key, sourceNode)) {
return false;
}
assert(targetDirectory->attachNode(key, sourceNode));
assert(sourceParentNode->detachNode(key));
return true;
}
@ -187,9 +180,8 @@ bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic
return false;
}
// TODO : remove code duplication
Directory* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Directory* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
Node* workingDirectorySource = source.isAbsolute() ? root : currentDirectory;
Node* workingDirectoryTarget = target.isAbsolute() ? root : currentDirectory;
auto sourceNode = workingDirectorySource->findNode(source.getChain());
if (!sourceNode) {
@ -197,13 +189,13 @@ bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic
return false;
}
if (sourceNode->mType == Node::LINK) {
if (sourceNode->isLink()) {
gError = "Link on link is not allowed";
return false;
}
auto targetNode = workingDirectoryTarget->findNode(target.getChain());
if (!targetNode || targetNode->mType != Node::DIRECTORY) {
if (!targetNode || !targetNode->isDirectory()) {
gError = "Invalid target directory";
return false;
}
@ -211,15 +203,12 @@ bool FileSystem::makeLink(const Path& source, const Path& target, bool isDynamic
const Key& key = source.getFilename();
auto targetDirectory = (Directory*)targetNode;
if (targetDirectory->findNode(key)) {
gError = "Node with such name already exists in the target directory";
auto newLink = new Link(sourceNode, !isDynamic);
if (!targetDirectory->attachNode(key, newLink)) {
delete newLink;
return false;
}
auto newLink = new Link(sourceNode, !isDynamic);
assert(targetDirectory->attachNode(key, newLink));
return true;
}
@ -229,7 +218,7 @@ bool FileSystem::removeFileOrLink(const Path &path) {
return false;
}
Directory* parentDirectory = path.isAbsolute() ? root : currentDirectory;
Node* parentDirectory = path.isAbsolute() ? root : currentDirectory;
auto existingNode = parentDirectory->findNode(path.getChain());
if (!existingNode) {
@ -237,12 +226,15 @@ bool FileSystem::removeFileOrLink(const Path &path) {
return false;
}
if (existingNode->mType == Node::DIRECTORY) {
if (existingNode->isDirectory()) {
gError = "Path is a directory";
return false;
}
assert(parentDirectory->detachNode(path.getParentChain(), path.getFilename()));
if (!parentDirectory->detachNode(path.getParentChain(), path.getFilename())) {
gError = "Can not remove node";
return false;
}
delete existingNode;
return true;
@ -255,12 +247,12 @@ bool FileSystem::changeCurrent(const Path& path) {
}
auto node = path.isAbsolute() ? root->findNode(path.getChain(), 0) : currentDirectory->findNode(path.getChain(), 0);
if (!node || node->mType != Node::DIRECTORY) {
if (!node || !node->isDirectory()) {
gError = "No such directory";
return false;
}
currentDirectory = (Directory*) node;
currentDirectory = node;
return true;
}

View file

@ -92,7 +92,7 @@ Interpreter::Interpreter() {
}
void Interpreter::reportError(const std::string& description) {
std::cout << "ERROR : " << description << std::endl;
std::cout << "ERROR : " << description << "\n\n";
}
void Interpreter::printHelp() {
@ -102,13 +102,14 @@ void Interpreter::printHelp() {
std::cout << command.second.description;
std::cout << "\n";
}
std::cout << "\n\n";
}
void Interpreter::interpret(const std::string& command) {
std::vector<std::string> words;
getWords(command, words);
std::cout << command << "\n";
std::cout << ">> " << command << "\n";
if (words.empty()) {
reportError("Empty command");

74
src/Link.cpp Normal file
View file

@ -0,0 +1,74 @@
#include "Link.hpp"
#include <sstream>
#include <cassert>
#include <algorithm>
Link::Link(Node* target, bool isHard) {
mIsHard = isHard;
mLink = target;
if (mIsHard) {
target->mIncomingHardLinks.push_back(this);
} else {
target->mIncomingDynamicLinks.push_back(this);
}
}
Link::Link(const Link &node) : Node(node) {
mLink = node.mLink;
mIsHard = node.mIsHard;
assert(mLink);
if (mIsHard) {
mLink->mIncomingHardLinks.push_back(this);
} else {
mLink->mIncomingDynamicLinks.push_back(this);
}
}
Link *Link::clone() const {
return new Link(*this);
}
Link::~Link() {
// assert(mLink);
// auto& links = mIsHard ? mLink->mIncomingHardLinks : mLink->mIncomingDynamicLinks;
// links.erase(std::remove(links.begin(), links.end(), this), links.end());
// Directory::updateTreeLinkCount(mLink);
// mLink = nullptr;
}
Node *Link::getLink() const {
return mLink;
}
bool Link::isHard() const {
return mIsHard;
}
Node* Link::getTarget() {
return getLink();
}
Node* Link::findNode(const std::vector<Key>& path, ui32 currentDepth) {
if (path.size() == currentDepth) {
return this;
}
assert(mLink);
return mLink->findNode(path, currentDepth + 1);
}
void Link::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indent(ss, currentDepth, indents);
ss << key << (isHard() ? " hlink[/" : " dlink[/");
std::vector<const Node*> path;
getNodeStraightPath(getLink(), path);
std::reverse(path.begin(), path.end());
for (auto tmp : path)
ss << "X" << "/";
ss << "]\n";
}

64
src/Node.cpp Normal file
View file

@ -0,0 +1,64 @@
#include "Node.hpp"
#include <sstream>
#include <cassert>
#include <algorithm>
std::string gError;
bool gDebug = true;
Node::Node(const Node &node) {}
Node::~Node() {
// assert(mIncomingHardLinks.empty());
// for (auto dynamicLink : mIncomingDynamicLinks) {
// dynamicLink->mParent->detachNode(dynamicLink->mTreeNode->key.val);
// delete dynamicLink;
//
}
Node *Node::clone() const {
return new Node(*this);
}
ui32 Node::getMaxDepth() const {
ui32 maxDepth = 1;
getMaxDepthUtil(1, maxDepth);
return maxDepth;
}
Node* Node::findNode(const std::vector<Key>& path, ui32 currentDepth) {
if (path.size() - 1 == currentDepth) {
return this;
}
return nullptr;
}
void Node::getNodeStraightPath(Node* node, std::vector<const Node*>& path) const {
if (!node) return;
path.push_back(node);
getNodeStraightPath(node->mParent, path);
}
void Node::dump(std::stringstream& ss) {
std::vector<bool> indents;
indents.resize(getMaxDepth());
dumpUtil(ss, "/", 0, indents);
ss << "\n";
}
void Node::dumpUtil(std::stringstream& ss, const Key& key, ui32 currentDepth, std::vector<bool>& indents) {
indent(ss, currentDepth, indents);
ss << key;
if (gDebug) ss << " [file]";
ss << "\n";
}
void Node::indent(std::stringstream & ss, ui32 depth, std::vector<bool>& indents) {
if (!depth) return;
for (auto i = 0; i < depth - 1; i++) {
ss << (indents[i] ? " |" : " ");
}
ss << " |_ ";
}

View file

@ -11,7 +11,7 @@ void initializeTransitions() {
for (char i = 'A'; i <= 'Z'; i++) transitions[i] = i /* + ('a' - 'A')*/;
transitions['/'] = '/';
transitions['.'] = '.';
transitions['-'] = '-';
transitions['_'] = '_';
}
Path::Path(const std::string& path) {

View file

@ -24,7 +24,7 @@ int main() {
interpreter.interpret("rd d");
interpreter.interpret("deltree A123");
interpreter.interpret("deltree A123-copy");
interpreter.interpret("deltree A123_copy");
interpreter.interpret("md a");
interpreter.interpret("md a/b");
@ -33,11 +33,11 @@ int main() {
interpreter.interpret("md a/b/c/a/k");
interpreter.interpret("copy a /");
interpreter.interpret("mdl a/b/c /a-copy/k");
interpreter.interpret("mdl a/b/c /a_copy/k");
interpreter.interpret("move a/b/c /a-copy");
interpreter.interpret("move a/b/c /a_copy");
interpreter.interpret("del /a-copy/k/c");
interpreter.interpret("del /a_copy/k/c");
return UnitTest::RunAllTests();
}