diff --git a/Include/Aurora/IO/FS/FS.hpp b/Include/Aurora/IO/FS/FS.hpp index b2320c95..f0ec96e5 100644 --- a/Include/Aurora/IO/FS/FS.hpp +++ b/Include/Aurora/IO/FS/FS.hpp @@ -37,7 +37,7 @@ namespace Aurora::IO::FS * @param string * @return */ - AUKN_SYM AuSPtr ReadDirRecursive(const AuString &string); + AUKN_SYM AuSPtr ReadDirRecursive(const AuString &string, AuOptional bTraverseSymlinks = { true }); /** * @brief Recursively deletes any given path diff --git a/Include/Aurora/IO/FS/IReadDir.hpp b/Include/Aurora/IO/FS/IReadDir.hpp index 36bddea0..e9f4cf90 100644 --- a/Include/Aurora/IO/FS/IReadDir.hpp +++ b/Include/Aurora/IO/FS/IReadDir.hpp @@ -30,8 +30,12 @@ namespace Aurora::IO::FS * @return * 1) a temporary pointer to an `StatEx` of the next file/dir in the directory * 1) nullptr to indicate end of listing - * 2) nullptr to indicate error; wont recover TODO (Reece): this sucks but it's still an acceptable ambiguation for end of iteration. + * 2) nullptr to indicate error; wont recover */ virtual StatEx *Next() = 0; + + virtual AuUInt32 GetErrorCount() = 0; + + virtual AuList GetErrorPaths() = 0; }; } \ No newline at end of file diff --git a/Source/IO/FS/DirDeleter.cpp b/Source/IO/FS/DirDeleter.cpp index be1be767..f006a190 100644 --- a/Source/IO/FS/DirDeleter.cpp +++ b/Source/IO/FS/DirDeleter.cpp @@ -18,6 +18,44 @@ namespace Aurora::IO::FS AuString curPath; AuString curSubDir; AuList failedPaths; + AuUInt32 uErrorCount {}; + + virtual AuUInt32 GetErrorCount() override + { + return this->uErrorCount; + } + + virtual AuList GetErrorPaths() override + { + if (this->uErrorCount || this->failedPaths.size()) + { + return this->failedPaths; + } + else + { + return {}; + } + } + + bool DoThing(const AuString &string) + { + AU_DEBUG_MEMCRUNCH; + + if (!this->OpenDir(string)) + { + return {}; + } + + while (this->Next()) + { + + } + + this->RemoveDirs(); + + AuFS::Remove(string); + return true; + } bool OpenDir(const AuString &str) { @@ -35,6 +73,15 @@ namespace Aurora::IO::FS 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()) @@ -86,6 +133,7 @@ namespace Aurora::IO::FS if (!AuFS::Remove(pNext->path)) { this->failedPaths.push_back(pNext->fileName); + this->uErrorCount++; } } } @@ -105,6 +153,7 @@ namespace Aurora::IO::FS if (!AuFS::Remove(dir)) { this->failedPaths.push_back(itr->c_str()); + this->uErrorCount++; } } } @@ -117,19 +166,10 @@ namespace Aurora::IO::FS try { - if (!pObj->OpenDir(string)) + if (!pObj->DoThing(string)) { return {}; } - - while (pObj->Next()) - { - - } - - pObj->RemoveDirs(); - - AuFS::Remove(string); } catch (...) { @@ -146,20 +186,11 @@ namespace Aurora::IO::FS try { - if (!pObj->OpenDir(string)) + if (!pObj->DoThing(string)) { return {}; } - while (pObj->Next()) - { - - } - - pObj->RemoveDirs(); - - AuFS::Remove(string); - if (AuFS::DirExists(string)) { for (const auto &str : pObj->failedPaths) diff --git a/Source/IO/FS/FS.NT.cpp b/Source/IO/FS/FS.NT.cpp index 4c6e8ea4..01021a90 100644 --- a/Source/IO/FS/FS.NT.cpp +++ b/Source/IO/FS/FS.NT.cpp @@ -28,18 +28,43 @@ namespace Aurora::IO::FS bool bDead {false}; StatEx stat; AuString sPath; + AuUInt32 uErrorCount {}; + AuList errorPaths; ~ReadDirStructure() { ::FindClose(this->hFind); } + virtual AuUInt32 GetErrorCount() override + { + return this->uErrorCount; + } + + virtual AuList GetErrorPaths() override + { + if (this->uErrorCount) + { + return { this->sPath }; + } + else + { + return {}; + } + } + virtual StatEx *Next() override { + AU_DEBUG_MEMCRUNCH; + if (!AuExchange(this->bFirstTick, false)) { if (::FindNextFileW(this->hFind, &this->ffd) == 0) { + if (GetLastError() != ERROR_NO_MORE_FILES) + { + this->uErrorCount++; + } return {}; } } @@ -61,6 +86,7 @@ namespace Aurora::IO::FS if (stat.fileName.empty()) { this->bDead = true; + this->uErrorCount++; return {}; } @@ -68,6 +94,7 @@ namespace Aurora::IO::FS if (stat.path.empty()) { this->bDead = true; + this->uErrorCount++; return {}; } diff --git a/Source/IO/FS/FS.Unix.cpp b/Source/IO/FS/FS.Unix.cpp index 8c51d650..f9cee46a 100755 --- a/Source/IO/FS/FS.Unix.cpp +++ b/Source/IO/FS/FS.Unix.cpp @@ -61,6 +61,7 @@ namespace Aurora::IO::FS StatEx stat; AuString sPath; bool bFast {}; + AuUInt32 uErrorCount {}; ~ReadDirStructure() { @@ -70,8 +71,27 @@ namespace Aurora::IO::FS } } + virtual AuUInt32 GetErrorCount() override + { + return this->uErrorCount; + } + + virtual AuList GetErrorPaths() override + { + if (this->uErrorCount) + { + return { this->sPath }; + } + else + { + return {}; + } + } + virtual StatEx *Next() override { + AU_DEBUG_MEMCRUNCH; + bool bTryAgain {}; if (this->bDead) @@ -81,9 +101,15 @@ namespace Aurora::IO::FS do { + errno = 0; + if (!(this->pDE = ::readdir(this->pDIR))) { this->bDead = true; + if (errno) + { + this->uErrorCount++; + } return {}; } diff --git a/Source/IO/FS/FSRecursion.cpp b/Source/IO/FS/FSRecursion.cpp index 9a83b2a5..bd6869e1 100644 --- a/Source/IO/FS/FSRecursion.cpp +++ b/Source/IO/FS/FSRecursion.cpp @@ -16,6 +16,19 @@ namespace Aurora::IO::FS AuList nextLevel; AuString curPath; AuString curSubDir; + bool bSymlinkTraversal { true }; + AuUInt32 uErrorCount {}; + AuList failedPaths; + + virtual AuUInt32 GetErrorCount() override + { + return this->uErrorCount; + } + + virtual AuList GetErrorPaths() override + { + return this->failedPaths; + } bool OpenDir(const AuString &str) { @@ -33,6 +46,15 @@ namespace Aurora::IO::FS 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 (!nextLevel.size()) @@ -48,46 +70,58 @@ namespace Aurora::IO::FS virtual StatEx *Next() override { + AU_DEBUG_MEMCRUNCH; + StatEx *pNext {}; if (!this->pDir) { return {}; } - try + do { - pNext = this->pDir->Next(); - while (!pNext) + try { - DoNext(); - if (!this->pDir) + pNext = this->pDir->Next(); + + while (!pNext) { - return {}; + DoNext(); + if (!this->pDir) + { + return {}; + } + + pNext = this->pDir->Next(); } - pNext = this->pDir->Next(); - } + if (curSubDir.size()) + { + pNext->fileName.insert(pNext->fileName.begin(), curSubDir.begin(), curSubDir.end()); + } - if (curSubDir.size()) - { - pNext->fileName.insert(pNext->fileName.begin(), curSubDir.begin(), curSubDir.end()); - } + if (!this->bSymlinkTraversal && pNext->bSymLink) + { + continue; + } - if (pNext->bExistsDirectory) + if (pNext->bExistsDirectory) + { + nextLevel.push_back(pNext->fileName + "/"); + } + } + catch (...) { - nextLevel.push_back(pNext->fileName + "/"); + SysPushErrorCatch(); } } - catch (...) - { - SysPushErrorCatch(); - } - + while (false); + return pNext; } }; - AUKN_SYM AuSPtr ReadDirRecursive(const AuString &string) + AUKN_SYM AuSPtr ReadDirRecursive(const AuString &string, AuOptional bTraverseSymlinks) { auto pObj = AuMakeShared(); if (!pObj) @@ -96,6 +130,8 @@ namespace Aurora::IO::FS return {}; } + pObj->bSymlinkTraversal = bTraverseSymlinks.ValueOr(true); + try { if (!pObj->OpenDir(string))