Source code

Revision control

Copy as Markdown

Other Tools

// EnumDirItems.cpp↩
#include "StdAfx.h"
#include <wchar.h>↩
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/FileName.h"
#if defined(_WIN32) && !defined(UNDER_CE)↩
#define _USE_SECURITY_CODE↩
#include "../../../Windows/SecurityUtils.h"
#endif
#include "EnumDirItems.h"
#include "SortUtils.h"
using namespace NWindows;↩
using namespace NFile;↩
using namespace NName;↩
void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,↩
const NFind::CFileInfo &fi)↩
{↩
CDirItem di;↩
di.Size = fi.Size;↩
di.CTime = fi.CTime;↩
di.ATime = fi.ATime;↩
di.MTime = fi.MTime;↩
di.Attrib = fi.Attrib;↩
di.IsAltStream = fi.IsAltStream;↩
di.PhyParent = phyParent;↩
di.LogParent = logParent;↩
di.SecureIndex = secureIndex;↩
di.Name = fs2us(fi.Name);↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
// di.ShortName = fs2us(fi.ShortName);↩
#endif
Items.Add(di);↩
if (fi.IsDir())↩
Stat.NumDirs++;↩
else if (fi.IsAltStream)↩
{↩
Stat.NumAltStreams++;↩
Stat.AltStreamsSize += fi.Size;↩
}↩
else
{↩
Stat.NumFiles++;↩
Stat.FilesSize += fi.Size;↩
}↩
}↩
HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)↩
{↩
Stat.NumErrors++;↩
if (Callback)↩
return Callback->ScanError(path, errorCode);↩
return S_OK;↩
}↩
HRESULT CDirItems::AddError(const FString &path)↩
{↩
return AddError(path, ::GetLastError());↩
}↩
static const unsigned kScanProgressStepMask = (1 << 12) - 1;↩
HRESULT CDirItems::ScanProgress(const FString &dirPath)↩
{↩
if (Callback)↩
return Callback->ScanProgress(Stat, dirPath, true);↩
return S_OK;↩
}↩
UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
{↩
UString path;↩
unsigned len = name.Len();↩
int i;↩
for (i = index; i >= 0; i = parents[i])↩
len += Prefixes[i].Len();↩
wchar_t *p = path.GetBuf_SetEnd(len) + len;↩
p -= name.Len();↩
wmemcpy(p, (const wchar_t *)name, name.Len());↩
for (i = index; i >= 0; i = parents[i])↩
{↩
const UString &s = Prefixes[i];↩
p -= s.Len();↩
wmemcpy(p, (const wchar_t *)s, s.Len());↩
}↩
return path;↩
}↩
FString CDirItems::GetPhyPath(unsigned index) const
{↩
const CDirItem &di = Items[index];↩
return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name));↩
}↩
UString CDirItems::GetLogPath(unsigned index) const
{↩
const CDirItem &di = Items[index];↩
return GetPrefixesPath(LogParents, di.LogParent, di.Name);↩
}↩
void CDirItems::ReserveDown()↩
{↩
Prefixes.ReserveDown();↩
PhyParents.ReserveDown();↩
LogParents.ReserveDown();↩
Items.ReserveDown();↩
}↩
unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)↩
{↩
PhyParents.Add(phyParent);↩
LogParents.Add(logParent);↩
return Prefixes.Add(prefix);↩
}↩
void CDirItems::DeleteLastPrefix()↩
{↩
PhyParents.DeleteBack();↩
LogParents.DeleteBack();↩
Prefixes.DeleteBack();↩
}↩
bool InitLocalPrivileges();↩
CDirItems::CDirItems():↩
SymLinks(false),↩
ScanAltStreams(false)↩
#ifdef _USE_SECURITY_CODE↩
, ReadSecure(false)↩
#endif
, Callback(NULL)↩
{↩
#ifdef _USE_SECURITY_CODE↩
_saclEnabled = InitLocalPrivileges();↩
#endif
}↩
#ifdef _USE_SECURITY_CODE↩
HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)↩
{↩
secureIndex = -1;↩
SECURITY_INFORMATION securInfo =↩
DACL_SECURITY_INFORMATION |↩
GROUP_SECURITY_INFORMATION |↩
OWNER_SECURITY_INFORMATION;↩
if (_saclEnabled)↩
securInfo |= SACL_SECURITY_INFORMATION;↩
DWORD errorCode = 0;↩
DWORD secureSize;↩
BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);↩
if (res)↩
{↩
if (secureSize == 0)↩
return S_OK;↩
if (secureSize > TempSecureBuf.Size())↩
errorCode = ERROR_INVALID_FUNCTION;↩
}↩
else
{↩
errorCode = GetLastError();↩
if (errorCode == ERROR_INSUFFICIENT_BUFFER)↩
{↩
if (secureSize <= TempSecureBuf.Size())↩
errorCode = ERROR_INVALID_FUNCTION;↩
else
{↩
TempSecureBuf.Alloc(secureSize);↩
res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);↩
if (res)↩
{↩
if (secureSize != TempSecureBuf.Size())↩
errorCode = ERROR_INVALID_FUNCTION;;↩
}↩
else
errorCode = GetLastError();↩
}↩
}↩
}↩
if (res)↩
{↩
secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);↩
return S_OK;↩
}↩
if (errorCode == 0)↩
errorCode = ERROR_INVALID_FUNCTION;↩
return AddError(path, errorCode);↩
}↩
#endif
HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)↩
{↩
RINOK(ScanProgress(phyPrefix));↩
NFind::CEnumerator enumerator;↩
enumerator.SetDirPrefix(phyPrefix);↩
for (unsigned ttt = 0; ; ttt++)↩
{↩
NFind::CFileInfo fi;↩
bool found;↩
if (!enumerator.Next(fi, found))↩
{↩
return AddError(phyPrefix);↩
}↩
if (!found)↩
return S_OK;↩
int secureIndex = -1;↩
#ifdef _USE_SECURITY_CODE↩
if (ReadSecure)↩
{↩
RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex));↩
}↩
#endif
AddDirFileInfo(phyParent, logParent, secureIndex, fi);↩
if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)↩
{↩
RINOK(ScanProgress(phyPrefix));↩
}↩
if (fi.IsDir())↩
{↩
const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;↩
unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));↩
RINOK(EnumerateDir(parent, parent, phyPrefix + name2));↩
}↩
}↩
}↩
HRESULT CDirItems::EnumerateItems2(↩
const FString &phyPrefix,↩
const UString &logPrefix,↩
const FStringVector &filePaths,↩
FStringVector *requestedPaths)↩
{↩
int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix));↩
int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);↩
FOR_VECTOR (i, filePaths)↩
{↩
const FString &filePath = filePaths[i];↩
NFind::CFileInfo fi;↩
const FString phyPath = phyPrefix + filePath;↩
if (!fi.Find(phyPath))↩
{↩
RINOK(AddError(phyPath));↩
continue;↩
}↩
if (requestedPaths)↩
requestedPaths->Add(phyPath);↩
int delimiter = filePath.ReverseFind_PathSepar();↩
FString phyPrefixCur;↩
int phyParentCur = phyParent;↩
if (delimiter >= 0)↩
{↩
phyPrefixCur.SetFrom(filePath, delimiter + 1);↩
phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));↩
}↩
int secureIndex = -1;↩
#ifdef _USE_SECURITY_CODE↩
if (ReadSecure)↩
{↩
RINOK(AddSecurityItem(phyPath, secureIndex));↩
}↩
#endif
AddDirFileInfo(phyParentCur, logParent, secureIndex, fi);↩
if (fi.IsDir())↩
{↩
const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;↩
unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));↩
RINOK(EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2));↩
}↩
}↩
ReserveDown();↩
return S_OK;↩
}↩
static HRESULT EnumerateDirItems(↩
const NWildcard::CCensorNode &curNode,↩
int phyParent, int logParent, const FString &phyPrefix,↩
const UStringVector &addArchivePrefix,↩
CDirItems &dirItems,↩
bool enterToSubFolders);↩
static HRESULT EnumerateDirItems_Spec(↩
const NWildcard::CCensorNode &curNode,↩
int phyParent, int logParent, const FString &curFolderName,↩
const FString &phyPrefix,↩
const UStringVector &addArchivePrefix,↩
CDirItems &dirItems,↩
bool enterToSubFolders)↩
{↩
const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;↩
unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));↩
unsigned numItems = dirItems.Items.Size();↩
HRESULT res = EnumerateDirItems(↩
curNode, parent, parent, phyPrefix + name2,↩
addArchivePrefix, dirItems, enterToSubFolders);↩
if (numItems == dirItems.Items.Size())↩
dirItems.DeleteLastPrefix();↩
return res;↩
}↩
#ifndef UNDER_CE↩
#ifdef _WIN32↩
static HRESULT EnumerateAltStreams(↩
const NFind::CFileInfo &fi,↩
const NWildcard::CCensorNode &curNode,↩
int phyParent, int logParent, const FString &fullPath,↩
const UStringVector &addArchivePrefix, // prefix from curNode↩
bool addAllItems,↩
CDirItems &dirItems)↩
{↩
NFind::CStreamEnumerator enumerator(fullPath);↩
for (;;)↩
{↩
NFind::CStreamInfo si;↩
bool found;↩
if (!enumerator.Next(si, found))↩
{↩
return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL↩
}↩
if (!found)↩
return S_OK;↩
if (si.IsMainStream())↩
continue;↩
UStringVector addArchivePrefixNew = addArchivePrefix;↩
UString reducedName = si.GetReducedName();↩
addArchivePrefixNew.Back() += reducedName;↩
if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))↩
continue;↩
if (!addAllItems)↩
if (!curNode.CheckPathToRoot(true, addArchivePrefixNew, true))↩
continue;↩
NFind::CFileInfo fi2 = fi;↩
fi2.Name += us2fs(reducedName);↩
fi2.Size = si.Size;↩
fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;↩
fi2.IsAltStream = true;↩
dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);↩
}↩
}↩
#endif
HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,↩
const FString &phyPrefix)↩
{↩
if (!SymLinks || !fi.HasReparsePoint())↩
return S_OK;↩
const FString path = phyPrefix + fi.Name;↩
CByteBuffer &buf = dirItem.ReparseData;↩
DWORD res = 0;↩
if (NIO::GetReparseData(path, buf))↩
{↩
CReparseAttr attr;↩
if (attr.Parse(buf, buf.Size(), res))↩
return S_OK;↩
// we ignore unknown reparse points↩
if (res != ERROR_INVALID_REPARSE_DATA)↩
res = 0;↩
}↩
else
{↩
res = ::GetLastError();↩
if (res == 0)↩
res = ERROR_INVALID_FUNCTION;↩
}↩
buf.Free();↩
if (res == 0)↩
return S_OK;↩
return AddError(path, res);↩
}↩
#endif
static HRESULT EnumerateForItem(↩
NFind::CFileInfo &fi,↩
const NWildcard::CCensorNode &curNode,↩
int phyParent, int logParent, const FString &phyPrefix,↩
const UStringVector &addArchivePrefix, // prefix from curNode↩
CDirItems &dirItems,↩
bool enterToSubFolders)↩
{↩
const UString name = fs2us(fi.Name);↩
bool enterToSubFolders2 = enterToSubFolders;↩
UStringVector addArchivePrefixNew = addArchivePrefix;↩
addArchivePrefixNew.Add(name);↩
{↩
UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);↩
if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))↩
return S_OK;↩
}↩
int dirItemIndex = -1;↩
bool addAllSubStreams = false;↩
if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))↩
{↩
int secureIndex = -1;↩
#ifdef _USE_SECURITY_CODE↩
if (dirItems.ReadSecure)↩
{↩
RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex));↩
}↩
#endif
dirItemIndex = dirItems.Items.Size();↩
dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);↩
if (fi.IsDir())↩
enterToSubFolders2 = true;↩
addAllSubStreams = true;↩
}↩
#ifndef UNDER_CE↩
if (dirItems.ScanAltStreams)↩
{↩
RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,↩
phyPrefix + fi.Name,↩
addArchivePrefixNew,↩
addAllSubStreams,↩
dirItems));↩
}↩
if (dirItemIndex >= 0)↩
{↩
CDirItem &dirItem = dirItems.Items[dirItemIndex];↩
RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));↩
if (dirItem.ReparseData.Size() != 0)↩
return S_OK;↩
}↩
#endif
if (!fi.IsDir())↩
return S_OK;↩
const NWildcard::CCensorNode *nextNode = 0;↩
if (addArchivePrefix.IsEmpty())↩
{↩
int index = curNode.FindSubNode(name);↩
if (index >= 0)↩
nextNode = &curNode.SubNodes[index];↩
}↩
if (!enterToSubFolders2 && nextNode == 0)↩
return S_OK;↩
addArchivePrefixNew = addArchivePrefix;↩
if (nextNode == 0)↩
{↩
nextNode = &curNode;↩
addArchivePrefixNew.Add(name);↩
}↩
return EnumerateDirItems_Spec(↩
*nextNode, phyParent, logParent, fi.Name, phyPrefix,↩
addArchivePrefixNew,↩
dirItems,↩
enterToSubFolders2);↩
}↩
static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)↩
{↩
FOR_VECTOR (i, curNode.IncludeItems)↩
{↩
const NWildcard::CItem &item = curNode.IncludeItems[i];↩
if (item.Recursive || item.PathParts.Size() != 1)↩
return false;↩
const UString &name = item.PathParts.Front();↩
/*↩
if (name.IsEmpty())↩
return false;↩
*/
/* Windows doesn't support file name with wildcard↩
But if another system supports file name with wildcard,↩
and wildcard mode is disabled, we can ignore wildcard in name */
/*↩
if (!item.WildcardParsing)↩
continue;↩
*/
if (DoesNameContainWildcard(name))↩
return false;↩
}↩
return true;↩
}↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
static bool IsVirtualFsFolder(const FString &prefix, const UString &name)↩
{↩
UString s = fs2us(prefix);↩
s += name;↩
s.Add_PathSepar();↩
return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0;↩
}↩
#endif
static HRESULT EnumerateDirItems(↩
const NWildcard::CCensorNode &curNode,↩
int phyParent, int logParent, const FString &phyPrefix,↩
const UStringVector &addArchivePrefix, // prefix from curNode↩
CDirItems &dirItems,↩
bool enterToSubFolders)↩
{↩
if (!enterToSubFolders)↩
if (curNode.NeedCheckSubDirs())↩
enterToSubFolders = true;↩
RINOK(dirItems.ScanProgress(phyPrefix));↩
// try direct_names case at first↩
if (addArchivePrefix.IsEmpty() && !enterToSubFolders)↩
{↩
if (CanUseFsDirect(curNode))↩
{↩
// all names are direct (no wildcards)↩
// so we don't need file_system's dir enumerator↩
CRecordVector<bool> needEnterVector;↩
unsigned i;↩
for (i = 0; i < curNode.IncludeItems.Size(); i++)↩
{↩
const NWildcard::CItem &item = curNode.IncludeItems[i];↩
const UString &name = item.PathParts.Front();↩
FString fullPath = phyPrefix + us2fs(name);↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
bool needAltStreams = true;↩
#endif
#ifdef _USE_SECURITY_CODE↩
bool needSecurity = true;↩
#endif
if (phyPrefix.IsEmpty())↩
{↩
if (!item.ForFile)↩
{↩
/* we don't like some names for alt streams inside archive:↩
":sname" for "\"↩
"c:::sname" for "C:\"↩
So we ignore alt streams for these cases */
if (name.IsEmpty())↩
{↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
needAltStreams = false;↩
#endif
/*↩
// do we need to ignore security info for "\\" folder ?↩
#ifdef _USE_SECURITY_CODE↩
needSecurity = false;↩
#endif↩
*/
fullPath = CHAR_PATH_SEPARATOR;↩
}↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
else if (item.IsDriveItem())↩
{↩
needAltStreams = false;↩
fullPath.Add_PathSepar();↩
}↩
#endif
}↩
}↩
NFind::CFileInfo fi;↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
if (IsVirtualFsFolder(phyPrefix, name))↩
{↩
fi.SetAsDir();↩
fi.Name = us2fs(name);↩
}↩
else
#endif
if (!fi.Find(fullPath))↩
{↩
RINOK(dirItems.AddError(fullPath));↩
continue;↩
}↩
bool isDir = fi.IsDir();↩
if (isDir && !item.ForDir || !isDir && !item.ForFile)↩
{↩
RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));↩
continue;↩
}↩
{↩
UStringVector pathParts;↩
pathParts.Add(fs2us(fi.Name));↩
if (curNode.CheckPathToRoot(false, pathParts, !isDir))↩
continue;↩
}↩
int secureIndex = -1;↩
#ifdef _USE_SECURITY_CODE↩
if (needSecurity && dirItems.ReadSecure)↩
{↩
RINOK(dirItems.AddSecurityItem(fullPath, secureIndex));↩
}↩
#endif
dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);↩
#ifndef UNDER_CE↩
{↩
CDirItem &dirItem = dirItems.Items.Back();↩
RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));↩
if (dirItem.ReparseData.Size() != 0)↩
{↩
if (fi.IsAltStream)↩
dirItems.Stat.AltStreamsSize -= fi.Size;↩
else
dirItems.Stat.FilesSize -= fi.Size;↩
continue;↩
}↩
}↩
#endif
#ifndef UNDER_CE↩
if (needAltStreams && dirItems.ScanAltStreams)↩
{↩
UStringVector pathParts;↩
pathParts.Add(fs2us(fi.Name));↩
RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,↩
fullPath, pathParts,↩
true, /* addAllSubStreams */
dirItems));↩
}↩
#endif
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 fi.Name. It's for shortnames support↩
}↩
RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,↩
addArchivePrefixNew, dirItems, true));↩
}↩
for (i = 0; i < curNode.SubNodes.Size(); i++)↩
{↩
if (i < needEnterVector.Size())↩
if (!needEnterVector[i])↩
continue;↩
const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];↩
FString fullPath = phyPrefix + us2fs(nextNode.Name);↩
NFind::CFileInfo fi;↩
if (phyPrefix.IsEmpty())↩
{↩
{↩
if (nextNode.Name.IsEmpty())↩
fullPath = CHAR_PATH_SEPARATOR;↩
#ifdef _WIN32↩
else if (NWildcard::IsDriveColonName(nextNode.Name))↩
fullPath.Add_PathSepar();↩
#endif
}↩
}↩
// we don't want to call fi.Find() for root folder or virtual folder↩
if (phyPrefix.IsEmpty() && nextNode.Name.IsEmpty()↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
|| IsVirtualFsFolder(phyPrefix, nextNode.Name)↩
#endif
)↩
{↩
fi.SetAsDir();↩
fi.Name = us2fs(nextNode.Name);↩
}↩
else
{↩
if (!fi.Find(fullPath))↩
{↩
if (!nextNode.AreThereIncludeItems())↩
continue;↩
RINOK(dirItems.AddError(fullPath));↩
continue;↩
}↩
if (!fi.IsDir())↩
{↩
RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));↩
continue;↩
}↩
}↩
RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,↩
UStringVector(), dirItems, false));↩
}↩
return S_OK;↩
}↩
}↩
#ifdef _WIN32↩
#ifndef UNDER_CE↩
// scan drives, if wildcard is "*:\"↩
if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0)↩
{↩
unsigned i;↩
for (i = 0; i < curNode.IncludeItems.Size(); i++)↩
{↩
const NWildcard::CItem &item = curNode.IncludeItems[i];↩
if (item.PathParts.Size() < 1)↩
break;↩
const UString &name = item.PathParts.Front();↩
if (name.Len() != 2 || name[1] != ':')↩
break;↩
if (item.PathParts.Size() == 1)↩
if (item.ForFile || !item.ForDir)↩
break;↩
if (NWildcard::IsDriveColonName(name))↩
continue;↩
if (name[0] != '*' && name[0] != '?')↩
break;↩
}↩
if (i == curNode.IncludeItems.Size())↩
{↩
FStringVector driveStrings;↩
NFind::MyGetLogicalDriveStrings(driveStrings);↩
for (i = 0; i < driveStrings.Size(); i++)↩
{↩
FString driveName = driveStrings[i];↩
if (driveName.Len() < 3 || driveName.Back() != '\\')↩
return E_FAIL;↩
driveName.DeleteBack();↩
NFind::CFileInfo fi;↩
fi.SetAsDir();↩
fi.Name = driveName;↩
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,↩
addArchivePrefix, dirItems, enterToSubFolders));↩
}↩
return S_OK;↩
}↩
}↩
#endif
#endif
NFind::CEnumerator enumerator;↩
enumerator.SetDirPrefix(phyPrefix);↩
for (unsigned ttt = 0; ; ttt++)↩
{↩
NFind::CFileInfo fi;↩
bool found;↩
if (!enumerator.Next(fi, found))↩
{↩
RINOK(dirItems.AddError(phyPrefix));↩
break;↩
}↩
if (!found)↩
break;↩
if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)↩
{↩
RINOK(dirItems.ScanProgress(phyPrefix));↩
}↩
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,↩
addArchivePrefix, dirItems, enterToSubFolders));↩
}↩
return S_OK;↩
}↩
HRESULT EnumerateItems(↩
const NWildcard::CCensor &censor,↩
const NWildcard::ECensorPathMode pathMode,↩
const UString &addPathPrefix,↩
CDirItems &dirItems)↩
{↩
FOR_VECTOR (i, censor.Pairs)↩
{↩
const NWildcard::CPair &pair = censor.Pairs[i];↩
int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);↩
int logParent = -1;↩
if (pathMode == NWildcard::k_AbsPath)↩
logParent = phyParent;↩
else
{↩
if (!addPathPrefix.IsEmpty())↩
logParent = dirItems.AddPrefix(-1, -1, addPathPrefix);↩
}↩
RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(),↩
dirItems,↩
false // enterToSubFolders↩
));↩
}↩
dirItems.ReserveDown();↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
dirItems.FillFixedReparse();↩
#endif
return S_OK;↩
}↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
void CDirItems::FillFixedReparse()↩
{↩
/* imagex/WIM reduces absolute pathes in links (raparse data),↩
if we archive non root folder. We do same thing here */
if (!SymLinks)↩
return;↩
FOR_VECTOR(i, Items)↩
{↩
CDirItem &item = Items[i];↩
if (item.ReparseData.Size() == 0)↩
continue;↩
CReparseAttr attr;↩
DWORD errorCode = 0;↩
if (!attr.Parse(item.ReparseData, item.ReparseData.Size(), errorCode))↩
continue;↩
if (attr.IsRelative())↩
continue;↩
const UString &link = attr.GetPath();↩
if (!IsDrivePath(link))↩
continue;↩
// maybe we need to support networks paths also ?↩
FString fullPathF;↩
if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF))↩
continue;↩
UString fullPath = fs2us(fullPathF);↩
const UString logPath = GetLogPath(i);↩
if (logPath.Len() >= fullPath.Len())↩
continue;↩
if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0)↩
continue;↩
const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len());↩
if (!IsPathSepar(prefix.Back()))↩
continue;↩
unsigned rootPrefixSize = GetRootPrefixSize(prefix);↩
if (rootPrefixSize == 0)↩
continue;↩
if (rootPrefixSize == prefix.Len())↩
continue; // simple case: paths are from root↩
if (link.Len() <= prefix.Len())↩
continue;↩
if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)↩
continue;↩
UString newLink = prefix.Left(rootPrefixSize);↩
newLink += link.Ptr(prefix.Len());↩
CByteBuffer data;↩
if (!FillLinkData(data, newLink, attr.IsSymLink()))↩
continue;↩
item.ReparseData2 = data;↩
}↩
}↩
#endif
static const char * const kCannotFindArchive = "Cannot find archive";↩
HRESULT EnumerateDirItemsAndSort(↩
NWildcard::CCensor &censor,↩
NWildcard::ECensorPathMode censorPathMode,↩
const UString &addPathPrefix,↩
UStringVector &sortedPaths,↩
UStringVector &sortedFullPaths,↩
CDirItemsStat &st,↩
IDirItemsCallback *callback)↩
{↩
FStringVector paths;↩
{↩
CDirItems dirItems;↩
dirItems.Callback = callback;↩
{↩
HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems);↩
st = dirItems.Stat;↩
RINOK(res);↩
}↩
FOR_VECTOR (i, dirItems.Items)↩
{↩
const CDirItem &dirItem = dirItems.Items[i];↩
if (!dirItem.IsDir())↩
paths.Add(dirItems.GetPhyPath(i));↩
}↩
}↩
if (paths.Size() == 0)↩
{↩
// return S_OK;↩
throw CMessagePathException(kCannotFindArchive);↩
}↩
UStringVector fullPaths;↩
unsigned i;↩
for (i = 0; i < paths.Size(); i++)↩
{↩
FString fullPath;↩
NFile::NDir::MyGetFullPathName(paths[i], fullPath);↩
fullPaths.Add(fs2us(fullPath));↩
}↩
CUIntVector indices;↩
SortFileNames(fullPaths, indices);↩
sortedPaths.ClearAndReserve(indices.Size());↩
sortedFullPaths.ClearAndReserve(indices.Size());↩
for (i = 0; i < indices.Size(); i++)↩
{↩
unsigned index = indices[i];↩
sortedPaths.AddInReserved(fs2us(paths[index]));↩
sortedFullPaths.AddInReserved(fullPaths[index]);↩
if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0)↩
throw CMessagePathException("Duplicate archive path:", sortedFullPaths[i]);↩
}↩
return S_OK;↩
}↩
#ifdef _WIN32↩
// This code converts all short file names to long file names.↩
static void ConvertToLongName(const UString &prefix, UString &name)↩
{↩
if (name.IsEmpty() || DoesNameContainWildcard(name))↩
return;↩
NFind::CFileInfo fi;↩
const FString path (us2fs(prefix + name));↩
#ifndef UNDER_CE↩
if (NFile::NName::IsDevicePath(path))↩
return;↩
#endif
if (fi.Find(path))↩
name = fs2us(fi.Name);↩
}↩
static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)↩
{↩
FOR_VECTOR (i, items)↩
{↩
NWildcard::CItem &item = items[i];↩
if (item.Recursive || item.PathParts.Size() != 1)↩
continue;↩
if (prefix.IsEmpty() && item.IsDriveItem())↩
continue;↩
ConvertToLongName(prefix, item.PathParts.Front());↩
}↩
}↩
static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)↩
{↩
ConvertToLongNames(prefix, node.IncludeItems);↩
ConvertToLongNames(prefix, node.ExcludeItems);↩
unsigned i;↩
for (i = 0; i < node.SubNodes.Size(); i++)↩
{↩
UString &name = node.SubNodes[i].Name;↩
if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name))↩
continue;↩
ConvertToLongName(prefix, name);↩
}↩
// mix folders with same name↩
for (i = 0; i < node.SubNodes.Size(); i++)↩
{↩
NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];↩
for (unsigned j = i + 1; j < node.SubNodes.Size();)↩
{↩
const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];↩
if (nextNode1.Name.IsEqualTo_NoCase(nextNode2.Name))↩
{↩
nextNode1.IncludeItems += nextNode2.IncludeItems;↩
nextNode1.ExcludeItems += nextNode2.ExcludeItems;↩
node.SubNodes.Delete(j);↩
}↩
else
j++;↩
}↩
}↩
for (i = 0; i < node.SubNodes.Size(); i++)↩
{↩
NWildcard::CCensorNode &nextNode = node.SubNodes[i];↩
ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode);↩
}↩
}↩
void ConvertToLongNames(NWildcard::CCensor &censor)↩
{↩
FOR_VECTOR (i, censor.Pairs)↩
{↩
NWildcard::CPair &pair = censor.Pairs[i];↩
ConvertToLongNames(pair.Prefix, pair.Head);↩
}↩
}↩
#endif
CMessagePathException::CMessagePathException(const char *a, const wchar_t *u)↩
{↩
(*this) += a;↩
if (u)↩
{↩
Add_LF();↩
(*this) += u;↩
}↩
}↩