1 // EnumDirItems.cpp
2
3 #include "StdAfx.h"
4
5 #include "EnumDirItems.h"
6
7 using namespace NWindows;
8 using namespace NFile;
9 using namespace NName;
10
AddDirFileInfo(int phyParent,int logParent,const NFind::CFileInfoW & fi,CObjectVector<CDirItem> & dirItems)11 void AddDirFileInfo(int phyParent, int logParent,
12 const NFind::CFileInfoW &fi, CObjectVector<CDirItem> &dirItems)
13 {
14 CDirItem di;
15 di.Size = fi.Size;
16 di.CTime = fi.CTime;
17 di.ATime = fi.ATime;
18 di.MTime = fi.MTime;
19 di.Attrib = fi.Attrib;
20 di.PhyParent = phyParent;
21 di.LogParent = logParent;
22 di.Name = fi.Name;
23 dirItems.Add(di);
24 }
25
GetPrefixesPath(const CIntVector & parents,int index,const UString & name) const26 UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
27 {
28 UString path;
29 int len = name.Length();
30 int i;
31 for (i = index; i >= 0; i = parents[i])
32 len += Prefixes[i].Length();
33 int totalLen = len;
34 wchar_t *p = path.GetBuffer(len);
35 p[len] = 0;
36 len -= name.Length();
37 memcpy(p + len, (const wchar_t *)name, name.Length() * sizeof(wchar_t));
38 for (i = index; i >= 0; i = parents[i])
39 {
40 const UString &s = Prefixes[i];
41 len -= s.Length();
42 memcpy(p + len, (const wchar_t *)s, s.Length() * sizeof(wchar_t));
43 }
44 path.ReleaseBuffer(totalLen);
45 return path;
46 }
47
GetPhyPath(int index) const48 UString CDirItems::GetPhyPath(int index) const
49 {
50 const CDirItem &di = Items[index];
51 return GetPrefixesPath(PhyParents, di.PhyParent, di.Name);
52 }
53
GetLogPath(int index) const54 UString CDirItems::GetLogPath(int index) const
55 {
56 const CDirItem &di = Items[index];
57 return GetPrefixesPath(LogParents, di.LogParent, di.Name);
58 }
59
ReserveDown()60 void CDirItems::ReserveDown()
61 {
62 Prefixes.ReserveDown();
63 PhyParents.ReserveDown();
64 LogParents.ReserveDown();
65 Items.ReserveDown();
66 }
67
AddPrefix(int phyParent,int logParent,const UString & prefix)68 int CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
69 {
70 PhyParents.Add(phyParent);
71 LogParents.Add(logParent);
72 return Prefixes.Add(prefix);
73 }
74
DeleteLastPrefix()75 void CDirItems::DeleteLastPrefix()
76 {
77 PhyParents.DeleteBack();
78 LogParents.DeleteBack();
79 Prefixes.DeleteBack();
80 }
81
EnumerateDirectory(int phyParent,int logParent,const UString & phyPrefix,UStringVector & errorPaths,CRecordVector<DWORD> & errorCodes)82 void CDirItems::EnumerateDirectory(int phyParent, int logParent, const UString &phyPrefix,
83 UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
84 {
85 NFind::CEnumeratorW enumerator(phyPrefix + (wchar_t)kAnyStringWildcard);
86 for (;;)
87 {
88 NFind::CFileInfoW fi;
89 bool found;
90 if (!enumerator.Next(fi, found))
91 {
92 errorCodes.Add(::GetLastError());
93 errorPaths.Add(phyPrefix);
94 return;
95 }
96 if (!found)
97 break;
98 AddDirFileInfo(phyParent, logParent, fi, Items);
99 if (fi.IsDir())
100 {
101 const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
102 int parent = AddPrefix(phyParent, logParent, name2);
103 EnumerateDirectory(parent, parent, phyPrefix + name2, errorPaths, errorCodes);
104 }
105 }
106 }
107
EnumerateDirItems2(const UString & phyPrefix,const UString & logPrefix,const UStringVector & filePaths,UStringVector & errorPaths,CRecordVector<DWORD> & errorCodes)108 void CDirItems::EnumerateDirItems2(const UString &phyPrefix, const UString &logPrefix,
109 const UStringVector &filePaths, UStringVector &errorPaths, CRecordVector<DWORD> &errorCodes)
110 {
111 int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, phyPrefix);
112 int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
113
114 for (int i = 0; i < filePaths.Size(); i++)
115 {
116 const UString &filePath = filePaths[i];
117 NFind::CFileInfoW fi;
118 const UString phyPath = phyPrefix + filePath;
119 if (!fi.Find(phyPath))
120 {
121 errorCodes.Add(::GetLastError());
122 errorPaths.Add(phyPath);
123 continue;
124 }
125 int delimiter = filePath.ReverseFind((wchar_t)kDirDelimiter);
126 UString phyPrefixCur;
127 int phyParentCur = phyParent;
128 if (delimiter >= 0)
129 {
130 phyPrefixCur = filePath.Left(delimiter + 1);
131 phyParentCur = AddPrefix(phyParent, logParent, phyPrefixCur);
132 }
133 AddDirFileInfo(phyParentCur, logParent, fi, Items);
134 if (fi.IsDir())
135 {
136 const UString name2 = fi.Name + (wchar_t)kDirDelimiter;
137 int parent = AddPrefix(phyParentCur, logParent, name2);
138 EnumerateDirectory(parent, parent, phyPrefix + phyPrefixCur + name2, errorPaths, errorCodes);
139 }
140 }
141 ReserveDown();
142 }
143
144 static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
145 int phyParent, int logParent, const UString &phyPrefix,
146 const UStringVector &addArchivePrefix,
147 CDirItems &dirItems,
148 bool enterToSubFolders,
149 IEnumDirItemCallback *callback,
150 UStringVector &errorPaths,
151 CRecordVector<DWORD> &errorCodes);
152
EnumerateDirItems_Spec(const NWildcard::CCensorNode & curNode,int phyParent,int logParent,const UString & curFolderName,const UString & phyPrefix,const UStringVector & addArchivePrefix,CDirItems & dirItems,bool enterToSubFolders,IEnumDirItemCallback * callback,UStringVector & errorPaths,CRecordVector<DWORD> & errorCodes)153 static HRESULT EnumerateDirItems_Spec(const NWildcard::CCensorNode &curNode,
154 int phyParent, int logParent, const UString &curFolderName,
155 const UString &phyPrefix,
156 const UStringVector &addArchivePrefix,
157 CDirItems &dirItems,
158 bool enterToSubFolders,
159 IEnumDirItemCallback *callback,
160 UStringVector &errorPaths,
161 CRecordVector<DWORD> &errorCodes)
162
163 {
164 const UString name2 = curFolderName + (wchar_t)kDirDelimiter;
165 int parent = dirItems.AddPrefix(phyParent, logParent, name2);
166 int numItems = dirItems.Items.Size();
167 HRESULT res = EnumerateDirItems(curNode, parent, parent, phyPrefix + name2,
168 addArchivePrefix, dirItems, enterToSubFolders, callback, errorPaths, errorCodes);
169 if (numItems == dirItems.Items.Size())
170 dirItems.DeleteLastPrefix();
171 return res;
172 }
173
174
EnumerateDirItems(const NWildcard::CCensorNode & curNode,int phyParent,int logParent,const UString & phyPrefix,const UStringVector & addArchivePrefix,CDirItems & dirItems,bool enterToSubFolders,IEnumDirItemCallback * callback,UStringVector & errorPaths,CRecordVector<DWORD> & errorCodes)175 static HRESULT EnumerateDirItems(const NWildcard::CCensorNode &curNode,
176 int phyParent, int logParent, const UString &phyPrefix,
177 const UStringVector &addArchivePrefix, // prefix from curNode
178 CDirItems &dirItems,
179 bool enterToSubFolders,
180 IEnumDirItemCallback *callback,
181 UStringVector &errorPaths,
182 CRecordVector<DWORD> &errorCodes)
183 {
184 if (!enterToSubFolders)
185 if (curNode.NeedCheckSubDirs())
186 enterToSubFolders = true;
187 if (callback)
188 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
189
190 // try direct_names case at first
191 if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
192 {
193 // check that all names are direct
194 int i;
195 for (i = 0; i < curNode.IncludeItems.Size(); i++)
196 {
197 const NWildcard::CItem &item = curNode.IncludeItems[i];
198 if (item.Recursive || item.PathParts.Size() != 1)
199 break;
200 const UString &name = item.PathParts.Front();
201 if (name.IsEmpty() || DoesNameContainWildCard(name))
202 break;
203 }
204 if (i == curNode.IncludeItems.Size())
205 {
206 // all names are direct (no wildcards)
207 // so we don't need file_system's dir enumerator
208 CRecordVector<bool> needEnterVector;
209 for (i = 0; i < curNode.IncludeItems.Size(); i++)
210 {
211 const NWildcard::CItem &item = curNode.IncludeItems[i];
212 const UString &name = item.PathParts.Front();
213 const UString fullPath = phyPrefix + name;
214 NFind::CFileInfoW fi;
215 if (!fi.Find(fullPath))
216 {
217 errorCodes.Add(::GetLastError());
218 errorPaths.Add(fullPath);
219 continue;
220 }
221 bool isDir = fi.IsDir();
222 if (isDir && !item.ForDir || !isDir && !item.ForFile)
223 {
224 errorCodes.Add((DWORD)E_FAIL);
225 errorPaths.Add(fullPath);
226 continue;
227 }
228 {
229 UStringVector pathParts;
230 pathParts.Add(fi.Name);
231 if (curNode.CheckPathToRoot(false, pathParts, !isDir))
232 continue;
233 }
234 AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
235 if (!isDir)
236 continue;
237
238 UStringVector addArchivePrefixNew;
239 const NWildcard::CCensorNode *nextNode = 0;
240 int index = curNode.FindSubNode(name);
241 if (index >= 0)
242 {
243 for (int t = needEnterVector.Size(); t <= index; t++)
244 needEnterVector.Add(true);
245 needEnterVector[index] = false;
246 nextNode = &curNode.SubNodes[index];
247 }
248 else
249 {
250 nextNode = &curNode;
251 addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
252 }
253
254 RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
255 addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
256 }
257 for (i = 0; i < curNode.SubNodes.Size(); i++)
258 {
259 if (i < needEnterVector.Size())
260 if (!needEnterVector[i])
261 continue;
262 const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
263 const UString fullPath = phyPrefix + nextNode.Name;
264 NFind::CFileInfoW fi;
265 if (!fi.Find(fullPath))
266 {
267 if (!nextNode.AreThereIncludeItems())
268 continue;
269 errorCodes.Add(::GetLastError());
270 errorPaths.Add(fullPath);
271 continue;
272 }
273 if (!fi.IsDir())
274 {
275 errorCodes.Add((DWORD)E_FAIL);
276 errorPaths.Add(fullPath);
277 continue;
278 }
279
280 RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
281 UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
282 }
283 return S_OK;
284 }
285 }
286
287
288 NFind::CEnumeratorW enumerator(phyPrefix + wchar_t(kAnyStringWildcard));
289 for (int ttt = 0; ; ttt++)
290 {
291 NFind::CFileInfoW fi;
292 bool found;
293 if (!enumerator.Next(fi, found))
294 {
295 errorCodes.Add(::GetLastError());
296 errorPaths.Add(phyPrefix);
297 break;
298 }
299 if (!found)
300 break;
301
302 if (callback && (ttt & 0xFF) == 0xFF)
303 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), phyPrefix));
304 const UString &name = fi.Name;
305 bool enterToSubFolders2 = enterToSubFolders;
306 UStringVector addArchivePrefixNew = addArchivePrefix;
307 addArchivePrefixNew.Add(name);
308 {
309 UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
310 if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
311 continue;
312 }
313 if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
314 {
315 AddDirFileInfo(phyParent, logParent, fi, dirItems.Items);
316 if (fi.IsDir())
317 enterToSubFolders2 = true;
318 }
319 if (!fi.IsDir())
320 continue;
321
322 const NWildcard::CCensorNode *nextNode = 0;
323 if (addArchivePrefix.IsEmpty())
324 {
325 int index = curNode.FindSubNode(name);
326 if (index >= 0)
327 nextNode = &curNode.SubNodes[index];
328 }
329 if (!enterToSubFolders2 && nextNode == 0)
330 continue;
331
332 addArchivePrefixNew = addArchivePrefix;
333 if (nextNode == 0)
334 {
335 nextNode = &curNode;
336 addArchivePrefixNew.Add(name);
337 }
338
339 RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, name, phyPrefix,
340 addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
341 }
342 return S_OK;
343 }
344
EnumerateItems(const NWildcard::CCensor & censor,CDirItems & dirItems,IEnumDirItemCallback * callback,UStringVector & errorPaths,CRecordVector<DWORD> & errorCodes)345 HRESULT EnumerateItems(
346 const NWildcard::CCensor &censor,
347 CDirItems &dirItems,
348 IEnumDirItemCallback *callback,
349 UStringVector &errorPaths,
350 CRecordVector<DWORD> &errorCodes)
351 {
352 for (int i = 0; i < censor.Pairs.Size(); i++)
353 {
354 const NWildcard::CPair &pair = censor.Pairs[i];
355 int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
356 RINOK(EnumerateDirItems(pair.Head, phyParent, -1, pair.Prefix, UStringVector(), dirItems, false,
357 callback, errorPaths, errorCodes));
358 }
359 dirItems.ReserveDown();
360 return S_OK;
361 }
362