/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: FSRecursion.cpp Date: 2022-11-06 Author: Reece ***/ #include #include "FS.hpp" namespace Aurora::IO::FS { struct RecursiveDirIterator : IReadDir { AuSPtr pDir; AuList> nextLevel; AuString curPath; AuString curSubDir; AuUInt uCurrentDepth {}; bool bSymlinkTraversal { true }; AuUInt32 uErrorCount {}; AuList failedPaths; AuOptional optMaxRecursion {}; virtual AuUInt32 GetErrorCount() override { return this->uErrorCount; } virtual AuList GetErrorPaths() override { return this->failedPaths; } bool OpenDir(const AuROString &str) { this->curPath = str; this->pDir = ReadDir(str); return bool(pDir); } bool OpenNext(const AuROString &str) { this->curPath = str; this->pDir = ReadDir(str); return bool(pDir); } void DoNext() { if (this->pDir) { if (auto uCount = this->pDir->GetErrorCount()) { this->failedPaths.push_back(this->curPath + AuString(1, AuFS::kPathSplitter) + this->curSubDir); this->uErrorCount += uCount; } } this->pDir.reset(); if (!this->nextLevel.size()) { return; } auto next = AuMove(this->nextLevel[0]); this->nextLevel.erase(this->nextLevel.begin()); this->pDir = ReadDir(this->curPath + "/" + AuGet<1>(next)); this->curSubDir = AuGet<1>(next); this->uCurrentDepth = AuGet<0>(next); } virtual StatEx *Next() override { AU_DEBUG_MEMCRUNCH; StatEx *pNext {}; if (!this->pDir) { return {}; } do { try { pNext = this->pDir->Next(); while (!pNext) { DoNext(); if (!this->pDir) { return {}; } pNext = this->pDir->Next(); } if (this->curSubDir.size()) { pNext->fileName.insert(pNext->fileName.begin(), this->curSubDir.begin(), this->curSubDir.end()); } if (!this->bSymlinkTraversal && pNext->bSymLink) { continue; } if (pNext->bExistsDirectory) { if (this->optMaxRecursion && this->optMaxRecursion.Value() <= this->uCurrentDepth + 1) { this->failedPaths.push_back(pNext->fileName); } else { this->nextLevel.push_back(AuMakePair(this->uCurrentDepth + 1, pNext->fileName + "/")); } } } catch (...) { SysPushErrorCatch(); } } while (false); return pNext; } }; AUKN_SYM AuSPtr ReadDirRecursive(const AuROString &string, AuOptional bTraverseSymlinks, AuOptional optMaxRecursion) { SysCheckArgNotNull(string.size(), {}); auto pObj = AuMakeShared(); SysCheckNotNullMemory(pObj, {}); pObj->bSymlinkTraversal = bTraverseSymlinks.ValueOr(true); pObj->optMaxRecursion = optMaxRecursion; try { if (!pObj->OpenDir(string)) { return {}; } } catch (...) { SysPushErrorCatch(); } return pObj; } }