diff -r ea891871f481 -r bb5522e88ab2 misc/libphysfs/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/misc/libphysfs/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp Mon Apr 10 12:06:43 2017 -0400 @@ -0,0 +1,281 @@ +// EnumDirItems.cpp + +#include "StdAfx.h" + +#include "Common/StringConvert.h" +#include "Common/Wildcard.h" +#include "Common/MyCom.h" + +#include "EnumDirItems.h" + +using namespace NWindows; +using namespace NFile; +using namespace NName; + +void AddDirFileInfo( + const UString &prefix, // prefix for logical path + const UString &fullPathName, // path on disk: can be relative to some basePrefix + const NFind::CFileInfoW &fileInfo, + CObjectVector &dirItems) +{ + CDirItem item; + item.Attributes = fileInfo.Attributes; + item.Size = fileInfo.Size; + item.CreationTime = fileInfo.CreationTime; + item.LastAccessTime = fileInfo.LastAccessTime; + item.LastWriteTime = fileInfo.LastWriteTime; + item.Name = prefix + fileInfo.Name; + item.FullPath = fullPathName; + dirItems.Add(item); +} + +static void EnumerateDirectory( + const UString &baseFolderPrefix, // base (disk) prefix for scanning + const UString &directory, // additional disk prefix starting from baseFolderPrefix + const UString &prefix, // logical prefix + CObjectVector &dirItems, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard)); + for (;;) + { + NFind::CFileInfoW fileInfo; + bool found; + if (!enumerator.Next(fileInfo, found)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(baseFolderPrefix + directory); + return; + } + if (!found) + break; + AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems); + if (fileInfo.IsDirectory()) + { + EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter), + prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes); + } + } +} + +void EnumerateDirItems( + const UString &baseFolderPrefix, // base (disk) prefix for scanning + const UStringVector &fileNames, // names relative to baseFolderPrefix + const UString &archiveNamePrefix, + CObjectVector &dirItems, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + for(int i = 0; i < fileNames.Size(); i++) + { + const UString &fileName = fileNames[i]; + NFind::CFileInfoW fileInfo; + if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(baseFolderPrefix + fileName); + continue; + } + AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems); + if (fileInfo.IsDirectory()) + { + EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter), + archiveNamePrefix + fileInfo.Name + wchar_t(kDirDelimiter), + dirItems, errorPaths, errorCodes); + } + } +} + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, + const UString &diskPrefix, // full disk path prefix + const UString &archivePrefix, // prefix from root + const UStringVector &addArchivePrefix, // prefix from curNode + CObjectVector &dirItems, + bool enterToSubFolders, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + if (!enterToSubFolders) + if (curNode.NeedCheckSubDirs()) + enterToSubFolders = true; + if (callback) + RINOK(callback->CheckBreak()); + + // try direct_names case at first + if (addArchivePrefix.IsEmpty() && !enterToSubFolders) + { + // check that all names are direct + int i; + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + if (item.Recursive || item.PathParts.Size() != 1) + break; + const UString &name = item.PathParts.Front(); + if (name.IsEmpty() || DoesNameContainWildCard(name)) + break; + } + if (i == curNode.IncludeItems.Size()) + { + // all names are direct (no wildcards) + // so we don't need file_system's dir enumerator + CRecordVector needEnterVector; + for (i = 0; i < curNode.IncludeItems.Size(); i++) + { + const NWildcard::CItem &item = curNode.IncludeItems[i]; + const UString &name = item.PathParts.Front(); + const UString fullPath = diskPrefix + name; + NFind::CFileInfoW fileInfo; + if (!NFind::FindFile(fullPath, fileInfo)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(fullPath); + continue; + } + bool isDir = fileInfo.IsDirectory(); + if (isDir && !item.ForDir || !isDir && !item.ForFile) + { + errorCodes.Add((DWORD)E_FAIL); + errorPaths.Add(fullPath); + continue; + } + const UString realName = fileInfo.Name; + const UString realDiskPath = diskPrefix + realName; + { + UStringVector pathParts; + pathParts.Add(fileInfo.Name); + if (curNode.CheckPathToRoot(false, pathParts, !isDir)) + continue; + } + AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems); + if (!isDir) + continue; + + UStringVector addArchivePrefixNew; + const NWildcard::CCensorNode *nextNode = 0; + int index = curNode.FindSubNode(name); + if (index >= 0) + { + for (int t = needEnterVector.Size(); t <= index; t++) + needEnterVector.Add(true); + needEnterVector[index] = false; + nextNode = &curNode.SubNodes[index]; + } + else + { + nextNode = &curNode; + addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support + } + RINOK(EnumerateDirItems(*nextNode, + realDiskPath + wchar_t(kDirDelimiter), + archivePrefix + realName + wchar_t(kDirDelimiter), + addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes)); + } + for (i = 0; i < curNode.SubNodes.Size(); i++) + { + if (i < needEnterVector.Size()) + if (!needEnterVector[i]) + continue; + const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i]; + const UString fullPath = diskPrefix + nextNode.Name; + NFind::CFileInfoW fileInfo; + if (!NFind::FindFile(fullPath, fileInfo)) + { + if (!nextNode.AreThereIncludeItems()) + continue; + errorCodes.Add(::GetLastError()); + errorPaths.Add(fullPath); + continue; + } + if (!fileInfo.IsDirectory()) + { + errorCodes.Add((DWORD)E_FAIL); + errorPaths.Add(fullPath); + continue; + } + RINOK(EnumerateDirItems(nextNode, + diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter), + archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter), + UStringVector(), dirItems, false, callback, errorPaths, errorCodes)); + } + return S_OK; + } + } + + + NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard)); + for (;;) + { + NFind::CFileInfoW fileInfo; + bool found; + if (!enumerator.Next(fileInfo, found)) + { + errorCodes.Add(::GetLastError()); + errorPaths.Add(diskPrefix); + break; + } + if (!found) + break; + + if (callback) + RINOK(callback->CheckBreak()); + const UString &name = fileInfo.Name; + bool enterToSubFolders2 = enterToSubFolders; + UStringVector addArchivePrefixNew = addArchivePrefix; + addArchivePrefixNew.Add(name); + { + UStringVector addArchivePrefixNewTemp(addArchivePrefixNew); + if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory())) + continue; + } + if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory())) + { + AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems); + if (fileInfo.IsDirectory()) + enterToSubFolders2 = true; + } + if (!fileInfo.IsDirectory()) + continue; + + const NWildcard::CCensorNode *nextNode = 0; + if (addArchivePrefix.IsEmpty()) + { + int index = curNode.FindSubNode(name); + if (index >= 0) + nextNode = &curNode.SubNodes[index]; + } + if (!enterToSubFolders2 && nextNode == 0) + continue; + + addArchivePrefixNew = addArchivePrefix; + if (nextNode == 0) + { + nextNode = &curNode; + addArchivePrefixNew.Add(name); + } + RINOK(EnumerateDirItems(*nextNode, + diskPrefix + name + wchar_t(kDirDelimiter), + archivePrefix + name + wchar_t(kDirDelimiter), + addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes)); + } + return S_OK; +} + +HRESULT EnumerateItems( + const NWildcard::CCensor &censor, + CObjectVector &dirItems, + IEnumDirItemCallback *callback, + UStringVector &errorPaths, + CRecordVector &errorCodes) +{ + for (int i = 0; i < censor.Pairs.Size(); i++) + { + const NWildcard::CPair &pair = censor.Pairs[i]; + RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false, + callback, errorPaths, errorCodes)); + } + return S_OK; +}