summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp')
-rw-r--r--3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp1166
1 files changed, 962 insertions, 204 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
index 3ebf25aad8f..d536c4739aa 100644
--- a/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/3rdparty/lzma/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -3,6 +3,13 @@
#include "StdAfx.h"
#include <wchar.h>
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <grp.h>
+#include <pwd.h>
+#include "../../../Common/UTFConvert.h"
+#endif
#include "../../../Common/Wildcard.h"
@@ -11,42 +18,71 @@
#include "../../../Windows/FileName.h"
#if defined(_WIN32) && !defined(UNDER_CE)
-#define _USE_SECURITY_CODE
+#define Z7_USE_SECURITY_CODE
#include "../../../Windows/SecurityUtils.h"
#endif
#include "EnumDirItems.h"
+#include "SortUtils.h"
using namespace NWindows;
using namespace NFile;
using namespace NName;
+
+static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink)
+{
+ const bool res = fi.Find(path, followLink);
+ if (!res)
+ return res;
+ if (path.IsEmpty())
+ return res;
+ // we keep name "." and "..", if it's without tail slash
+ const FChar *p = path.RightPtr(1);
+ if (*p != '.')
+ return res;
+ if (p != path.Ptr())
+ {
+ FChar c = p[-1];
+ if (!IS_PATH_SEPAR(c))
+ {
+ if (c != '.')
+ return res;
+ p--;
+ if (p != path.Ptr())
+ {
+ c = p[-1];
+ if (!IS_PATH_SEPAR(c))
+ return res;
+ }
+ }
+ }
+ fi.Name = p;
+ return res;
+}
+
+
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;
+ /*
+ CDirItem di(fi);
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);
+ */
+ VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex))
if (fi.IsDir())
Stat.NumDirs++;
+ #ifdef _WIN32
else if (fi.IsAltStream)
{
Stat.NumAltStreams++;
Stat.AltStreamsSize += fi.Size;
}
+ #endif
else
{
Stat.NumFiles++;
@@ -54,8 +90,13 @@ void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,
}
}
+// (DWORD)E_FAIL
+#define DI_DEFAULT_ERROR ERROR_INVALID_FUNCTION
+
HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)
{
+ if (errorCode == 0)
+ errorCode = DI_DEFAULT_ERROR;
Stat.NumErrors++;
if (Callback)
return Callback->ScanError(path, errorCode);
@@ -82,17 +123,17 @@ UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const U
unsigned len = name.Len();
int i;
- for (i = index; i >= 0; i = parents[i])
- len += Prefixes[i].Len();
+ for (i = index; i >= 0; i = parents[(unsigned)i])
+ len += Prefixes[(unsigned)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])
+ for (i = index; i >= 0; i = parents[(unsigned)i])
{
- const UString &s = Prefixes[i];
+ const UString &s = Prefixes[(unsigned)i];
p -= s.Len();
wmemcpy(p, (const wchar_t *)s, s.Len());
}
@@ -139,17 +180,24 @@ bool InitLocalPrivileges();
CDirItems::CDirItems():
SymLinks(false),
ScanAltStreams(false)
- #ifdef _USE_SECURITY_CODE
+ , ExcludeDirItems(false)
+ , ExcludeFileItems(false)
+ , ShareForWrite(false)
+ #ifdef Z7_USE_SECURITY_CODE
, ReadSecure(false)
- #endif
+ #endif
+ #ifndef _WIN32
+ , StoreOwnerName(false)
+ #endif
, Callback(NULL)
{
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
_saclEnabled = InitLocalPrivileges();
#endif
}
-#ifdef _USE_SECURITY_CODE
+
+#ifdef Z7_USE_SECURITY_CODE
HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
{
@@ -165,7 +213,7 @@ HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
DWORD errorCode = 0;
DWORD secureSize;
- BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
+ BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
if (res)
{
@@ -184,11 +232,11 @@ HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
else
{
TempSecureBuf.Alloc(secureSize);
- res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
+ res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
if (res)
{
if (secureSize != TempSecureBuf.Size())
- errorCode = ERROR_INVALID_FUNCTION;;
+ errorCode = ERROR_INVALID_FUNCTION;
}
else
errorCode = GetLastError();
@@ -198,103 +246,224 @@ HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
if (res)
{
- secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);
+ secureIndex = (int)SecureBlocks.AddUniq(TempSecureBuf, secureSize);
return S_OK;
}
- if (errorCode == 0)
- errorCode = ERROR_INVALID_FUNCTION;
return AddError(path, errorCode);
}
-#endif
+#endif // Z7_USE_SECURITY_CODE
-HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
+
+HRESULT CDirItems::EnumerateOneDir(const FString &phyPrefix, CObjectVector<NFind::CFileInfo> &files)
{
- RINOK(ScanProgress(phyPrefix));
+ NFind::CEnumerator enumerator;
+ // printf("\n enumerator.SetDirPrefix(phyPrefix) \n");
+
+ enumerator.SetDirPrefix(phyPrefix);
+
+ #ifdef _WIN32
+
+ NFind::CFileInfo fi;
- NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
for (unsigned ttt = 0; ; ttt++)
{
- NFind::CFileInfo fi;
bool found;
if (!enumerator.Next(fi, found))
+ return AddError(phyPrefix);
+ if (!found)
+ return S_OK;
+ files.Add(fi);
+ if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(ScanProgress(phyPrefix))
+ }
+ }
+
+ #else // _WIN32
+
+ // enumerator.SolveLinks = !SymLinks;
+
+ CObjectVector<NFind::CDirEntry> entries;
+
+ for (unsigned ttt = 0; ; ttt++)
+ {
+ bool found;
+ NFind::CDirEntry de;
+ if (!enumerator.Next(de, found))
{
return AddError(phyPrefix);
}
if (!found)
- return S_OK;
+ break;
+ entries.Add(de);
+ }
+
+ FOR_VECTOR(i, entries)
+ {
+ const NFind::CDirEntry &de = entries[i];
+ NFind::CFileInfo fi;
+ if (!enumerator.Fill_FileInfo(de, fi, !SymLinks))
+ // if (!fi.Find_AfterEnumerator(path))
+ {
+ const FString path = phyPrefix + de.Name;
+ {
+ RINOK(AddError(path))
+ continue;
+ }
+ }
+
+ files.Add(fi);
+
+ if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(ScanProgress(phyPrefix))
+ }
+ }
+
+ return S_OK;
+
+ #endif // _WIN32
+}
+
+
+
+
+HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
+{
+ RINOK(ScanProgress(phyPrefix))
+
+ CObjectVector<NFind::CFileInfo> files;
+ RINOK(EnumerateOneDir(phyPrefix, files))
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ const NFind::CFileInfo &fi = files[i];
+ #else
+ const NFind::CFileInfo &fi = files[i];
+ /*
+ NFind::CFileInfo fi;
+ {
+ const NFind::CDirEntry &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
+ }
+ */
+ #endif
+
+ if (CanIncludeItem(fi.IsDir()))
+ {
int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
if (ReadSecure)
{
- RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex));
+ RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex))
}
#endif
-
AddDirFileInfo(phyParent, logParent, secureIndex, fi);
+ }
- if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
+ if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
{
- RINOK(ScanProgress(phyPrefix));
+ 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));
+ RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + name2))
}
}
+ return S_OK;
}
+
+/*
+EnumerateItems2()
+ const FStringVector &filePaths - are path without tail slashes.
+ All dir prefixes of filePaths will be not stores in logical paths
+fix it: we can scan AltStream also.
+*/
+
+#ifdef _WIN32
+// #define FOLLOW_LINK_PARAM
+// #define FOLLOW_LINK_PARAM2
+#define FOLLOW_LINK_PARAM , (!SymLinks)
+#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks)
+#else
+#define FOLLOW_LINK_PARAM , (!SymLinks)
+#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks)
+#endif
+
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);
+ const int phyParent = phyPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, fs2us(phyPrefix));
+ const int logParent = logPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, logPrefix);
+
+ #ifdef _WIN32
+ const bool phyPrefix_isAltStreamPrefix =
+ NFile::NName::IsAltStreamPrefixWithColon(fs2us(phyPrefix));
+ #endif
FOR_VECTOR (i, filePaths)
{
const FString &filePath = filePaths[i];
NFind::CFileInfo fi;
const FString phyPath = phyPrefix + filePath;
- if (!fi.Find(phyPath))
+ if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM))
{
- RINOK(AddError(phyPath));
+ RINOK(AddError(phyPath))
continue;
}
if (requestedPaths)
requestedPaths->Add(phyPath);
- int delimiter = filePath.ReverseFind_PathSepar();
+ const int delimiter = filePath.ReverseFind_PathSepar();
FString phyPrefixCur;
int phyParentCur = phyParent;
if (delimiter >= 0)
{
- phyPrefixCur.SetFrom(filePath, delimiter + 1);
- phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
+ phyPrefixCur.SetFrom(filePath, (unsigned)(delimiter + 1));
+ phyParentCur = (int)AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
}
+ if (CanIncludeItem(fi.IsDir()))
+ {
int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
if (ReadSecure)
{
- RINOK(AddSecurityItem(phyPath, secureIndex));
+ RINOK(AddSecurityItem(phyPath, secureIndex))
}
#endif
-
+ #ifdef _WIN32
+ if (phyPrefix_isAltStreamPrefix && fi.IsAltStream)
+ {
+ const int pos = fi.Name.Find(FChar(':'));
+ if (pos >= 0)
+ fi.Name.DeleteFrontal((unsigned)pos + 1);
+ }
+ #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));
+ const unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
+ RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + phyPrefixCur + name2))
}
}
@@ -305,34 +474,46 @@ HRESULT CDirItems::EnumerateItems2(
-
-
static HRESULT EnumerateDirItems(
const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &phyPrefix,
- const UStringVector &addArchivePrefix,
+ const int phyParent, const int logParent,
+ const FString &phyPrefix,
+ const UStringVector &addParts, // additional parts from curNode
CDirItems &dirItems,
bool enterToSubFolders);
+
+/* EnumerateDirItems_Spec()
+ adds new Dir item prefix, and enumerates dir items,
+ then it can remove that Dir item prefix, if there are no items in that dir.
+*/
+
+
+/*
+ EnumerateDirItems_Spec()
+ it's similar to EnumerateDirItems, but phyPrefix doesn't include (curFolderName)
+*/
+
static HRESULT EnumerateDirItems_Spec(
const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &curFolderName,
- const FString &phyPrefix,
- const UStringVector &addArchivePrefix,
+ const int phyParent, const int logParent, const FString &curFolderName,
+ const FString &phyPrefix, // without (curFolderName)
+ const UStringVector &addParts, // (curNode + addParts) includes (curFolderName)
CDirItems &dirItems,
bool enterToSubFolders)
{
const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;
- unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
- unsigned numItems = dirItems.Items.Size();
+ const unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
+ const unsigned numItems = dirItems.Items.Size();
HRESULT res = EnumerateDirItems(
- curNode, parent, parent, phyPrefix + name2,
- addArchivePrefix, dirItems, enterToSubFolders);
+ curNode, (int)parent, (int)parent, phyPrefix + name2,
+ addParts, dirItems, enterToSubFolders);
if (numItems == dirItems.Items.Size())
dirItems.DeleteLastPrefix();
return res;
}
+
#ifndef UNDER_CE
#ifdef _WIN32
@@ -340,136 +521,222 @@ static HRESULT EnumerateDirItems_Spec(
static HRESULT EnumerateAltStreams(
const NFind::CFileInfo &fi,
const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &fullPath,
- const UStringVector &addArchivePrefix, // prefix from curNode
+ const int phyParent, const int logParent,
+ const FString &phyPath, // with (fi.Name), without tail slash for folders
+ const UStringVector &addParts, // with (fi.Name), prefix parts from curNode
+ bool addAllSubStreams,
CDirItems &dirItems)
{
- NFind::CStreamEnumerator enumerator(fullPath);
+ // we don't use (ExcludeFileItems) rules for AltStreams
+ // if (dirItems.ExcludeFileItems) return S_OK;
+
+ NFind::CStreamEnumerator enumerator(phyPath);
for (;;)
{
NFind::CStreamInfo si;
bool found;
if (!enumerator.Next(si, found))
{
- return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL
+ return dirItems.AddError(phyPath + 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))
+ UStringVector parts = addParts;
+ const UString reducedName = si.GetReducedName();
+ parts.Back() += reducedName;
+ if (curNode.CheckPathToRoot(false, parts, true))
continue;
+ if (!addAllSubStreams)
+ if (!curNode.CheckPathToRoot(true, parts, true))
+ continue;
+
NFind::CFileInfo fi2 = fi;
fi2.Name += us2fs(reducedName);
fi2.Size = si.Size;
- fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
+ fi2.Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
fi2.IsAltStream = true;
dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);
}
}
-#endif
+#endif // _WIN32
+
+
+/* We get Reparse data and parse it.
+ If there is Reparse error, we free dirItem.Reparse data.
+ Do we need to work with empty reparse data?
+*/
HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
const FString &phyPrefix)
{
- if (!SymLinks || !fi.HasReparsePoint())
+ if (!SymLinks)
return S_OK;
+
+ #ifdef _WIN32
+ if (!fi.HasReparsePoint() || fi.IsAltStream)
+ #else // _WIN32
+ if (!fi.IsPosixLink())
+ #endif // _WIN32
+ 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;
+ // if (dirItem.ReparseData.Size() != 0)
+ Stat.FilesSize -= fi.Size;
+ return S_OK;
}
+
DWORD res = ::GetLastError();
buf.Free();
- return AddError(path , res);
+ return AddError(path, res);
}
-#endif
+#endif // UNDER_CE
+
+
static HRESULT EnumerateForItem(
- NFind::CFileInfo &fi,
+ const NFind::CFileInfo &fi,
const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &phyPrefix,
- const UStringVector &addArchivePrefix, // prefix from curNode
+ const int phyParent, const int logParent, const FString &phyPrefix,
+ const UStringVector &addParts, // additional parts from curNode, without (fi.Name)
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;
+ UStringVector newParts = addParts;
+ newParts.Add(name);
- if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
+ // check the path in exclude rules
+ if (curNode.CheckPathToRoot(false, newParts, !fi.IsDir()))
+ return S_OK;
+
+ #if !defined(UNDER_CE)
+ int dirItemIndex = -1;
+ #if defined(_WIN32)
+ bool addAllSubStreams = false;
+ bool needAltStreams = true;
+ #endif // _WIN32
+ #endif // !defined(UNDER_CE)
+
+ // check the path in inlcude rules
+ if (curNode.CheckPathToRoot(true, newParts, !fi.IsDir()))
{
- int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
- if (dirItems.ReadSecure)
+ #if !defined(UNDER_CE)
+ // dirItemIndex = (int)dirItems.Items.Size();
+ #if defined(_WIN32)
+ // we will not check include rules for substreams.
+ addAllSubStreams = true;
+ #endif // _WIN32
+ #endif // !defined(UNDER_CE)
+
+ if (dirItems.CanIncludeItem(fi.IsDir()))
{
- RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex));
- }
+ int secureIndex = -1;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (dirItems.ReadSecure)
+ {
+ RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex))
+ }
#endif
+ #if !defined(UNDER_CE)
+ dirItemIndex = (int)dirItems.Items.Size();
+ #endif // !defined(UNDER_CE)
+ dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
+ }
+ else
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ needAltStreams = false;
+ #endif
+ }
- dirItemIndex = dirItems.Items.Size();
- dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
if (fi.IsDir())
- enterToSubFolders2 = true;
+ enterToSubFolders = true;
}
- #ifndef UNDER_CE
- if (dirItems.ScanAltStreams)
- {
- RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
- phyPrefix + fi.Name,
- addArchivePrefixNew, dirItems));
- }
+ #if !defined(UNDER_CE)
+
+ // we don't scan AltStreams for link files
if (dirItemIndex >= 0)
{
- CDirItem &dirItem = dirItems.Items[dirItemIndex];
- RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
+ CDirItem &dirItem = dirItems.Items[(unsigned)dirItemIndex];
+ RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix))
if (dirItem.ReparseData.Size() != 0)
return S_OK;
}
- #endif
+ #if defined(_WIN32)
+ if (needAltStreams && dirItems.ScanAltStreams)
+ {
+ RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
+ phyPrefix + fi.Name, // with (fi.Name)
+ newParts, // with (fi.Name)
+ addAllSubStreams,
+ dirItems))
+ }
+ #endif
+
+ #endif // !defined(UNDER_CE)
+
+
+ #ifndef _WIN32
+ if (!fi.IsPosixLink()) // posix link can follow to dir
+ #endif
if (!fi.IsDir())
return S_OK;
-
- const NWildcard::CCensorNode *nextNode = 0;
- if (addArchivePrefix.IsEmpty())
+
+ const NWildcard::CCensorNode *nextNode = NULL;
+
+ if (addParts.IsEmpty())
{
int index = curNode.FindSubNode(name);
if (index >= 0)
- nextNode = &curNode.SubNodes[index];
+ {
+ nextNode = &curNode.SubNodes[(unsigned)index];
+ newParts.Clear();
+ }
}
- if (!enterToSubFolders2 && nextNode == 0)
- return S_OK;
-
- addArchivePrefixNew = addArchivePrefix;
- if (nextNode == 0)
+
+ if (!nextNode)
{
+ if (!enterToSubFolders)
+ return S_OK;
+
+ #ifndef _WIN32
+ if (fi.IsPosixLink())
+ {
+ // here we can try to resolve posix link
+ // if the link to dir, then can we follow it
+ return S_OK; // we don't follow posix link
+ }
+ #else
+ if (dirItems.SymLinks && fi.HasReparsePoint())
+ {
+ /* 20.03: in SymLinks mode: we don't enter to directory that
+ has reparse point and has no CCensorNode
+ NOTE: (curNode and parent nodes) still can have wildcard rules
+ to include some items of target directory (of reparse point),
+ but we ignore these rules here.
+ */
+ return S_OK;
+ }
+ #endif
nextNode = &curNode;
- addArchivePrefixNew.Add(name);
}
return EnumerateDirItems_Spec(
- *nextNode, phyParent, logParent, fi.Name, phyPrefix,
- addArchivePrefixNew,
+ *nextNode, phyParent, logParent, fi.Name,
+ phyPrefix, // without (fi.Name)
+ newParts, // relative to (*nextNode). (*nextNode + newParts) includes (fi.Name)
dirItems,
- enterToSubFolders2);
+ enterToSubFolders);
}
@@ -488,10 +755,13 @@ static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)
/* 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 */
+ and wildcard mode is disabled, we can ignore wildcard in name
+ */
/*
+ #ifndef _WIN32
if (!item.WildcardParsing)
continue;
+ #endif
*/
if (DoesNameContainWildcard(name))
return false;
@@ -507,26 +777,33 @@ static bool IsVirtualFsFolder(const FString &prefix, const UString &name)
UString s = fs2us(prefix);
s += name;
s.Add_PathSepar();
+ // it returns (true) for non real FS folder path like - "\\SERVER\"
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
+ const int phyParent, const int logParent, const FString &phyPrefix,
+ const UStringVector &addParts, // prefix from curNode including
CDirItems &dirItems,
bool enterToSubFolders)
{
if (!enterToSubFolders)
+ {
+ /* if there are IncludeItems censor rules that affect items in subdirs,
+ then we will enter to all subfolders */
if (curNode.NeedCheckSubDirs())
enterToSubFolders = true;
+ }
- RINOK(dirItems.ScanProgress(phyPrefix));
+ RINOK(dirItems.ScanProgress(phyPrefix))
// try direct_names case at first
- if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
+ if (addParts.IsEmpty() && !enterToSubFolders)
{
if (CanUseFsDirect(curNode))
{
@@ -541,11 +818,20 @@ static HRESULT EnumerateDirItems(
const UString &name = item.PathParts.Front();
FString fullPath = phyPrefix + us2fs(name);
+ /*
+ // not possible now
+ if (!item.ForDir && !item.ForFile)
+ {
+ RINOK(dirItems.AddError(fullPath, ERROR_INVALID_PARAMETER));
+ continue;
+ }
+ */
+
#if defined(_WIN32) && !defined(UNDER_CE)
bool needAltStreams = true;
#endif
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
bool needSecurity = true;
#endif
@@ -565,12 +851,12 @@ static HRESULT EnumerateDirItems(
/*
// do we need to ignore security info for "\\" folder ?
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
needSecurity = false;
#endif
*/
- fullPath = FCHAR_PATH_SEPARATOR;
+ fullPath = CHAR_PATH_SEPARATOR;
}
#if defined(_WIN32) && !defined(UNDER_CE)
else if (item.IsDriveItem())
@@ -591,16 +877,27 @@ static HRESULT EnumerateDirItems(
}
else
#endif
- if (!fi.Find(fullPath))
+ if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
{
- RINOK(dirItems.AddError(fullPath));
+ RINOK(dirItems.AddError(fullPath))
continue;
}
- bool isDir = fi.IsDir();
- if (isDir && !item.ForDir || !isDir && !item.ForFile)
+ /*
+ #ifdef _WIN32
+ #define MY_ERROR_IS_DIR ERROR_FILE_NOT_FOUND
+ #define MY_ERROR_NOT_DIR DI_DEFAULT_ERROR
+ #else
+ #define MY_ERROR_IS_DIR EISDIR
+ #define MY_ERROR_NOT_DIR ENOTDIR
+ #endif
+ */
+
+ const bool isDir = fi.IsDir();
+ if (isDir ? !item.ForDir : !item.ForFile)
{
- RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
+ // RINOK(dirItems.AddError(fullPath, isDir ? MY_ERROR_IS_DIR: MY_ERROR_NOT_DIR));
+ RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR))
continue;
}
{
@@ -610,65 +907,90 @@ static HRESULT EnumerateDirItems(
continue;
}
+
+ if (dirItems.CanIncludeItem(fi.IsDir()))
+ {
int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
if (needSecurity && dirItems.ReadSecure)
{
- RINOK(dirItems.AddSecurityItem(fullPath, secureIndex));
+ RINOK(dirItems.AddSecurityItem(fullPath, secureIndex))
}
#endif
dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
- #ifndef UNDER_CE
+ // we don't scan AltStreams for link files
+
+ #if !defined(UNDER_CE)
{
CDirItem &dirItem = dirItems.Items.Back();
- RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
+ 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 defined(_WIN32)
if (needAltStreams && dirItems.ScanAltStreams)
{
UStringVector pathParts;
pathParts.Add(fs2us(fi.Name));
RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
- fullPath, pathParts, dirItems));
+ fullPath, // including (name)
+ pathParts, // including (fi.Name)
+ true, /* addAllSubStreams */
+ dirItems))
}
- #endif
+ #endif // defined(_WIN32)
+
+ #endif // !defined(UNDER_CE)
+ }
+
+ #ifndef _WIN32
+ if (!fi.IsPosixLink()) // posix link can follow to dir
+ #endif
if (!isDir)
continue;
-
- UStringVector addArchivePrefixNew;
- const NWildcard::CCensorNode *nextNode = 0;
+
+ UStringVector newParts;
+ const NWildcard::CCensorNode *nextNode = NULL;
int index = curNode.FindSubNode(name);
if (index >= 0)
{
- for (int t = needEnterVector.Size(); t <= index; t++)
+ for (int t = (int)needEnterVector.Size(); t <= index; t++)
needEnterVector.Add(true);
- needEnterVector[index] = false;
- nextNode = &curNode.SubNodes[index];
+ needEnterVector[(unsigned)index] = false;
+ nextNode = &curNode.SubNodes[(unsigned)index];
}
else
{
+ #ifndef _WIN32
+ if (fi.IsPosixLink())
+ {
+ // here we can try to resolve posix link
+ // if the link to dir, then can we follow it
+ continue; // we don't follow posix link
+ }
+ #else
+ if (dirItems.SymLinks)
+ {
+ if (fi.HasReparsePoint())
+ {
+ /* 20.03: in SymLinks mode: we don't enter to directory that
+ has reparse point and has no CCensorNode */
+ continue;
+ }
+ }
+ #endif
nextNode = &curNode;
- addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
+ newParts.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));
+ newParts, dirItems, true))
}
-
+
for (i = 0; i < curNode.SubNodes.Size(); i++)
{
if (i < needEnterVector.Size())
@@ -678,20 +1000,23 @@ static HRESULT EnumerateDirItems(
FString fullPath = phyPrefix + us2fs(nextNode.Name);
NFind::CFileInfo fi;
- if (phyPrefix.IsEmpty())
+ if (nextNode.Name.IsEmpty())
{
- {
- if (nextNode.Name.IsEmpty())
- fullPath = FCHAR_PATH_SEPARATOR;
- #ifdef _WIN32
- else if (NWildcard::IsDriveColonName(nextNode.Name))
- fullPath.Add_PathSepar();
- #endif
- }
+ if (phyPrefix.IsEmpty())
+ fullPath = CHAR_PATH_SEPARATOR;
}
+ #ifdef _WIN32
+ else if(phyPrefix.IsEmpty()
+ || (phyPrefix.Len() == NName::kSuperPathPrefixSize
+ && IsSuperPath(phyPrefix)))
+ {
+ 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 ((phyPrefix.IsEmpty() && nextNode.Name.IsEmpty())
#if defined(_WIN32) && !defined(UNDER_CE)
|| IsVirtualFsFolder(phyPrefix, nextNode.Name)
#endif
@@ -702,23 +1027,23 @@ static HRESULT EnumerateDirItems(
}
else
{
- if (!fi.Find(fullPath))
+ if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
{
if (!nextNode.AreThereIncludeItems())
continue;
- RINOK(dirItems.AddError(fullPath));
+ RINOK(dirItems.AddError(fullPath))
continue;
}
if (!fi.IsDir())
{
- RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
+ RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR))
continue;
}
}
RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
- UStringVector(), dirItems, false));
+ UStringVector(), dirItems, false))
}
return S_OK;
@@ -764,7 +1089,7 @@ static HRESULT EnumerateDirItems(
fi.Name = driveName;
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
- addArchivePrefix, dirItems, enterToSubFolders));
+ addParts, dirItems, enterToSubFolders))
}
return S_OK;
}
@@ -773,41 +1098,81 @@ static HRESULT EnumerateDirItems(
#endif
#endif
- NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
- for (unsigned ttt = 0; ; ttt++)
+
+ CObjectVector<NFind::CFileInfo> files;
+
+ // for (int y = 0; y < 1; y++)
{
- NFind::CFileInfo fi;
- bool found;
- if (!enumerator.Next(fi, found))
+ // files.Clear();
+ RINOK(dirItems.EnumerateOneDir(phyPrefix, files))
+ /*
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ // const NFind::CFileInfo &fi = files[i];
+ #else
+ NFind::CFileInfo &fi = files[i];
{
- RINOK(dirItems.AddError(phyPrefix));
- break;
+ const NFind::CFileInfo &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(dirItems.AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
}
- if (!found)
- break;
+ #endif
+
+ }
+ */
+ }
- if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ const NFind::CFileInfo &fi = files[i];
+ #else
+ const NFind::CFileInfo &fi = files[i];
+ /*
+ NFind::CFileInfo fi;
{
- RINOK(dirItems.ScanProgress(phyPrefix));
+ const NFind::CDirEntry &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(dirItems.AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
}
+ */
+ #endif
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
- addArchivePrefix, dirItems, enterToSubFolders));
+ addParts, dirItems, enterToSubFolders))
+ if (dirItems.Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(dirItems.ScanProgress(phyPrefix))
+ }
}
return S_OK;
}
+
+
+
HRESULT EnumerateItems(
const NWildcard::CCensor &censor,
const NWildcard::ECensorPathMode pathMode,
- const UString &addPathPrefix,
+ const UString &addPathPrefix, // prefix that will be added to Logical Path
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);
+ const int phyParent = pair.Prefix.IsEmpty() ? -1 : (int)dirItems.AddPrefix(-1, -1, pair.Prefix);
int logParent = -1;
if (pathMode == NWildcard::k_AbsPath)
@@ -815,44 +1180,117 @@ HRESULT EnumerateItems(
else
{
if (!addPathPrefix.IsEmpty())
- logParent = dirItems.AddPrefix(-1, -1, addPathPrefix);
+ logParent = (int)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
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ RINOK(dirItems.FillFixedReparse())
+ #endif
+
+ #ifndef _WIN32
+ RINOK(dirItems.FillDeviceSizes())
+ #endif
return S_OK;
}
+
#if defined(_WIN32) && !defined(UNDER_CE)
-void CDirItems::FillFixedReparse()
+HRESULT 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 (!SymLinks)
+ {
+ // continue; // for debug
+ if (!item.Has_Attrib_ReparsePoint())
+ continue;
+
+ // if (item.IsDir()) continue;
+
+ const FString phyPath = GetPhyPath(i);
+
+ NFind::CFileInfo fi;
+ if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir()
+ {
+ item.Size = fi.Size;
+ item.CTime = fi.CTime;
+ item.ATime = fi.ATime;
+ item.MTime = fi.MTime;
+ item.Attrib = fi.Attrib;
+ continue;
+ }
+
+ /*
+ // we request properties of target file instead of properies of symbolic link
+ // here we also can manually parse unsupported links (like WSL links)
+ NIO::CInFile inFile;
+ if (inFile.Open(phyPath))
+ {
+ BY_HANDLE_FILE_INFORMATION info;
+ if (inFile.GetFileInformation(&info))
+ {
+ // Stat.FilesSize doesn't contain item.Size already
+ // Stat.FilesSize -= item.Size;
+ item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ Stat.FilesSize += item.Size;
+ item.CTime = info.ftCreationTime;
+ item.ATime = info.ftLastAccessTime;
+ item.MTime = info.ftLastWriteTime;
+ item.Attrib = info.dwFileAttributes;
+ continue;
+ }
+ }
+ */
+
+ RINOK(AddError(phyPath))
+ continue;
+ }
+
+ // (SymLinks == true) here
+
if (item.ReparseData.Size() == 0)
continue;
+
+ // if (item.Size == 0)
+ {
+ // 20.03: we use Reparse Data instead of real data
+ item.Size = item.ReparseData.Size();
+ }
CReparseAttr attr;
if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
+ {
+ const FString phyPath = GetPhyPath(i);
+ AddError(phyPath, attr.ErrorCode);
continue;
- if (attr.IsRelative())
+ }
+
+ /* imagex/WIM reduces absolute paths in links (raparse data),
+ if we archive non root folder. We do same thing here */
+
+ bool isWSL = false;
+ if (attr.IsSymLink_WSL())
+ {
+ // isWSL = true;
+ // we don't change WSL symlinks
continue;
+ }
+ else
+ {
+ if (attr.IsRelative_Win())
+ continue;
+ }
const UString &link = attr.GetPath();
if (!IsDrivePath(link))
@@ -862,7 +1300,7 @@ void CDirItems::FillFixedReparse()
FString fullPathF;
if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF))
continue;
- UString fullPath = fs2us(fullPathF);
+ const UString fullPath = fs2us(fullPathF);
const UString logPath = GetLogPath(i);
if (logPath.Len() >= fullPath.Len())
continue;
@@ -873,7 +1311,7 @@ void CDirItems::FillFixedReparse()
if (!IsPathSepar(prefix.Back()))
continue;
- unsigned rootPrefixSize = GetRootPrefixSize(prefix);
+ const unsigned rootPrefixSize = GetRootPrefixSize(prefix);
if (rootPrefixSize == 0)
continue;
if (rootPrefixSize == prefix.Len())
@@ -889,10 +1327,330 @@ void CDirItems::FillFixedReparse()
newLink += link.Ptr(prefix.Len());
CByteBuffer data;
- if (!FillLinkData(data, newLink, attr.IsSymLink()))
+ bool isSymLink = !attr.IsMountPoint();
+ if (!FillLinkData(data, newLink, isSymLink, isWSL))
continue;
item.ReparseData2 = data;
}
+ return S_OK;
}
#endif
+
+
+#ifndef _WIN32
+
+HRESULT CDirItems::FillDeviceSizes()
+{
+ {
+ FOR_VECTOR (i, Items)
+ {
+ CDirItem &item = Items[i];
+
+ if (S_ISBLK(item.mode) && item.Size == 0)
+ {
+ const FString phyPath = GetPhyPath(i);
+ NIO::CInFile inFile;
+ inFile.PreserveATime = true;
+ if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ??
+ {
+ UInt64 size = 0;
+ if (inFile.GetLength(size))
+ item.Size = size;
+ }
+ }
+ if (StoreOwnerName)
+ {
+ OwnerNameMap.Add_UInt32(item.uid);
+ OwnerGroupMap.Add_UInt32(item.gid);
+ }
+ }
+ }
+
+ if (StoreOwnerName)
+ {
+ UString u;
+ AString a;
+ {
+ FOR_VECTOR (i, OwnerNameMap.Numbers)
+ {
+ // 200K/sec speed
+ u.Empty();
+ const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]);
+ // printf("\ngetpwuid=%s\n", pw->pw_name);
+ if (pw)
+ {
+ a = pw->pw_name;
+ ConvertUTF8ToUnicode(a, u);
+ }
+ OwnerNameMap.Strings.Add(u);
+ }
+ }
+ {
+ FOR_VECTOR (i, OwnerGroupMap.Numbers)
+ {
+ u.Empty();
+ const group *gr = getgrgid(OwnerGroupMap.Numbers[i]);
+ if (gr)
+ {
+ // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name);
+ a = gr->gr_name;
+ ConvertUTF8ToUnicode(a, u);
+ }
+ OwnerGroupMap.Strings.Add(u);
+ }
+ }
+
+ FOR_VECTOR (i, Items)
+ {
+ CDirItem &item = Items[i];
+ {
+ const int index = OwnerNameMap.Find(item.uid);
+ if (index < 0) throw 1;
+ item.OwnerNameIndex = index;
+ }
+ {
+ const int index = OwnerGroupMap.Find(item.gid);
+ if (index < 0) throw 1;
+ item.OwnerGroupIndex = index;
+ }
+ }
+ }
+
+
+ // if (NeedOwnerNames)
+ {
+ /*
+ {
+ for (unsigned i = 0 ; i < 10000; i++)
+ {
+ const passwd *pw = getpwuid(i);
+ if (pw)
+ {
+ UString u;
+ ConvertUTF8ToUnicode(AString(pw->pw_name), u);
+ OwnerNameMap.Add(i, u);
+ OwnerNameMap.Add(i, u);
+ OwnerNameMap.Add(i, u);
+ }
+ const group *gr = getgrgid(i);
+ if (gr)
+ {
+ // we can use utf-8 here.
+ UString u;
+ ConvertUTF8ToUnicode(AString(gr->gr_name), u);
+ OwnerGroupMap.Add(i, u);
+ }
+ }
+ }
+ */
+ /*
+ {
+ FOR_VECTOR (i, OwnerNameMap.Strings)
+ {
+ AString s;
+ ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s);
+ printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr());
+ }
+ }
+ {
+ printf("\n\n=========Groups\n");
+ FOR_VECTOR (i, OwnerGroupMap.Strings)
+ {
+ AString s;
+ ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s);
+ printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr());
+ }
+ }
+ */
+ }
+ /*
+ for (unsigned i = 0 ; i < 100000000; i++)
+ {
+ // const passwd *pw = getpwuid(1000);
+ // pw = pw;
+ int pos = OwnerNameMap.Find(1000);
+ if (pos < 0 - (int)i)
+ throw 1;
+ }
+ */
+
+ return S_OK;
+}
+
+#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
+
+static bool IsDotsName(const wchar_t *s)
+{
+ return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0));
+}
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+ if (name.IsEmpty()
+ || DoesNameContainWildcard(name)
+ || IsDotsName(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;
+ }
+}
+
+CMessagePathException::CMessagePathException(const wchar_t *a, const wchar_t *u)
+{
+ (*this) += a;
+ if (u)
+ {
+ Add_LF();
+ (*this) += u;
+ }
+}