282 lines
8.9 KiB
C++
282 lines
8.9 KiB
C++
|
// 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<CDirItem> &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<CDirItem> &dirItems,
|
||
|
UStringVector &errorPaths,
|
||
|
CRecordVector<DWORD> &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<CDirItem> &dirItems,
|
||
|
UStringVector &errorPaths,
|
||
|
CRecordVector<DWORD> &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<CDirItem> &dirItems,
|
||
|
bool enterToSubFolders,
|
||
|
IEnumDirItemCallback *callback,
|
||
|
UStringVector &errorPaths,
|
||
|
CRecordVector<DWORD> &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<bool> 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<CDirItem> &dirItems,
|
||
|
IEnumDirItemCallback *callback,
|
||
|
UStringVector &errorPaths,
|
||
|
CRecordVector<DWORD> &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;
|
||
|
}
|