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