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