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 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 42 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 64 UString CDirItems::GetPhyPath(unsigned index) const 65 { 66 const CDirItem &di = Items[index]; 67 return GetPrefixesPath(PhyParents, di.PhyParent, di.Name); 68 } 69 70 UString CDirItems::GetLogPath(unsigned index) const 71 { 72 const CDirItem &di = Items[index]; 73 return GetPrefixesPath(LogParents, di.LogParent, di.Name); 74 } 75 76 void CDirItems::ReserveDown() 77 { 78 Prefixes.ReserveDown(); 79 PhyParents.ReserveDown(); 80 LogParents.ReserveDown(); 81 Items.ReserveDown(); 82 } 83 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 91 void CDirItems::DeleteLastPrefix() 92 { 93 PhyParents.DeleteBack(); 94 LogParents.DeleteBack(); 95 Prefixes.DeleteBack(); 96 } 97 98 bool InitLocalPrivileges(); 99 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 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 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 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 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 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 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 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 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 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 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 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