1 // ArchiveExtractCallback.cpp 2 3 #include "StdAfx.h" 4 5 #undef sprintf 6 #undef printf 7 8 #include "../../../../C/Alloc.h" 9 10 #include "../../../Common/ComTry.h" 11 #include "../../../Common/IntToString.h" 12 #include "../../../Common/StringConvert.h" 13 #include "../../../Common/Wildcard.h" 14 15 #include "../../../Windows/ErrorMsg.h" 16 #include "../../../Windows/FileDir.h" 17 #include "../../../Windows/FileFind.h" 18 #include "../../../Windows/FileName.h" 19 #include "../../../Windows/PropVariant.h" 20 #include "../../../Windows/PropVariantConv.h" 21 22 #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX) 23 #define _USE_SECURITY_CODE 24 #include "../../../Windows/SecurityUtils.h" 25 #endif 26 27 #include "../../Common/FilePathAutoRename.h" 28 // #include "../../Common/StreamUtils.h" 29 30 #include "../Common/ExtractingFilePath.h" 31 #include "../Common/PropIDUtils.h" 32 33 #include "ArchiveExtractCallback.h" 34 35 using namespace NWindows; 36 using namespace NFile; 37 using namespace NDir; 38 39 static const char *kCantAutoRename = "Can not create file with auto name"; 40 static const char *kCantRenameFile = "Can not rename existing file"; 41 static const char *kCantDeleteOutputFile = "Can not delete output file"; 42 static const char *kCantDeleteOutputDir = "Can not delete output folder"; 43 44 45 #ifndef _SFX 46 47 STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize) 48 { 49 HRESULT result = S_OK; 50 if (_stream) 51 result = _stream->Write(data, size, &size); 52 if (_calculate) 53 _hash->Update(data, size); 54 _size += size; 55 if (processedSize) 56 *processedSize = size; 57 return result; 58 } 59 60 #endif 61 62 #ifdef _USE_SECURITY_CODE 63 bool InitLocalPrivileges() 64 { 65 NSecurity::CAccessToken token; 66 if (!token.OpenProcessToken(GetCurrentProcess(), 67 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)) 68 return false; 69 70 TOKEN_PRIVILEGES tp; 71 72 tp.PrivilegeCount = 1; 73 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 74 75 if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid)) 76 return false; 77 if (!token.AdjustPrivileges(&tp)) 78 return false; 79 return (GetLastError() == ERROR_SUCCESS); 80 } 81 #endif 82 83 #ifdef SUPPORT_LINKS 84 85 int CHardLinkNode::Compare(const CHardLinkNode &a) const 86 { 87 if (StreamId < a.StreamId) return -1; 88 if (StreamId > a.StreamId) return 1; 89 return MyCompare(INode, a.INode); 90 } 91 92 static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined) 93 { 94 h.INode = 0; 95 h.StreamId = (UInt64)(Int64)-1; 96 defined = false; 97 { 98 NCOM::CPropVariant prop; 99 RINOK(archive->GetProperty(index, kpidINode, &prop)); 100 if (!ConvertPropVariantToUInt64(prop, h.INode)) 101 return S_OK; 102 } 103 { 104 NCOM::CPropVariant prop; 105 RINOK(archive->GetProperty(index, kpidStreamId, &prop)); 106 ConvertPropVariantToUInt64(prop, h.StreamId); 107 } 108 defined = true; 109 return S_OK; 110 } 111 112 113 HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *realIndices) 114 { 115 _hardLinks.Clear(); 116 117 if (!_arc->Ask_INode) 118 return S_OK; 119 120 IInArchive *archive = _arc->Archive; 121 CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs; 122 123 { 124 UInt32 numItems; 125 if (realIndices) 126 numItems = realIndices->Size(); 127 else 128 { 129 RINOK(archive->GetNumberOfItems(&numItems)); 130 } 131 132 for (UInt32 i = 0; i < numItems; i++) 133 { 134 CHardLinkNode h; 135 bool defined; 136 UInt32 realIndex = realIndices ? (*realIndices)[i] : i; 137 138 RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined)); 139 if (defined) 140 { 141 bool isAltStream = false; 142 RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream)); 143 if (!isAltStream) 144 hardIDs.Add(h); 145 } 146 } 147 } 148 149 hardIDs.Sort2(); 150 151 { 152 // wee keep only items that have 2 or more items 153 unsigned k = 0; 154 unsigned numSame = 1; 155 for (unsigned i = 1; i < hardIDs.Size(); i++) 156 { 157 if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) 158 numSame = 1; 159 else if (++numSame == 2) 160 { 161 if (i - 1 != k) 162 hardIDs[k] = hardIDs[i - 1]; 163 k++; 164 } 165 } 166 hardIDs.DeleteFrom(k); 167 } 168 169 _hardLinks.PrepareLinks(); 170 return S_OK; 171 } 172 173 #endif 174 175 CArchiveExtractCallback::CArchiveExtractCallback(): 176 WriteCTime(true), 177 WriteATime(true), 178 WriteMTime(true), 179 _multiArchives(false) 180 { 181 LocalProgressSpec = new CLocalProgress(); 182 _localProgress = LocalProgressSpec; 183 184 #ifdef _USE_SECURITY_CODE 185 _saclEnabled = InitLocalPrivileges(); 186 #endif 187 } 188 189 void CArchiveExtractCallback::Init( 190 const CExtractNtOptions &ntOptions, 191 const NWildcard::CCensorNode *wildcardCensor, 192 const CArc *arc, 193 IFolderArchiveExtractCallback *extractCallback2, 194 bool stdOutMode, bool testMode, 195 const FString &directoryPath, 196 const UStringVector &removePathParts, bool removePartsForAltStreams, 197 UInt64 packSize) 198 { 199 _extractedFolderPaths.Clear(); 200 _extractedFolderIndices.Clear(); 201 202 #ifdef SUPPORT_LINKS 203 _hardLinks.Clear(); 204 #endif 205 206 #ifdef SUPPORT_ALT_STREAMS 207 _renamedFiles.Clear(); 208 #endif 209 210 _ntOptions = ntOptions; 211 _wildcardCensor = wildcardCensor; 212 213 _stdOutMode = stdOutMode; 214 _testMode = testMode; 215 216 // _progressTotal = 0; 217 // _progressTotal_Defined = false; 218 219 _packTotal = packSize; 220 _progressTotal = packSize; 221 _progressTotal_Defined = true; 222 223 _extractCallback2 = extractCallback2; 224 _compressProgress.Release(); 225 _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); 226 _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage); 227 _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2); 228 229 #ifndef _SFX 230 231 _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback); 232 if (ExtractToStreamCallback) 233 { 234 Int32 useStreams = 0; 235 if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK) 236 useStreams = 0; 237 if (useStreams == 0) 238 ExtractToStreamCallback.Release(); 239 } 240 241 #endif 242 243 LocalProgressSpec->Init(extractCallback2, true); 244 LocalProgressSpec->SendProgress = false; 245 246 _removePathParts = removePathParts; 247 _removePartsForAltStreams = removePartsForAltStreams; 248 249 #ifndef _SFX 250 _baseParentFolder = (UInt32)(Int32)-1; 251 _use_baseParentFolder_mode = false; 252 #endif 253 254 _arc = arc; 255 _dirPathPrefix = directoryPath; 256 _dirPathPrefix_Full = directoryPath; 257 #if defined(_WIN32) && !defined(UNDER_CE) 258 if (!NName::IsAltPathPrefix(_dirPathPrefix)) 259 #endif 260 { 261 NName::NormalizeDirPathPrefix(_dirPathPrefix); 262 NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full); 263 NName::NormalizeDirPathPrefix(_dirPathPrefix_Full); 264 } 265 } 266 267 STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) 268 { 269 COM_TRY_BEGIN 270 _progressTotal = size; 271 _progressTotal_Defined = true; 272 if (!_multiArchives && _extractCallback2) 273 return _extractCallback2->SetTotal(size); 274 return S_OK; 275 COM_TRY_END 276 } 277 278 static void NormalizeVals(UInt64 &v1, UInt64 &v2) 279 { 280 const UInt64 kMax = (UInt64)1 << 31; 281 while (v1 > kMax) 282 { 283 v1 >>= 1; 284 v2 >>= 1; 285 } 286 } 287 288 static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) 289 { 290 NormalizeVals(packTotal, unpTotal); 291 NormalizeVals(unpCur, unpTotal); 292 if (unpTotal == 0) 293 unpTotal = 1; 294 return unpCur * packTotal / unpTotal; 295 } 296 297 STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) 298 { 299 COM_TRY_BEGIN 300 301 if (!_extractCallback2) 302 return S_OK; 303 304 UInt64 packCur; 305 if (_multiArchives) 306 { 307 packCur = LocalProgressSpec->InSize; 308 if (completeValue && _progressTotal_Defined) 309 packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal); 310 completeValue = &packCur; 311 } 312 return _extractCallback2->SetCompleted(completeValue); 313 314 COM_TRY_END 315 } 316 317 STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) 318 { 319 COM_TRY_BEGIN 320 return _localProgress->SetRatioInfo(inSize, outSize); 321 COM_TRY_END 322 } 323 324 void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) 325 { 326 bool isAbsPath = false; 327 328 if (!dirPathParts.IsEmpty()) 329 { 330 const UString &s = dirPathParts[0]; 331 if (s.IsEmpty()) 332 isAbsPath = true; 333 #if defined(_WIN32) && !defined(UNDER_CE) 334 else 335 { 336 if (NName::IsDrivePath2(s)) 337 isAbsPath = true; 338 } 339 #endif 340 } 341 342 if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) 343 fullPath.Empty(); 344 else 345 fullPath = _dirPathPrefix; 346 347 FOR_VECTOR (i, dirPathParts) 348 { 349 if (i != 0) 350 fullPath.Add_PathSepar(); 351 const UString &s = dirPathParts[i]; 352 fullPath += us2fs(s); 353 #if defined(_WIN32) && !defined(UNDER_CE) 354 if (_pathMode == NExtract::NPathMode::kAbsPaths) 355 if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s)) 356 continue; 357 #endif 358 CreateDir(fullPath); 359 } 360 } 361 362 HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) 363 { 364 filetimeIsDefined = false; 365 NCOM::CPropVariant prop; 366 RINOK(_arc->Archive->GetProperty(index, propID, &prop)); 367 if (prop.vt == VT_FILETIME) 368 { 369 filetime = prop.filetime; 370 filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); 371 } 372 else if (prop.vt != VT_EMPTY) 373 return E_FAIL; 374 return S_OK; 375 } 376 377 HRESULT CArchiveExtractCallback::GetUnpackSize() 378 { 379 return _arc->GetItemSize(_index, _curSize, _curSizeDefined); 380 } 381 382 static void AddPathToMessage(UString &s, const FString &path) 383 { 384 s.AddAscii(" : "); 385 s += fs2us(path); 386 } 387 388 HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) 389 { 390 UString s; 391 s.AddAscii(message); 392 AddPathToMessage(s, path); 393 return _extractCallback2->MessageError(s); 394 } 395 396 HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path) 397 { 398 DWORD errorCode = GetLastError(); 399 UString s; 400 s.AddAscii(message); 401 if (errorCode != 0) 402 { 403 s.AddAscii(" : "); 404 s += NError::MyFormatMessage(errorCode); 405 } 406 AddPathToMessage(s, path); 407 return _extractCallback2->MessageError(s); 408 } 409 410 HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2) 411 { 412 UString s; 413 s.AddAscii(message); 414 AddPathToMessage(s, path1); 415 AddPathToMessage(s, path2); 416 return _extractCallback2->MessageError(s); 417 } 418 419 #ifndef _SFX 420 421 STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value) 422 { 423 /* 424 if (propID == kpidName) 425 { 426 COM_TRY_BEGIN 427 NCOM::CPropVariant prop = Name; 428 prop.Detach(value); 429 return S_OK; 430 COM_TRY_END 431 } 432 */ 433 return Arc->Archive->GetProperty(IndexInArc, propID, value); 434 } 435 436 #endif 437 438 439 #ifdef SUPPORT_LINKS 440 441 static UString GetDirPrefixOf(const UString &src) 442 { 443 UString s = src; 444 if (!s.IsEmpty()) 445 { 446 if (IsPathSepar(s.Back())) 447 s.DeleteBack(); 448 int pos = s.ReverseFind_PathSepar(); 449 s.DeleteFrom(pos + 1); 450 } 451 return s; 452 } 453 454 #endif 455 456 457 bool IsSafePath(const UString &path) 458 { 459 if (NName::IsAbsolutePath(path)) 460 return false; 461 462 UStringVector parts; 463 SplitPathToParts(path, parts); 464 unsigned level = 0; 465 466 FOR_VECTOR (i, parts) 467 { 468 const UString &s = parts[i]; 469 if (s.IsEmpty()) 470 { 471 if (i == 0) 472 return false; 473 continue; 474 } 475 if (s == L".") 476 continue; 477 if (s == L"..") 478 { 479 if (level == 0) 480 return false; 481 level--; 482 } 483 else 484 level++; 485 } 486 487 return level > 0; 488 } 489 490 491 bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include) 492 { 493 bool found = false; 494 495 if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include)) 496 { 497 if (!include) 498 return true; 499 500 #ifdef SUPPORT_ALT_STREAMS 501 if (!item.IsAltStream) 502 return true; 503 #endif 504 505 found = true; 506 } 507 508 #ifdef SUPPORT_ALT_STREAMS 509 510 if (!item.IsAltStream) 511 return false; 512 513 UStringVector pathParts2 = item.PathParts; 514 if (pathParts2.IsEmpty()) 515 pathParts2.AddNew(); 516 UString &back = pathParts2.Back(); 517 back += L':'; 518 back += item.AltStreamName; 519 bool include2; 520 521 if (node.CheckPathVect(pathParts2, 522 true, // isFile, 523 include2)) 524 { 525 include = include2; 526 return true; 527 } 528 529 #endif 530 531 return found; 532 } 533 534 bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item) 535 { 536 bool include; 537 if (CensorNode_CheckPath2(node, item, include)) 538 return include; 539 return false; 540 } 541 542 static FString MakePath_from_2_Parts(const FString &prefix, const FString &path) 543 { 544 FString s = prefix; 545 #if defined(_WIN32) && !defined(UNDER_CE) 546 if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back())) 547 { 548 if (!NName::IsDriveRootPath_SuperAllowed(prefix)) 549 s.DeleteBack(); 550 } 551 #endif 552 s += path; 553 return s; 554 } 555 556 557 /* 558 #ifdef SUPPORT_LINKS 559 560 struct CTempMidBuffer 561 { 562 void *Buf; 563 564 CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); } 565 ~CTempMidBuffer() { ::MidFree(Buf); } 566 }; 567 568 HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream) 569 { 570 const size_t kBufSize = 1 << 16; 571 CTempMidBuffer buf(kBufSize); 572 if (!buf.Buf) 573 return E_OUTOFMEMORY; 574 575 NIO::CInFile inFile; 576 NIO::COutFile outFile; 577 578 if (!inFile.Open(_CopyFile_Path)) 579 return SendMessageError_with_LastError("Open error", _CopyFile_Path); 580 581 for (;;) 582 { 583 UInt32 num; 584 585 if (!inFile.Read(buf.Buf, kBufSize, num)) 586 return SendMessageError_with_LastError("Read error", _CopyFile_Path); 587 588 if (num == 0) 589 return S_OK; 590 591 592 RINOK(WriteStream(outStream, buf.Buf, num)); 593 } 594 } 595 596 #endif 597 */ 598 599 STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) 600 { 601 COM_TRY_BEGIN 602 603 *outStream = NULL; 604 605 #ifndef _SFX 606 if (_hashStream) 607 _hashStreamSpec->ReleaseStream(); 608 _hashStreamWasUsed = false; 609 #endif 610 611 _outFileStream.Release(); 612 613 _encrypted = false; 614 _position = 0; 615 _isSplit = false; 616 617 _curSize = 0; 618 _curSizeDefined = false; 619 _index = index; 620 621 _diskFilePath.Empty(); 622 623 // _fi.Clear(); 624 625 #ifdef SUPPORT_LINKS 626 // _CopyFile_Path.Empty(); 627 linkPath.Empty(); 628 #endif 629 630 IInArchive *archive = _arc->Archive; 631 632 #ifndef _SFX 633 _item._use_baseParentFolder_mode = _use_baseParentFolder_mode; 634 if (_use_baseParentFolder_mode) 635 { 636 _item._baseParentFolder = _baseParentFolder; 637 if (_pathMode == NExtract::NPathMode::kFullPaths || 638 _pathMode == NExtract::NPathMode::kAbsPaths) 639 _item._baseParentFolder = -1; 640 } 641 #endif 642 643 #ifdef SUPPORT_ALT_STREAMS 644 _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon; 645 #endif 646 647 RINOK(_arc->GetItem(index, _item)); 648 649 { 650 NCOM::CPropVariant prop; 651 RINOK(archive->GetProperty(index, kpidPosition, &prop)); 652 if (prop.vt != VT_EMPTY) 653 { 654 if (prop.vt != VT_UI8) 655 return E_FAIL; 656 _position = prop.uhVal.QuadPart; 657 _isSplit = true; 658 } 659 } 660 661 #ifdef SUPPORT_LINKS 662 663 // bool isCopyLink = false; 664 bool isHardLink = false; 665 bool isJunction = false; 666 bool isRelative = false; 667 668 { 669 NCOM::CPropVariant prop; 670 RINOK(archive->GetProperty(index, kpidHardLink, &prop)); 671 if (prop.vt == VT_BSTR) 672 { 673 isHardLink = true; 674 // isCopyLink = false; 675 isRelative = false; // RAR5, TAR: hard links are from root folder of archive 676 linkPath.SetFromBstr(prop.bstrVal); 677 } 678 else if (prop.vt != VT_EMPTY) 679 return E_FAIL; 680 } 681 682 /* 683 { 684 NCOM::CPropVariant prop; 685 RINOK(archive->GetProperty(index, kpidCopyLink, &prop)); 686 if (prop.vt == VT_BSTR) 687 { 688 isHardLink = false; 689 isCopyLink = true; 690 isRelative = false; // RAR5: copy links are from root folder of archive 691 linkPath.SetFromBstr(prop.bstrVal); 692 } 693 else if (prop.vt != VT_EMPTY) 694 return E_FAIL; 695 } 696 */ 697 698 { 699 NCOM::CPropVariant prop; 700 RINOK(archive->GetProperty(index, kpidSymLink, &prop)); 701 if (prop.vt == VT_BSTR) 702 { 703 isHardLink = false; 704 // isCopyLink = false; 705 isRelative = true; // RAR5, TAR: symbolic links can be relative 706 linkPath.SetFromBstr(prop.bstrVal); 707 } 708 else if (prop.vt != VT_EMPTY) 709 return E_FAIL; 710 } 711 712 713 bool isOkReparse = false; 714 715 if (linkPath.IsEmpty() && _arc->GetRawProps) 716 { 717 const void *data; 718 UInt32 dataSize; 719 UInt32 propType; 720 721 _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); 722 723 if (dataSize != 0) 724 { 725 if (propType != NPropDataType::kRaw) 726 return E_FAIL; 727 UString s; 728 CReparseAttr reparse; 729 isOkReparse = reparse.Parse((const Byte *)data, dataSize); 730 if (isOkReparse) 731 { 732 isHardLink = false; 733 // isCopyLink = false; 734 linkPath = reparse.GetPath(); 735 isJunction = reparse.IsMountPoint(); 736 isRelative = reparse.IsRelative(); 737 #ifndef _WIN32 738 linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR); 739 #endif 740 } 741 } 742 } 743 744 if (!linkPath.IsEmpty()) 745 { 746 #ifdef _WIN32 747 linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR); 748 #endif 749 750 // rar5 uses "\??\" prefix for absolute links 751 if (linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR)) 752 { 753 isRelative = false; 754 linkPath.DeleteFrontal(4); 755 } 756 757 for (;;) 758 // while (NName::IsAbsolutePath(linkPath)) 759 { 760 unsigned n = NName::GetRootPrefixSize(linkPath); 761 if (n == 0) 762 break; 763 isRelative = false; 764 linkPath.DeleteFrontal(n); 765 } 766 } 767 768 if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0) 769 { 770 UStringVector pathParts; 771 SplitPathToParts(linkPath, pathParts); 772 bool badPrefix = false; 773 FOR_VECTOR (i, _removePathParts) 774 { 775 if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) 776 { 777 badPrefix = true; 778 break; 779 } 780 } 781 if (!badPrefix) 782 pathParts.DeleteFrontal(_removePathParts.Size()); 783 linkPath = MakePathFromParts(pathParts); 784 } 785 786 #endif 787 788 RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)); 789 790 RINOK(GetUnpackSize()); 791 792 #ifdef SUPPORT_ALT_STREAMS 793 794 if (!_ntOptions.AltStreams.Val && _item.IsAltStream) 795 return S_OK; 796 797 #endif 798 799 800 UStringVector &pathParts = _item.PathParts; 801 802 if (_wildcardCensor) 803 { 804 if (!CensorNode_CheckPath(*_wildcardCensor, _item)) 805 return S_OK; 806 } 807 808 #ifndef _SFX 809 if (_use_baseParentFolder_mode) 810 { 811 if (!pathParts.IsEmpty()) 812 { 813 unsigned numRemovePathParts = 0; 814 815 #ifdef SUPPORT_ALT_STREAMS 816 if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream) 817 numRemovePathParts = pathParts.Size(); 818 else 819 #endif 820 if (_pathMode == NExtract::NPathMode::kNoPaths || 821 _pathMode == NExtract::NPathMode::kNoPathsAlt) 822 numRemovePathParts = pathParts.Size() - 1; 823 pathParts.DeleteFrontal(numRemovePathParts); 824 } 825 } 826 else 827 #endif 828 { 829 if (pathParts.IsEmpty()) 830 { 831 if (_item.IsDir) 832 return S_OK; 833 /* 834 #ifdef SUPPORT_ALT_STREAMS 835 if (!_item.IsAltStream) 836 #endif 837 return E_FAIL; 838 */ 839 } 840 841 unsigned numRemovePathParts = 0; 842 843 switch (_pathMode) 844 { 845 case NExtract::NPathMode::kFullPaths: 846 case NExtract::NPathMode::kCurPaths: 847 { 848 if (_removePathParts.IsEmpty()) 849 break; 850 bool badPrefix = false; 851 852 if (pathParts.Size() < _removePathParts.Size()) 853 badPrefix = true; 854 else 855 { 856 if (pathParts.Size() == _removePathParts.Size()) 857 { 858 if (_removePartsForAltStreams) 859 { 860 #ifdef SUPPORT_ALT_STREAMS 861 if (!_item.IsAltStream) 862 #endif 863 badPrefix = true; 864 } 865 else 866 { 867 if (!_item.MainIsDir) 868 badPrefix = true; 869 } 870 } 871 872 if (!badPrefix) 873 FOR_VECTOR (i, _removePathParts) 874 { 875 if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0) 876 { 877 badPrefix = true; 878 break; 879 } 880 } 881 } 882 883 if (badPrefix) 884 { 885 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) 886 return E_FAIL; 887 } 888 else 889 numRemovePathParts = _removePathParts.Size(); 890 break; 891 } 892 893 case NExtract::NPathMode::kNoPaths: 894 { 895 if (!pathParts.IsEmpty()) 896 numRemovePathParts = pathParts.Size() - 1; 897 break; 898 } 899 case NExtract::NPathMode::kNoPathsAlt: 900 { 901 #ifdef SUPPORT_ALT_STREAMS 902 if (_item.IsAltStream) 903 numRemovePathParts = pathParts.Size(); 904 else 905 #endif 906 if (!pathParts.IsEmpty()) 907 numRemovePathParts = pathParts.Size() - 1; 908 break; 909 } 910 /* 911 case NExtract::NPathMode::kFullPaths: 912 case NExtract::NPathMode::kAbsPaths: 913 break; 914 */ 915 } 916 917 pathParts.DeleteFrontal(numRemovePathParts); 918 } 919 920 #ifndef _SFX 921 922 if (ExtractToStreamCallback) 923 { 924 if (!GetProp) 925 { 926 GetProp_Spec = new CGetProp; 927 GetProp = GetProp_Spec; 928 } 929 GetProp_Spec->Arc = _arc; 930 GetProp_Spec->IndexInArc = index; 931 UString name = MakePathFromParts(pathParts); 932 933 #ifdef SUPPORT_ALT_STREAMS 934 if (_item.IsAltStream) 935 { 936 if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt)) 937 name += L':'; 938 name += _item.AltStreamName; 939 } 940 #endif 941 942 return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp); 943 } 944 945 #endif 946 947 CMyComPtr<ISequentialOutStream> outStreamLoc; 948 949 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) 950 { 951 if (_stdOutMode) 952 { 953 outStreamLoc = new CStdOutFileStream; 954 } 955 else 956 { 957 { 958 NCOM::CPropVariant prop; 959 RINOK(archive->GetProperty(index, kpidAttrib, &prop)); 960 if (prop.vt == VT_UI4) 961 { 962 _fi.Attrib = prop.ulVal; 963 _fi.AttribDefined = true; 964 } 965 else if (prop.vt == VT_EMPTY) 966 _fi.AttribDefined = false; 967 else 968 return E_FAIL; 969 } 970 971 RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); 972 RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); 973 RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); 974 975 bool isAnti = false; 976 RINOK(_arc->IsItemAnti(index, isAnti)); 977 978 #ifdef SUPPORT_ALT_STREAMS 979 if (!_item.IsAltStream 980 || !pathParts.IsEmpty() 981 || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)) 982 #endif 983 Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir); 984 985 #ifdef SUPPORT_ALT_STREAMS 986 987 if (_item.IsAltStream) 988 { 989 UString s = _item.AltStreamName; 990 Correct_AltStream_Name(s); 991 bool needColon = true; 992 993 if (pathParts.IsEmpty()) 994 { 995 pathParts.AddNew(); 996 if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt) 997 needColon = false; 998 } 999 else if (_pathMode == NExtract::NPathMode::kAbsPaths && 1000 NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size()) 1001 pathParts.AddNew(); 1002 1003 UString &name = pathParts.Back(); 1004 if (needColon) 1005 name += (wchar_t)(_ntOptions.ReplaceColonForAltStream ? L'_' : L':'); 1006 name += s; 1007 } 1008 1009 #endif 1010 1011 UString processedPath = MakePathFromParts(pathParts); 1012 1013 if (!isAnti) 1014 { 1015 if (!_item.IsDir) 1016 { 1017 if (!pathParts.IsEmpty()) 1018 pathParts.DeleteBack(); 1019 } 1020 1021 if (!pathParts.IsEmpty()) 1022 { 1023 FString fullPathNew; 1024 CreateComplexDirectory(pathParts, fullPathNew); 1025 if (_item.IsDir) 1026 { 1027 _extractedFolderPaths.Add(fullPathNew); 1028 _extractedFolderIndices.Add(index); 1029 SetDirTime(fullPathNew, 1030 (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, 1031 (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, 1032 (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); 1033 } 1034 } 1035 } 1036 1037 1038 FString fullProcessedPath = us2fs(processedPath); 1039 if (_pathMode != NExtract::NPathMode::kAbsPaths 1040 || !NName::IsAbsolutePath(processedPath)) 1041 { 1042 fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath); 1043 } 1044 1045 #ifdef SUPPORT_ALT_STREAMS 1046 1047 if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1) 1048 { 1049 int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex)); 1050 if (renIndex >= 0) 1051 { 1052 const CIndexToPathPair &pair = _renamedFiles[renIndex]; 1053 fullProcessedPath = pair.Path; 1054 fullProcessedPath += (FChar)':'; 1055 UString s = _item.AltStreamName; 1056 Correct_AltStream_Name(s); 1057 fullProcessedPath += us2fs(s); 1058 } 1059 } 1060 1061 #endif 1062 1063 bool isRenamed = false; 1064 1065 if (_item.IsDir) 1066 { 1067 _diskFilePath = fullProcessedPath; 1068 if (isAnti) 1069 RemoveDir(_diskFilePath); 1070 #ifdef SUPPORT_LINKS 1071 if (linkPath.IsEmpty()) 1072 #endif 1073 return S_OK; 1074 } 1075 else if (!_isSplit) 1076 { 1077 1078 // ----- Is file (not split) ----- 1079 NFind::CFileInfo fileInfo; 1080 if (fileInfo.Find(fullProcessedPath)) 1081 { 1082 switch (_overwriteMode) 1083 { 1084 case NExtract::NOverwriteMode::kSkip: 1085 return S_OK; 1086 case NExtract::NOverwriteMode::kAsk: 1087 { 1088 int slashPos = fullProcessedPath.ReverseFind_PathSepar(); 1089 FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name; 1090 1091 Int32 overwriteResult; 1092 RINOK(_extractCallback2->AskOverwrite( 1093 fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path, 1094 _fi.MTimeDefined ? &_fi.MTime : NULL, 1095 _curSizeDefined ? &_curSize : NULL, 1096 &overwriteResult)) 1097 1098 switch (overwriteResult) 1099 { 1100 case NOverwriteAnswer::kCancel: return E_ABORT; 1101 case NOverwriteAnswer::kNo: return S_OK; 1102 case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; 1103 case NOverwriteAnswer::kYes: break; 1104 case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break; 1105 case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break; 1106 default: 1107 return E_FAIL; 1108 } 1109 } 1110 } 1111 if (_overwriteMode == NExtract::NOverwriteMode::kRename) 1112 { 1113 if (!AutoRenamePath(fullProcessedPath)) 1114 { 1115 RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); 1116 return E_FAIL; 1117 } 1118 isRenamed = true; 1119 } 1120 else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting) 1121 { 1122 FString existPath = fullProcessedPath; 1123 if (!AutoRenamePath(existPath)) 1124 { 1125 RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); 1126 return E_FAIL; 1127 } 1128 // MyMoveFile can raname folders. So it's OK to use it for folders too 1129 if (!MyMoveFile(fullProcessedPath, existPath)) 1130 { 1131 RINOK(SendMessageError2(kCantRenameFile, existPath, fullProcessedPath)); 1132 return E_FAIL; 1133 } 1134 } 1135 else 1136 { 1137 if (fileInfo.IsDir()) 1138 { 1139 // do we need to delete all files in folder? 1140 if (!RemoveDir(fullProcessedPath)) 1141 { 1142 RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath)); 1143 return S_OK; 1144 } 1145 } 1146 else 1147 { 1148 bool needDelete = true; 1149 if (needDelete) 1150 { 1151 if (!DeleteFileAlways(fullProcessedPath)) 1152 { 1153 RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath)); 1154 return S_OK; 1155 // return E_FAIL; 1156 } 1157 } 1158 } 1159 } 1160 } 1161 else // not Find(fullProcessedPath) 1162 { 1163 // we need to clear READ-ONLY of parent before creating alt stream 1164 #if defined(_WIN32) && !defined(UNDER_CE) 1165 int colonPos = NName::FindAltStreamColon(fullProcessedPath); 1166 if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0) 1167 { 1168 FString parentFsPath = fullProcessedPath; 1169 parentFsPath.DeleteFrom(colonPos); 1170 NFind::CFileInfo parentFi; 1171 if (parentFi.Find(parentFsPath)) 1172 { 1173 if (parentFi.IsReadOnly()) 1174 SetFileAttrib(parentFsPath, parentFi.Attrib & ~FILE_ATTRIBUTE_READONLY); 1175 } 1176 } 1177 #endif 1178 } 1179 // ----- END of code for Is file (not split) ----- 1180 1181 } 1182 _diskFilePath = fullProcessedPath; 1183 1184 1185 if (!isAnti) 1186 { 1187 #ifdef SUPPORT_LINKS 1188 1189 if (!linkPath.IsEmpty()) 1190 { 1191 #ifndef UNDER_CE 1192 1193 UString relatPath; 1194 if (isRelative) 1195 relatPath = GetDirPrefixOf(_item.Path); 1196 relatPath += linkPath; 1197 1198 if (!IsSafePath(relatPath)) 1199 { 1200 RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath))); 1201 } 1202 else 1203 { 1204 FString existPath; 1205 if (isHardLink /* || isCopyLink */ || !isRelative) 1206 { 1207 if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath)) 1208 { 1209 RINOK(SendMessageError("Incorrect path", us2fs(relatPath))); 1210 } 1211 } 1212 else 1213 { 1214 existPath = us2fs(linkPath); 1215 } 1216 1217 if (!existPath.IsEmpty()) 1218 { 1219 if (isHardLink /* || isCopyLink */) 1220 { 1221 // if (isHardLink) 1222 { 1223 if (!MyCreateHardLink(fullProcessedPath, existPath)) 1224 { 1225 RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath)); 1226 // return S_OK; 1227 } 1228 } 1229 /* 1230 else 1231 { 1232 NFind::CFileInfo fi; 1233 if (!fi.Find(existPath)) 1234 { 1235 RINOK(SendMessageError2("Can not find the file for copying", existPath, fullProcessedPath)); 1236 } 1237 else 1238 { 1239 if (_curSizeDefined && _curSize == fi.Size) 1240 _CopyFile_Path = existPath; 1241 else 1242 { 1243 RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath)); 1244 } 1245 1246 // RINOK(MyCopyFile(existPath, fullProcessedPath)); 1247 } 1248 } 1249 */ 1250 } 1251 else if (_ntOptions.SymLinks.Val) 1252 { 1253 // bool isSymLink = true; // = false for junction 1254 if (_item.IsDir && !isRelative) 1255 { 1256 // if it's before Vista we use Junction Point 1257 // isJunction = true; 1258 // convertToAbs = true; 1259 } 1260 1261 CByteBuffer data; 1262 if (FillLinkData(data, fs2us(existPath), !isJunction)) 1263 { 1264 CReparseAttr attr; 1265 if (!attr.Parse(data, data.Size())) 1266 { 1267 RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path))); 1268 // return E_FAIL; 1269 } 1270 else 1271 if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size())) 1272 { 1273 RINOK(SendMessageError_with_LastError("Can not create symbolic link", fullProcessedPath)); 1274 } 1275 } 1276 } 1277 } 1278 } 1279 1280 #endif 1281 } 1282 1283 if (linkPath.IsEmpty() /* || !_CopyFile_Path.IsEmpty() */) 1284 #endif // SUPPORT_LINKS 1285 { 1286 bool needWriteFile = true; 1287 1288 #ifdef SUPPORT_LINKS 1289 if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream) 1290 { 1291 CHardLinkNode h; 1292 bool defined; 1293 RINOK(Archive_Get_HardLinkNode(archive, index, h, defined)); 1294 if (defined) 1295 { 1296 { 1297 int linkIndex = _hardLinks.IDs.FindInSorted2(h); 1298 if (linkIndex >= 0) 1299 { 1300 FString &hl = _hardLinks.Links[linkIndex]; 1301 if (hl.IsEmpty()) 1302 hl = fullProcessedPath; 1303 else 1304 { 1305 if (!MyCreateHardLink(fullProcessedPath, hl)) 1306 { 1307 RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, hl)); 1308 return S_OK; 1309 } 1310 needWriteFile = false; 1311 } 1312 } 1313 } 1314 } 1315 } 1316 #endif 1317 1318 if (needWriteFile) 1319 { 1320 _outFileStreamSpec = new COutFileStream; 1321 CMyComPtr<ISequentialOutStream> outStreamLoc2(_outFileStreamSpec); 1322 if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS)) 1323 { 1324 // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit) 1325 { 1326 RINOK(SendMessageError_with_LastError("Can not open output file", fullProcessedPath)); 1327 return S_OK; 1328 } 1329 } 1330 1331 1332 #ifdef SUPPORT_ALT_STREAMS 1333 if (isRenamed && !_item.IsAltStream) 1334 { 1335 CIndexToPathPair pair(index, fullProcessedPath); 1336 unsigned oldSize = _renamedFiles.Size(); 1337 unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair); 1338 if (oldSize == _renamedFiles.Size()) 1339 _renamedFiles[insertIndex].Path = fullProcessedPath; 1340 } 1341 #endif 1342 1343 if (_isSplit) 1344 { 1345 RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); 1346 } 1347 1348 _outFileStream = outStreamLoc2; 1349 } 1350 } 1351 } 1352 1353 outStreamLoc = _outFileStream; 1354 } 1355 } 1356 1357 #ifndef _SFX 1358 1359 if (_hashStream) 1360 { 1361 if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || 1362 askExtractMode == NArchive::NExtract::NAskMode::kTest) 1363 { 1364 _hashStreamSpec->SetStream(outStreamLoc); 1365 outStreamLoc = _hashStream; 1366 _hashStreamSpec->Init(true); 1367 _hashStreamWasUsed = true; 1368 } 1369 } 1370 1371 #endif 1372 1373 1374 if (outStreamLoc) 1375 { 1376 /* 1377 #ifdef SUPPORT_LINKS 1378 1379 if (!_CopyFile_Path.IsEmpty()) 1380 { 1381 RINOK(PrepareOperation(askExtractMode)); 1382 RINOK(MyCopyFile(outStreamLoc)); 1383 return SetOperationResult(NArchive::NExtract::NOperationResult::kOK); 1384 } 1385 1386 if (isCopyLink && _testMode) 1387 return S_OK; 1388 1389 #endif 1390 */ 1391 1392 *outStream = outStreamLoc.Detach(); 1393 } 1394 1395 return S_OK; 1396 1397 COM_TRY_END 1398 } 1399 1400 1401 STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) 1402 { 1403 COM_TRY_BEGIN 1404 1405 #ifndef _SFX 1406 if (ExtractToStreamCallback) 1407 return ExtractToStreamCallback->PrepareOperation7(askExtractMode); 1408 #endif 1409 1410 _extractMode = false; 1411 1412 switch (askExtractMode) 1413 { 1414 case NArchive::NExtract::NAskMode::kExtract: 1415 if (_testMode) 1416 askExtractMode = NArchive::NExtract::NAskMode::kTest; 1417 else 1418 _extractMode = true; 1419 break; 1420 }; 1421 1422 return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir), 1423 askExtractMode, _isSplit ? &_position: 0); 1424 1425 COM_TRY_END 1426 } 1427 1428 1429 STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes) 1430 { 1431 COM_TRY_BEGIN 1432 1433 #ifndef _SFX 1434 if (ExtractToStreamCallback) 1435 return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted)); 1436 #endif 1437 1438 #ifndef _SFX 1439 1440 if (_hashStreamWasUsed) 1441 { 1442 _hashStreamSpec->_hash->Final(_item.IsDir, 1443 #ifdef SUPPORT_ALT_STREAMS 1444 _item.IsAltStream 1445 #else 1446 false 1447 #endif 1448 , _item.Path); 1449 _curSize = _hashStreamSpec->GetSize(); 1450 _curSizeDefined = true; 1451 _hashStreamSpec->ReleaseStream(); 1452 _hashStreamWasUsed = false; 1453 } 1454 1455 #endif 1456 1457 if (_outFileStream) 1458 { 1459 _outFileStreamSpec->SetTime( 1460 (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL, 1461 (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL, 1462 (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); 1463 _curSize = _outFileStreamSpec->ProcessedSize; 1464 _curSizeDefined = true; 1465 RINOK(_outFileStreamSpec->Close()); 1466 _outFileStream.Release(); 1467 } 1468 1469 #ifdef _USE_SECURITY_CODE 1470 if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps) 1471 { 1472 const void *data; 1473 UInt32 dataSize; 1474 UInt32 propType; 1475 _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType); 1476 if (dataSize != 0) 1477 { 1478 if (propType != NPropDataType::kRaw) 1479 return E_FAIL; 1480 if (CheckNtSecure((const Byte *)data, dataSize)) 1481 { 1482 SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION; 1483 if (_saclEnabled) 1484 securInfo |= SACL_SECURITY_INFORMATION; 1485 ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data); 1486 } 1487 } 1488 } 1489 #endif 1490 1491 if (!_curSizeDefined) 1492 GetUnpackSize(); 1493 1494 if (_curSizeDefined) 1495 { 1496 #ifdef SUPPORT_ALT_STREAMS 1497 if (_item.IsAltStream) 1498 AltStreams_UnpackSize += _curSize; 1499 else 1500 #endif 1501 UnpackSize += _curSize; 1502 } 1503 1504 if (_item.IsDir) 1505 NumFolders++; 1506 #ifdef SUPPORT_ALT_STREAMS 1507 else if (_item.IsAltStream) 1508 NumAltStreams++; 1509 #endif 1510 else 1511 NumFiles++; 1512 1513 if (!_stdOutMode && _extractMode && _fi.AttribDefined) 1514 SetFileAttrib(_diskFilePath, _fi.Attrib); 1515 1516 RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted))); 1517 1518 return S_OK; 1519 1520 COM_TRY_END 1521 } 1522 1523 STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes) 1524 { 1525 if (_folderArchiveExtractCallback2) 1526 { 1527 bool isEncrypted = false; 1528 wchar_t temp[16]; 1529 UString s2; 1530 const wchar_t *s = NULL; 1531 1532 if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1) 1533 { 1534 CReadArcItem item; 1535 RINOK(_arc->GetItem(index, item)); 1536 s2 = item.Path; 1537 s = s2; 1538 RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted)); 1539 } 1540 else 1541 { 1542 temp[0] = '#'; 1543 ConvertUInt32ToString(index, temp + 1); 1544 s = temp; 1545 // if (indexType == NArchive::NEventIndexType::kBlockIndex) {} 1546 } 1547 1548 return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s); 1549 } 1550 1551 return S_OK; 1552 } 1553 1554 1555 STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) 1556 { 1557 COM_TRY_BEGIN 1558 if (!_cryptoGetTextPassword) 1559 { 1560 RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, 1561 &_cryptoGetTextPassword)); 1562 } 1563 return _cryptoGetTextPassword->CryptoGetTextPassword(password); 1564 COM_TRY_END 1565 } 1566 1567 1568 struct CExtrRefSortPair 1569 { 1570 unsigned Len; 1571 unsigned Index; 1572 1573 int Compare(const CExtrRefSortPair &a) const; 1574 }; 1575 1576 #define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } 1577 1578 int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const 1579 { 1580 RINOZ(-MyCompare(Len, a.Len)); 1581 return MyCompare(Index, a.Index); 1582 } 1583 1584 static unsigned GetNumSlashes(const FChar *s) 1585 { 1586 for (unsigned numSlashes = 0;;) 1587 { 1588 FChar c = *s++; 1589 if (c == 0) 1590 return numSlashes; 1591 if (IS_PATH_SEPAR(c)) 1592 numSlashes++; 1593 } 1594 } 1595 1596 HRESULT CArchiveExtractCallback::SetDirsTimes() 1597 { 1598 CRecordVector<CExtrRefSortPair> pairs; 1599 pairs.ClearAndSetSize(_extractedFolderPaths.Size()); 1600 unsigned i; 1601 1602 for (i = 0; i < _extractedFolderPaths.Size(); i++) 1603 { 1604 CExtrRefSortPair &pair = pairs[i]; 1605 pair.Index = i; 1606 pair.Len = GetNumSlashes(_extractedFolderPaths[i]); 1607 } 1608 1609 pairs.Sort2(); 1610 1611 for (i = 0; i < pairs.Size(); i++) 1612 { 1613 int pairIndex = pairs[i].Index; 1614 int index = _extractedFolderIndices[pairIndex]; 1615 1616 FILETIME CTime; 1617 FILETIME ATime; 1618 FILETIME MTime; 1619 1620 bool CTimeDefined; 1621 bool ATimeDefined; 1622 bool MTimeDefined; 1623 1624 RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined)); 1625 RINOK(GetTime(index, kpidATime, ATime, ATimeDefined)); 1626 RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined)); 1627 1628 // printf("\n%S", _extractedFolderPaths[pairIndex]); 1629 SetDirTime(_extractedFolderPaths[pairIndex], 1630 (WriteCTime && CTimeDefined) ? &CTime : NULL, 1631 (WriteATime && ATimeDefined) ? &ATime : NULL, 1632 (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL)); 1633 } 1634 return S_OK; 1635 } 1636