1 // EnumDirItems.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../Common/Wildcard.h"
6
7 #include "../../../Windows/FileDir.h"
8 #include "../../../Windows/FileIO.h"
9 #include "../../../Windows/FileName.h"
10
11 #if defined(_WIN32) && !defined(UNDER_CE)
12 #define _USE_SECURITY_CODE
13 #include "../../../Windows/SecurityUtils.h"
14 #endif
15
16 #include "EnumDirItems.h"
17
18 using namespace NWindows;
19 using namespace NFile;
20 using namespace NName;
21
AddDirFileInfo(int phyParent,int logParent,int secureIndex,const NFind::CFileInfo & fi,CObjectVector<CDirItem> & dirItems)22 void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
23 const NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems)
24 {
25 CDirItem di;
26 di.Size = fi.Size;
27 di.CTime = fi.CTime;
28 di.ATime = fi.ATime;
29 di.MTime = fi.MTime;
30 di.Attrib = fi.Attrib;
31 di.IsAltStream = fi.IsAltStream;
32 di.PhyParent = phyParent;
33 di.LogParent = logParent;
34 di.SecureIndex = secureIndex;
35 di.Name = fs2us(fi.Name);
36 #if defined(_WIN32) && !defined(UNDER_CE)
37 // di.ShortName = fs2us(fi.ShortName);
38 #endif
39 dirItems.Add(di);
40 }
41
GetPrefixesPath(const CIntVector & parents,int index,const UString & name) const42 UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
43 {
44 UString path;
45 unsigned len = name.Len();
46 int i;
47 for (i = index; i >= 0; i = parents[i])
48 len += Prefixes[i].Len();
49 unsigned totalLen = len;
50 wchar_t *p = path.GetBuffer(len);
51 p[len] = 0;
52 len -= name.Len();
53 memcpy(p + len, (const wchar_t *)name, name.Len() * sizeof(wchar_t));
54 for (i = index; i >= 0; i = parents[i])
55 {
56 const UString &s = Prefixes[i];
57 len -= s.Len();
58 memcpy(p + len, (const wchar_t *)s, s.Len() * sizeof(wchar_t));
59 }
60 path.ReleaseBuffer(totalLen);
61 return path;
62 }
63
GetPhyPath(unsigned index) const64 UString CDirItems::GetPhyPath(unsigned index) const
65 {
66 const CDirItem &di = Items[index];
67 return GetPrefixesPath(PhyParents, di.PhyParent, di.Name);
68 }
69
GetLogPath(unsigned index) const70 UString CDirItems::GetLogPath(unsigned index) const
71 {
72 const CDirItem &di = Items[index];
73 return GetPrefixesPath(LogParents, di.LogParent, di.Name);
74 }
75
ReserveDown()76 void CDirItems::ReserveDown()
77 {
78 Prefixes.ReserveDown();
79 PhyParents.ReserveDown();
80 LogParents.ReserveDown();
81 Items.ReserveDown();
82 }
83
AddPrefix(int phyParent,int logParent,const UString & prefix)84 unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
85 {
86 PhyParents.Add(phyParent);
87 LogParents.Add(logParent);
88 return Prefixes.Add(prefix);
89 }
90
DeleteLastPrefix()91 void CDirItems::DeleteLastPrefix()
92 {
93 PhyParents.DeleteBack();
94 LogParents.DeleteBack();
95 Prefixes.DeleteBack();
96 }
97
98 bool InitLocalPrivileges();
99
CDirItems()100 CDirItems::CDirItems():
101 SymLinks(false),
102 TotalSize(0)
103 #ifdef _USE_SECURITY_CODE
104 , ReadSecure(false)
105 #endif
106 {
107 #ifdef _USE_SECURITY_CODE
108 _saclEnabled = InitLocalPrivileges();
109 #endif
110 }
111
112 #ifdef _USE_SECURITY_CODE
113
AddSecurityItem(const FString & path,int & secureIndex)114 void CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
115 {
116 secureIndex = -1;
117
118 SECURITY_INFORMATION securInfo =
119 DACL_SECURITY_INFORMATION |
120 GROUP_SECURITY_INFORMATION |
121 OWNER_SECURITY_INFORMATION;
122 if (_saclEnabled)
123 securInfo |= SACL_SECURITY_INFORMATION;
124
125 DWORD errorCode = 0;
126 DWORD secureSize;
127 BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
128 if (res)
129 {
130 if (secureSize == 0)
131 return;
132 if (secureSize > TempSecureBuf.Size())
133 errorCode = ERROR_INVALID_FUNCTION;
134 }
135 else
136 {
137 errorCode = GetLastError();
138 if (errorCode == ERROR_INSUFFICIENT_BUFFER)
139 {
140 if (secureSize <= TempSecureBuf.Size())
141 errorCode = ERROR_INVALID_FUNCTION;
142 else
143 {
144 TempSecureBuf.Alloc(secureSize);
145 res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
146 if (res)
147 {
148 if (secureSize != TempSecureBuf.Size())
149 errorCode = ERROR_INVALID_FUNCTION;;
150 }
151 else
152 errorCode = GetLastError();
153 }
154 }
155 }
156 if (res)
157 {
158 secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);
159 return;
160 }
161 if (errorCode == 0)
162 errorCode = ERROR_INVALID_FUNCTION;
163 AddError(path, errorCode);
164 }
165
166 #endif
167
EnumerateDir(int phyParent,int logParent,const FString & phyPrefix)168 void CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
169 {
170 NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
171 for (;;)
172 {
173 NFind::CFileInfo fi;
174 bool found;
175 if (!enumerator.Next(fi, found))
176 {
177 AddError(phyPrefix);
178 return;
179 }
180 if (!found)
181 break;
182
183 int secureIndex = -1;
184 #ifdef _USE_SECURITY_CODE
185 if (ReadSecure)
186 AddSecurityItem(phyPrefix + fi.Name, secureIndex);
187 #endif
188
189 AddDirFileInfo(phyParent, logParent, secureIndex, fi, Items);
190
191 if (fi.IsDir())
192 {
193 const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
194 unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));
195 EnumerateDir(parent, parent, phyPrefix + name2);
196 }
197 }
198 }
199
EnumerateItems2(const FString & phyPrefix,const UString & logPrefix,const FStringVector & filePaths,FStringVector * requestedPaths)200 void CDirItems::EnumerateItems2(
201 const FString &phyPrefix,
202 const UString &logPrefix,
203 const FStringVector &filePaths,
204 FStringVector *requestedPaths)
205 {
206 int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix));
207 int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
208
209 FOR_VECTOR (i, filePaths)
210 {
211 const FString &filePath = filePaths[i];
212 NFind::CFileInfo fi;
213 const FString phyPath = phyPrefix + filePath;
214 if (!fi.Find(phyPath))
215 {
216 AddError(phyPath);
217 continue;
218 }
219 if (requestedPaths)
220 requestedPaths->Add(phyPath);
221
222 int delimiter = filePath.ReverseFind(FCHAR_PATH_SEPARATOR);
223 FString phyPrefixCur;
224 int phyParentCur = phyParent;
225 if (delimiter >= 0)
226 {
227 phyPrefixCur.SetFrom(filePath, delimiter + 1);
228 phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
229 }
230
231 int secureIndex = -1;
232 #ifdef _USE_SECURITY_CODE
233 if (ReadSecure)
234 AddSecurityItem(phyPath, secureIndex);
235 #endif
236
237 AddDirFileInfo(phyParentCur, logParent, secureIndex, fi, Items);
238
239 if (fi.IsDir())
240 {
241 const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
242 unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
243 EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2);
244 }
245 }
246 ReserveDown();
247 }
248
249
250
251
252
253
254 static HRESULT EnumerateDirItems(
255 const NWildcard::CCensorNode &curNode,
256 int phyParent, int logParent, const FString &phyPrefix,
257 const UStringVector &addArchivePrefix,
258 CDirItems &dirItems,
259 bool enterToSubFolders,
260 IEnumDirItemCallback *callback);
261
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)262 static HRESULT EnumerateDirItems_Spec(
263 const NWildcard::CCensorNode &curNode,
264 int phyParent, int logParent, const FString &curFolderName,
265 const FString &phyPrefix,
266 const UStringVector &addArchivePrefix,
267 CDirItems &dirItems,
268 bool enterToSubFolders,
269 IEnumDirItemCallback *callback)
270 {
271 const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;
272 unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
273 unsigned numItems = dirItems.Items.Size();
274 HRESULT res = EnumerateDirItems(
275 curNode, parent, parent, phyPrefix + name2,
276 addArchivePrefix, dirItems, enterToSubFolders, callback);
277 if (numItems == dirItems.Items.Size())
278 dirItems.DeleteLastPrefix();
279 return res;
280 }
281
282 #ifndef UNDER_CE
283
EnumerateAltStreams(const NFind::CFileInfo & fi,const NWildcard::CCensorNode & curNode,int phyParent,int logParent,const FString & phyPrefix,const UStringVector & addArchivePrefix,CDirItems & dirItems)284 static void EnumerateAltStreams(
285 const NFind::CFileInfo &fi,
286 const NWildcard::CCensorNode &curNode,
287 int phyParent, int logParent, const FString &phyPrefix,
288 const UStringVector &addArchivePrefix, // prefix from curNode
289 CDirItems &dirItems)
290 {
291 const FString fullPath = phyPrefix + fi.Name;
292 NFind::CStreamEnumerator enumerator(fullPath);
293 for (;;)
294 {
295 NFind::CStreamInfo si;
296 bool found;
297 if (!enumerator.Next(si, found))
298 {
299 dirItems.AddError(fullPath + FTEXT(":*"), (DWORD)E_FAIL);
300 break;
301 }
302 if (!found)
303 break;
304 if (si.IsMainStream())
305 continue;
306 UStringVector addArchivePrefixNew = addArchivePrefix;
307 UString reducedName = si.GetReducedName();
308 addArchivePrefixNew.Back() += reducedName;
309 if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))
310 continue;
311 NFind::CFileInfo fi2 = fi;
312 fi2.Name += us2fs(reducedName);
313 fi2.Size = si.Size;
314 fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
315 fi2.IsAltStream = true;
316 AddDirFileInfo(phyParent, logParent, -1, fi2, dirItems.Items);
317 dirItems.TotalSize += fi2.Size;
318 }
319 }
320
SetLinkInfo(CDirItem & dirItem,const NFind::CFileInfo & fi,const FString & phyPrefix)321 void CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
322 const FString &phyPrefix)
323 {
324 if (!SymLinks || !fi.HasReparsePoint())
325 return;
326 const FString path = phyPrefix + fi.Name;
327 CByteBuffer &buf = dirItem.ReparseData;
328 if (NIO::GetReparseData(path, buf))
329 {
330 CReparseAttr attr;
331 if (attr.Parse(buf, buf.Size()))
332 return;
333 }
334 AddError(path);
335 buf.Free();
336 }
337
338 #endif
339
EnumerateForItem(NFind::CFileInfo & fi,const NWildcard::CCensorNode & curNode,int phyParent,int logParent,const FString & phyPrefix,const UStringVector & addArchivePrefix,CDirItems & dirItems,bool enterToSubFolders,IEnumDirItemCallback * callback)340 static HRESULT EnumerateForItem(
341 NFind::CFileInfo &fi,
342 const NWildcard::CCensorNode &curNode,
343 int phyParent, int logParent, const FString &phyPrefix,
344 const UStringVector &addArchivePrefix, // prefix from curNode
345 CDirItems &dirItems,
346 bool enterToSubFolders,
347 IEnumDirItemCallback *callback)
348 {
349 const UString name = fs2us(fi.Name);
350 bool enterToSubFolders2 = enterToSubFolders;
351 UStringVector addArchivePrefixNew = addArchivePrefix;
352 addArchivePrefixNew.Add(name);
353 {
354 UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
355 if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
356 return S_OK;
357 }
358 int dirItemIndex = -1;
359
360 if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
361 {
362 int secureIndex = -1;
363 #ifdef _USE_SECURITY_CODE
364 if (dirItems.ReadSecure)
365 dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex);
366 #endif
367
368 dirItemIndex = dirItems.Items.Size();
369 AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items);
370 dirItems.TotalSize += fi.Size;
371 if (fi.IsDir())
372 enterToSubFolders2 = true;
373 }
374
375 #ifndef UNDER_CE
376 if (dirItems.ScanAltStreams)
377 {
378 EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix,
379 addArchivePrefixNew, dirItems);
380 }
381
382 if (dirItemIndex >= 0)
383 {
384 CDirItem &dirItem = dirItems.Items[dirItemIndex];
385 dirItems.SetLinkInfo(dirItem, fi, phyPrefix);
386 if (dirItem.ReparseData.Size() != 0)
387 return S_OK;
388 }
389 #endif
390
391 if (!fi.IsDir())
392 return S_OK;
393
394 const NWildcard::CCensorNode *nextNode = 0;
395 if (addArchivePrefix.IsEmpty())
396 {
397 int index = curNode.FindSubNode(name);
398 if (index >= 0)
399 nextNode = &curNode.SubNodes[index];
400 }
401 if (!enterToSubFolders2 && nextNode == 0)
402 return S_OK;
403
404 addArchivePrefixNew = addArchivePrefix;
405 if (nextNode == 0)
406 {
407 nextNode = &curNode;
408 addArchivePrefixNew.Add(name);
409 }
410
411 return EnumerateDirItems_Spec(
412 *nextNode, phyParent, logParent, fi.Name, phyPrefix,
413 addArchivePrefixNew,
414 dirItems,
415 enterToSubFolders2, callback);
416 }
417
418
CanUseFsDirect(const NWildcard::CCensorNode & curNode)419 static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)
420 {
421 FOR_VECTOR (i, curNode.IncludeItems)
422 {
423 const NWildcard::CItem &item = curNode.IncludeItems[i];
424 if (item.Recursive || item.PathParts.Size() != 1)
425 return false;
426 const UString &name = item.PathParts.Front();
427 if (name.IsEmpty())
428 return false;
429
430 /* Windows doesn't support file name with wildcard.
431 but if another system supports file name with wildcard,
432 and wildcard mode is disabled, we can ignore wildcard in name */
433 /*
434 if (!item.WildcardParsing)
435 continue;
436 */
437 if (DoesNameContainWildcard(name))
438 return false;
439 }
440 return true;
441 }
442
443
EnumerateDirItems(const NWildcard::CCensorNode & curNode,int phyParent,int logParent,const FString & phyPrefix,const UStringVector & addArchivePrefix,CDirItems & dirItems,bool enterToSubFolders,IEnumDirItemCallback * callback)444 static HRESULT EnumerateDirItems(
445 const NWildcard::CCensorNode &curNode,
446 int phyParent, int logParent, const FString &phyPrefix,
447 const UStringVector &addArchivePrefix, // prefix from curNode
448 CDirItems &dirItems,
449 bool enterToSubFolders,
450 IEnumDirItemCallback *callback)
451 {
452 if (!enterToSubFolders)
453 if (curNode.NeedCheckSubDirs())
454 enterToSubFolders = true;
455 if (callback)
456 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true));
457
458 // try direct_names case at first
459 if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
460 {
461 if (CanUseFsDirect(curNode))
462 {
463 // all names are direct (no wildcards)
464 // so we don't need file_system's dir enumerator
465 CRecordVector<bool> needEnterVector;
466 unsigned i;
467
468 for (i = 0; i < curNode.IncludeItems.Size(); i++)
469 {
470 const NWildcard::CItem &item = curNode.IncludeItems[i];
471 const UString &name = item.PathParts.Front();
472 const FString fullPath = phyPrefix + us2fs(name);
473 NFind::CFileInfo fi;
474 #ifdef _WIN32
475 if (phyPrefix.IsEmpty() && item.IsDriveItem())
476 {
477 fi.SetAsDir();
478 fi.Name = fullPath;
479 }
480 else
481 #endif
482 if (!fi.Find(fullPath))
483 {
484 dirItems.AddError(fullPath);
485 continue;
486 }
487 bool isDir = fi.IsDir();
488 if (isDir && !item.ForDir || !isDir && !item.ForFile)
489 {
490 dirItems.AddError(fullPath, (DWORD)E_FAIL);
491 continue;
492 }
493 {
494 UStringVector pathParts;
495 pathParts.Add(fs2us(fi.Name));
496 if (curNode.CheckPathToRoot(false, pathParts, !isDir))
497 continue;
498 }
499
500 int secureIndex = -1;
501 #ifdef _USE_SECURITY_CODE
502 if (dirItems.ReadSecure)
503 dirItems.AddSecurityItem(fullPath, secureIndex);
504 #endif
505
506 AddDirFileInfo(phyParent, logParent, secureIndex, fi, dirItems.Items);
507
508 #ifndef UNDER_CE
509 {
510 CDirItem &dirItem = dirItems.Items.Back();
511 dirItems.SetLinkInfo(dirItem, fi, phyPrefix);
512 if (dirItem.ReparseData.Size() != 0)
513 continue;
514 }
515 #endif
516
517 dirItems.TotalSize += fi.Size;
518
519 #ifndef UNDER_CE
520 if (dirItems.ScanAltStreams)
521 {
522 UStringVector pathParts;
523 pathParts.Add(fs2us(fi.Name));
524 EnumerateAltStreams(fi, curNode, phyParent, logParent, phyPrefix,
525 pathParts, dirItems);
526 }
527 #endif
528
529 if (!isDir)
530 continue;
531
532 UStringVector addArchivePrefixNew;
533 const NWildcard::CCensorNode *nextNode = 0;
534 int index = curNode.FindSubNode(name);
535 if (index >= 0)
536 {
537 for (int t = needEnterVector.Size(); t <= index; t++)
538 needEnterVector.Add(true);
539 needEnterVector[index] = false;
540 nextNode = &curNode.SubNodes[index];
541 }
542 else
543 {
544 nextNode = &curNode;
545 addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
546 }
547
548 RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
549 addArchivePrefixNew, dirItems, true, callback));
550 }
551
552 for (i = 0; i < curNode.SubNodes.Size(); i++)
553 {
554 if (i < needEnterVector.Size())
555 if (!needEnterVector[i])
556 continue;
557 const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
558 const FString fullPath = phyPrefix + us2fs(nextNode.Name);
559 NFind::CFileInfo fi;
560 #ifdef _WIN32
561 if (phyPrefix.IsEmpty() && NWildcard::IsDriveColonName(nextNode.Name))
562 {
563 fi.SetAsDir();
564 fi.Name = fullPath;
565 }
566 else
567 #endif
568 if (!fi.Find(fullPath))
569 {
570 if (!nextNode.AreThereIncludeItems())
571 continue;
572 dirItems.AddError(fullPath);
573 continue;
574 }
575 if (!fi.IsDir())
576 {
577 dirItems.AddError(fullPath, (DWORD)E_FAIL);
578 continue;
579 }
580
581 RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
582 UStringVector(), dirItems, false, callback));
583 }
584
585 return S_OK;
586 }
587 }
588
589 #ifdef _WIN32
590 #ifndef UNDER_CE
591
592 // scan drives, if wildcard is "*:\"
593
594 if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0)
595 {
596 unsigned i;
597 for (i = 0; i < curNode.IncludeItems.Size(); i++)
598 {
599 const NWildcard::CItem &item = curNode.IncludeItems[i];
600 if (item.PathParts.Size() < 1)
601 break;
602 const UString &name = item.PathParts.Front();
603 if (name.Len() != 2 || name[1] != ':')
604 break;
605 if (item.PathParts.Size() == 1)
606 if (item.ForFile || !item.ForDir)
607 break;
608 if (NWildcard::IsDriveColonName(name))
609 continue;
610 if (name[0] != '*' && name[0] != '?')
611 break;
612 }
613 if (i == curNode.IncludeItems.Size())
614 {
615 FStringVector driveStrings;
616 NFind::MyGetLogicalDriveStrings(driveStrings);
617 for (i = 0; i < driveStrings.Size(); i++)
618 {
619 FString driveName = driveStrings[i];
620 if (driveName.Len() < 3 || driveName.Back() != '\\')
621 return E_FAIL;
622 driveName.DeleteBack();
623 NFind::CFileInfo fi;
624 fi.SetAsDir();
625 fi.Name = driveName;
626
627 RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
628 addArchivePrefix, dirItems, enterToSubFolders, callback));
629 }
630 return S_OK;
631 }
632 }
633
634 #endif
635 #endif
636
637 NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
638 for (unsigned ttt = 0; ; ttt++)
639 {
640 NFind::CFileInfo fi;
641 bool found;
642 if (!enumerator.Next(fi, found))
643 {
644 dirItems.AddError(phyPrefix);
645 break;
646 }
647 if (!found)
648 break;
649
650 if (callback && (ttt & 0xFF) == 0xFF)
651 RINOK(callback->ScanProgress(dirItems.GetNumFolders(), dirItems.Items.Size(), dirItems.TotalSize, fs2us(phyPrefix), true));
652
653 RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
654 addArchivePrefix, dirItems, enterToSubFolders, callback));
655 }
656 return S_OK;
657 }
658
EnumerateItems(const NWildcard::CCensor & censor,const NWildcard::ECensorPathMode pathMode,const UString & addPathPrefix,CDirItems & dirItems,IEnumDirItemCallback * callback)659 HRESULT EnumerateItems(
660 const NWildcard::CCensor &censor,
661 const NWildcard::ECensorPathMode pathMode,
662 const UString &addPathPrefix,
663 CDirItems &dirItems,
664 IEnumDirItemCallback *callback)
665 {
666 FOR_VECTOR (i, censor.Pairs)
667 {
668 const NWildcard::CPair &pair = censor.Pairs[i];
669 int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
670 int logParent = -1;
671
672 if (pathMode == NWildcard::k_AbsPath)
673 logParent = phyParent;
674 else
675 {
676 if (!addPathPrefix.IsEmpty())
677 logParent = dirItems.AddPrefix(-1, -1, addPathPrefix);
678 }
679
680 RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(),
681 dirItems,
682 false, // enterToSubFolders
683 callback));
684 }
685 dirItems.ReserveDown();
686
687 #if defined(_WIN32) && !defined(UNDER_CE)
688 dirItems.FillFixedReparse();
689 #endif
690
691 return S_OK;
692 }
693
694 #if defined(_WIN32) && !defined(UNDER_CE)
695
FillFixedReparse()696 void CDirItems::FillFixedReparse()
697 {
698 /* imagex/WIM reduces absolute pathes in links (raparse data),
699 if we archive non root folder. We do same thing here */
700
701 if (!SymLinks)
702 return;
703
704 FOR_VECTOR(i, Items)
705 {
706 CDirItem &item = Items[i];
707 if (item.ReparseData.Size() == 0)
708 continue;
709
710 CReparseAttr attr;
711 if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
712 continue;
713 if (attr.IsRelative())
714 continue;
715
716 const UString &link = attr.GetPath();
717 if (!IsDrivePath(link))
718 continue;
719 // maybe we need to support networks paths also ?
720
721 FString fullPathF;
722 if (!NDir::MyGetFullPathName(us2fs(GetPhyPath(i)), fullPathF))
723 continue;
724 UString fullPath = fs2us(fullPathF);
725 const UString logPath = GetLogPath(i);
726 if (logPath.Len() >= fullPath.Len())
727 continue;
728 if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0)
729 continue;
730
731 const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len());
732 if (prefix.Back() != WCHAR_PATH_SEPARATOR)
733 continue;
734
735 unsigned rootPrefixSize = GetRootPrefixSize(prefix);
736 if (rootPrefixSize == 0)
737 continue;
738 if (rootPrefixSize == prefix.Len())
739 continue; // simple case: paths are from root
740
741 if (link.Len() <= prefix.Len())
742 continue;
743
744 if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
745 continue;
746
747 UString newLink = prefix.Left(rootPrefixSize);
748 newLink += link.Ptr(prefix.Len());
749
750 CByteBuffer data;
751 if (!FillLinkData(data, newLink, attr.IsSymLink()))
752 continue;
753 item.ReparseData2 = data;
754 }
755 }
756
757 #endif
758