1// UpdateCallback.cpp 2 3#include "StdAfx.h" 4 5// #include <stdio.h> 6 7#ifndef _WIN32 8// #include <grp.h> 9// #include <pwd.h> 10/* 11inclusion of <sys/sysmacros.h> by <sys/types.h> is deprecated since glibc 2.25. 12Since glibc 2.3.3, macros have been aliases for three GNU-specific 13functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor() 14*/ 15// for major()/minor(): 16#include <sys/types.h> 17#if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__) 18#else 19#ifndef major 20#include <sys/sysmacros.h> 21#endif 22#endif 23 24#endif // _WIN32 25 26#ifndef Z7_ST 27#include "../../../Windows/Synchronization.h" 28#endif 29 30#include "../../../Common/ComTry.h" 31#include "../../../Common/IntToString.h" 32#include "../../../Common/StringConvert.h" 33#include "../../../Common/Wildcard.h" 34#include "../../../Common/UTFConvert.h" 35 36#include "../../../Windows/FileDir.h" 37#include "../../../Windows/FileName.h" 38#include "../../../Windows/PropVariant.h" 39 40#include "../../Common/StreamObjects.h" 41 42#include "UpdateCallback.h" 43 44#if defined(_WIN32) && !defined(UNDER_CE) 45#define Z7_USE_SECURITY_CODE 46#include "../../../Windows/SecurityUtils.h" 47#endif 48 49using namespace NWindows; 50using namespace NFile; 51 52#ifndef Z7_ST 53static NSynchronization::CCriticalSection g_CriticalSection; 54#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); 55#else 56#define MT_LOCK 57#endif 58 59 60#ifdef Z7_USE_SECURITY_CODE 61bool InitLocalPrivileges(); 62#endif 63 64CArchiveUpdateCallback::CArchiveUpdateCallback(): 65 PreserveATime(false), 66 ShareForWrite(false), 67 StopAfterOpenError(false), 68 StdInMode(false), 69 70 KeepOriginalItemNames(false), 71 StoreNtSecurity(false), 72 StoreHardLinks(false), 73 StoreSymLinks(false), 74 75 #ifndef _WIN32 76 StoreOwnerId(false), 77 StoreOwnerName(false), 78 #endif 79 80 /* 81 , Need_ArcMTime_Report(false), 82 , ArcMTime_WasReported(false), 83 */ 84 Need_LatestMTime(false), 85 LatestMTime_Defined(false), 86 87 Callback(NULL), 88 89 DirItems(NULL), 90 ParentDirItem(NULL), 91 92 Arc(NULL), 93 ArcItems(NULL), 94 UpdatePairs(NULL), 95 NewNames(NULL), 96 Comment(NULL), 97 CommentIndex(-1), 98 99 ProcessedItemsStatuses(NULL), 100 _hardIndex_From((UInt32)(Int32)-1) 101{ 102 #ifdef Z7_USE_SECURITY_CODE 103 _saclEnabled = InitLocalPrivileges(); 104 #endif 105} 106 107 108Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 size)) 109{ 110 COM_TRY_BEGIN 111 return Callback->SetTotal(size); 112 COM_TRY_END 113} 114 115Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)) 116{ 117 COM_TRY_BEGIN 118 return Callback->SetCompleted(completeValue); 119 COM_TRY_END 120} 121 122Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)) 123{ 124 COM_TRY_BEGIN 125 return Callback->SetRatioInfo(inSize, outSize); 126 COM_TRY_END 127} 128 129 130/* 131static const CStatProp kProps[] = 132{ 133 { NULL, kpidPath, VT_BSTR}, 134 { NULL, kpidIsDir, VT_BOOL}, 135 { NULL, kpidSize, VT_UI8}, 136 { NULL, kpidCTime, VT_FILETIME}, 137 { NULL, kpidATime, VT_FILETIME}, 138 { NULL, kpidMTime, VT_FILETIME}, 139 { NULL, kpidAttrib, VT_UI4}, 140 { NULL, kpidIsAnti, VT_BOOL} 141}; 142 143Z7_COM7F_IMF(CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **) 144{ 145 return CStatPropEnumerator::CreateEnumerator(kProps, Z7_ARRAY_SIZE(kProps), enumerator); 146} 147*/ 148 149Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index, 150 Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) 151{ 152 COM_TRY_BEGIN 153 RINOK(Callback->CheckBreak()) 154 const CUpdatePair2 &up = (*UpdatePairs)[index]; 155 if (newData) *newData = BoolToInt(up.NewData); 156 if (newProps) *newProps = BoolToInt(up.NewProps); 157 if (indexInArchive) 158 { 159 *indexInArchive = (UInt32)(Int32)-1; 160 if (up.ExistInArchive()) 161 *indexInArchive = ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex; 162 } 163 return S_OK; 164 COM_TRY_END 165} 166 167 168Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)) 169{ 170 NCOM::CPropVariant prop; 171 switch (propID) 172 { 173 case kpidIsDir: prop = true; break; 174 case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break; 175 case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break; 176 case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break; 177 case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break; 178 case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break; 179 } 180 prop.Detach(value); 181 return S_OK; 182} 183 184Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)) 185{ 186 *parentType = NParentType::kDir; 187 *parent = (UInt32)(Int32)-1; 188 return S_OK; 189} 190 191Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)) 192{ 193 *numProps = 0; 194 if (StoreNtSecurity) 195 *numProps = 1; 196 return S_OK; 197} 198 199Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)) 200{ 201 *name = NULL; 202 *propID = kpidNtSecure; 203 return S_OK; 204} 205 206Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp(PROPID 207 propID 208 , const void **data, UInt32 *dataSize, UInt32 *propType)) 209{ 210 #ifndef Z7_USE_SECURITY_CODE 211 UNUSED_VAR(propID) 212 #endif 213 214 *data = NULL; 215 *dataSize = 0; 216 *propType = 0; 217 if (!StoreNtSecurity) 218 return S_OK; 219 #ifdef Z7_USE_SECURITY_CODE 220 if (propID == kpidNtSecure) 221 { 222 if (StdInMode) 223 return S_OK; 224 225 if (ParentDirItem) 226 { 227 if (ParentDirItem->SecureIndex < 0) 228 return S_OK; 229 const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)ParentDirItem->SecureIndex]; 230 *data = buf; 231 *dataSize = (UInt32)buf.Size(); 232 *propType = NPropDataType::kRaw; 233 return S_OK; 234 } 235 236 if (Arc && Arc->GetRootProps) 237 return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType); 238 } 239 #endif 240 return S_OK; 241} 242 243 244Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) 245{ 246 *data = NULL; 247 *dataSize = 0; 248 *propType = 0; 249 250 if (propID == kpidNtSecure || 251 propID == kpidNtReparse) 252 { 253 if (StdInMode) 254 return S_OK; 255 256 const CUpdatePair2 &up = (*UpdatePairs)[index]; 257 if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps) 258 return Arc->GetRawProps->GetRawProp( 259 ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, 260 propID, data, dataSize, propType); 261 { 262 /* 263 if (!up.NewData) 264 return E_FAIL; 265 */ 266 if (up.IsAnti) 267 return S_OK; 268 269 #if defined(_WIN32) && !defined(UNDER_CE) 270 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 271 #endif 272 273 #ifdef Z7_USE_SECURITY_CODE 274 if (propID == kpidNtSecure) 275 { 276 if (!StoreNtSecurity) 277 return S_OK; 278 if (di.SecureIndex < 0) 279 return S_OK; 280 const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)di.SecureIndex]; 281 *data = buf; 282 *dataSize = (UInt32)buf.Size(); 283 *propType = NPropDataType::kRaw; 284 } 285 else 286 #endif 287 if (propID == kpidNtReparse) 288 { 289 if (!StoreSymLinks) 290 return S_OK; 291 #if defined(_WIN32) && !defined(UNDER_CE) 292 // we use ReparseData2 instead of ReparseData for WIM format 293 const CByteBuffer *buf = &di.ReparseData2; 294 if (buf->Size() == 0) 295 buf = &di.ReparseData; 296 if (buf->Size() != 0) 297 { 298 *data = *buf; 299 *dataSize = (UInt32)buf->Size(); 300 *propType = NPropDataType::kRaw; 301 } 302 #endif 303 } 304 305 return S_OK; 306 } 307 } 308 309 return S_OK; 310} 311 312#if defined(_WIN32) && !defined(UNDER_CE) 313 314static UString GetRelativePath(const UString &to, const UString &from) 315{ 316 UStringVector partsTo, partsFrom; 317 SplitPathToParts(to, partsTo); 318 SplitPathToParts(from, partsFrom); 319 320 unsigned i; 321 for (i = 0;; i++) 322 { 323 if (i + 1 >= partsFrom.Size() || 324 i + 1 >= partsTo.Size()) 325 break; 326 if (CompareFileNames(partsFrom[i], partsTo[i]) != 0) 327 break; 328 } 329 330 if (i == 0) 331 { 332 #ifdef _WIN32 333 if (NName::IsDrivePath(to) || 334 NName::IsDrivePath(from)) 335 return to; 336 #endif 337 } 338 339 UString s; 340 unsigned k; 341 342 for (k = i + 1; k < partsFrom.Size(); k++) 343 s += ".." STRING_PATH_SEPARATOR; 344 345 for (k = i; k < partsTo.Size(); k++) 346 { 347 if (k != i) 348 s.Add_PathSepar(); 349 s += partsTo[k]; 350 } 351 352 return s; 353} 354 355#endif 356 357Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) 358{ 359 COM_TRY_BEGIN 360 const CUpdatePair2 &up = (*UpdatePairs)[index]; 361 NCOM::CPropVariant prop; 362 363 if (up.NewData) 364 { 365 /* 366 if (propID == kpidIsHardLink) 367 { 368 prop = _isHardLink; 369 prop.Detach(value); 370 return S_OK; 371 } 372 */ 373 if (propID == kpidSymLink) 374 { 375 if (index == _hardIndex_From) 376 { 377 prop.Detach(value); 378 return S_OK; 379 } 380 381 #if !defined(UNDER_CE) 382 383 if (up.DirIndex >= 0) 384 { 385 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 386 387 #ifdef _WIN32 388 // if (di.IsDir()) 389 { 390 CReparseAttr attr; 391 if (attr.Parse(di.ReparseData, di.ReparseData.Size())) 392 { 393 const UString simpleName = attr.GetPath(); 394 if (!attr.IsSymLink_WSL() && attr.IsRelative_Win()) 395 prop = simpleName; 396 else 397 { 398 const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex); 399 FString fullPath; 400 if (NDir::MyGetFullPathName(phyPath, fullPath)) 401 { 402 prop = GetRelativePath(simpleName, fs2us(fullPath)); 403 } 404 } 405 prop.Detach(value); 406 return S_OK; 407 } 408 } 409 410 #else // _WIN32 411 412 if (di.ReparseData.Size() != 0) 413 { 414 AString utf; 415 utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size()); 416 417 UString us; 418 if (ConvertUTF8ToUnicode(utf, us)) 419 { 420 prop = us; 421 prop.Detach(value); 422 return S_OK; 423 } 424 } 425 426 #endif // _WIN32 427 } 428 #endif // !defined(UNDER_CE) 429 } 430 else if (propID == kpidHardLink) 431 { 432 if (index == _hardIndex_From) 433 { 434 const CKeyKeyValPair &pair = _map[_hardIndex_To]; 435 const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value]; 436 prop = DirItems->GetLogPath((unsigned)up2.DirIndex); 437 prop.Detach(value); 438 return S_OK; 439 } 440 if (up.DirIndex >= 0) 441 { 442 prop.Detach(value); 443 return S_OK; 444 } 445 } 446 } 447 448 if (up.IsAnti 449 && propID != kpidIsDir 450 && propID != kpidPath 451 && propID != kpidIsAltStream) 452 { 453 switch (propID) 454 { 455 case kpidSize: prop = (UInt64)0; break; 456 case kpidIsAnti: prop = true; break; 457 } 458 } 459 else if (propID == kpidPath && up.NewNameIndex >= 0) 460 prop = (*NewNames)[(unsigned)up.NewNameIndex]; 461 else if (propID == kpidComment 462 && CommentIndex >= 0 463 && (unsigned)CommentIndex == index 464 && Comment) 465 prop = *Comment; 466 else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem) 467 { 468 // we can generate new ShortName here; 469 } 470 else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream))) 471 && up.ExistInArchive() && Archive) 472 return Archive->GetProperty(ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, propID, value); 473 else if (up.ExistOnDisk()) 474 { 475 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 476 switch (propID) 477 { 478 case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break; 479 case kpidIsDir: prop = di.IsDir(); break; 480 case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break; 481 case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break; 482 case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break; 483 case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break; 484 case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break; 485 case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break; 486 487 #if defined(_WIN32) 488 case kpidIsAltStream: prop = di.IsAltStream; break; 489 // case kpidShortName: prop = di.ShortName; break; 490 #else 491 492 #if defined(__APPLE__) 493 #pragma GCC diagnostic push 494 #pragma GCC diagnostic ignored "-Wsign-conversion" 495 #endif 496 497 case kpidDeviceMajor: 498 /* 499 printf("\ndi.mode = %o\n", di.mode); 500 printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev)); 501 printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev)); 502 */ 503 if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) 504 prop = (UInt32)major(di.rdev); 505 break; 506 507 case kpidDeviceMinor: 508 if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) 509 prop = (UInt32)minor(di.rdev); 510 break; 511 512 #if defined(__APPLE__) 513 #pragma GCC diagnostic pop 514 #endif 515 516 // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break; 517 518 case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break; 519 case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break; 520 case kpidUser: 521 if (di.OwnerNameIndex >= 0) 522 prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; 523 break; 524 case kpidGroup: 525 if (di.OwnerGroupIndex >= 0) 526 prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; 527 break; 528 #endif 529 } 530 } 531 prop.Detach(value); 532 return S_OK; 533 COM_TRY_END 534} 535 536#ifndef Z7_ST 537static NSynchronization::CCriticalSection g_CS; 538#endif 539 540void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex) 541{ 542 if (ProcessedItemsStatuses) 543 { 544 #ifndef Z7_ST 545 NSynchronization::CCriticalSectionLock lock(g_CS); 546 #endif 547 ProcessedItemsStatuses[dirIndex] = 1; 548 } 549} 550 551Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)) 552{ 553 COM_TRY_BEGIN 554 *inStream = NULL; 555 const CUpdatePair2 &up = (*UpdatePairs)[index]; 556 if (!up.NewData) 557 return E_FAIL; 558 559 RINOK(Callback->CheckBreak()) 560 // RINOK(Callback->Finalize()); 561 562 bool isDir = IsDir(up); 563 564 if (up.IsAnti) 565 { 566 UString name; 567 if (up.ArcIndex >= 0) 568 name = (*ArcItems)[(unsigned)up.ArcIndex].Name; 569 else if (up.DirIndex >= 0) 570 name = DirItems->GetLogPath((unsigned)up.DirIndex); 571 RINOK(Callback->GetStream(name, isDir, true, mode)) 572 573 /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file. 574 so we return empty stream */ 575 576 if (!isDir) 577 { 578 CBufInStream *inStreamSpec = new CBufInStream(); 579 CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec; 580 inStreamSpec->Init(NULL, 0); 581 *inStream = inStreamLoc.Detach(); 582 } 583 return S_OK; 584 } 585 586 RINOK(Callback->GetStream(DirItems->GetLogPath((unsigned)up.DirIndex), isDir, false, mode)) 587 588 if (isDir) 589 return S_OK; 590 591 if (StdInMode) 592 { 593 if (mode != NUpdateNotifyOp::kAdd && 594 mode != NUpdateNotifyOp::kUpdate) 595 return S_OK; 596 597 CStdInFileStream *inStreamSpec = new CStdInFileStream; 598 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 599 *inStream = inStreamLoc.Detach(); 600 } 601 else 602 { 603 #if !defined(UNDER_CE) 604 const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex]; 605 if (di.AreReparseData()) 606 { 607 /* 608 // we still need DeviceIoControlOut() instead of Read 609 if (!inStreamSpec->File.OpenReparse(path)) 610 { 611 return Callback->OpenFileError(path, ::GetLastError()); 612 } 613 */ 614 // 20.03: we use Reparse Data instead of real data 615 616 CBufInStream *inStreamSpec = new CBufInStream(); 617 CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec; 618 inStreamSpec->Init(di.ReparseData, di.ReparseData.Size()); 619 *inStream = inStreamLoc.Detach(); 620 621 UpdateProcessedItemStatus((unsigned)up.DirIndex); 622 return S_OK; 623 } 624 #endif // !defined(UNDER_CE) 625 626 CInFileStream *inStreamSpec = new CInFileStream; 627 CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec); 628 629 /* 630 // for debug: 631 #ifdef _WIN32 632 inStreamSpec->StoreOwnerName = true; 633 inStreamSpec->OwnerName = "user_name"; 634 inStreamSpec->OwnerName += di.Name; 635 inStreamSpec->OwnerName += "11111111112222222222222333333333333"; 636 inStreamSpec->OwnerGroup = "gname_"; 637 inStreamSpec->OwnerGroup += inStreamSpec->OwnerName; 638 #endif 639 */ 640 641 #ifndef _WIN32 642 inStreamSpec->StoreOwnerId = StoreOwnerId; 643 inStreamSpec->StoreOwnerName = StoreOwnerName; 644 645 // if (StoreOwner) 646 { 647 inStreamSpec->_uid = di.uid; 648 inStreamSpec->_gid = di.gid; 649 if (di.OwnerNameIndex >= 0) 650 inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex]; 651 if (di.OwnerGroupIndex >= 0) 652 inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex]; 653 } 654 #endif 655 656 inStreamSpec->SupportHardLinks = StoreHardLinks; 657 const bool preserveATime = (PreserveATime 658 || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass. 659 inStreamSpec->Set_PreserveATime(preserveATime); 660 661 const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex); 662 _openFiles_Indexes.Add(index); 663 _openFiles_Paths.Add(path); 664 // _openFiles_Streams.Add(inStreamSpec); 665 666 /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding 667 for correct working if exception was raised in GetPhyPath */ 668 inStreamSpec->Callback = this; 669 inStreamSpec->CallbackRef = index; 670 671 if (!inStreamSpec->OpenShared(path, ShareForWrite)) 672 { 673 bool isOpen = false; 674 if (preserveATime) 675 { 676 inStreamSpec->Set_PreserveATime(false); 677 isOpen = inStreamSpec->OpenShared(path, ShareForWrite); 678 } 679 if (!isOpen) 680 { 681 const DWORD error = ::GetLastError(); 682 const HRESULT hres = Callback->OpenFileError(path, error); 683 if (hres == S_OK || hres == S_FALSE) 684 if (StopAfterOpenError || 685 // v23: we check also for some critical errors: 686 #ifdef _WIN32 687 error == ERROR_NO_SYSTEM_RESOURCES 688 #else 689 error == EMFILE 690 #endif 691 ) 692 { 693 if (error == 0) 694 return E_FAIL; 695 return HRESULT_FROM_WIN32(error); 696 } 697 return hres; 698 } 699 } 700 701 /* 702 { 703 // for debug: 704 Byte b = 0; 705 UInt32 processedSize = 0; 706 if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK || 707 processedSize != 1) 708 return E_FAIL; 709 } 710 */ 711 712 if (Need_LatestMTime) 713 { 714 inStreamSpec->ReloadProps(); 715 } 716 717 // #if defined(Z7_FILE_STREAMS_USE_WIN_FILE) || !defined(_WIN32) 718 if (StoreHardLinks) 719 { 720 CStreamFileProps props; 721 if (inStreamSpec->GetProps2(&props) == S_OK) 722 { 723 if (props.NumLinks > 1) 724 { 725 CKeyKeyValPair pair; 726 pair.Key1 = props.VolID; 727 pair.Key2 = props.FileID_Low; 728 pair.Value = index; 729 const unsigned numItems = _map.Size(); 730 const unsigned pairIndex = _map.AddToUniqueSorted2(pair); 731 if (numItems == _map.Size()) 732 { 733 // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex]; 734 _hardIndex_From = index; 735 _hardIndex_To = pairIndex; 736 // we could return NULL as stream, but it's better to return real stream 737 // return S_OK; 738 } 739 } 740 } 741 } 742 // #endif 743 744 UpdateProcessedItemStatus((unsigned)up.DirIndex); 745 *inStream = inStreamLoc.Detach(); 746 } 747 748 return S_OK; 749 COM_TRY_END 750} 751 752Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 opRes)) 753{ 754 COM_TRY_BEGIN 755 return Callback->SetOperationResult(opRes); 756 COM_TRY_END 757} 758 759Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)) 760{ 761 COM_TRY_BEGIN 762 return GetStream2(index, inStream, 763 (*UpdatePairs)[index].ArcIndex < 0 ? 764 NUpdateNotifyOp::kAdd : 765 NUpdateNotifyOp::kUpdate); 766 COM_TRY_END 767} 768 769Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)) 770{ 771 COM_TRY_BEGIN 772 773 // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index); 774 775 bool isDir = false; 776 777 if (indexType == NArchive::NEventIndexType::kOutArcIndex) 778 { 779 UString name; 780 if (index != (UInt32)(Int32)-1) 781 { 782 const CUpdatePair2 &up = (*UpdatePairs)[index]; 783 if (up.ExistOnDisk()) 784 { 785 name = DirItems->GetLogPath((unsigned)up.DirIndex); 786 isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir(); 787 } 788 } 789 return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir); 790 } 791 792 wchar_t temp[16]; 793 UString s2; 794 const wchar_t *s = NULL; 795 796 if (indexType == NArchive::NEventIndexType::kInArcIndex) 797 { 798 if (index != (UInt32)(Int32)-1) 799 { 800 if (ArcItems) 801 { 802 const CArcItem &ai = (*ArcItems)[index]; 803 s = ai.Name; 804 isDir = ai.IsDir; 805 } 806 else if (Arc) 807 { 808 RINOK(Arc->GetItem_Path(index, s2)) 809 s = s2; 810 RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir)) 811 } 812 } 813 } 814 else if (indexType == NArchive::NEventIndexType::kBlockIndex) 815 { 816 temp[0] = '#'; 817 ConvertUInt32ToString(index, temp + 1); 818 s = temp; 819 } 820 821 if (!s) 822 s = L""; 823 824 return Callback->ReportUpdateOperation(op, s, isDir); 825 826 COM_TRY_END 827} 828 829Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)) 830{ 831 COM_TRY_BEGIN 832 833 bool isEncrypted = false; 834 wchar_t temp[16]; 835 UString s2; 836 const wchar_t *s = NULL; 837 838 if (indexType == NArchive::NEventIndexType::kOutArcIndex) 839 { 840 /* 841 UString name; 842 if (index != (UInt32)(Int32)-1) 843 { 844 const CUpdatePair2 &up = (*UpdatePairs)[index]; 845 if (up.ExistOnDisk()) 846 { 847 s2 = DirItems->GetLogPath(up.DirIndex); 848 s = s2; 849 } 850 } 851 */ 852 return E_FAIL; 853 } 854 855 if (indexType == NArchive::NEventIndexType::kInArcIndex) 856 { 857 if (index != (UInt32)(Int32)-1) 858 { 859 if (ArcItems) 860 s = (*ArcItems)[index].Name; 861 else if (Arc) 862 { 863 RINOK(Arc->GetItem_Path(index, s2)) 864 s = s2; 865 } 866 if (Archive) 867 { 868 RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted)) 869 } 870 } 871 } 872 else if (indexType == NArchive::NEventIndexType::kBlockIndex) 873 { 874 temp[0] = '#'; 875 ConvertUInt32ToString(index, temp + 1); 876 s = temp; 877 } 878 879 return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s); 880 881 COM_TRY_END 882} 883 884 885/* 886Z7_COM7F_IMF(CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer)) 887{ 888 *answer = 0; 889 if (Need_ArcMTime_Report && propID == kpidComboMTime) 890 *answer = 1; 891 return S_OK; 892} 893 894Z7_COM7F_IMF(CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) 895{ 896 if (indexType == NArchive::NEventIndexType::kArcProp) 897 { 898 if (propID == kpidComboMTime) 899 { 900 ArcMTime_WasReported = true; 901 if (value->vt == VT_FILETIME) 902 { 903 Reported_ArcMTime.Set_From_Prop(*value); 904 Reported_ArcMTime.Def = true; 905 } 906 else 907 { 908 Reported_ArcMTime.Clear(); 909 if (value->vt != VT_EMPTY) 910 return E_FAIL; // for debug 911 } 912 } 913 } 914 return Callback->ReportProp(indexType, index, propID, value); 915} 916 917Z7_COM7F_IMF(CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index, 918 PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) 919{ 920 return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType); 921} 922 923Z7_COM7F_IMF(CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) 924{ 925 return Callback->ReportFinished(indexType, index, opRes); 926} 927*/ 928 929Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)) 930{ 931 if (VolumesSizes.Size() == 0) 932 return S_FALSE; 933 if (index >= (UInt32)VolumesSizes.Size()) 934 index = VolumesSizes.Size() - 1; 935 *size = VolumesSizes[index]; 936 return S_OK; 937} 938 939Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) 940{ 941 COM_TRY_BEGIN 942 char temp[16]; 943 ConvertUInt32ToString(index + 1, temp); 944 FString res (temp); 945 while (res.Len() < 2) 946 res.InsertAtFront(FTEXT('0')); 947 FString fileName = VolName; 948 fileName.Add_Dot(); 949 fileName += res; 950 fileName += VolExt; 951 COutFileStream *streamSpec = new COutFileStream; 952 CMyComPtr<ISequentialOutStream> streamLoc(streamSpec); 953 if (!streamSpec->Create(fileName, false)) 954 return GetLastError_noZero_HRESULT(); 955 *volumeStream = streamLoc.Detach(); 956 return S_OK; 957 COM_TRY_END 958} 959 960Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)) 961{ 962 COM_TRY_BEGIN 963 return Callback->CryptoGetTextPassword2(passwordIsDefined, password); 964 COM_TRY_END 965} 966 967Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)) 968{ 969 COM_TRY_BEGIN 970 return Callback->CryptoGetTextPassword(password); 971 COM_TRY_END 972} 973 974HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error) 975{ 976 #ifdef _WIN32 // FIX IT !!! 977 // why did we check only for ERROR_LOCK_VIOLATION ? 978 // if (error == ERROR_LOCK_VIOLATION) 979 #endif 980 { 981 MT_LOCK 982 const UInt32 index = (UInt32)val; 983 FOR_VECTOR(i, _openFiles_Indexes) 984 { 985 if (_openFiles_Indexes[i] == index) 986 { 987 RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error)) 988 break; 989 } 990 } 991 } 992 return HRESULT_FROM_WIN32(error); 993} 994 995void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) 996{ 997 MT_LOCK 998 if (Need_LatestMTime) 999 { 1000 if (stream->_info_WasLoaded) 1001 { 1002 const CFiTime &ft = ST_MTIME(stream->_info); 1003 if (!LatestMTime_Defined 1004 || Compare_FiTime(&LatestMTime, &ft) < 0) 1005 LatestMTime = ft; 1006 LatestMTime_Defined = true; 1007 } 1008 } 1009 const UInt32 index = (UInt32)val; 1010 FOR_VECTOR(i, _openFiles_Indexes) 1011 { 1012 if (_openFiles_Indexes[i] == index) 1013 { 1014 _openFiles_Indexes.Delete(i); 1015 _openFiles_Paths.Delete(i); 1016 // _openFiles_Streams.Delete(i); 1017 return; 1018 } 1019 } 1020 /* 21.02 : this function can be called in destructor. 1021 And destructor can be called after some exception. 1022 If we don't want to throw exception in desctructors or after another exceptions, 1023 we must disable the code below that raises new exception. 1024 */ 1025 // throw 20141125; 1026} 1027