1 // UpdateCallback.cpp 2 3 #include "StdAfx.h" 4 5 #ifndef _7ZIP_ST 6 #include "../../../Windows/Synchronization.h" 7 #endif 8 9 #include "../../../Common/ComTry.h" 10 #include "../../../Common/IntToString.h" 11 #include "../../../Common/StringConvert.h" 12 #include "../../../Common/Wildcard.h" 13 14 #include "../../../Windows/FileDir.h" 15 #include "../../../Windows/FileName.h" 16 #include "../../../Windows/PropVariant.h" 17 18 #include "../../Common/StreamObjects.h" 19 20 #include "UpdateCallback.h" 21 22 #if defined(_WIN32) && !defined(UNDER_CE) 23 #define _USE_SECURITY_CODE 24 #include "../../../Windows/SecurityUtils.h" 25 #endif 26 27 using namespace NWindows; 28 using namespace NFile; 29 30 #ifndef _7ZIP_ST 31 static NSynchronization::CCriticalSection g_CriticalSection; 32 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); 33 #else 34 #define MT_LOCK 35 #endif 36 37 38 #ifdef _USE_SECURITY_CODE 39 bool InitLocalPrivileges(); 40 #endif 41 42 CArchiveUpdateCallback::CArchiveUpdateCallback(): 43 _hardIndex_From((UInt32)(Int32)-1), 44 45 Callback(NULL), 46 47 DirItems(NULL), 48 ParentDirItem(NULL), 49 50 Arc(NULL), 51 ArcItems(NULL), 52 UpdatePairs(NULL), 53 NewNames(NULL), 54 CommentIndex(-1), 55 Comment(NULL), 56 57 ShareForWrite(false), 58 StopAfterOpenError(false), 59 StdInMode(false), 60 61 KeepOriginalItemNames(false), 62 StoreNtSecurity(false), 63 StoreHardLinks(false), 64 StoreSymLinks(false), 65 66 ProcessedItemsStatuses(NULL) 67 { 68 #ifdef _USE_SECURITY_CODE 69 _saclEnabled = InitLocalPrivileges(); 70 #endif 71 } 72 73 74 STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size) 75 { 76 COM_TRY_BEGIN 77 return Callback->SetTotal(size); 78 COM_TRY_END 79 } 80 81 STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue) 82 { 83 COM_TRY_BEGIN 84 return Callback->SetCompleted(completeValue); 85 COM_TRY_END 86 } 87 88 STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) 89 { 90 COM_TRY_BEGIN 91 return Callback->SetRatioInfo(inSize, outSize); 92 COM_TRY_END 93 } 94 95 96 /* 97 static const CStatProp kProps[] = 98 { 99 { NULL, kpidPath, VT_BSTR}, 100 { NULL, kpidIsDir, VT_BOOL}, 101 { NULL, kpidSize, VT_UI8}, 102 { NULL, kpidCTime, VT_FILETIME}, 103 { NULL, kpidATime, VT_FILETIME}, 104 { NULL, kpidMTime, VT_FILETIME}, 105 { NULL, kpidAttrib, VT_UI4}, 106 { NULL, kpidIsAnti, VT_BOOL} 107 }; 108 109 STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) 110 { 111 return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator); 112 } 113 */ 114 115 STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, 116 Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) 117 { 118 COM_TRY_BEGIN 119 RINOK(Callback->CheckBreak()); 120 const CUpdatePair2 &up = (*UpdatePairs)[index]; 121 if (newData) *newData = BoolToInt(up.NewData); 122 if (newProps) *newProps = BoolToInt(up.NewProps); 123 if (indexInArchive) 124 { 125 *indexInArchive = (UInt32)(Int32)-1; 126 if (up.ExistInArchive()) 127 *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer; 128 } 129 return S_OK; 130 COM_TRY_END 131 } 132 133 STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value) 134 { 135 NCOM::CPropVariant prop; 136 switch (propID) 137 { 138 case kpidIsDir: prop = true; break; 139 case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break; 140 case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break; 141 case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break; 142 case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break; 143 } 144 prop.Detach(value); 145 return S_OK; 146 } 147 148 STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType) 149 { 150 *parentType = NParentType::kDir; 151 *parent = (UInt32)(Int32)-1; 152 return S_OK; 153 } 154 155 STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps) 156 { 157 *numProps = 0; 158 if (StoreNtSecurity) 159 *numProps = 1; 160 return S_OK; 161 } 162 163 STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID) 164 { 165 *name = NULL; 166 *propID = kpidNtSecure; 167 return S_OK; 168 } 169 170 STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID 171 #ifdef _USE_SECURITY_CODE 172 propID 173 #endif 174 , const void **data, UInt32 *dataSize, UInt32 *propType) 175 { 176 *data = 0; 177 *dataSize = 0; 178 *propType = 0; 179 if (!StoreNtSecurity) 180 return S_OK; 181 #ifdef _USE_SECURITY_CODE 182 if (propID == kpidNtSecure) 183 { 184 if (StdInMode) 185 return S_OK; 186 187 if (ParentDirItem) 188 { 189 if (ParentDirItem->SecureIndex < 0) 190 return S_OK; 191 const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex]; 192 *data = buf; 193 *dataSize = (UInt32)buf.Size(); 194 *propType = NPropDataType::kRaw; 195 return S_OK; 196 } 197 198 if (Arc && Arc->GetRootProps) 199 return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType); 200 } 201 #endif 202 return S_OK; 203 } 204 205 // #ifdef _USE_SECURITY_CODE 206 // #endif 207 208 STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) 209 { 210 *data = 0; 211 *dataSize = 0; 212 *propType = 0; 213 214 if (propID == kpidNtSecure || 215 propID == kpidNtReparse) 216 { 217 if (StdInMode) 218 return S_OK; 219 220 const CUpdatePair2 &up = (*UpdatePairs)[index]; 221 if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps) 222 return Arc->GetRawProps->GetRawProp( 223 ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, 224 propID, data, dataSize, propType); 225 { 226 /* 227 if (!up.NewData) 228 return E_FAIL; 229 */ 230 if (up.IsAnti) 231 return S_OK; 232 233 #ifndef UNDER_CE 234 const CDirItem &di = DirItems->Items[up.DirIndex]; 235 #endif 236 237 #ifdef _USE_SECURITY_CODE 238 if (propID == kpidNtSecure) 239 { 240 if (!StoreNtSecurity) 241 return S_OK; 242 if (di.SecureIndex < 0) 243 return S_OK; 244 const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex]; 245 *data = buf; 246 *dataSize = (UInt32)buf.Size(); 247 *propType = NPropDataType::kRaw; 248 } 249 else 250 #endif 251 { 252 // propID == kpidNtReparse 253 if (!StoreSymLinks) 254 return S_OK; 255 #ifndef UNDER_CE 256 const CByteBuffer *buf = &di.ReparseData2; 257 if (buf->Size() == 0) 258 buf = &di.ReparseData; 259 if (buf->Size() != 0) 260 { 261 *data = *buf; 262 *dataSize = (UInt32)buf->Size(); 263 *propType = NPropDataType::kRaw; 264 } 265 #endif 266 } 267 268 return S_OK; 269 } 270 } 271 272 return S_OK; 273 } 274 275 #ifndef UNDER_CE 276 277 static UString GetRelativePath(const UString &to, const UString &from) 278 { 279 UStringVector partsTo, partsFrom; 280 SplitPathToParts(to, partsTo); 281 SplitPathToParts(from, partsFrom); 282 283 unsigned i; 284 for (i = 0;; i++) 285 { 286 if (i + 1 >= partsFrom.Size() || 287 i + 1 >= partsTo.Size()) 288 break; 289 if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) 290 break; 291 } 292 293 if (i == 0) 294 { 295 #ifdef _WIN32 296 if (NName::IsDrivePath(to) || 297 NName::IsDrivePath(from)) 298 return to; 299 #endif 300 } 301 302 UString s; 303 unsigned k; 304 305 for (k = i + 1; k < partsFrom.Size(); k++) 306 s += ".." STRING_PATH_SEPARATOR; 307 308 for (k = i; k < partsTo.Size(); k++) 309 { 310 if (k != i) 311 s.Add_PathSepar(); 312 s += partsTo[k]; 313 } 314 315 return s; 316 } 317 318 #endif 319 320 STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) 321 { 322 COM_TRY_BEGIN 323 const CUpdatePair2 &up = (*UpdatePairs)[index]; 324 NCOM::CPropVariant prop; 325 326 if (up.NewData) 327 { 328 /* 329 if (propID == kpidIsHardLink) 330 { 331 prop = _isHardLink; 332 prop.Detach(value); 333 return S_OK; 334 } 335 */ 336 if (propID == kpidSymLink) 337 { 338 if (index == _hardIndex_From) 339 { 340 prop.Detach(value); 341 return S_OK; 342 } 343 if (up.DirIndex >= 0) 344 { 345 #ifndef UNDER_CE 346 const CDirItem &di = DirItems->Items[up.DirIndex]; 347 // if (di.IsDir()) 348 { 349 CReparseAttr attr; 350 DWORD errorCode = 0; 351 if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode)) 352 { 353 UString simpleName = attr.GetPath(); 354 if (attr.IsRelative()) 355 prop = simpleName; 356 else 357 { 358 const FString phyPath = DirItems->GetPhyPath(up.DirIndex); 359 FString fullPath; 360 if (NDir::MyGetFullPathName(phyPath, fullPath)) 361 { 362 prop = GetRelativePath(simpleName, fs2us(fullPath)); 363 } 364 } 365 prop.Detach(value); 366 return S_OK; 367 } 368 } 369 #endif 370 } 371 } 372 else if (propID == kpidHardLink) 373 { 374 if (index == _hardIndex_From) 375 { 376 const CKeyKeyValPair &pair = _map[_hardIndex_To]; 377 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; 378 prop = DirItems->GetLogPath(up2.DirIndex); 379 prop.Detach(value); 380 return S_OK; 381 } 382 if (up.DirIndex >= 0) 383 { 384 prop.Detach(value); 385 return S_OK; 386 } 387 } 388 } 389 390 if (up.IsAnti 391 && propID != kpidIsDir 392 && propID != kpidPath 393 && propID != kpidIsAltStream) 394 { 395 switch (propID) 396 { 397 case kpidSize: prop = (UInt64)0; break; 398 case kpidIsAnti: prop = true; break; 399 } 400 } 401 else if (propID == kpidPath && up.NewNameIndex >= 0) 402 prop = (*NewNames)[up.NewNameIndex]; 403 else if (propID == kpidComment 404 && CommentIndex >= 0 405 && (unsigned)CommentIndex == index 406 && Comment) 407 prop = *Comment; 408 else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) 409 { 410 // we can generate new ShortName here; 411 } 412 else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) 413 && up.ExistInArchive() && Archive) 414 return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value); 415 else if (up.ExistOnDisk()) 416 { 417 const CDirItem &di = DirItems->Items[up.DirIndex]; 418 switch (propID) 419 { 420 case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break; 421 case kpidIsDir: prop = di.IsDir(); break; 422 case kpidSize: prop = di.IsDir() ? (UInt64)0 : di.Size; break; 423 case kpidAttrib: prop = di.Attrib; break; 424 case kpidCTime: prop = di.CTime; break; 425 case kpidATime: prop = di.ATime; break; 426 case kpidMTime: prop = di.MTime; break; 427 case kpidIsAltStream: prop = di.IsAltStream; break; 428 #if defined(_WIN32) && !defined(UNDER_CE) 429 // case kpidShortName: prop = di.ShortName; break; 430 #endif 431 } 432 } 433 prop.Detach(value); 434 return S_OK; 435 COM_TRY_END 436 } 437 438 #ifndef _7ZIP_ST 439 static NSynchronization::CCriticalSection CS; 440 #endif 441 442 STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode) 443 { 444 COM_TRY_BEGIN 445 *inStream = NULL; 446 const CUpdatePair2 &up = (*UpdatePairs)[index]; 447 if (!up.NewData) 448 return E_FAIL; 449 450 RINOK(Callback->CheckBreak()); 451 // RINOK(Callback->Finalize()); 452 453 bool isDir = IsDir(up); 454 455 if (up.IsAnti) 456 { 457 UString name; 458 if (up.ArcIndex >= 0) 459 name = (*ArcItems)[up.ArcIndex].Name; 460 else if (up.DirIndex >= 0) 461 name = DirItems->GetLogPath(up.DirIndex); 462 RINOK(Callback->GetStream(name, isDir, true, mode)); 463 464 /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. 465 so we return empty stream */ 466 467 if (!isDir) 468 { 469 CBufInStream *inStreamSpec = new CBufInStream(); 470 CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec; 471 inStreamSpec->Init(NULL, 0); 472 *inStream = inStreamLoc.Detach(); 473 } 474 return S_OK; 475 } 476 477 RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode)); 478 479 if (isDir) 480 return S_OK; 481 482 if (StdInMode) 483 { 484 if (mode != NUpdateNotifyOp::kAdd && 485 mode != NUpdateNotifyOp::kUpdate) 486 return S_OK; 487 488 CStdInFileStream *inStreamSpec = new CStdInFileStream; 489 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 490 *inStream = inStreamLoc.Detach(); 491 } 492 else 493 { 494 CInFileStream *inStreamSpec = new CInFileStream; 495 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 496 497 inStreamSpec->SupportHardLinks = StoreHardLinks; 498 inStreamSpec->Callback = this; 499 inStreamSpec->CallbackRef = index; 500 501 const FString path = DirItems->GetPhyPath(up.DirIndex); 502 _openFiles_Indexes.Add(index); 503 _openFiles_Paths.Add(path); 504 505 #if defined(_WIN32) && !defined(UNDER_CE) 506 if (DirItems->Items[up.DirIndex].AreReparseData()) 507 { 508 if (!inStreamSpec->File.OpenReparse(path)) 509 { 510 return Callback->OpenFileError(path, ::GetLastError()); 511 } 512 } 513 else 514 #endif 515 if (!inStreamSpec->OpenShared(path, ShareForWrite)) 516 { 517 DWORD error = ::GetLastError(); 518 HRESULT hres = Callback->OpenFileError(path, error); 519 if (StopAfterOpenError) 520 if (hres == S_OK || hres == S_FALSE) 521 return HRESULT_FROM_WIN32(error); 522 return hres; 523 } 524 525 if (StoreHardLinks) 526 { 527 CStreamFileProps props; 528 if (inStreamSpec->GetProps2(&props) == S_OK) 529 { 530 if (props.NumLinks > 1) 531 { 532 CKeyKeyValPair pair; 533 pair.Key1 = props.VolID; 534 pair.Key2 = props.FileID_Low; 535 pair.Value = index; 536 unsigned numItems = _map.Size(); 537 unsigned pairIndex = _map.AddToUniqueSorted2(pair); 538 if (numItems == _map.Size()) 539 { 540 // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; 541 _hardIndex_From = index; 542 _hardIndex_To = pairIndex; 543 // we could return NULL as stream, but it's better to return real stream 544 // return S_OK; 545 } 546 } 547 } 548 } 549 550 if (ProcessedItemsStatuses) 551 { 552 #ifndef _7ZIP_ST 553 NSynchronization::CCriticalSectionLock lock(CS); 554 #endif 555 ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1; 556 } 557 *inStream = inStreamLoc.Detach(); 558 } 559 560 return S_OK; 561 COM_TRY_END 562 } 563 564 STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes) 565 { 566 COM_TRY_BEGIN 567 return Callback->SetOperationResult(opRes); 568 COM_TRY_END 569 } 570 571 STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream) 572 { 573 COM_TRY_BEGIN 574 return GetStream2(index, inStream, 575 (*UpdatePairs)[index].ArcIndex < 0 ? 576 NUpdateNotifyOp::kAdd : 577 NUpdateNotifyOp::kUpdate); 578 COM_TRY_END 579 } 580 581 STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op) 582 { 583 COM_TRY_BEGIN 584 585 bool isDir = false; 586 587 if (indexType == NArchive::NEventIndexType::kOutArcIndex) 588 { 589 UString name; 590 if (index != (UInt32)(Int32)-1) 591 { 592 const CUpdatePair2 &up = (*UpdatePairs)[index]; 593 if (up.ExistOnDisk()) 594 { 595 name = DirItems->GetLogPath(up.DirIndex); 596 isDir = DirItems->Items[up.DirIndex].IsDir(); 597 } 598 } 599 return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); 600 } 601 602 wchar_t temp[16]; 603 UString s2; 604 const wchar_t *s = NULL; 605 606 if (indexType == NArchive::NEventIndexType::kInArcIndex) 607 { 608 if (index != (UInt32)(Int32)-1) 609 { 610 if (ArcItems) 611 { 612 const CArcItem &ai = (*ArcItems)[index]; 613 s = ai.Name; 614 isDir = ai.IsDir; 615 } 616 else if (Arc) 617 { 618 RINOK(Arc->GetItemPath(index, s2)); 619 s = s2; 620 RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)); 621 } 622 } 623 } 624 else if (indexType == NArchive::NEventIndexType::kBlockIndex) 625 { 626 temp[0] = '#'; 627 ConvertUInt32ToString(index, temp + 1); 628 s = temp; 629 } 630 631 if (!s) 632 s = L""; 633 634 return Callback->ReportUpdateOpeartion(op, s, isDir); 635 636 COM_TRY_END 637 } 638 639 STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes) 640 { 641 COM_TRY_BEGIN 642 643 bool isEncrypted = false; 644 wchar_t temp[16]; 645 UString s2; 646 const wchar_t *s = NULL; 647 648 if (indexType == NArchive::NEventIndexType::kOutArcIndex) 649 { 650 /* 651 UString name; 652 if (index != (UInt32)(Int32)-1) 653 { 654 const CUpdatePair2 &up = (*UpdatePairs)[index]; 655 if (up.ExistOnDisk()) 656 { 657 s2 = DirItems->GetLogPath(up.DirIndex); 658 s = s2; 659 } 660 } 661 */ 662 return E_FAIL; 663 } 664 665 if (indexType == NArchive::NEventIndexType::kInArcIndex) 666 { 667 if (index != (UInt32)(Int32)-1) 668 { 669 if (ArcItems) 670 s = (*ArcItems)[index].Name; 671 else if (Arc) 672 { 673 RINOK(Arc->GetItemPath(index, s2)); 674 s = s2; 675 } 676 if (Archive) 677 { 678 RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted)); 679 } 680 } 681 } 682 else if (indexType == NArchive::NEventIndexType::kBlockIndex) 683 { 684 temp[0] = '#'; 685 ConvertUInt32ToString(index, temp + 1); 686 s = temp; 687 } 688 689 return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s); 690 691 COM_TRY_END 692 } 693 694 STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size) 695 { 696 if (VolumesSizes.Size() == 0) 697 return S_FALSE; 698 if (index >= (UInt32)VolumesSizes.Size()) 699 index = VolumesSizes.Size() - 1; 700 *size = VolumesSizes[index]; 701 return S_OK; 702 } 703 704 STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream) 705 { 706 COM_TRY_BEGIN 707 char temp[16]; 708 ConvertUInt32ToString(index + 1, temp); 709 FString res (temp); 710 while (res.Len() < 2) 711 res.InsertAtFront(FTEXT('0')); 712 FString fileName = VolName; 713 fileName += '.'; 714 fileName += res; 715 fileName += VolExt; 716 COutFileStream *streamSpec = new COutFileStream; 717 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec); 718 if (!streamSpec->Create(fileName, false)) 719 return ::GetLastError(); 720 *volumeStream = streamLoc.Detach(); 721 return S_OK; 722 COM_TRY_END 723 } 724 725 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) 726 { 727 COM_TRY_BEGIN 728 return Callback->CryptoGetTextPassword2(passwordIsDefined, password); 729 COM_TRY_END 730 } 731 732 STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password) 733 { 734 COM_TRY_BEGIN 735 return Callback->CryptoGetTextPassword(password); 736 COM_TRY_END 737 } 738 739 HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error) 740 { 741 if (error == ERROR_LOCK_VIOLATION) 742 { 743 MT_LOCK 744 UInt32 index = (UInt32)val; 745 FOR_VECTOR(i, _openFiles_Indexes) 746 { 747 if (_openFiles_Indexes[i] == index) 748 { 749 RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error)); 750 break; 751 } 752 } 753 } 754 return HRESULT_FROM_WIN32(error); 755 } 756 757 void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val) 758 { 759 MT_LOCK 760 UInt32 index = (UInt32)val; 761 FOR_VECTOR(i, _openFiles_Indexes) 762 { 763 if (_openFiles_Indexes[i] == index) 764 { 765 _openFiles_Indexes.Delete(i); 766 _openFiles_Paths.Delete(i); 767 return; 768 } 769 } 770 throw 20141125; 771 } 772