/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: DirDeleter.cpp Date: 2022-11-06 Author: Reece ***/ #include #include "FS.hpp" namespace Aurora::IO::FS { struct RecursiveDirDeleter : IReadDir { AuSPtr pDir; AuList nextLevel; AuList nextLevel2; 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 AuROString &string) { AU_DEBUG_MEMCRUNCH; if (!this->OpenDir(string)) { return {}; } while (this->Next()) { } this->RemoveDirs(); AuFS::Remove(string); return true; } bool OpenDir(const AuROString &str) { this->curPath = str; this->pDir = ReadDir(str); return bool(pDir); } bool OpenNext(const AuString &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 a = this->nextLevel[0]; this->nextLevel.erase(this->nextLevel.begin()); this->pDir = ReadDir(this->curPath + "/" + a); this->curSubDir = a; } virtual StatEx *Next() override { StatEx *pNext {}; if (!this->pDir) { return {}; } try { pNext = this->pDir->Next(); while (!pNext) { DoNext(); if (!this->pDir) { return {}; } pNext = this->pDir->Next(); } if (curSubDir.size()) { pNext->fileName.insert(pNext->fileName.begin(), curSubDir.begin(), curSubDir.end()); } if (pNext->bExistsDirectory && !pNext->bSymLink) { nextLevel.push_back(pNext->fileName + "/"); nextLevel2.push_back(pNext->fileName + "/"); } else { if (!AuFS::Remove(pNext->path)) { this->failedPaths.push_back(pNext->fileName); this->uErrorCount++; } } } catch (...) { SysPushErrorCatch(); } return pNext; } void RemoveDirs() { for (auto itr = this->nextLevel2.rbegin(); itr != this->nextLevel2.rend(); itr++) { auto dir = this->curPath + "/" + itr->c_str(); if (!AuFS::Remove(dir)) { this->failedPaths.push_back(itr->c_str()); this->uErrorCount++; } } } }; AUKN_SYM bool DirDeleter(const AuROString &string) { auto pObj = AuMakeShared(); SysCheckNotNullMemory(pObj, false); try { if (!pObj->DoThing(string)) { return {}; } } catch (...) { SysPushErrorCatch(); } return !AuFS::DirExists(string); } AUKN_SYM bool DirDeleterEx(const AuROString &string, AuList &failingPaths) { auto pObj = AuMakeShared(); SysCheckNotNullMemory(pObj, false); try { if (!pObj->DoThing(string)) { return {}; } if (AuFS::DirExists(string)) { for (const auto &str : pObj->failedPaths) { auto normalizedUserDir = AuString(string) + "/"; auto normalizedUserDir2 = normalizedUserDir + str; if (AuFS::FileExists(normalizedUserDir2) || AuFS::DirExists(normalizedUserDir2)) { if (AuEndsWith(normalizedUserDir, "//") || AuEndsWith(normalizedUserDir, "\\/")) { normalizedUserDir.pop_back(); normalizedUserDir[normalizedUserDir.size() - 1] = '/'; } normalizedUserDir += str; failingPaths.push_back(normalizedUserDir); } } return false; } } catch (...) { SysPushErrorCatch(); } return true; } }