Update.cpp (43747B)
1 // Update.cpp 2 3 #include "StdAfx.h" 4 5 #include "Update.h" 6 7 #include "../../../Common/StringConvert.h" 8 9 #include "../../../Windows/DLL.h" 10 #include "../../../Windows/FileDir.h" 11 #include "../../../Windows/FileFind.h" 12 #include "../../../Windows/FileName.h" 13 #include "../../../Windows/PropVariant.h" 14 #include "../../../Windows/PropVariantConv.h" 15 #include "../../../Windows/TimeUtils.h" 16 17 #include "../../Common/FileStreams.h" 18 #include "../../Common/LimitedStreams.h" 19 20 #include "../../Compress/CopyCoder.h" 21 22 #include "../Common/DirItem.h" 23 #include "../Common/EnumDirItems.h" 24 #include "../Common/OpenArchive.h" 25 #include "../Common/UpdateProduce.h" 26 27 #include "EnumDirItems.h" 28 #include "SetProperties.h" 29 #include "TempFiles.h" 30 #include "UpdateCallback.h" 31 32 static const char * const kUpdateIsNotSupoorted = 33 "update operations are not supported for this archive"; 34 35 static const char * const kUpdateIsNotSupoorted_MultiVol = 36 "Updating for multivolume archives is not implemented"; 37 38 using namespace NWindows; 39 using namespace NCOM; 40 using namespace NFile; 41 using namespace NDir; 42 using namespace NName; 43 44 static CFSTR const kTempFolderPrefix = FTEXT("7zE"); 45 46 47 void CUpdateErrorInfo::SetFromLastError(const char *message) 48 { 49 SystemError = ::GetLastError(); 50 Message = message; 51 } 52 53 HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName) 54 { 55 SetFromLastError(message); 56 FileNames.Add(fileName); 57 return Get_HRESULT_Error(); 58 } 59 60 static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) 61 { 62 NFind::CFileInfo fileInfo; 63 FString pathPrefix = path + FCHAR_PATH_SEPARATOR; 64 { 65 NFind::CEnumerator enumerator; 66 enumerator.SetDirPrefix(pathPrefix); 67 while (enumerator.Next(fileInfo)) 68 { 69 if (fileInfo.IsDir()) 70 if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) 71 return false; 72 } 73 } 74 /* 75 // we don't need clear read-only for folders 76 if (!MySetFileAttributes(path, 0)) 77 return false; 78 */ 79 return RemoveDir(path); 80 } 81 82 83 using namespace NUpdateArchive; 84 85 class COutMultiVolStream: 86 public IOutStream, 87 public CMyUnknownImp 88 { 89 unsigned _streamIndex; // required stream 90 UInt64 _offsetPos; // offset from start of _streamIndex index 91 UInt64 _absPos; 92 UInt64 _length; 93 94 struct CAltStreamInfo 95 { 96 COutFileStream *StreamSpec; 97 CMyComPtr<IOutStream> Stream; 98 FString Name; 99 UInt64 Pos; 100 UInt64 RealSize; 101 }; 102 CObjectVector<CAltStreamInfo> Streams; 103 public: 104 // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; 105 CRecordVector<UInt64> Sizes; 106 FString Prefix; 107 CTempFiles *TempFiles; 108 109 void Init() 110 { 111 _streamIndex = 0; 112 _offsetPos = 0; 113 _absPos = 0; 114 _length = 0; 115 } 116 117 bool SetMTime(const FILETIME *mTime); 118 HRESULT Close(); 119 120 UInt64 GetSize() const { return _length; } 121 122 MY_UNKNOWN_IMP1(IOutStream) 123 124 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); 125 STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); 126 STDMETHOD(SetSize)(UInt64 newSize); 127 }; 128 129 // static NSynchronization::CCriticalSection g_TempPathsCS; 130 131 HRESULT COutMultiVolStream::Close() 132 { 133 HRESULT res = S_OK; 134 FOR_VECTOR (i, Streams) 135 { 136 COutFileStream *s = Streams[i].StreamSpec; 137 if (s) 138 { 139 HRESULT res2 = s->Close(); 140 if (res2 != S_OK) 141 res = res2; 142 } 143 } 144 return res; 145 } 146 147 bool COutMultiVolStream::SetMTime(const FILETIME *mTime) 148 { 149 bool res = true; 150 FOR_VECTOR (i, Streams) 151 { 152 COutFileStream *s = Streams[i].StreamSpec; 153 if (s) 154 if (!s->SetMTime(mTime)) 155 res = false; 156 } 157 return res; 158 } 159 160 STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize) 161 { 162 if (processedSize) 163 *processedSize = 0; 164 while (size > 0) 165 { 166 if (_streamIndex >= Streams.Size()) 167 { 168 CAltStreamInfo altStream; 169 170 FString name; 171 name.Add_UInt32(_streamIndex + 1); 172 while (name.Len() < 3) 173 name.InsertAtFront(FTEXT('0')); 174 name.Insert(0, Prefix); 175 altStream.StreamSpec = new COutFileStream; 176 altStream.Stream = altStream.StreamSpec; 177 if (!altStream.StreamSpec->Create(name, false)) 178 return ::GetLastError(); 179 { 180 // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); 181 TempFiles->Paths.Add(name); 182 } 183 184 altStream.Pos = 0; 185 altStream.RealSize = 0; 186 altStream.Name = name; 187 Streams.Add(altStream); 188 continue; 189 } 190 CAltStreamInfo &altStream = Streams[_streamIndex]; 191 192 unsigned index = _streamIndex; 193 if (index >= Sizes.Size()) 194 index = Sizes.Size() - 1; 195 UInt64 volSize = Sizes[index]; 196 197 if (_offsetPos >= volSize) 198 { 199 _offsetPos -= volSize; 200 _streamIndex++; 201 continue; 202 } 203 if (_offsetPos != altStream.Pos) 204 { 205 // CMyComPtr<IOutStream> outStream; 206 // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream)); 207 RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); 208 altStream.Pos = _offsetPos; 209 } 210 211 UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos); 212 UInt32 realProcessed; 213 RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); 214 data = (void *)((Byte *)data + realProcessed); 215 size -= realProcessed; 216 altStream.Pos += realProcessed; 217 _offsetPos += realProcessed; 218 _absPos += realProcessed; 219 if (_absPos > _length) 220 _length = _absPos; 221 if (_offsetPos > altStream.RealSize) 222 altStream.RealSize = _offsetPos; 223 if (processedSize) 224 *processedSize += realProcessed; 225 if (altStream.Pos == volSize) 226 { 227 _streamIndex++; 228 _offsetPos = 0; 229 } 230 if (realProcessed == 0 && curSize != 0) 231 return E_FAIL; 232 break; 233 } 234 return S_OK; 235 } 236 237 STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) 238 { 239 if (seekOrigin >= 3) 240 return STG_E_INVALIDFUNCTION; 241 switch (seekOrigin) 242 { 243 case STREAM_SEEK_SET: _absPos = offset; break; 244 case STREAM_SEEK_CUR: _absPos += offset; break; 245 case STREAM_SEEK_END: _absPos = _length + offset; break; 246 } 247 _offsetPos = _absPos; 248 if (newPosition) 249 *newPosition = _absPos; 250 _streamIndex = 0; 251 return S_OK; 252 } 253 254 STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) 255 { 256 unsigned i = 0; 257 while (i < Streams.Size()) 258 { 259 CAltStreamInfo &altStream = Streams[i++]; 260 if ((UInt64)newSize < altStream.RealSize) 261 { 262 RINOK(altStream.Stream->SetSize(newSize)); 263 altStream.RealSize = newSize; 264 break; 265 } 266 newSize -= altStream.RealSize; 267 } 268 while (i < Streams.Size()) 269 { 270 { 271 CAltStreamInfo &altStream = Streams.Back(); 272 altStream.Stream.Release(); 273 DeleteFileAlways(altStream.Name); 274 } 275 Streams.DeleteBack(); 276 } 277 _offsetPos = _absPos; 278 _streamIndex = 0; 279 _length = newSize; 280 return S_OK; 281 } 282 283 void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) 284 { 285 OriginalPath = path; 286 287 SplitPathToParts_2(path, Prefix, Name); 288 289 if (mode == k_ArcNameMode_Add) 290 return; 291 if (mode == k_ArcNameMode_Exact) 292 { 293 BaseExtension.Empty(); 294 return; 295 } 296 297 int dotPos = Name.ReverseFind_Dot(); 298 if (dotPos < 0) 299 return; 300 if ((unsigned)dotPos == Name.Len() - 1) 301 { 302 Name.DeleteBack(); 303 BaseExtension.Empty(); 304 return; 305 } 306 const UString ext = Name.Ptr(dotPos + 1); 307 if (BaseExtension.IsEqualTo_NoCase(ext)) 308 { 309 BaseExtension = ext; 310 Name.DeleteFrom(dotPos); 311 } 312 else 313 BaseExtension.Empty(); 314 } 315 316 UString CArchivePath::GetFinalPath() const 317 { 318 UString path = GetPathWithoutExt(); 319 if (!BaseExtension.IsEmpty()) 320 { 321 path += '.'; 322 path += BaseExtension; 323 } 324 return path; 325 } 326 327 UString CArchivePath::GetFinalVolPath() const 328 { 329 UString path = GetPathWithoutExt(); 330 if (!BaseExtension.IsEmpty()) 331 { 332 path += '.'; 333 path += VolExtension; 334 } 335 return path; 336 } 337 338 FString CArchivePath::GetTempPath() const 339 { 340 FString path = TempPrefix; 341 path += us2fs(Name); 342 if (!BaseExtension.IsEmpty()) 343 { 344 path += '.'; 345 path += us2fs(BaseExtension); 346 } 347 path += ".tmp"; 348 path += TempPostfix; 349 return path; 350 } 351 352 static const char * const kDefaultArcType = "7z"; 353 static const char * const kDefaultArcExt = "7z"; 354 static const char * const kSFXExtension = 355 #ifdef _WIN32 356 "exe"; 357 #else 358 ""; 359 #endif 360 361 bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, 362 const CObjectVector<COpenType> &types, const UString &arcPath) 363 { 364 if (types.Size() > 1) 365 return false; 366 // int arcTypeIndex = -1; 367 if (types.Size() != 0) 368 { 369 MethodMode.Type = types[0]; 370 MethodMode.Type_Defined = true; 371 } 372 if (MethodMode.Type.FormatIndex < 0) 373 { 374 // MethodMode.Type = -1; 375 MethodMode.Type = COpenType(); 376 if (ArcNameMode != k_ArcNameMode_Add) 377 { 378 MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); 379 if (MethodMode.Type.FormatIndex >= 0) 380 MethodMode.Type_Defined = true; 381 } 382 } 383 return true; 384 } 385 386 bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) 387 { 388 UString typeExt; 389 int formatIndex = MethodMode.Type.FormatIndex; 390 if (formatIndex < 0) 391 { 392 typeExt = kDefaultArcExt; 393 } 394 else 395 { 396 const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; 397 if (!arcInfo.UpdateEnabled) 398 return false; 399 typeExt = arcInfo.GetMainExt(); 400 } 401 UString ext = typeExt; 402 if (SfxMode) 403 ext = kSFXExtension; 404 ArchivePath.BaseExtension = ext; 405 ArchivePath.VolExtension = typeExt; 406 ArchivePath.ParseFromPath(arcPath, ArcNameMode); 407 FOR_VECTOR (i, Commands) 408 { 409 CUpdateArchiveCommand &uc = Commands[i]; 410 uc.ArchivePath.BaseExtension = ext; 411 uc.ArchivePath.VolExtension = typeExt; 412 uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); 413 } 414 return true; 415 } 416 417 418 struct CUpdateProduceCallbackImp: public IUpdateProduceCallback 419 { 420 const CObjectVector<CArcItem> *_arcItems; 421 IUpdateCallbackUI *_callback; 422 CDirItemsStat *_stat; 423 424 CUpdateProduceCallbackImp( 425 const CObjectVector<CArcItem> *a, 426 CDirItemsStat *stat, 427 IUpdateCallbackUI *callback): 428 _arcItems(a), 429 _stat(stat), 430 _callback(callback) {} 431 432 virtual HRESULT ShowDeleteFile(unsigned arcIndex); 433 }; 434 435 436 HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex) 437 { 438 const CArcItem &ai = (*_arcItems)[arcIndex]; 439 { 440 CDirItemsStat &stat = *_stat; 441 if (ai.IsDir) 442 stat.NumDirs++; 443 else if (ai.IsAltStream) 444 { 445 stat.NumAltStreams++; 446 stat.AltStreamsSize += ai.Size; 447 } 448 else 449 { 450 stat.NumFiles++; 451 stat.FilesSize += ai.Size; 452 } 453 } 454 return _callback->ShowDeleteFile(ai.Name, ai.IsDir); 455 } 456 457 bool CRenamePair::Prepare() 458 { 459 if (RecursedType != NRecursedType::kNonRecursed) 460 return false; 461 if (!WildcardParsing) 462 return true; 463 return !DoesNameContainWildcard(OldName); 464 } 465 466 extern bool g_CaseSensitive; 467 468 static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2) 469 { 470 for (unsigned i = 0;; i++) 471 { 472 wchar_t c1 = s1[i]; 473 wchar_t c2 = s2[i]; 474 if (c1 == 0 || c2 == 0) 475 return i; 476 if (c1 == c2) 477 continue; 478 if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) 479 continue; 480 if (IsPathSepar(c1) && IsPathSepar(c2)) 481 continue; 482 return i; 483 } 484 } 485 486 bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const 487 { 488 unsigned num = CompareTwoNames(OldName, src); 489 if (OldName[num] == 0) 490 { 491 if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1])) 492 return false; 493 } 494 else 495 { 496 // OldName[num] != 0 497 // OldName = "1\1a.txt" 498 // src = "1" 499 500 if (!isFolder 501 || src[num] != 0 502 || !IsPathSepar(OldName[num]) 503 || OldName[num + 1] != 0) 504 return false; 505 } 506 dest = NewName + src.Ptr(num); 507 return true; 508 } 509 510 #ifdef SUPPORT_ALT_STREAMS 511 int FindAltStreamColon_in_Path(const wchar_t *path); 512 #endif 513 514 static HRESULT Compress( 515 const CUpdateOptions &options, 516 bool isUpdatingItself, 517 CCodecs *codecs, 518 const CActionSet &actionSet, 519 const CArc *arc, 520 CArchivePath &archivePath, 521 const CObjectVector<CArcItem> &arcItems, 522 Byte *processedItemsStatuses, 523 const CDirItems &dirItems, 524 const CDirItem *parentDirItem, 525 CTempFiles &tempFiles, 526 CUpdateErrorInfo &errorInfo, 527 IUpdateCallbackUI *callback, 528 CFinishArchiveStat &st) 529 { 530 CMyComPtr<IOutArchive> outArchive; 531 int formatIndex = options.MethodMode.Type.FormatIndex; 532 533 if (arc) 534 { 535 formatIndex = arc->FormatIndex; 536 if (formatIndex < 0) 537 return E_NOTIMPL; 538 CMyComPtr<IInArchive> archive2 = arc->Archive; 539 HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); 540 if (result != S_OK) 541 throw kUpdateIsNotSupoorted; 542 } 543 else 544 { 545 RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); 546 547 #ifdef EXTERNAL_CODECS 548 { 549 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; 550 outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); 551 if (setCompressCodecsInfo) 552 { 553 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); 554 } 555 } 556 #endif 557 } 558 559 if (outArchive == 0) 560 throw kUpdateIsNotSupoorted; 561 562 NFileTimeType::EEnum fileTimeType; 563 { 564 UInt32 value; 565 RINOK(outArchive->GetFileTimeType(&value)); 566 567 switch (value) 568 { 569 case NFileTimeType::kWindows: 570 case NFileTimeType::kUnix: 571 case NFileTimeType::kDOS: 572 fileTimeType = (NFileTimeType::EEnum)value; 573 break; 574 default: 575 return E_FAIL; 576 } 577 } 578 579 { 580 const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; 581 if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) 582 return E_NOTIMPL; 583 if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) 584 return E_NOTIMPL; 585 } 586 587 CRecordVector<CUpdatePair2> updatePairs2; 588 589 UStringVector newNames; 590 591 CArcToDoStat stat2; 592 593 if (options.RenamePairs.Size() != 0) 594 { 595 FOR_VECTOR (i, arcItems) 596 { 597 const CArcItem &ai = arcItems[i]; 598 bool needRename = false; 599 UString dest; 600 601 if (ai.Censored) 602 { 603 FOR_VECTOR (j, options.RenamePairs) 604 { 605 const CRenamePair &rp = options.RenamePairs[j]; 606 if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) 607 { 608 needRename = true; 609 break; 610 } 611 612 #ifdef SUPPORT_ALT_STREAMS 613 if (ai.IsAltStream) 614 { 615 int colonPos = FindAltStreamColon_in_Path(ai.Name); 616 if (colonPos >= 0) 617 { 618 UString mainName = ai.Name.Left(colonPos); 619 /* 620 actually we must improve that code to support cases 621 with folder renaming like: rn arc dir1\ dir2\ 622 */ 623 if (rp.GetNewPath(false, mainName, dest)) 624 { 625 needRename = true; 626 dest += ':'; 627 dest += ai.Name.Ptr(colonPos + 1); 628 break; 629 } 630 } 631 } 632 #endif 633 } 634 } 635 636 CUpdatePair2 up2; 637 up2.SetAs_NoChangeArcItem(ai.IndexInServer); 638 if (needRename) 639 { 640 up2.NewProps = true; 641 RINOK(arc->IsItemAnti(i, up2.IsAnti)); 642 up2.NewNameIndex = newNames.Add(dest); 643 } 644 updatePairs2.Add(up2); 645 } 646 } 647 else 648 { 649 CRecordVector<CUpdatePair> updatePairs; 650 GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! 651 CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback); 652 653 UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL); 654 } 655 656 { 657 FOR_VECTOR (i, updatePairs2) 658 { 659 const CUpdatePair2 &up = updatePairs2[i]; 660 661 // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases)) 662 663 if (up.NewData && !up.UseArcProps) 664 { 665 if (up.ExistOnDisk()) 666 { 667 CDirItemsStat2 &stat = stat2.NewData; 668 const CDirItem &di = dirItems.Items[up.DirIndex]; 669 if (di.IsDir()) 670 { 671 if (up.IsAnti) 672 stat.Anti_NumDirs++; 673 else 674 stat.NumDirs++; 675 } 676 else if (di.IsAltStream) 677 { 678 if (up.IsAnti) 679 stat.Anti_NumAltStreams++; 680 else 681 { 682 stat.NumAltStreams++; 683 stat.AltStreamsSize += di.Size; 684 } 685 } 686 else 687 { 688 if (up.IsAnti) 689 stat.Anti_NumFiles++; 690 else 691 { 692 stat.NumFiles++; 693 stat.FilesSize += di.Size; 694 } 695 } 696 } 697 } 698 else if (up.ArcIndex >= 0) 699 { 700 CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData); 701 const CArcItem &ai = arcItems[up.ArcIndex]; 702 if (ai.IsDir) 703 { 704 if (up.IsAnti) 705 stat.Anti_NumDirs++; 706 else 707 stat.NumDirs++; 708 } 709 else if (ai.IsAltStream) 710 { 711 if (up.IsAnti) 712 stat.Anti_NumAltStreams++; 713 else 714 { 715 stat.NumAltStreams++; 716 stat.AltStreamsSize += ai.Size; 717 } 718 } 719 else 720 { 721 if (up.IsAnti) 722 stat.Anti_NumFiles++; 723 else 724 { 725 stat.NumFiles++; 726 stat.FilesSize += ai.Size; 727 } 728 } 729 } 730 } 731 RINOK(callback->SetNumItems(stat2)); 732 } 733 734 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; 735 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); 736 737 updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; 738 updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError; 739 updateCallbackSpec->StdInMode = options.StdInMode; 740 updateCallbackSpec->Callback = callback; 741 742 if (arc) 743 { 744 // we set Archive to allow to transfer GetProperty requests back to DLL. 745 updateCallbackSpec->Archive = arc->Archive; 746 } 747 748 updateCallbackSpec->DirItems = &dirItems; 749 updateCallbackSpec->ParentDirItem = parentDirItem; 750 751 updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; 752 updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; 753 updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; 754 755 updateCallbackSpec->Arc = arc; 756 updateCallbackSpec->ArcItems = &arcItems; 757 updateCallbackSpec->UpdatePairs = &updatePairs2; 758 759 updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; 760 761 if (options.RenamePairs.Size() != 0) 762 updateCallbackSpec->NewNames = &newNames; 763 764 CMyComPtr<IOutStream> outSeekStream; 765 CMyComPtr<ISequentialOutStream> outStream; 766 767 if (!options.StdOutMode) 768 { 769 FString dirPrefix; 770 if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) 771 throw 1417161; 772 CreateComplexDir(dirPrefix); 773 } 774 775 COutFileStream *outStreamSpec = NULL; 776 CStdOutFileStream *stdOutFileStreamSpec = NULL; 777 COutMultiVolStream *volStreamSpec = NULL; 778 779 if (options.VolumesSizes.Size() == 0) 780 { 781 if (options.StdOutMode) 782 { 783 stdOutFileStreamSpec = new CStdOutFileStream; 784 outStream = stdOutFileStreamSpec; 785 } 786 else 787 { 788 outStreamSpec = new COutFileStream; 789 outSeekStream = outStreamSpec; 790 outStream = outSeekStream; 791 bool isOK = false; 792 FString realPath; 793 794 for (unsigned i = 0; i < (1 << 16); i++) 795 { 796 if (archivePath.Temp) 797 { 798 if (i > 0) 799 { 800 archivePath.TempPostfix.Empty(); 801 archivePath.TempPostfix.Add_UInt32(i); 802 } 803 realPath = archivePath.GetTempPath(); 804 } 805 else 806 realPath = us2fs(archivePath.GetFinalPath()); 807 if (outStreamSpec->Create(realPath, false)) 808 { 809 tempFiles.Paths.Add(realPath); 810 isOK = true; 811 break; 812 } 813 if (::GetLastError() != ERROR_FILE_EXISTS) 814 break; 815 if (!archivePath.Temp) 816 break; 817 } 818 819 if (!isOK) 820 return errorInfo.SetFromLastError("cannot open file", realPath); 821 } 822 } 823 else 824 { 825 if (options.StdOutMode) 826 return E_FAIL; 827 if (arc && arc->GetGlobalOffset() > 0) 828 return E_NOTIMPL; 829 830 volStreamSpec = new COutMultiVolStream; 831 outSeekStream = volStreamSpec; 832 outStream = outSeekStream; 833 volStreamSpec->Sizes = options.VolumesSizes; 834 volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath()); 835 volStreamSpec->Prefix += '.'; 836 volStreamSpec->TempFiles = &tempFiles; 837 volStreamSpec->Init(); 838 839 /* 840 updateCallbackSpec->VolumesSizes = volumesSizes; 841 updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; 842 if (!archivePath.VolExtension.IsEmpty()) 843 updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension; 844 */ 845 } 846 847 RINOK(SetProperties(outArchive, options.MethodMode.Properties)); 848 849 if (options.SfxMode) 850 { 851 CInFileStream *sfxStreamSpec = new CInFileStream; 852 CMyComPtr<IInStream> sfxStream(sfxStreamSpec); 853 if (!sfxStreamSpec->Open(options.SfxModule)) 854 return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); 855 856 CMyComPtr<ISequentialOutStream> sfxOutStream; 857 COutFileStream *outStreamSpec2 = NULL; 858 if (options.VolumesSizes.Size() == 0) 859 sfxOutStream = outStream; 860 else 861 { 862 outStreamSpec2 = new COutFileStream; 863 sfxOutStream = outStreamSpec2; 864 FString realPath = us2fs(archivePath.GetFinalPath()); 865 if (!outStreamSpec2->Create(realPath, false)) 866 return errorInfo.SetFromLastError("cannot open file", realPath); 867 } 868 869 { 870 UInt64 sfxSize; 871 RINOK(sfxStreamSpec->GetSize(&sfxSize)); 872 RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)); 873 } 874 875 RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); 876 877 if (outStreamSpec2) 878 { 879 RINOK(outStreamSpec2->Close()); 880 } 881 } 882 883 CMyComPtr<ISequentialOutStream> tailStream; 884 885 if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) 886 tailStream = outStream; 887 else 888 { 889 // Int64 globalOffset = arc->GetGlobalOffset(); 890 RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); 891 RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); 892 if (options.StdOutMode) 893 tailStream = outStream; 894 else 895 { 896 CTailOutStream *tailStreamSpec = new CTailOutStream; 897 tailStream = tailStreamSpec; 898 tailStreamSpec->Stream = outSeekStream; 899 tailStreamSpec->Offset = arc->ArcStreamOffset; 900 tailStreamSpec->Init(); 901 } 902 } 903 904 905 HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); 906 // callback->Finalize(); 907 RINOK(result); 908 909 if (!updateCallbackSpec->AreAllFilesClosed()) 910 { 911 errorInfo.Message = "There are unclosed input file:"; 912 errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths; 913 return E_FAIL; 914 } 915 916 if (options.SetArcMTime) 917 { 918 FILETIME ft; 919 ft.dwLowDateTime = 0; 920 ft.dwHighDateTime = 0; 921 FOR_VECTOR (i, updatePairs2) 922 { 923 CUpdatePair2 &pair2 = updatePairs2[i]; 924 const FILETIME *ft2 = NULL; 925 if (pair2.NewProps && pair2.DirIndex >= 0) 926 ft2 = &dirItems.Items[pair2.DirIndex].MTime; 927 else if (pair2.UseArcProps && pair2.ArcIndex >= 0) 928 ft2 = &arcItems[pair2.ArcIndex].MTime; 929 if (ft2) 930 { 931 if (::CompareFileTime(&ft, ft2) < 0) 932 ft = *ft2; 933 } 934 } 935 if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) 936 { 937 if (outStreamSpec) 938 outStreamSpec->SetMTime(&ft); 939 else if (volStreamSpec) 940 volStreamSpec->SetMTime(&ft);; 941 } 942 } 943 944 if (callback) 945 { 946 UInt64 size = 0; 947 if (outStreamSpec) 948 outStreamSpec->GetSize(&size); 949 else if (stdOutFileStreamSpec) 950 size = stdOutFileStreamSpec->GetSize(); 951 else 952 size = volStreamSpec->GetSize(); 953 954 st.OutArcFileSize = size; 955 } 956 957 if (outStreamSpec) 958 result = outStreamSpec->Close(); 959 else if (volStreamSpec) 960 result = volStreamSpec->Close(); 961 return result; 962 } 963 964 bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); 965 966 static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) 967 { 968 bool finded = false; 969 FOR_VECTOR (i, censor.Pairs) 970 { 971 bool include; 972 if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) 973 { 974 if (!include) 975 return false; 976 finded = true; 977 } 978 } 979 return finded; 980 } 981 982 static HRESULT EnumerateInArchiveItems( 983 // bool storeStreamsMode, 984 const NWildcard::CCensor &censor, 985 const CArc &arc, 986 CObjectVector<CArcItem> &arcItems) 987 { 988 arcItems.Clear(); 989 UInt32 numItems; 990 IInArchive *archive = arc.Archive; 991 RINOK(archive->GetNumberOfItems(&numItems)); 992 arcItems.ClearAndReserve(numItems); 993 994 CReadArcItem item; 995 996 for (UInt32 i = 0; i < numItems; i++) 997 { 998 CArcItem ai; 999 1000 RINOK(arc.GetItem(i, item)); 1001 ai.Name = item.Path; 1002 ai.IsDir = item.IsDir; 1003 ai.IsAltStream = 1004 #ifdef SUPPORT_ALT_STREAMS 1005 item.IsAltStream; 1006 #else 1007 false; 1008 #endif 1009 1010 /* 1011 if (!storeStreamsMode && ai.IsAltStream) 1012 continue; 1013 */ 1014 ai.Censored = Censor_CheckPath(censor, item); 1015 1016 RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); 1017 RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); 1018 1019 { 1020 CPropVariant prop; 1021 RINOK(archive->GetProperty(i, kpidTimeType, &prop)); 1022 if (prop.vt == VT_UI4) 1023 { 1024 ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; 1025 switch (ai.TimeType) 1026 { 1027 case NFileTimeType::kWindows: 1028 case NFileTimeType::kUnix: 1029 case NFileTimeType::kDOS: 1030 break; 1031 default: 1032 return E_FAIL; 1033 } 1034 } 1035 } 1036 1037 ai.IndexInServer = i; 1038 arcItems.AddInReserved(ai); 1039 } 1040 return S_OK; 1041 } 1042 1043 #if defined(_WIN32) && !defined(UNDER_CE) 1044 1045 #include <mapi.h> 1046 1047 #endif 1048 1049 HRESULT UpdateArchive( 1050 CCodecs *codecs, 1051 const CObjectVector<COpenType> &types, 1052 const UString &cmdArcPath2, 1053 NWildcard::CCensor &censor, 1054 CUpdateOptions &options, 1055 CUpdateErrorInfo &errorInfo, 1056 IOpenCallbackUI *openCallback, 1057 IUpdateCallbackUI2 *callback, 1058 bool needSetPath) 1059 { 1060 if (options.StdOutMode && options.EMailMode) 1061 return E_FAIL; 1062 1063 if (types.Size() > 1) 1064 return E_NOTIMPL; 1065 1066 bool renameMode = !options.RenamePairs.IsEmpty(); 1067 if (renameMode) 1068 { 1069 if (options.Commands.Size() != 1) 1070 return E_FAIL; 1071 } 1072 1073 if (options.DeleteAfterCompressing) 1074 { 1075 if (options.Commands.Size() != 1) 1076 return E_NOTIMPL; 1077 const CActionSet &as = options.Commands[0].ActionSet; 1078 for (int i = 2; i < NPairState::kNumValues; i++) 1079 if (as.StateActions[i] != NPairAction::kCompress) 1080 return E_NOTIMPL; 1081 } 1082 1083 censor.AddPathsToCensor(options.PathMode); 1084 #ifdef _WIN32 1085 ConvertToLongNames(censor); 1086 #endif 1087 censor.ExtendExclude(); 1088 1089 1090 if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) 1091 return E_NOTIMPL; 1092 1093 if (options.SfxMode) 1094 { 1095 CProperty property; 1096 property.Name = "rsfx"; 1097 options.MethodMode.Properties.Add(property); 1098 if (options.SfxModule.IsEmpty()) 1099 { 1100 errorInfo.Message = "SFX file is not specified"; 1101 return E_FAIL; 1102 } 1103 bool found = false; 1104 if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) 1105 { 1106 const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule; 1107 if (NFind::DoesFileExist(fullName)) 1108 { 1109 options.SfxModule = fullName; 1110 found = true; 1111 } 1112 } 1113 if (!found) 1114 { 1115 if (!NFind::DoesFileExist(options.SfxModule)) 1116 return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule); 1117 } 1118 } 1119 1120 CArchiveLink arcLink; 1121 1122 1123 if (needSetPath) 1124 { 1125 if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || 1126 !options.SetArcPath(codecs, cmdArcPath2)) 1127 return E_NOTIMPL; 1128 } 1129 1130 UString arcPath = options.ArchivePath.GetFinalPath(); 1131 1132 if (!options.VolumesSizes.IsEmpty()) 1133 { 1134 arcPath = options.ArchivePath.GetFinalVolPath(); 1135 arcPath += '.'; 1136 arcPath += "001"; 1137 } 1138 1139 if (cmdArcPath2.IsEmpty()) 1140 { 1141 if (options.MethodMode.Type.FormatIndex < 0) 1142 throw "type of archive is not specified"; 1143 } 1144 else 1145 { 1146 NFind::CFileInfo fi; 1147 if (!fi.Find(us2fs(arcPath))) 1148 { 1149 if (renameMode) 1150 throw "can't find archive";; 1151 if (options.MethodMode.Type.FormatIndex < 0) 1152 { 1153 if (!options.SetArcPath(codecs, cmdArcPath2)) 1154 return E_NOTIMPL; 1155 } 1156 } 1157 else 1158 { 1159 if (fi.IsDir()) 1160 throw "there is no such archive"; 1161 if (fi.IsDevice) 1162 return E_NOTIMPL; 1163 1164 if (!options.StdOutMode && options.UpdateArchiveItself) 1165 if (fi.IsReadOnly()) 1166 { 1167 errorInfo.SystemError = ERROR_ACCESS_DENIED; 1168 errorInfo.Message = "The file is read-only"; 1169 errorInfo.FileNames.Add(arcPath); 1170 return errorInfo.Get_HRESULT_Error(); 1171 } 1172 1173 if (options.VolumesSizes.Size() > 0) 1174 { 1175 errorInfo.FileNames.Add(us2fs(arcPath)); 1176 errorInfo.SystemError = (DWORD)E_NOTIMPL; 1177 errorInfo.Message = kUpdateIsNotSupoorted_MultiVol; 1178 return E_NOTIMPL; 1179 } 1180 CObjectVector<COpenType> types2; 1181 // change it. 1182 if (options.MethodMode.Type_Defined) 1183 types2.Add(options.MethodMode.Type); 1184 // We need to set Properties to open archive only in some cases (WIM archives). 1185 1186 CIntVector excl; 1187 COpenOptions op; 1188 #ifndef _SFX 1189 op.props = &options.MethodMode.Properties; 1190 #endif 1191 op.codecs = codecs; 1192 op.types = &types2; 1193 op.excludedFormats = ! 1194 op.stdInMode = false; 1195 op.stream = NULL; 1196 op.filePath = arcPath; 1197 1198 RINOK(callback->StartOpenArchive(arcPath)); 1199 1200 HRESULT result = arcLink.Open_Strict(op, openCallback); 1201 1202 if (result == E_ABORT) 1203 return result; 1204 1205 HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result); 1206 /* 1207 if (result == S_FALSE) 1208 return E_FAIL; 1209 */ 1210 RINOK(res2); 1211 RINOK(result); 1212 1213 if (arcLink.VolumePaths.Size() > 1) 1214 { 1215 errorInfo.SystemError = (DWORD)E_NOTIMPL; 1216 errorInfo.Message = kUpdateIsNotSupoorted_MultiVol; 1217 return E_NOTIMPL; 1218 } 1219 1220 CArc &arc = arcLink.Arcs.Back(); 1221 arc.MTimeDefined = !fi.IsDevice; 1222 arc.MTime = fi.MTime; 1223 1224 if (arc.ErrorInfo.ThereIsTail) 1225 { 1226 errorInfo.SystemError = (DWORD)E_NOTIMPL; 1227 errorInfo.Message = "There is some data block after the end of the archive"; 1228 return E_NOTIMPL; 1229 } 1230 if (options.MethodMode.Type.FormatIndex < 0) 1231 { 1232 options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; 1233 if (!options.SetArcPath(codecs, cmdArcPath2)) 1234 return E_NOTIMPL; 1235 } 1236 } 1237 } 1238 1239 if (options.MethodMode.Type.FormatIndex < 0) 1240 { 1241 options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType); 1242 if (options.MethodMode.Type.FormatIndex < 0) 1243 return E_NOTIMPL; 1244 } 1245 1246 bool thereIsInArchive = arcLink.IsOpen; 1247 if (!thereIsInArchive && renameMode) 1248 return E_FAIL; 1249 1250 CDirItems dirItems; 1251 dirItems.Callback = callback; 1252 1253 CDirItem parentDirItem; 1254 CDirItem *parentDirItem_Ptr = NULL; 1255 1256 /* 1257 FStringVector requestedPaths; 1258 FStringVector *requestedPaths_Ptr = NULL; 1259 if (options.DeleteAfterCompressing) 1260 requestedPaths_Ptr = &requestedPaths; 1261 */ 1262 1263 if (options.StdInMode) 1264 { 1265 CDirItem di; 1266 di.Name = options.StdInFileName; 1267 di.Size = (UInt64)(Int64)-1; 1268 di.Attrib = 0; 1269 NTime::GetCurUtcFileTime(di.MTime); 1270 di.CTime = di.ATime = di.MTime; 1271 dirItems.Items.Add(di); 1272 } 1273 else 1274 { 1275 bool needScanning = false; 1276 1277 if (!renameMode) 1278 FOR_VECTOR (i, options.Commands) 1279 if (options.Commands[i].ActionSet.NeedScanning()) 1280 needScanning = true; 1281 1282 if (needScanning) 1283 { 1284 RINOK(callback->StartScanning()); 1285 1286 dirItems.SymLinks = options.SymLinks.Val; 1287 1288 #if defined(_WIN32) && !defined(UNDER_CE) 1289 dirItems.ReadSecure = options.NtSecurity.Val; 1290 #endif 1291 1292 dirItems.ScanAltStreams = options.AltStreams.Val; 1293 1294 HRESULT res = EnumerateItems(censor, 1295 options.PathMode, 1296 options.AddPathPrefix, 1297 dirItems); 1298 1299 if (res != S_OK) 1300 { 1301 if (res != E_ABORT) 1302 errorInfo.Message = "Scanning error"; 1303 return res; 1304 } 1305 1306 RINOK(callback->FinishScanning(dirItems.Stat)); 1307 1308 if (censor.Pairs.Size() == 1) 1309 { 1310 NFind::CFileInfo fi; 1311 FString prefix = us2fs(censor.Pairs[0].Prefix); 1312 prefix += '.'; 1313 // UString prefix = censor.Pairs[0].Prefix; 1314 /* 1315 if (prefix.Back() == WCHAR_PATH_SEPARATOR) 1316 { 1317 prefix.DeleteBack(); 1318 } 1319 */ 1320 if (fi.Find(prefix)) 1321 if (fi.IsDir()) 1322 { 1323 parentDirItem.Size = fi.Size; 1324 parentDirItem.CTime = fi.CTime; 1325 parentDirItem.ATime = fi.ATime; 1326 parentDirItem.MTime = fi.MTime; 1327 parentDirItem.Attrib = fi.Attrib; 1328 parentDirItem_Ptr = &parentDirItem; 1329 1330 int secureIndex = -1; 1331 #if defined(_WIN32) && !defined(UNDER_CE) 1332 if (options.NtSecurity.Val) 1333 dirItems.AddSecurityItem(prefix, secureIndex); 1334 #endif 1335 parentDirItem.SecureIndex = secureIndex; 1336 1337 parentDirItem_Ptr = &parentDirItem; 1338 } 1339 } 1340 } 1341 } 1342 1343 FString tempDirPrefix; 1344 bool usesTempDir = false; 1345 1346 #ifdef _WIN32 1347 CTempDir tempDirectory; 1348 if (options.EMailMode && options.EMailRemoveAfter) 1349 { 1350 tempDirectory.Create(kTempFolderPrefix); 1351 tempDirPrefix = tempDirectory.GetPath(); 1352 NormalizeDirPathPrefix(tempDirPrefix); 1353 usesTempDir = true; 1354 } 1355 #endif 1356 1357 CTempFiles tempFiles; 1358 1359 bool createTempFile = false; 1360 1361 if (!options.StdOutMode && options.UpdateArchiveItself) 1362 { 1363 CArchivePath &ap = options.Commands[0].ArchivePath; 1364 ap = options.ArchivePath; 1365 // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) 1366 if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0) 1367 { 1368 createTempFile = true; 1369 ap.Temp = true; 1370 if (!options.WorkingDir.IsEmpty()) 1371 ap.TempPrefix = options.WorkingDir; 1372 else 1373 ap.TempPrefix = us2fs(ap.Prefix); 1374 NormalizeDirPathPrefix(ap.TempPrefix); 1375 } 1376 } 1377 1378 unsigned ci; 1379 1380 for (ci = 0; ci < options.Commands.Size(); ci++) 1381 { 1382 CArchivePath &ap = options.Commands[ci].ArchivePath; 1383 if (usesTempDir) 1384 { 1385 // Check it 1386 ap.Prefix = fs2us(tempDirPrefix); 1387 // ap.Temp = true; 1388 // ap.TempPrefix = tempDirPrefix; 1389 } 1390 if (!options.StdOutMode && 1391 (ci > 0 || !createTempFile)) 1392 { 1393 const FString path = us2fs(ap.GetFinalPath()); 1394 if (NFind::DoesFileOrDirExist(path)) 1395 { 1396 errorInfo.SystemError = ERROR_FILE_EXISTS; 1397 errorInfo.Message = "The file already exists"; 1398 errorInfo.FileNames.Add(path); 1399 return errorInfo.Get_HRESULT_Error(); 1400 } 1401 } 1402 } 1403 1404 CObjectVector<CArcItem> arcItems; 1405 if (thereIsInArchive) 1406 { 1407 RINOK(EnumerateInArchiveItems( 1408 // options.StoreAltStreams, 1409 censor, arcLink.Arcs.Back(), arcItems)); 1410 } 1411 1412 /* 1413 FStringVector processedFilePaths; 1414 FStringVector *processedFilePaths_Ptr = NULL; 1415 if (options.DeleteAfterCompressing) 1416 processedFilePaths_Ptr = &processedFilePaths; 1417 */ 1418 1419 CByteBuffer processedItems; 1420 if (options.DeleteAfterCompressing) 1421 { 1422 unsigned num = dirItems.Items.Size(); 1423 processedItems.Alloc(num); 1424 for (unsigned i = 0; i < num; i++) 1425 processedItems[i] = 0; 1426 } 1427 1428 /* 1429 #ifndef _NO_CRYPTO 1430 if (arcLink.PasswordWasAsked) 1431 { 1432 // We set password, if open have requested password 1433 RINOK(callback->SetPassword(arcLink.Password)); 1434 } 1435 #endif 1436 */ 1437 1438 for (ci = 0; ci < options.Commands.Size(); ci++) 1439 { 1440 const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL; 1441 CUpdateArchiveCommand &command = options.Commands[ci]; 1442 UString name; 1443 bool isUpdating; 1444 1445 if (options.StdOutMode) 1446 { 1447 name = "stdout"; 1448 isUpdating = thereIsInArchive; 1449 } 1450 else 1451 { 1452 name = command.ArchivePath.GetFinalPath(); 1453 isUpdating = (ci == 0 && options.UpdateArchiveItself && thereIsInArchive); 1454 } 1455 1456 RINOK(callback->StartArchive(name, isUpdating)) 1457 1458 CFinishArchiveStat st; 1459 1460 RINOK(Compress(options, 1461 isUpdating, 1462 codecs, 1463 command.ActionSet, 1464 arc, 1465 command.ArchivePath, 1466 arcItems, 1467 options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, 1468 1469 dirItems, 1470 parentDirItem_Ptr, 1471 1472 tempFiles, 1473 errorInfo, callback, st)); 1474 1475 RINOK(callback->FinishArchive(st)); 1476 } 1477 1478 1479 if (thereIsInArchive) 1480 { 1481 RINOK(arcLink.Close()); 1482 arcLink.Release(); 1483 } 1484 1485 tempFiles.Paths.Clear(); 1486 if (createTempFile) 1487 { 1488 try 1489 { 1490 CArchivePath &ap = options.Commands[0].ArchivePath; 1491 const FString &tempPath = ap.GetTempPath(); 1492 1493 // DWORD attrib = 0; 1494 if (thereIsInArchive) 1495 { 1496 // attrib = NFind::GetFileAttrib(us2fs(arcPath)); 1497 if (!DeleteFileAlways(us2fs(arcPath))) 1498 return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); 1499 } 1500 1501 if (!MyMoveFile(tempPath, us2fs(arcPath))) 1502 { 1503 errorInfo.SetFromLastError("cannot move the file", tempPath); 1504 errorInfo.FileNames.Add(us2fs(arcPath)); 1505 return errorInfo.Get_HRESULT_Error(); 1506 } 1507 1508 /* 1509 if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) 1510 { 1511 DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath)); 1512 if (attrib2 != INVALID_FILE_ATTRIBUTES) 1513 NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY); 1514 } 1515 */ 1516 } 1517 catch(...) 1518 { 1519 throw; 1520 } 1521 } 1522 1523 1524 #if defined(_WIN32) && !defined(UNDER_CE) 1525 1526 if (options.EMailMode) 1527 { 1528 NDLL::CLibrary mapiLib; 1529 if (!mapiLib.Load(FTEXT("Mapi32.dll"))) 1530 { 1531 errorInfo.SetFromLastError("cannot load Mapi32.dll"); 1532 return errorInfo.Get_HRESULT_Error(); 1533 } 1534 1535 /* 1536 LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); 1537 if (fnSend == 0) 1538 { 1539 errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function"); 1540 return errorInfo.Get_HRESULT_Error(); 1541 } 1542 */ 1543 1544 LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); 1545 if (sendMail == 0) 1546 { 1547 errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); 1548 return errorInfo.Get_HRESULT_Error();; 1549 } 1550 1551 FStringVector fullPaths; 1552 unsigned i; 1553 1554 for (i = 0; i < options.Commands.Size(); i++) 1555 { 1556 CArchivePath &ap = options.Commands[i].ArchivePath; 1557 FString finalPath = us2fs(ap.GetFinalPath()); 1558 FString arcPath2; 1559 if (!MyGetFullPathName(finalPath, arcPath2)) 1560 return errorInfo.SetFromLastError("GetFullPathName error", finalPath); 1561 fullPaths.Add(arcPath2); 1562 } 1563 1564 CCurrentDirRestorer curDirRestorer; 1565 1566 for (i = 0; i < fullPaths.Size(); i++) 1567 { 1568 const UString arcPath2 = fs2us(fullPaths[i]); 1569 const UString fileName = ExtractFileNameFromPath(arcPath2); 1570 const AString path (GetAnsiString(arcPath2)); 1571 const AString name (GetAnsiString(fileName)); 1572 // Warning!!! MAPISendDocuments function changes Current directory 1573 // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); 1574 1575 MapiFileDesc f; 1576 memset(&f, 0, sizeof(f)); 1577 f.nPosition = 0xFFFFFFFF; 1578 f.lpszPathName = (char *)(const char *)path; 1579 f.lpszFileName = (char *)(const char *)name; 1580 1581 MapiMessage m; 1582 memset(&m, 0, sizeof(m)); 1583 m.nFileCount = 1; 1584 m.lpFiles = &f; 1585 1586 const AString addr (GetAnsiString(options.EMailAddress)); 1587 MapiRecipDesc rec; 1588 if (!addr.IsEmpty()) 1589 { 1590 memset(&rec, 0, sizeof(rec)); 1591 rec.ulRecipClass = MAPI_TO; 1592 rec.lpszAddress = (char *)(const char *)addr; 1593 m.nRecipCount = 1; 1594 m.lpRecips = &rec; 1595 } 1596 1597 sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); 1598 } 1599 } 1600 1601 #endif 1602 1603 if (options.DeleteAfterCompressing) 1604 { 1605 CRecordVector<CDirPathSortPair> pairs; 1606 FStringVector foldersNames; 1607 1608 unsigned i; 1609 1610 for (i = 0; i < dirItems.Items.Size(); i++) 1611 { 1612 const CDirItem &dirItem = dirItems.Items[i]; 1613 const FString phyPath = dirItems.GetPhyPath(i); 1614 if (dirItem.IsDir()) 1615 { 1616 CDirPathSortPair pair; 1617 pair.Index = i; 1618 pair.SetNumSlashes(phyPath); 1619 pairs.Add(pair); 1620 } 1621 else 1622 { 1623 if (processedItems[i] != 0 || dirItem.Size == 0) 1624 { 1625 NFind::CFileInfo fileInfo; 1626 if (fileInfo.Find(phyPath)) 1627 { 1628 // maybe we must exclude also files with archive name: "a a.7z * -sdel" 1629 if (fileInfo.Size == dirItem.Size 1630 && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0 1631 && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0) 1632 { 1633 RINOK(callback->DeletingAfterArchiving(phyPath, false)); 1634 DeleteFileAlways(phyPath); 1635 } 1636 } 1637 } 1638 else 1639 { 1640 // file was skipped 1641 /* 1642 errorInfo.SystemError = 0; 1643 errorInfo.Message = "file was not processed"; 1644 errorInfo.FileName = phyPath; 1645 return E_FAIL; 1646 */ 1647 } 1648 } 1649 } 1650 1651 pairs.Sort2(); 1652 1653 for (i = 0; i < pairs.Size(); i++) 1654 { 1655 const FString phyPath = dirItems.GetPhyPath(pairs[i].Index); 1656 if (NFind::DoesDirExist(phyPath)) 1657 { 1658 RINOK(callback->DeletingAfterArchiving(phyPath, true)); 1659 RemoveDir(phyPath); 1660 } 1661 } 1662 1663 RINOK(callback->FinishDeletingAfterArchiving()); 1664 } 1665 1666 return S_OK; 1667 }