Engine.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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, std::string* lastFileScanned =nullptr, bool* threadStopping =nullptr);
  29. FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex, std::string* lastFileScanned =nullptr, 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, std::string* lastFileScanned, 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. if (nullptr != lastFileScanned)
  130. *lastFileScanned = BuildCurrentDirPath(fileInfos);
  131. try
  132. {
  133. cryptoEngine.Compute(path, fileInfos);
  134. }
  135. catch (std::runtime_error&)
  136. {
  137. }
  138. result.push_back(fileInfos);
  139. }
  140. if (threadStopping && *threadStopping)
  141. return result;
  142. }
  143. return result;
  144. }
  145. void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir, std::string* lastFileScanned, bool* threadStopping)
  146. {
  147. int index = 0;
  148. for (const auto& i : rootPaths)
  149. {
  150. const FileAndSumList files = ListFiles(i, currentDir, index++, lastFileScanned, threadStopping);
  151. result.FileAndSumListByRepositoryIndex.push_back(files);
  152. for (const FileAndSum& file : files)
  153. result.FileList[BuildCurrentDirPath(file)] = file;
  154. if (threadStopping && *threadStopping)
  155. return;
  156. }
  157. }
  158. FileAndSumListByRepositoryIndex Engine::ListFiles()
  159. {
  160. FileAndSumListByRepositoryIndex result;
  161. ListFiles(result, currentDir);
  162. return result;
  163. }
  164. void Engine::ListFilesRecur(FileAndSumListByRepositoryIndex* result, bool* threadStopping)
  165. {
  166. std::deque<PathParts> itemsToDo { currentDir };
  167. do
  168. {
  169. FileAndSumListByRepositoryIndex newItems;
  170. const PathParts currentPath = itemsToDo.front();
  171. ListFiles(newItems, currentPath, &result->lastInsertedFilename, threadStopping);
  172. itemsToDo.pop_front();
  173. std::copy(newItems.FileAndSumListByRepositoryIndex.begin(), newItems.FileAndSumListByRepositoryIndex.end(), std::back_inserter(result->FileAndSumListByRepositoryIndex));
  174. for (const auto& file : newItems.FileList)
  175. {
  176. result->FileList[file.first] = file.second;
  177. if (file.second.isDir)
  178. {
  179. PathParts dirPath = currentPath;
  180. dirPath.push_back(file.second.fileName);
  181. itemsToDo.push_back(dirPath);
  182. }
  183. }
  184. } while (!itemsToDo.empty() && !*threadStopping);
  185. }
  186. size_t Engine::CountFilesRecur()
  187. {
  188. size_t result =0;
  189. std::deque<std::filesystem::path> itemsToDo;
  190. for (const auto& i: rootPaths)
  191. itemsToDo.push_back(i);
  192. do
  193. {
  194. std::filesystem::directory_iterator directoryIterator;
  195. try
  196. {
  197. directoryIterator = std::filesystem::directory_iterator(itemsToDo.front());
  198. }
  199. catch (std::exception& e)
  200. {
  201. itemsToDo.pop_front();
  202. continue;
  203. }
  204. for (const std::filesystem::directory_entry& file : directoryIterator)
  205. {
  206. try {
  207. if (file.is_regular_file())
  208. ++result;
  209. else if (file.is_directory())
  210. {
  211. itemsToDo.push_back(file.path());
  212. ++result;
  213. }
  214. }
  215. catch (std::exception)
  216. {}
  217. }
  218. itemsToDo.pop_front();
  219. } while (!itemsToDo.empty());
  220. return result;
  221. }
  222. void Engine::DirExistsOrThrow() const
  223. {
  224. char errorBuffer[1024];
  225. for (const std::string& fullPath : GetPaths())
  226. {
  227. struct stat fileInfo;
  228. if (stat(fullPath.c_str(), &fileInfo))
  229. {
  230. strerror_s(errorBuffer, errno);
  231. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  232. }
  233. if (!(fileInfo.st_mode & S_IFDIR))
  234. {
  235. strerror_s(errorBuffer, ENOTDIR);
  236. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  237. }
  238. }
  239. }
  240. void Engine::RemoveFiles(const std::vector<std::string>& paths) const
  241. {
  242. for (const std::string& path: paths)
  243. std::filesystem::remove(path);
  244. }
  245. void Engine::RemoveDirs(const std::vector<std::string>& paths) const
  246. {
  247. for (const std::string& path : paths)
  248. std::filesystem::remove_all(path);
  249. }
  250. void Engine::CopyItem(const IEngine::CopyInstruction& item) const
  251. {
  252. std::filesystem::copy(item.source, item.destination, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
  253. }
  254. void Engine::CopyItems(const std::vector<IEngine::CopyInstruction>& paths) const
  255. {
  256. for (const CopyInstruction& item: paths)
  257. CopyItem(item);
  258. }
  259. IEngine* EngineManager::Open(const std::vector<std::string>& path)
  260. {
  261. return new Engine(path);
  262. }