diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp | 809 |
1 files changed, 672 insertions, 137 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp index 8c83a9fbdc0..3ebf25aad8f 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp @@ -2,7 +2,18 @@ #include "StdAfx.h" -#include "Windows/FileName.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" @@ -10,8 +21,8 @@ using namespace NWindows; using namespace NFile; using namespace NName; -void AddDirFileInfo(int phyParent, int logParent, - const NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems) +void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex, + const NFind::CFileInfo &fi) { CDirItem di; di.Size = fi.Size; @@ -19,41 +30,83 @@ void AddDirFileInfo(int phyParent, int logParent, 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); - dirItems.Add(di); + #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; - int len = name.Length(); + unsigned len = name.Len(); + int i; for (i = index; i >= 0; i = parents[i]) - len += Prefixes[i].Length(); - int totalLen = len; - wchar_t *p = path.GetBuffer(len); - p[len] = 0; - len -= name.Length(); - memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t)); + 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]; - len -= s.Length(); - memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t)); + p -= s.Len(); + wmemcpy(p, (const wchar_t *)s, s.Len()); } - path.ReleaseBuffer(totalLen); + return path; } -UString CDirItems::GetPhyPath(int index) const +FString CDirItems::GetPhyPath(unsigned index) const { const CDirItem &di = Items[index]; - return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); + return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name)); } -UString CDirItems::GetLogPath(int index) const +UString CDirItems::GetLogPath(unsigned index) const { const CDirItem &di = Items[index]; return GetPrefixesPath(LogParents, di.LogParent, di.Name); @@ -67,7 +120,7 @@ void CDirItems::ReserveDown() Items.ReserveDown(); } -int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) +unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix) { PhyParents.Add(phyParent); LogParents.Add(logParent); @@ -81,150 +134,473 @@ void CDirItems::DeleteLastPrefix() Prefixes.DeleteBack(); } -void CDirItems::EnumerateDirectory(int phyParent, int logParent, const FString &phyPrefix, - FStringVector &errorPaths, CRecordVector<DWORD> &errorCodes) +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(phyPrefix + FCHAR_ANY_MASK); - for (;;) + for (unsigned ttt = 0; ; ttt++) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { - errorCodes.Add(::GetLastError()); - errorPaths.Add(phyPrefix); - return; + return AddError(phyPrefix); } if (!found) - break; - AddDirFileInfo(phyParent, logParent, fi, Items); + 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; - int parent = AddPrefix(phyParent, logParent, fs2us(name2)); - EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes); + unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2)); + RINOK(EnumerateDir(parent, parent, phyPrefix + name2)); } } } -void CDirItems::EnumerateDirItems2(const FString &phyPrefix, const UString &logPrefix, - const FStringVector &filePaths, FStringVector &errorPaths, CRecordVector<DWORD> &errorCodes) +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 (int i = 0; i < filePaths.Size(); i++) + FOR_VECTOR (i, filePaths) { const FString &filePath = filePaths[i]; NFind::CFileInfo fi; const FString phyPath = phyPrefix + filePath; if (!fi.Find(phyPath)) { - errorCodes.Add(::GetLastError()); - errorPaths.Add(phyPath); + RINOK(AddError(phyPath)); continue; } - int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR); + if (requestedPaths) + requestedPaths->Add(phyPath); + + int delimiter = filePath.ReverseFind_PathSepar(); FString phyPrefixCur; int phyParentCur = phyParent; if (delimiter >= 0) { - phyPrefixCur = filePath.Left(delimiter + 1); + phyPrefixCur.SetFrom(filePath, delimiter + 1); phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur)); } - AddDirFileInfo(phyParentCur, logParent, fi, Items); + + 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; - int parent = AddPrefix(phyParentCur, logParent, fs2us(name2)); - EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes); + 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, + + + + + +static HRESULT EnumerateDirItems( + const NWildcard::CCensorNode &curNode, int phyParent, int logParent, const FString &phyPrefix, const UStringVector &addArchivePrefix, CDirItems &dirItems, - bool enterToSubFolders, - IEnumDirItemCallback *callback, - FStringVector &errorPaths, - CRecordVector<DWORD> &errorCodes); + bool enterToSubFolders); -static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode, +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, - IEnumDirItemCallback *callback, - FStringVector &errorPaths, - CRecordVector<DWORD> &errorCodes) - + bool enterToSubFolders) { const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR; - int parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2)); - int numItems = dirItems.Items.Size(); - HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2, - addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes); + 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 + 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; + 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; + if (NIO::GetReparseData(path, buf)) + { + CReparseAttr attr; + if (attr.Parse(buf, buf.Size())) + return S_OK; + } + DWORD res = ::GetLastError(); + buf.Free(); + return AddError(path , res); +} + +#endif -static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, +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, - IEnumDirItemCallback *callback, - FStringVector &errorPaths, - CRecordVector<DWORD> &errorCodes) + 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; + + 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; + } + + #ifndef UNDER_CE + if (dirItems.ScanAltStreams) + { + RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent, + phyPrefix + fi.Name, + addArchivePrefixNew, 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; - if (callback) - RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), fs2us(phyPrefix))); + + RINOK(dirItems.ScanProgress(phyPrefix)); // 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()) + 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(); - const FString fullPath = phyPrefix + us2fs(name); + 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 = FCHAR_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)) { - errorCodes.Add(::GetLastError()); - errorPaths.Add(fullPath); + RINOK(dirItems.AddError(fullPath)); continue; } + bool isDir = fi.IsDir(); if (isDir && !item.ForDir || !isDir && !item.ForFile) { - errorCodes.Add((DWORD)E_FAIL); - errorPaths.Add(fullPath); + RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL)); continue; } { @@ -233,7 +609,43 @@ static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, if (curNode.CheckPathToRoot(false, pathParts, !isDir)) continue; } - AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); + + 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, dirItems)); + } + #endif + if (!isDir) continue; @@ -254,110 +666,233 @@ static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode, } RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, - addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes)); + 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]; - const FString fullPath = phyPrefix + us2fs(nextNode.Name); + FString fullPath = phyPrefix + us2fs(nextNode.Name); NFind::CFileInfo fi; - if (!fi.Find(fullPath)) + + if (phyPrefix.IsEmpty()) { - if (!nextNode.AreThereIncludeItems()) - continue; - errorCodes.Add(::GetLastError()); - errorPaths.Add(fullPath); - continue; + { + if (nextNode.Name.IsEmpty()) + fullPath = FCHAR_PATH_SEPARATOR; + #ifdef _WIN32 + else if (NWildcard::IsDriveColonName(nextNode.Name)) + fullPath.Add_PathSepar(); + #endif + } } - if (!fi.IsDir()) + + // 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 + ) { - errorCodes.Add((DWORD)E_FAIL); - errorPaths.Add(fullPath); - continue; + 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, callback, errorPaths, errorCodes)); + 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(phyPrefix + FCHAR_ANY_MASK); - for (int ttt = 0; ; ttt++) + for (unsigned ttt = 0; ; ttt++) { NFind::CFileInfo fi; bool found; if (!enumerator.Next(fi, found)) { - errorCodes.Add(::GetLastError()); - errorPaths.Add(phyPrefix); + RINOK(dirItems.AddError(phyPrefix)); break; } if (!found) break; - if (callback && (ttt & 0xFF) == 0xFF) - RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), fs2us(phyPrefix))); - 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())) - continue; - } - if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir())) - { - AddDirFileInfo(phyParent, logParent, fi, dirItems.Items); - if (fi.IsDir()) - enterToSubFolders2 = true; - } - if (!fi.IsDir()) - 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) + if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask) { - nextNode = &curNode; - addArchivePrefixNew.Add(name); + RINOK(dirItems.ScanProgress(phyPrefix)); } - RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix, - addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes)); + RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix, + addArchivePrefix, dirItems, enterToSubFolders)); } + return S_OK; } HRESULT EnumerateItems( const NWildcard::CCensor &censor, - CDirItems &dirItems, - IEnumDirItemCallback *callback, - FStringVector &errorPaths, - CRecordVector<DWORD> &errorCodes) + const NWildcard::ECensorPathMode pathMode, + const UString &addPathPrefix, + CDirItems &dirItems) { - for (int i = 0; i < censor.Pairs.Size(); i++) + FOR_VECTOR (i, censor.Pairs) { const NWildcard::CPair &pair = censor.Pairs[i]; int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix); - RINOK(EnumerateDirItems(pair.Head, phyParent, -1, us2fs(pair.Prefix), UStringVector(), dirItems, false, - callback, errorPaths, errorCodes)); + 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; + if (!attr.Parse(item.ReparseData, item.ReparseData.Size())) + 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 |