Engine.cpp 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  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 File& file) const override;
  24. std::string BuildFullPath(const File& file) const override;
  25. bool AnyFileExists(const std::vector<std::string>& files, const std::string& dropTo) const override;
  26. void RemoveFiles(const std::vector<std::string>& paths) const override;
  27. void RemoveDirs(const std::vector<std::string>& paths) const override;
  28. void CopyItems(const std::vector<CopyInstruction>& itemsToCopy) const override;
  29. void AddFiles(const std::vector<std::string>& files, const std::string& destination) const override;
  30. private:
  31. void ListFiles(FileAndSumListByRepositoryIndex& result, const PathParts& currentDir, std::string* lastFileScanned =nullptr, bool* threadStopping =nullptr);
  32. FileAndSumList ListFiles(const std::string& root, const PathParts& path, int repositoryIndex, std::string* lastFileScanned =nullptr, bool* threadStopping =nullptr);
  33. void CopyItem(const CopyInstruction& dst) const;
  34. const std::vector<std::string> rootPaths;
  35. std::deque<std::string> currentDir;
  36. };
  37. }
  38. Engine::Engine(const std::vector<std::string>& path): rootPaths(path), currentDir()
  39. {}
  40. std::vector<std::string> Engine::GetRootPaths() const
  41. {
  42. return rootPaths;
  43. }
  44. std::vector<std::string> Engine::GetPaths() const
  45. {
  46. std::vector<std::string> paths;
  47. const std::string workingDir = BuildCurrentDirPath("", currentDir);
  48. std::transform(rootPaths.begin(), rootPaths.end(), std::back_inserter(paths), [&workingDir](const std::string& val)
  49. {
  50. return (std::filesystem::path(val) / std::filesystem::path(workingDir)).string();
  51. });
  52. return paths;
  53. }
  54. std::deque<std::string> Engine::GetCurrentDir() const
  55. {
  56. return currentDir;
  57. }
  58. std::string Engine::BuildCurrentDirPath(const std::string& root, const PathParts& _currentDir) const
  59. {
  60. std::filesystem::path result(root);
  61. for (const std::string& path : _currentDir)
  62. result = result / path;
  63. return result.string();
  64. }
  65. std::string Engine::BuildCurrentDirPath(const File& file) const
  66. {
  67. std::filesystem::path result;
  68. for (const std::string& path : file.directory)
  69. result = result / path;
  70. result = result / file.fileName;
  71. return result.string();
  72. }
  73. std::string Engine::BuildFullPath(const File& file) const
  74. {
  75. std::filesystem::path result(rootPaths[file.repositoryIndex]);
  76. for (const std::string& path : file.directory)
  77. result /= path;
  78. result /= file.fileName;
  79. return result.string();
  80. }
  81. bool vectorEquals(const std::vector<std::string>& a, const std::deque<std::string>& b)
  82. {
  83. if (a.size() != b.size())
  84. return false;
  85. auto iterA = a.begin();
  86. auto iterB = b.begin();
  87. while (iterA != a.end())
  88. {
  89. if (*iterA != *iterB)
  90. return false;
  91. ++iterA;
  92. ++iterB;
  93. }
  94. return true;
  95. }
  96. bool Engine::SetWorkingDirectory(const std::vector<std::string>& path)
  97. {
  98. if (vectorEquals(path, currentDir))
  99. return false;
  100. currentDir.clear();
  101. std::copy(path.begin(), path.end(), std::back_inserter(currentDir));
  102. return true;
  103. }
  104. void Engine::Cd(const std::string& dirName)
  105. {
  106. currentDir.push_back(dirName);
  107. }
  108. FileAndSumList Engine::ListFiles(const std::string& root, const std::deque<std::string>& wd, int repositoryIndex, std::string* lastFileScanned, bool* threadStopping)
  109. {
  110. FileAndSumList result {};
  111. const std::string path = BuildCurrentDirPath(root, wd);
  112. Crypto cryptoEngine;
  113. std::filesystem::directory_iterator directoryIterator; // FIXME error handling
  114. try
  115. {
  116. directoryIterator = std::filesystem::directory_iterator(path);
  117. }
  118. catch (std::exception& e)
  119. {
  120. return result; // FIXME
  121. }
  122. for (const std::filesystem::directory_entry& file : directoryIterator)
  123. {
  124. bool isDirectory = false;
  125. bool isFile = false;
  126. try
  127. {
  128. isDirectory = file.is_directory();
  129. isFile = file.is_regular_file();
  130. }
  131. catch (std::exception& e)
  132. {}
  133. if (isDirectory || isFile)
  134. {
  135. FileAndSum fileInfos;
  136. fileInfos.fileName = file.path().filename().string();
  137. fileInfos.isDir = file.is_directory();
  138. fileInfos.directory = wd;
  139. fileInfos.repositoryIndex = repositoryIndex;
  140. if (nullptr != lastFileScanned)
  141. *lastFileScanned = BuildCurrentDirPath(fileInfos);
  142. try
  143. {
  144. cryptoEngine.Compute(path, fileInfos);
  145. }
  146. catch (std::runtime_error&)
  147. {
  148. }
  149. result.push_back(fileInfos);
  150. }
  151. if (threadStopping && *threadStopping)
  152. return result;
  153. }
  154. return result;
  155. }
  156. void Engine::ListFiles(FileAndSumListByRepositoryIndex& result, const std::deque<std::string>& currentDir, std::string* lastFileScanned, bool* threadStopping)
  157. {
  158. int index = 0;
  159. for (const auto& i : rootPaths)
  160. {
  161. const FileAndSumList files = ListFiles(i, currentDir, index++, lastFileScanned, threadStopping);
  162. result.FileAndSumListByRepositoryIndex.push_back(files);
  163. for (const FileAndSum& file : files)
  164. result.FileList[BuildCurrentDirPath(file)] = file;
  165. if (threadStopping && *threadStopping)
  166. return;
  167. }
  168. }
  169. FileAndSumListByRepositoryIndex Engine::ListFiles()
  170. {
  171. FileAndSumListByRepositoryIndex result;
  172. ListFiles(result, currentDir);
  173. return result;
  174. }
  175. void Engine::ListFilesRecur(FileAndSumListByRepositoryIndex* result, bool* threadStopping)
  176. {
  177. std::deque<PathParts> itemsToDo { currentDir };
  178. do
  179. {
  180. FileAndSumListByRepositoryIndex newItems;
  181. const PathParts currentPath = itemsToDo.front();
  182. ListFiles(newItems, currentPath, &result->lastInsertedFilename, threadStopping);
  183. itemsToDo.pop_front();
  184. std::copy(newItems.FileAndSumListByRepositoryIndex.begin(), newItems.FileAndSumListByRepositoryIndex.end(), std::back_inserter(result->FileAndSumListByRepositoryIndex));
  185. for (const auto& file : newItems.FileList)
  186. {
  187. result->FileList[file.first] = file.second;
  188. if (file.second.isDir)
  189. {
  190. PathParts dirPath = currentPath;
  191. dirPath.push_back(file.second.fileName);
  192. itemsToDo.push_back(dirPath);
  193. }
  194. }
  195. } while (!itemsToDo.empty() && !*threadStopping);
  196. }
  197. size_t Engine::CountFilesRecur()
  198. {
  199. size_t result =0;
  200. std::deque<std::filesystem::path> itemsToDo;
  201. for (const auto& i: rootPaths)
  202. itemsToDo.push_back(i);
  203. do
  204. {
  205. std::filesystem::directory_iterator directoryIterator; // FIXME error handling
  206. try
  207. {
  208. directoryIterator = std::filesystem::directory_iterator(itemsToDo.front());
  209. }
  210. catch (std::exception& e)
  211. {
  212. itemsToDo.pop_front();
  213. continue;
  214. }
  215. for (const std::filesystem::directory_entry& file : directoryIterator)
  216. {
  217. try {
  218. if (file.is_regular_file())
  219. ++result;
  220. else if (file.is_directory())
  221. {
  222. itemsToDo.push_back(file.path());
  223. ++result;
  224. }
  225. }
  226. catch (std::exception)
  227. {}
  228. }
  229. itemsToDo.pop_front();
  230. } while (!itemsToDo.empty());
  231. return result;
  232. }
  233. void Engine::DirExistsOrThrow() const
  234. {
  235. char errorBuffer[1024];
  236. for (const std::string& fullPath : GetPaths())
  237. {
  238. struct stat fileInfo;
  239. if (stat(fullPath.c_str(), &fileInfo))
  240. {
  241. strerror_s(errorBuffer, errno);
  242. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  243. }
  244. if (!(fileInfo.st_mode & S_IFDIR))
  245. {
  246. strerror_s(errorBuffer, ENOTDIR);
  247. throw std::runtime_error("cannot access " + fullPath + ": " + errorBuffer);
  248. }
  249. }
  250. }
  251. void Engine::RemoveFiles(const std::vector<std::string>& paths) const
  252. {
  253. for (const std::string& path: paths)
  254. std::filesystem::remove(path); // FIXME error handling
  255. }
  256. void Engine::RemoveDirs(const std::vector<std::string>& paths) const
  257. {
  258. for (const std::string& path : paths)
  259. std::filesystem::remove_all(path); // FIXME error handling
  260. }
  261. void Engine::CopyItem(const IEngine::CopyInstruction& item) const
  262. {
  263. std::filesystem::copy(item.source, item.destination, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive); // FIXME error handling
  264. }
  265. void Engine::CopyItems(const std::vector<IEngine::CopyInstruction>& paths) const
  266. {
  267. for (const CopyInstruction& item: paths)
  268. CopyItem(item);
  269. }
  270. bool Engine::AnyFileExists(const std::vector<std::string>& files, const std::string& destination) const
  271. {
  272. for (const std::string _file : files)
  273. {
  274. std::filesystem::path file(_file);
  275. for (const std::string& root : rootPaths)
  276. {
  277. std::filesystem::path outputPath(root + "/" + destination);
  278. outputPath /= file.filename();
  279. if (std::filesystem::exists(outputPath))
  280. {
  281. if (std::filesystem::equivalent(outputPath, file)) // FIXME error handling
  282. throw IEngine::SameFileError();
  283. return true;
  284. }
  285. }
  286. }
  287. return false;
  288. }
  289. void Engine::AddFiles(const std::vector<std::string>& files, const std::string& _destination) const
  290. {
  291. for (const std::string _file : files)
  292. {
  293. std::filesystem::path file(_file);
  294. for (const std::string& root : rootPaths)
  295. {
  296. std::filesystem::path destination(root + "/" + _destination);
  297. destination /= file.filename();
  298. std::filesystem::copy(file, destination, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive); // FIXME error handling
  299. }
  300. }
  301. }
  302. IEngine* EngineManager::Open(const std::vector<std::string>& path)
  303. {
  304. return new Engine(path);
  305. }