Engine.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #include "pch.h"
  2. #include "IEngine.h"
  3. #include "Crypto.h"
  4. #include <stdexcept>
  5. #include <filesystem>
  6. using namespace craftlab::fakeraid;
  7. namespace craftlab::fakeraid
  8. {
  9. class Engine : public IEngine
  10. {
  11. public:
  12. Engine(const std::vector<std::string>& path);
  13. void DirExistsOrThrow() const override;
  14. std::vector<std::string> GetRootPaths() const override;
  15. std::vector<std::string> GetPaths() const override;
  16. std::deque<std::string> GetCurrentDir() const override;
  17. bool SetWorkingDirectory(const std::vector<std::string>& path) override;
  18. FileAndSumListByRepositoryIndex ListFiles() override;
  19. void ListFilesRecur(FileAndSumListByRepositoryIndex*, bool* threadStopping) override;
  20. size_t CountFilesRecur() override;
  21. void Cd(const std::string& dirName) override;
  22. std::string BuildCurrentDirPath(const std::string& root, const PathParts& pathParts) const override;
  23. std::string BuildCurrentDirPath(const FileAndSum& file) const override;
  24. void RemoveFiles(const std::vector<std::string>& paths) const override;
  25. void RemoveDirs(const std::vector<std::string>& paths) const override;
  26. void CopyItems(const std::vector<CopyInstruction>& itemsToCopy) const override;
  27. private:
  28. void ListFiles(FileAndSumListByRepositoryIndex& result, const PathParts& currentDir, bool* threadStopping =nullptr);
  29. FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex, bool* threadStopping =nullptr);
  30. void CopyItem(const CopyInstruction& dst) const;
  31. const std::vector<std::string> rootPaths;
  32. std::deque<std::string> currentDir;
  33. };
  34. }
  35. Engine::Engine(const std::vector<std::string>& path): rootPaths(path), currentDir()
  36. {}
  37. std::vector<std::string> Engine::GetRootPaths() const
  38. {
  39. return rootPaths;
  40. }
  41. std::vector<std::string> Engine::GetPaths() const
  42. {
  43. std::vector<std::string> paths;
  44. const std::string workingDir = BuildCurrentDirPath("", currentDir);
  45. std::transform(rootPaths.begin(), rootPaths.end(), std::back_inserter(paths), [&workingDir](const std::string& val)
  46. {
  47. return (std::filesystem::path(val) / std::filesystem::path(workingDir)).string();
  48. });
  49. return paths;
  50. }
  51. std::deque<std::string> Engine::GetCurrentDir() const
  52. {
  53. return currentDir;
  54. }
  55. std::string Engine::BuildCurrentDirPath(const std::string& root, const std::deque<std::string>& _currentDir) const
  56. {
  57. std::filesystem::path result(root);
  58. for (const std::string& path : _currentDir)
  59. result = result / path;
  60. return result.string();
  61. }
  62. std::string Engine::BuildCurrentDirPath(const FileAndSum& file) const
  63. {
  64. std::filesystem::path result;
  65. for (const std::string& path : file.directory)
  66. result = result / path;
  67. result = result / file.fileName;
  68. return result.string();
  69. }
  70. bool vectorEquals(const std::vector<std::string>& a, const std::deque<std::string>& b)
  71. {
  72. if (a.size() != b.size())
  73. return false;
  74. auto iterA = a.begin();
  75. auto iterB = b.begin();
  76. while (iterA != a.end())
  77. {
  78. if (*iterA != *iterB)
  79. return false;
  80. ++iterA;
  81. ++iterB;
  82. }
  83. return true;
  84. }
  85. bool Engine::SetWorkingDirectory(const std::vector<std::string>& path)
  86. {
  87. if (vectorEquals(path, currentDir))
  88. return false;
  89. currentDir.clear();
  90. std::copy(path.begin(), path.end(), std::back_inserter(currentDir));
  91. return true;
  92. }
  93. void Engine::Cd(const std::string& dirName)
  94. {
  95. currentDir.push_back(dirName);
  96. }
  97. FileAndSumList Engine::ListFiles(const std::string& root, const std::deque<std::string>& wd, int repositoryIndex, bool* threadStopping)
  98. {
  99. FileAndSumList result {};
  100. const std::string path = BuildCurrentDirPath(root, wd);
  101. Crypto cryptoEngine;
  102. std::filesystem::directory_iterator directoryIterator;
  103. try
  104. {
  105. directoryIterator = std::filesystem::directory_iterator(path);
  106. }
  107. catch (std::exception& e)
  108. {
  109. return result; // FIXME
  110. }
  111. for (const std::filesystem::directory_entry& file : directoryIterator)
  112. {
  113. bool isDirectory = false;
  114. bool isFile = false;
  115. try
  116. {
  117. isDirectory = file.is_directory();
  118. isFile = file.is_regular_file();
  119. }
  120. catch (std::exception& e)
  121. {}
  122. if (isDirectory || isFile)
  123. {
  124. FileAndSum fileInfos;
  125. fileInfos.fileName = file.path().filename().string();
  126. fileInfos.isDir = file.is_directory();
  127. fileInfos.directory = wd;
  128. fileInfos.repositoryIndex = repositoryIndex;
  129. try
  130. {
  131. cryptoEngine.Compute(path, fileInfos);
  132. }
  133. catch (std::runtime_error&)
  134. {
  135. }
  136. result.push_back(fileInfos);
  137. }
  138. if (threadStopping && *threadStopping)
  139. return result;
  140. }
  141. return result;
  142. }
  143. void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir, bool* threadStopping)
  144. {
  145. int index = 0;
  146. for (const auto& i : rootPaths)
  147. {
  148. const FileAndSumList files = ListFiles(i, currentDir, index++, threadStopping);
  149. result.FileAndSumListByRepositoryIndex.push_back(files);
  150. for (const FileAndSum& file : files)
  151. result.FileList[BuildCurrentDirPath(file)] = file;
  152. if (threadStopping && *threadStopping)
  153. return;
  154. }
  155. }
  156. FileAndSumListByRepositoryIndex Engine::ListFiles()
  157. {
  158. FileAndSumListByRepositoryIndex result;
  159. ListFiles(result, currentDir);
  160. return result;
  161. }
  162. void Engine::ListFilesRecur(FileAndSumListByRepositoryIndex* result, bool* threadStopping)
  163. {
  164. std::deque<PathParts> itemsToDo { currentDir };
  165. do
  166. {
  167. FileAndSumListByRepositoryIndex newItems;
  168. const PathParts currentPath = itemsToDo.front();
  169. ListFiles(newItems, currentPath, threadStopping);
  170. itemsToDo.pop_front();
  171. std::copy(newItems.FileAndSumListByRepositoryIndex.begin(), newItems.FileAndSumListByRepositoryIndex.end(), std::back_inserter(result->FileAndSumListByRepositoryIndex));
  172. for (const auto& file : newItems.FileList)
  173. {
  174. result->FileList[file.first] = file.second;
  175. if (file.second.isDir)
  176. {
  177. PathParts dirPath = currentPath;
  178. dirPath.push_back(file.second.fileName);
  179. itemsToDo.push_back(dirPath);
  180. }
  181. }
  182. } while (!itemsToDo.empty() && !*threadStopping);
  183. }
  184. size_t Engine::CountFilesRecur()
  185. {
  186. size_t result =0;
  187. std::deque<std::filesystem::path> itemsToDo;
  188. for (const auto& i: rootPaths)
  189. itemsToDo.push_back(i);
  190. do
  191. {
  192. std::filesystem::directory_iterator directoryIterator;
  193. try
  194. {
  195. directoryIterator = std::filesystem::directory_iterator(itemsToDo.front());
  196. }
  197. catch (std::exception& e)
  198. {
  199. itemsToDo.pop_front();
  200. continue;
  201. }
  202. for (const std::filesystem::directory_entry& file : directoryIterator)
  203. {
  204. try {
  205. if (file.is_regular_file())
  206. ++result;
  207. else if (file.is_directory())
  208. {
  209. itemsToDo.push_back(file.path());
  210. ++result;
  211. }
  212. }
  213. catch (std::exception)
  214. {}
  215. }
  216. itemsToDo.pop_front();
  217. } while (!itemsToDo.empty());
  218. return result;
  219. }
  220. void Engine::DirExistsOrThrow() const
  221. {
  222. char errorBuffer[1024];
  223. for (const std::string& fullPath : GetPaths())
  224. {
  225. struct stat fileInfo;
  226. if (stat(fullPath.c_str(), &fileInfo))
  227. {
  228. strerror_s(errorBuffer, errno);
  229. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  230. }
  231. if (!(fileInfo.st_mode & S_IFDIR))
  232. {
  233. strerror_s(errorBuffer, ENOTDIR);
  234. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  235. }
  236. }
  237. }
  238. void Engine::RemoveFiles(const std::vector<std::string>& paths) const
  239. {
  240. for (const std::string& path: paths)
  241. std::filesystem::remove(path);
  242. }
  243. void Engine::RemoveDirs(const std::vector<std::string>& paths) const
  244. {
  245. for (const std::string& path : paths)
  246. std::filesystem::remove_all(path);
  247. }
  248. void Engine::CopyItem(const IEngine::CopyInstruction& item) const
  249. {
  250. std::filesystem::copy(item.source, item.destination, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
  251. }
  252. void Engine::CopyItems(const std::vector<IEngine::CopyInstruction>& paths) const
  253. {
  254. for (const CopyInstruction& item: paths)
  255. CopyItem(item);
  256. }
  257. IEngine* EngineManager::Open(const std::vector<std::string>& path)
  258. {
  259. return new Engine(path);
  260. }