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 20using namespace NWindows; 21using namespace NFile; 22using namespace NName; 23 24void 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 57HRESULT 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 65HRESULT CDirItems::AddError(const FString &path) 66{ 67 return AddError(path, ::GetLastError()); 68} 69 70static const unsigned kScanProgressStepMask = (1 << 12) - 1; 71 72HRESULT CDirItems::ScanProgress(const FString &dirPath) 73{ 74 if (Callback) 75 return Callback->ScanProgress(Stat, dirPath, true); 76 return S_OK; 77} 78 79UString 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 103FString CDirItems::GetPhyPath(unsigned index) const 104{ 105 const CDirItem &di = Items[index]; 106 return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name)); 107} 108 109UString CDirItems::GetLogPath(unsigned index) const 110{ 111 const CDirItem &di = Items[index]; 112 return GetPrefixesPath(LogParents, di.LogParent, di.Name); 113} 114 115void CDirItems::ReserveDown() 116{ 117 Prefixes.ReserveDown(); 118 PhyParents.ReserveDown(); 119 LogParents.ReserveDown(); 120 Items.ReserveDown(); 121} 122 123unsigned 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 130void CDirItems::DeleteLastPrefix() 131{ 132 PhyParents.DeleteBack(); 133 LogParents.DeleteBack(); 134 Prefixes.DeleteBack(); 135} 136 137bool InitLocalPrivileges(); 138 139CDirItems::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 154HRESULT 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 212HRESULT 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 252HRESULT 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 310static 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 317static 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 340static 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 376HRESULT 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 396static 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 476static 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 505static 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 515static 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 801HRESULT 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 837void 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