5 #include "EnumDirItems.h"
\r
7 using namespace NWindows;
\r
8 using namespace NFile;
\r
9 using namespace NName;
\r
11 void AddDirFileInfo(int phyParent, int logParent,
\r
12 const NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems)
\r
16 di.CTime = fi.CTime;
\r
17 di.ATime = fi.ATime;
\r
18 di.MTime = fi.MTime;
\r
19 di.Attrib = fi.Attrib;
\r
20 di.PhyParent = phyParent;
\r
21 di.LogParent = logParent;
\r
26 UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
\r
29 int len = name.Length();
\r
31 for (i = index; i >= 0; i = parents[i])
\r
32 len += Prefixes[i].Length();
\r
34 wchar_t *p = path.GetBuffer(len);
\r
36 len -= name.Length();
\r
37 memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t));
\r
38 for (i = index; i >= 0; i = parents[i])
\r
40 const UString &s = Prefixes[i];
\r
42 memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
\r
44 path.ReleaseBuffer(totalLen);
\r
48 UString CDirItems::GetPhyPath(int index) const
\r
50 const CDirItem &di = Items[index];
\r
51 return GetPrefixesPath(PhyParents, di.PhyParent, di.Name);
\r
54 UString CDirItems::GetLogPath(int index) const
\r
56 const CDirItem &di = Items[index];
\r
57 return GetPrefixesPath(LogParents, di.LogParent, di.Name);
\r
60 void CDirItems::ReserveDown()
\r
62 Prefixes.ReserveDown();
\r
63 PhyParents.ReserveDown();
\r
64 LogParents.ReserveDown();
\r
65 Items.ReserveDown();
\r
68 int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
\r
70 PhyParents.Add(phyParent);
\r
71 LogParents.Add(logParent);
\r
72 return Prefixes.Add(prefix);
\r
75 void CDirItems::DeleteLastPrefix()
\r
77 PhyParents.DeleteBack();
\r
78 LogParents.DeleteBack();
\r
79 Prefixes.DeleteBack();
\r
82 void CDirItems::EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
\r
83 UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
\r
85 NFind::CEnumeratorW enumerator(phyPrefix + (wchar_t)kAnyStringWildcard);
\r
88 NFind::CFileInfoW fi;
\r
90 if (!enumerator.Next(fi, found))
\r
92 errorCodes.Add(::GetLastError());
\r
93 errorPaths.Add(phyPrefix);
\r
98 AddDirFileInfo(phyParent, logParent, fi, Items);
\r
101 const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
\r
102 int parent = AddPrefix(phyParent, logParent, name2);
\r
103 EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes);
\r
108 void CDirItems::EnumerateDirItems2(const UString &phyPrefix, const UString &logPrefix,
\r
109 const UStringVector &filePaths, UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
\r
111 int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, phyPrefix);
\r
112 int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
\r
114 for (int i = 0; i < filePaths.Size(); i++)
\r
116 const UString &filePath = filePaths[i];
\r
117 NFind::CFileInfoW fi;
\r
118 const UString phyPath = phyPrefix + filePath;
\r
119 if (!fi.Find(phyPath))
\r
121 errorCodes.Add(::GetLastError());
\r
122 errorPaths.Add(phyPath);
\r
125 int delimiter = filePath.ReverseFind((wchar_t)kDirDelimiter);
\r
126 UString phyPrefixCur;
\r
127 int phyParentCur = phyParent;
\r
128 if (delimiter >= 0)
\r
130 phyPrefixCur = filePath.Left(delimiter + 1);
\r
131 phyParentCur = AddPrefix(phyParent, logParent, phyPrefixCur);
\r
133 AddDirFileInfo(phyParentCur, logParent, fi, Items);
\r
136 const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
\r
137 int parent = AddPrefix(phyParentCur, logParent, name2);
\r
138 EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes);
\r
144 static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
\r
145 int phyParent, int logParent, const UString &phyPrefix,
\r
146 const UStringVector &addArchivePrefix,
\r
147 CDirItems &dirItems,
\r
148 bool enterToSubFolders,
\r
149 IEnumDirItemCallback *callback,
\r
150 UStringVector &errorPaths,
\r
151 CRecordVector<DWORD> &errorCodes);
\r
153 static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode,
\r
154 int phyParent, int logParent, const UString &curFolderName,
\r
155 const UString &phyPrefix,
\r
156 const UStringVector &addArchivePrefix,
\r
157 CDirItems &dirItems,
\r
158 bool enterToSubFolders,
\r
159 IEnumDirItemCallback *callback,
\r
160 UStringVector &errorPaths,
\r
161 CRecordVector<DWORD> &errorCodes)
\r
164 const UString name2 = curFolderName + (wchar_t)kDirDelimiter;
\r
165 int parent = dirItems.AddPrefix(phyParent, logParent, name2);
\r
166 int numItems = dirItems.Items.Size();
\r
167 HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2,
\r
168 addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes);
\r
169 if (numItems == dirItems.Items.Size())
\r
170 dirItems.DeleteLastPrefix();
\r
175 static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
\r
176 int phyParent, int logParent, const UString &phyPrefix,
\r
177 const UStringVector &addArchivePrefix, // prefix from curNode
\r
178 CDirItems &dirItems,
\r
179 bool enterToSubFolders,
\r
180 IEnumDirItemCallback *callback,
\r
181 UStringVector &errorPaths,
\r
182 CRecordVector<DWORD> &errorCodes)
\r
184 if (!enterToSubFolders)
\r
185 if (curNode.NeedCheckSubDirs())
\r
186 enterToSubFolders = true;
\r
188 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
\r
190 // try direct_names case at first
\r
191 if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
\r
193 // check that all names are direct
\r
195 for (i = 0; i < curNode.IncludeItems.Size(); i++)
\r
197 const NWildcard::CItem &item = curNode.IncludeItems[i];
\r
198 if (item.Recursive || item.PathParts.Size() != 1)
\r
200 const UString &name = item.PathParts.Front();
\r
201 if (name.IsEmpty() || DoesNameContainWildCard(name))
\r
204 if (i == curNode.IncludeItems.Size())
\r
206 // all names are direct (no wildcards)
\r
207 // so we don't need file_system's dir enumerator
\r
208 CRecordVector<bool> needEnterVector;
\r
209 for (i = 0; i < curNode.IncludeItems.Size(); i++)
\r
211 const NWildcard::CItem &item = curNode.IncludeItems[i];
\r
212 const UString &name = item.PathParts.Front();
\r
213 const UString fullPath = phyPrefix + name;
\r
214 NFind::CFileInfoW fi;
\r
215 if (!fi.Find(fullPath))
\r
217 errorCodes.Add(::GetLastError());
\r
218 errorPaths.Add(fullPath);
\r
221 bool isDir = fi.IsDir();
\r
222 if (isDir && !item.ForDir || !isDir && !item.ForFile)
\r
224 errorCodes.Add((DWORD)E_FAIL);
\r
225 errorPaths.Add(fullPath);
\r
229 UStringVector pathParts;
\r
230 pathParts.Add(fi.Name);
\r
231 if (curNode.CheckPathToRoot(false, pathParts, !isDir))
\r
234 AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
\r
238 UStringVector addArchivePrefixNew;
\r
239 const NWildcard::CCensorNode *nextNode = 0;
\r
240 int index = curNode.FindSubNode(name);
\r
243 for (int t = needEnterVector.Size(); t <= index; t++)
\r
244 needEnterVector.Add(true);
\r
245 needEnterVector[index] = false;
\r
246 nextNode = &curNode.SubNodes[index];
\r
250 nextNode = &curNode;
\r
251 addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
\r
254 RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
\r
255 addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
\r
257 for (i = 0; i < curNode.SubNodes.Size(); i++)
\r
259 if (i < needEnterVector.Size())
\r
260 if (!needEnterVector[i])
\r
262 const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
\r
263 const UString fullPath = phyPrefix + nextNode.Name;
\r
264 NFind::CFileInfoW fi;
\r
265 if (!fi.Find(fullPath))
\r
267 if (!nextNode.AreThereIncludeItems())
\r
269 errorCodes.Add(::GetLastError());
\r
270 errorPaths.Add(fullPath);
\r
275 errorCodes.Add((DWORD)E_FAIL);
\r
276 errorPaths.Add(fullPath);
\r
280 RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
\r
281 UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
\r
288 NFind::CEnumeratorW enumerator(phyPrefix + wchar_t(kAnyStringWildcard));
\r
289 for (int ttt = 0; ; ttt++)
\r
291 NFind::CFileInfoW fi;
\r
293 if (!enumerator.Next(fi, found))
\r
295 errorCodes.Add(::GetLastError());
\r
296 errorPaths.Add(phyPrefix);
\r
302 if (callback && (ttt & 0xFF) == 0xFF)
\r
303 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
\r
304 const UString &name = fi.Name;
\r
305 bool enterToSubFolders2 = enterToSubFolders;
\r
306 UStringVector addArchivePrefixNew = addArchivePrefix;
\r
307 addArchivePrefixNew.Add(name);
\r
309 UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
\r
310 if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
\r
313 if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
\r
315 AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
\r
317 enterToSubFolders2 = true;
\r
322 const NWildcard::CCensorNode *nextNode = 0;
\r
323 if (addArchivePrefix.IsEmpty())
\r
325 int index = curNode.FindSubNode(name);
\r
327 nextNode = &curNode.SubNodes[index];
\r
329 if (!enterToSubFolders2 && nextNode == 0)
\r
332 addArchivePrefixNew = addArchivePrefix;
\r
335 nextNode = &curNode;
\r
336 addArchivePrefixNew.Add(name);
\r
339 RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, name, phyPrefix,
\r
340 addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
\r
345 HRESULT EnumerateItems(
\r
346 const NWildcard::CCensor &censor,
\r
347 CDirItems &dirItems,
\r
348 IEnumDirItemCallback *callback,
\r
349 UStringVector &errorPaths,
\r
350 CRecordVector<DWORD> &errorCodes)
\r
352 for (int i = 0; i < censor.Pairs.Size(); i++)
\r
354 const NWildcard::CPair &pair = censor.Pairs[i];
\r
355 int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
\r
356 RINOK(EnumerateDirItems(pair.Head, phyParent, -1, pair.Prefix, UStringVector(), dirItems, false,
\r
357 callback, errorPaths, errorCodes));
\r
359 dirItems.ReserveDown();
\r