159 lines
4.2 KiB
C++
159 lines
4.2 KiB
C++
/***
|
|
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: FSRecursion.cpp
|
|
Date: 2022-11-06
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "FS.hpp"
|
|
|
|
namespace Aurora::IO::FS
|
|
{
|
|
struct RecursiveDirIterator : IReadDir
|
|
{
|
|
AuSPtr<IReadDir> pDir;
|
|
AuList<AuPair<AuUInt, AuString>> nextLevel;
|
|
AuString curPath;
|
|
AuString curSubDir;
|
|
AuUInt uCurrentDepth {};
|
|
bool bSymlinkTraversal { true };
|
|
AuUInt32 uErrorCount {};
|
|
AuList<AuString> failedPaths;
|
|
AuOptional<AuUInt> optMaxRecursion {};
|
|
|
|
virtual AuUInt32 GetErrorCount() override
|
|
{
|
|
return this->uErrorCount;
|
|
}
|
|
|
|
virtual AuList<AuString> 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<IReadDir> ReadDirRecursive(const AuROString &string, AuOptional<bool> bTraverseSymlinks, AuOptional<AuUInt> optMaxRecursion)
|
|
{
|
|
SysCheckArgNotNull(string.size(), {});
|
|
|
|
auto pObj = AuMakeShared<RecursiveDirIterator>();
|
|
SysCheckNotNullMemory(pObj, {});
|
|
|
|
pObj->bSymlinkTraversal = bTraverseSymlinks.ValueOr(true);
|
|
pObj->optMaxRecursion = optMaxRecursion;
|
|
|
|
try
|
|
{
|
|
if (!pObj->OpenDir(string))
|
|
{
|
|
return {};
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
}
|
|
|
|
return pObj;
|
|
}
|
|
} |