#include "pch.h" #include "IEngine.h" #include "Crypto.h" #include #include using namespace craftlab::fakeraid; namespace craftlab::fakeraid { class Engine : public IEngine { public: Engine(const std::vector& path); void DirExistsOrThrow() const override; std::vector GetRootPaths() const override; std::vector GetPaths() const override; std::deque GetCurrentDir() const override; bool SetWorkingDirectory(const std::vector& path) override; FileAndSumListByRepositoryIndex ListFiles() override; void Cd(const std::string& dirName) override; void RemoveFiles(const std::vector& paths) const override; void RemoveDirs(const std::vector& paths) const override; private: FileAndSumList ListFiles(const std::string& root, int repositoryIndex); std::string BuildCurrentDirPath(const std::string& root ="") const; const std::vector rootPaths; std::deque currentDir; }; } Engine::Engine(const std::vector& path): rootPaths(path), currentDir() {} std::vector Engine::GetRootPaths() const { return rootPaths; } std::vector Engine::GetPaths() const { std::vector paths; const std::string workingDir = BuildCurrentDirPath(); std::transform(rootPaths.begin(), rootPaths.end(), std::back_inserter(paths), [&workingDir](const std::string& val) { return val + "/" + workingDir; }); return paths; } std::deque Engine::GetCurrentDir() const { return currentDir; } std::string Engine::BuildCurrentDirPath(const std::string& root) const { std::stringstream ss; ss << root; bool written = !root.empty(); for (const std::string& path : currentDir) { if (written) ss << "/"; ss << path; written = true; } return ss.str(); } bool vectorEquals(const std::vector& a, const std::deque& b) { if (a.size() != b.size()) return false; auto iterA = a.begin(); auto iterB = b.begin(); while (iterA != a.end()) { if (*iterA != *iterB) return false; ++iterA; ++iterB; } return true; } bool Engine::SetWorkingDirectory(const std::vector& path) { if (vectorEquals(path, currentDir)) return false; currentDir.clear(); std::copy(path.begin(), path.end(), std::back_inserter(currentDir)); return true; } void Engine::Cd(const std::string& dirName) { currentDir.push_back(dirName); } FileAndSumList Engine::ListFiles(const std::string& root, int repositoryIndex) { FileAndSumList result; const std::string path = BuildCurrentDirPath(root); Crypto cryptoEngine; for (const std::filesystem::directory_entry& file : std::filesystem::directory_iterator(path)) { if (file.is_directory() || file.is_regular_file()) { FileAndSum fileInfos; fileInfos.fileName = file.path().filename().string(); fileInfos.isDir = file.is_directory(); fileInfos.repositoryIndex = repositoryIndex; try { cryptoEngine.Compute(path, fileInfos); } catch (std::runtime_error&) {} result.push_back(fileInfos); } } return result; } FileAndSumListByRepositoryIndex Engine::ListFiles() { FileAndSumListByRepositoryIndex result; int index = 0; for (const auto& i : rootPaths) { const FileAndSumList files = ListFiles(i, index++); result.FileAndSumListByRepositoryIndex.push_back(files); for (const FileAndSum& file : files) result.FileList[file.fileName] = file; } return result; } void Engine::DirExistsOrThrow() const { char errorBuffer[1024]; for (const std::string& fullPath : GetPaths()) { struct stat fileInfo; if (stat(fullPath.c_str(), &fileInfo)) { strerror_s(errorBuffer, errno); throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer); } if (!(fileInfo.st_mode & S_IFDIR)) { strerror_s(errorBuffer, ENOTDIR); throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer); } } } void Engine::RemoveFiles(const std::vector& paths) const { for (const std::string& path: paths) std::filesystem::remove(path); } void Engine::RemoveDirs(const std::vector& paths) const { for (const std::string& path : paths) std::filesystem::remove_all(path); } IEngine* EngineManager::Open(const std::vector& path) { return new Engine(path); }