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