| OLD | NEW |
| (Empty) |
| 1 // Update.cpp | |
| 2 | |
| 3 #include "StdAfx.h" | |
| 4 | |
| 5 #include "Update.h" | |
| 6 | |
| 7 #include "Common/IntToString.h" | |
| 8 #include "Common/StringConvert.h" | |
| 9 | |
| 10 #ifdef _WIN32 | |
| 11 #include "Windows/DLL.h" | |
| 12 #endif | |
| 13 | |
| 14 #include "Windows/FileDir.h" | |
| 15 #include "Windows/FileFind.h" | |
| 16 #include "Windows/FileName.h" | |
| 17 #include "Windows/PropVariant.h" | |
| 18 #include "Windows/PropVariantConversions.h" | |
| 19 #include "Windows/Time.h" | |
| 20 | |
| 21 #include "../../Common/FileStreams.h" | |
| 22 | |
| 23 #include "../../Compress/CopyCoder.h" | |
| 24 | |
| 25 #include "../Common/DirItem.h" | |
| 26 #include "../Common/EnumDirItems.h" | |
| 27 #include "../Common/OpenArchive.h" | |
| 28 #include "../Common/UpdateProduce.h" | |
| 29 | |
| 30 #include "EnumDirItems.h" | |
| 31 #include "SetProperties.h" | |
| 32 #include "TempFiles.h" | |
| 33 #include "UpdateCallback.h" | |
| 34 | |
| 35 static const char *kUpdateIsNotSupoorted = | |
| 36 "update operations are not supported for this archive"; | |
| 37 | |
| 38 using namespace NWindows; | |
| 39 using namespace NCOM; | |
| 40 using namespace NFile; | |
| 41 using namespace NName; | |
| 42 | |
| 43 static const wchar_t *kTempFolderPrefix = L"7zE"; | |
| 44 | |
| 45 using namespace NUpdateArchive; | |
| 46 | |
| 47 static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *ou
tStream) | |
| 48 { | |
| 49 CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder; | |
| 50 return copyCoder->Code(inStream, outStream, NULL, NULL, NULL); | |
| 51 } | |
| 52 | |
| 53 class COutMultiVolStream: | |
| 54 public IOutStream, | |
| 55 public CMyUnknownImp | |
| 56 { | |
| 57 int _streamIndex; // required stream | |
| 58 UInt64 _offsetPos; // offset from start of _streamIndex index | |
| 59 UInt64 _absPos; | |
| 60 UInt64 _length; | |
| 61 | |
| 62 struct CSubStreamInfo | |
| 63 { | |
| 64 COutFileStream *StreamSpec; | |
| 65 CMyComPtr<IOutStream> Stream; | |
| 66 UString Name; | |
| 67 UInt64 Pos; | |
| 68 UInt64 RealSize; | |
| 69 }; | |
| 70 CObjectVector<CSubStreamInfo> Streams; | |
| 71 public: | |
| 72 // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; | |
| 73 CRecordVector<UInt64> Sizes; | |
| 74 UString Prefix; | |
| 75 CTempFiles *TempFiles; | |
| 76 | |
| 77 void Init() | |
| 78 { | |
| 79 _streamIndex = 0; | |
| 80 _offsetPos = 0; | |
| 81 _absPos = 0; | |
| 82 _length = 0; | |
| 83 } | |
| 84 | |
| 85 HRESULT Close(); | |
| 86 | |
| 87 MY_UNKNOWN_IMP1(IOutStream) | |
| 88 | |
| 89 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); | |
| 90 STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); | |
| 91 STDMETHOD(SetSize)(Int64 newSize); | |
| 92 }; | |
| 93 | |
| 94 // static NSynchronization::CCriticalSection g_TempPathsCS; | |
| 95 | |
| 96 HRESULT COutMultiVolStream::Close() | |
| 97 { | |
| 98 HRESULT res = S_OK; | |
| 99 for (int i = 0; i < Streams.Size(); i++) | |
| 100 { | |
| 101 CSubStreamInfo &s = Streams[i]; | |
| 102 if (s.StreamSpec) | |
| 103 { | |
| 104 HRESULT res2 = s.StreamSpec->Close(); | |
| 105 if (res2 != S_OK) | |
| 106 res = res2; | |
| 107 } | |
| 108 } | |
| 109 return res; | |
| 110 } | |
| 111 | |
| 112 STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *pr
ocessedSize) | |
| 113 { | |
| 114 if(processedSize != NULL) | |
| 115 *processedSize = 0; | |
| 116 while(size > 0) | |
| 117 { | |
| 118 if (_streamIndex >= Streams.Size()) | |
| 119 { | |
| 120 CSubStreamInfo subStream; | |
| 121 | |
| 122 wchar_t temp[32]; | |
| 123 ConvertUInt64ToString(_streamIndex + 1, temp); | |
| 124 UString res = temp; | |
| 125 while (res.Length() < 3) | |
| 126 res = UString(L'0') + res; | |
| 127 UString name = Prefix + res; | |
| 128 subStream.StreamSpec = new COutFileStream; | |
| 129 subStream.Stream = subStream.StreamSpec; | |
| 130 if(!subStream.StreamSpec->Create(name, false)) | |
| 131 return ::GetLastError(); | |
| 132 { | |
| 133 // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); | |
| 134 TempFiles->Paths.Add(name); | |
| 135 } | |
| 136 | |
| 137 subStream.Pos = 0; | |
| 138 subStream.RealSize = 0; | |
| 139 subStream.Name = name; | |
| 140 Streams.Add(subStream); | |
| 141 continue; | |
| 142 } | |
| 143 CSubStreamInfo &subStream = Streams[_streamIndex]; | |
| 144 | |
| 145 int index = _streamIndex; | |
| 146 if (index >= Sizes.Size()) | |
| 147 index = Sizes.Size() - 1; | |
| 148 UInt64 volSize = Sizes[index]; | |
| 149 | |
| 150 if (_offsetPos >= volSize) | |
| 151 { | |
| 152 _offsetPos -= volSize; | |
| 153 _streamIndex++; | |
| 154 continue; | |
| 155 } | |
| 156 if (_offsetPos != subStream.Pos) | |
| 157 { | |
| 158 // CMyComPtr<IOutStream> outStream; | |
| 159 // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)); | |
| 160 RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); | |
| 161 subStream.Pos = _offsetPos; | |
| 162 } | |
| 163 | |
| 164 UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos); | |
| 165 UInt32 realProcessed; | |
| 166 RINOK(subStream.Stream->Write(data, curSize, &realProcessed)); | |
| 167 data = (void *)((Byte *)data + realProcessed); | |
| 168 size -= realProcessed; | |
| 169 subStream.Pos += realProcessed; | |
| 170 _offsetPos += realProcessed; | |
| 171 _absPos += realProcessed; | |
| 172 if (_absPos > _length) | |
| 173 _length = _absPos; | |
| 174 if (_offsetPos > subStream.RealSize) | |
| 175 subStream.RealSize = _offsetPos; | |
| 176 if(processedSize != NULL) | |
| 177 *processedSize += realProcessed; | |
| 178 if (subStream.Pos == volSize) | |
| 179 { | |
| 180 _streamIndex++; | |
| 181 _offsetPos = 0; | |
| 182 } | |
| 183 if (realProcessed == 0 && curSize != 0) | |
| 184 return E_FAIL; | |
| 185 break; | |
| 186 } | |
| 187 return S_OK; | |
| 188 } | |
| 189 | |
| 190 STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *n
ewPosition) | |
| 191 { | |
| 192 if(seekOrigin >= 3) | |
| 193 return STG_E_INVALIDFUNCTION; | |
| 194 switch(seekOrigin) | |
| 195 { | |
| 196 case STREAM_SEEK_SET: | |
| 197 _absPos = offset; | |
| 198 break; | |
| 199 case STREAM_SEEK_CUR: | |
| 200 _absPos += offset; | |
| 201 break; | |
| 202 case STREAM_SEEK_END: | |
| 203 _absPos = _length + offset; | |
| 204 break; | |
| 205 } | |
| 206 _offsetPos = _absPos; | |
| 207 if (newPosition != NULL) | |
| 208 *newPosition = _absPos; | |
| 209 _streamIndex = 0; | |
| 210 return S_OK; | |
| 211 } | |
| 212 | |
| 213 STDMETHODIMP COutMultiVolStream::SetSize(Int64 newSize) | |
| 214 { | |
| 215 if (newSize < 0) | |
| 216 return E_INVALIDARG; | |
| 217 int i = 0; | |
| 218 while (i < Streams.Size()) | |
| 219 { | |
| 220 CSubStreamInfo &subStream = Streams[i++]; | |
| 221 if ((UInt64)newSize < subStream.RealSize) | |
| 222 { | |
| 223 RINOK(subStream.Stream->SetSize(newSize)); | |
| 224 subStream.RealSize = newSize; | |
| 225 break; | |
| 226 } | |
| 227 newSize -= subStream.RealSize; | |
| 228 } | |
| 229 while (i < Streams.Size()) | |
| 230 { | |
| 231 { | |
| 232 CSubStreamInfo &subStream = Streams.Back(); | |
| 233 subStream.Stream.Release(); | |
| 234 NDirectory::DeleteFileAlways(subStream.Name); | |
| 235 } | |
| 236 Streams.DeleteBack(); | |
| 237 } | |
| 238 _offsetPos = _absPos; | |
| 239 _streamIndex = 0; | |
| 240 _length = newSize; | |
| 241 return S_OK; | |
| 242 } | |
| 243 | |
| 244 static const wchar_t *kDefaultArchiveType = L"7z"; | |
| 245 static const wchar_t *kSFXExtension = | |
| 246 #ifdef _WIN32 | |
| 247 L"exe"; | |
| 248 #else | |
| 249 L""; | |
| 250 #endif | |
| 251 | |
| 252 bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices
, const UString &arcPath) | |
| 253 { | |
| 254 if (formatIndices.Size() > 1) | |
| 255 return false; | |
| 256 int arcTypeIndex = -1; | |
| 257 if (formatIndices.Size() != 0) | |
| 258 arcTypeIndex = formatIndices[0]; | |
| 259 if (arcTypeIndex >= 0) | |
| 260 MethodMode.FormatIndex = arcTypeIndex; | |
| 261 else | |
| 262 { | |
| 263 MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath); | |
| 264 if (MethodMode.FormatIndex < 0) | |
| 265 MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveT
ype); | |
| 266 } | |
| 267 if (MethodMode.FormatIndex < 0) | |
| 268 return false; | |
| 269 const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex]; | |
| 270 if (!arcInfo.UpdateEnabled) | |
| 271 return false; | |
| 272 UString typeExt = arcInfo.GetMainExt(); | |
| 273 UString ext = typeExt; | |
| 274 if (SfxMode) | |
| 275 ext = kSFXExtension; | |
| 276 ArchivePath.BaseExtension = ext; | |
| 277 ArchivePath.VolExtension = typeExt; | |
| 278 ArchivePath.ParseFromPath(arcPath); | |
| 279 for (int i = 0; i < Commands.Size(); i++) | |
| 280 { | |
| 281 CUpdateArchiveCommand &uc = Commands[i]; | |
| 282 uc.ArchivePath.BaseExtension = ext; | |
| 283 uc.ArchivePath.VolExtension = typeExt; | |
| 284 uc.ArchivePath.ParseFromPath(uc.UserArchivePath); | |
| 285 } | |
| 286 return true; | |
| 287 } | |
| 288 | |
| 289 /* | |
| 290 struct CUpdateProduceCallbackImp: public IUpdateProduceCallback | |
| 291 { | |
| 292 const CObjectVector<CArcItem> *_arcItems; | |
| 293 IUpdateCallbackUI *_callback; | |
| 294 | |
| 295 CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a, | |
| 296 IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} | |
| 297 virtual HRESULT ShowDeleteFile(int arcIndex); | |
| 298 }; | |
| 299 | |
| 300 HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) | |
| 301 { | |
| 302 return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); | |
| 303 } | |
| 304 */ | |
| 305 | |
| 306 static HRESULT Compress( | |
| 307 CCodecs *codecs, | |
| 308 const CActionSet &actionSet, | |
| 309 IInArchive *archive, | |
| 310 const CCompressionMethodMode &compressionMethod, | |
| 311 CArchivePath &archivePath, | |
| 312 const CObjectVector<CArcItem> &arcItems, | |
| 313 bool shareForWrite, | |
| 314 bool stdInMode, | |
| 315 /* const UString & stdInFileName, */ | |
| 316 bool stdOutMode, | |
| 317 const CDirItems &dirItems, | |
| 318 bool sfxMode, | |
| 319 const UString &sfxModule, | |
| 320 const CRecordVector<UInt64> &volumesSizes, | |
| 321 CTempFiles &tempFiles, | |
| 322 CUpdateErrorInfo &errorInfo, | |
| 323 IUpdateCallbackUI *callback) | |
| 324 { | |
| 325 CMyComPtr<IOutArchive> outArchive; | |
| 326 if(archive != NULL) | |
| 327 { | |
| 328 CMyComPtr<IInArchive> archive2 = archive; | |
| 329 HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); | |
| 330 if(result != S_OK) | |
| 331 throw kUpdateIsNotSupoorted; | |
| 332 } | |
| 333 else | |
| 334 { | |
| 335 RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive)); | |
| 336 | |
| 337 #ifdef EXTERNAL_CODECS | |
| 338 { | |
| 339 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; | |
| 340 outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompres
sCodecsInfo); | |
| 341 if (setCompressCodecsInfo) | |
| 342 { | |
| 343 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); | |
| 344 } | |
| 345 } | |
| 346 #endif | |
| 347 } | |
| 348 if (outArchive == 0) | |
| 349 throw kUpdateIsNotSupoorted; | |
| 350 | |
| 351 NFileTimeType::EEnum fileTimeType; | |
| 352 UInt32 value; | |
| 353 RINOK(outArchive->GetFileTimeType(&value)); | |
| 354 | |
| 355 switch(value) | |
| 356 { | |
| 357 case NFileTimeType::kWindows: | |
| 358 case NFileTimeType::kUnix: | |
| 359 case NFileTimeType::kDOS: | |
| 360 fileTimeType = (NFileTimeType::EEnum)value; | |
| 361 break; | |
| 362 default: | |
| 363 return E_FAIL; | |
| 364 } | |
| 365 | |
| 366 CRecordVector<CUpdatePair2> updatePairs2; | |
| 367 | |
| 368 { | |
| 369 CRecordVector<CUpdatePair> updatePairs; | |
| 370 GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // mus
t be done only once!!! | |
| 371 // CUpdateProduceCallbackImp upCallback(&arcItems, callback); | |
| 372 UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */); | |
| 373 } | |
| 374 | |
| 375 UInt32 numFiles = 0; | |
| 376 for (int i = 0; i < updatePairs2.Size(); i++) | |
| 377 if (updatePairs2[i].NewData) | |
| 378 numFiles++; | |
| 379 | |
| 380 RINOK(callback->SetNumFiles(numFiles)); | |
| 381 | |
| 382 | |
| 383 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; | |
| 384 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); | |
| 385 | |
| 386 updateCallbackSpec->ShareForWrite = shareForWrite; | |
| 387 updateCallbackSpec->StdInMode = stdInMode; | |
| 388 updateCallbackSpec->Callback = callback; | |
| 389 updateCallbackSpec->DirItems = &dirItems; | |
| 390 updateCallbackSpec->ArcItems = &arcItems; | |
| 391 updateCallbackSpec->UpdatePairs = &updatePairs2; | |
| 392 | |
| 393 CMyComPtr<ISequentialOutStream> outStream; | |
| 394 | |
| 395 const UString &archiveName = archivePath.GetFinalPath(); | |
| 396 if (!stdOutMode) | |
| 397 { | |
| 398 UString resultPath; | |
| 399 int pos; | |
| 400 if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos)) | |
| 401 throw 1417161; | |
| 402 NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos)); | |
| 403 } | |
| 404 | |
| 405 COutFileStream *outStreamSpec = NULL; | |
| 406 COutMultiVolStream *volStreamSpec = NULL; | |
| 407 | |
| 408 if (volumesSizes.Size() == 0) | |
| 409 { | |
| 410 if (stdOutMode) | |
| 411 outStream = new CStdOutFileStream; | |
| 412 else | |
| 413 { | |
| 414 outStreamSpec = new COutFileStream; | |
| 415 outStream = outStreamSpec; | |
| 416 bool isOK = false; | |
| 417 UString realPath; | |
| 418 for (int i = 0; i < (1 << 16); i++) | |
| 419 { | |
| 420 if (archivePath.Temp) | |
| 421 { | |
| 422 if (i > 0) | |
| 423 { | |
| 424 wchar_t s[32]; | |
| 425 ConvertUInt64ToString(i, s); | |
| 426 archivePath.TempPostfix = s; | |
| 427 } | |
| 428 realPath = archivePath.GetTempPath(); | |
| 429 } | |
| 430 else | |
| 431 realPath = archivePath.GetFinalPath(); | |
| 432 if (outStreamSpec->Create(realPath, false)) | |
| 433 { | |
| 434 tempFiles.Paths.Add(realPath); | |
| 435 isOK = true; | |
| 436 break; | |
| 437 } | |
| 438 if (::GetLastError() != ERROR_FILE_EXISTS) | |
| 439 break; | |
| 440 if (!archivePath.Temp) | |
| 441 break; | |
| 442 } | |
| 443 if (!isOK) | |
| 444 { | |
| 445 errorInfo.SystemError = ::GetLastError(); | |
| 446 errorInfo.FileName = realPath; | |
| 447 errorInfo.Message = L"Can not open file"; | |
| 448 return E_FAIL; | |
| 449 } | |
| 450 } | |
| 451 } | |
| 452 else | |
| 453 { | |
| 454 if (stdOutMode) | |
| 455 return E_FAIL; | |
| 456 volStreamSpec = new COutMultiVolStream; | |
| 457 outStream = volStreamSpec; | |
| 458 volStreamSpec->Sizes = volumesSizes; | |
| 459 volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L"."); | |
| 460 volStreamSpec->TempFiles = &tempFiles; | |
| 461 volStreamSpec->Init(); | |
| 462 | |
| 463 /* | |
| 464 updateCallbackSpec->VolumesSizes = volumesSizes; | |
| 465 updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; | |
| 466 if (!archivePath.VolExtension.IsEmpty()) | |
| 467 updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension; | |
| 468 */ | |
| 469 } | |
| 470 | |
| 471 RINOK(SetProperties(outArchive, compressionMethod.Properties)); | |
| 472 | |
| 473 if (sfxMode) | |
| 474 { | |
| 475 CInFileStream *sfxStreamSpec = new CInFileStream; | |
| 476 CMyComPtr<IInStream> sfxStream(sfxStreamSpec); | |
| 477 if (!sfxStreamSpec->Open(sfxModule)) | |
| 478 { | |
| 479 errorInfo.SystemError = ::GetLastError(); | |
| 480 errorInfo.Message = L"Can't open sfx module"; | |
| 481 errorInfo.FileName = sfxModule; | |
| 482 return E_FAIL; | |
| 483 } | |
| 484 | |
| 485 CMyComPtr<ISequentialOutStream> sfxOutStream; | |
| 486 COutFileStream *outStreamSpec = NULL; | |
| 487 if (volumesSizes.Size() == 0) | |
| 488 sfxOutStream = outStream; | |
| 489 else | |
| 490 { | |
| 491 outStreamSpec = new COutFileStream; | |
| 492 sfxOutStream = outStreamSpec; | |
| 493 UString realPath = archivePath.GetFinalPath(); | |
| 494 if (!outStreamSpec->Create(realPath, false)) | |
| 495 { | |
| 496 errorInfo.SystemError = ::GetLastError(); | |
| 497 errorInfo.FileName = realPath; | |
| 498 errorInfo.Message = L"Can not open file"; | |
| 499 return E_FAIL; | |
| 500 } | |
| 501 } | |
| 502 RINOK(CopyBlock(sfxStream, sfxOutStream)); | |
| 503 if (outStreamSpec) | |
| 504 { | |
| 505 RINOK(outStreamSpec->Close()); | |
| 506 } | |
| 507 } | |
| 508 | |
| 509 HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updat
eCallback); | |
| 510 callback->Finilize(); | |
| 511 RINOK(result); | |
| 512 if (outStreamSpec) | |
| 513 result = outStreamSpec->Close(); | |
| 514 else if (volStreamSpec) | |
| 515 result = volStreamSpec->Close(); | |
| 516 return result; | |
| 517 } | |
| 518 | |
| 519 HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, | |
| 520 IInArchive *archive, | |
| 521 const UString &defaultItemName, | |
| 522 const NWindows::NFile::NFind::CFileInfoW &archiveFileInfo, | |
| 523 CObjectVector<CArcItem> &arcItems) | |
| 524 { | |
| 525 arcItems.Clear(); | |
| 526 UInt32 numItems; | |
| 527 RINOK(archive->GetNumberOfItems(&numItems)); | |
| 528 arcItems.Reserve(numItems); | |
| 529 for (UInt32 i = 0; i < numItems; i++) | |
| 530 { | |
| 531 CArcItem ai; | |
| 532 | |
| 533 RINOK(GetArchiveItemPath(archive, i, ai.Name)); | |
| 534 // check it: defaultItemName !!! | |
| 535 if (ai.Name.IsEmpty()) | |
| 536 ai.Name = defaultItemName; | |
| 537 RINOK(IsArchiveItemFolder(archive, i, ai.IsDir)); | |
| 538 ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir); | |
| 539 RINOK(GetArchiveItemFileTime(archive, i, archiveFileInfo.MTime, ai.MTime)); | |
| 540 | |
| 541 { | |
| 542 CPropVariant prop; | |
| 543 RINOK(archive->GetProperty(i, kpidSize, &prop)); | |
| 544 ai.SizeDefined = (prop.vt != VT_EMPTY); | |
| 545 if (ai.SizeDefined) | |
| 546 ai.Size = ConvertPropVariantToUInt64(prop); | |
| 547 } | |
| 548 | |
| 549 { | |
| 550 CPropVariant prop; | |
| 551 RINOK(archive->GetProperty(i, kpidTimeType, &prop)); | |
| 552 if (prop.vt == VT_UI4) | |
| 553 { | |
| 554 ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; | |
| 555 switch(ai.TimeType) | |
| 556 { | |
| 557 case NFileTimeType::kWindows: | |
| 558 case NFileTimeType::kUnix: | |
| 559 case NFileTimeType::kDOS: | |
| 560 break; | |
| 561 default: | |
| 562 return E_FAIL; | |
| 563 } | |
| 564 } | |
| 565 } | |
| 566 | |
| 567 ai.IndexInServer = i; | |
| 568 arcItems.Add(ai); | |
| 569 } | |
| 570 return S_OK; | |
| 571 } | |
| 572 | |
| 573 | |
| 574 static HRESULT UpdateWithItemLists( | |
| 575 CCodecs *codecs, | |
| 576 CUpdateOptions &options, | |
| 577 IInArchive *archive, | |
| 578 const CObjectVector<CArcItem> &arcItems, | |
| 579 CDirItems &dirItems, | |
| 580 CTempFiles &tempFiles, | |
| 581 CUpdateErrorInfo &errorInfo, | |
| 582 IUpdateCallbackUI2 *callback) | |
| 583 { | |
| 584 for(int i = 0; i < options.Commands.Size(); i++) | |
| 585 { | |
| 586 CUpdateArchiveCommand &command = options.Commands[i]; | |
| 587 if (options.StdOutMode) | |
| 588 { | |
| 589 RINOK(callback->StartArchive(0, archive != 0)); | |
| 590 } | |
| 591 else | |
| 592 { | |
| 593 RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(), | |
| 594 i == 0 && options.UpdateArchiveItself && archive != 0)); | |
| 595 } | |
| 596 | |
| 597 RINOK(Compress( | |
| 598 codecs, | |
| 599 command.ActionSet, archive, | |
| 600 options.MethodMode, | |
| 601 command.ArchivePath, | |
| 602 arcItems, | |
| 603 options.OpenShareForWrite, | |
| 604 options.StdInMode, | |
| 605 /* options.StdInFileName, */ | |
| 606 options.StdOutMode, | |
| 607 dirItems, | |
| 608 options.SfxMode, options.SfxModule, | |
| 609 options.VolumesSizes, | |
| 610 tempFiles, | |
| 611 errorInfo, callback)); | |
| 612 | |
| 613 RINOK(callback->FinishArchive()); | |
| 614 } | |
| 615 return S_OK; | |
| 616 } | |
| 617 | |
| 618 #ifdef _WIN32 | |
| 619 class CCurrentDirRestorer | |
| 620 { | |
| 621 UString m_CurrentDirectory; | |
| 622 public: | |
| 623 CCurrentDirRestorer() | |
| 624 { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); } | |
| 625 ~CCurrentDirRestorer() | |
| 626 { RestoreDirectory();} | |
| 627 bool RestoreDirectory() | |
| 628 { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(m_CurrentDirect
ory)); } | |
| 629 }; | |
| 630 #endif | |
| 631 | |
| 632 struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback | |
| 633 { | |
| 634 IUpdateCallbackUI2 *Callback; | |
| 635 HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) | |
| 636 { | |
| 637 return Callback->ScanProgress(numFolders, numFiles, path); | |
| 638 } | |
| 639 }; | |
| 640 | |
| 641 #ifdef _WIN32 | |
| 642 typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)( | |
| 643 ULONG_PTR ulUIParam, | |
| 644 LPSTR lpszDelimChar, | |
| 645 LPSTR lpszFilePaths, | |
| 646 LPSTR lpszFileNames, | |
| 647 ULONG ulReserved | |
| 648 ); | |
| 649 typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS; | |
| 650 #endif | |
| 651 | |
| 652 HRESULT UpdateArchive( | |
| 653 CCodecs *codecs, | |
| 654 const NWildcard::CCensor &censor, | |
| 655 CUpdateOptions &options, | |
| 656 CUpdateErrorInfo &errorInfo, | |
| 657 IOpenCallbackUI *openCallback, | |
| 658 IUpdateCallbackUI2 *callback) | |
| 659 { | |
| 660 if (options.StdOutMode && options.EMailMode) | |
| 661 return E_FAIL; | |
| 662 | |
| 663 if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode)) | |
| 664 return E_NOTIMPL; | |
| 665 | |
| 666 if (options.SfxMode) | |
| 667 { | |
| 668 CProperty property; | |
| 669 property.Name = L"rsfx"; | |
| 670 property.Value = L"on"; | |
| 671 options.MethodMode.Properties.Add(property); | |
| 672 if (options.SfxModule.IsEmpty()) | |
| 673 { | |
| 674 errorInfo.Message = L"sfx file is not specified"; | |
| 675 return E_FAIL; | |
| 676 } | |
| 677 UString name = options.SfxModule; | |
| 678 if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule)) | |
| 679 { | |
| 680 errorInfo.Message = L"can't find specified sfx module"; | |
| 681 return E_FAIL; | |
| 682 } | |
| 683 } | |
| 684 | |
| 685 const UString archiveName = options.ArchivePath.GetFinalPath(); | |
| 686 | |
| 687 UString defaultItemName; | |
| 688 NFind::CFileInfoW archiveFileInfo; | |
| 689 | |
| 690 CArchiveLink archiveLink; | |
| 691 IInArchive *archive = 0; | |
| 692 if (NFind::FindFile(archiveName, archiveFileInfo)) | |
| 693 { | |
| 694 if (archiveFileInfo.IsDir()) | |
| 695 throw "there is no such archive"; | |
| 696 if (options.VolumesSizes.Size() > 0) | |
| 697 return E_NOTIMPL; | |
| 698 CIntVector formatIndices; | |
| 699 if (options.MethodMode.FormatIndex >= 0) | |
| 700 formatIndices.Add(options.MethodMode.FormatIndex); | |
| 701 HRESULT result = MyOpenArchive(codecs, formatIndices, archiveName, archiveLi
nk, openCallback); | |
| 702 if (result == E_ABORT) | |
| 703 return result; | |
| 704 RINOK(callback->OpenResult(archiveName, result)); | |
| 705 RINOK(result); | |
| 706 if (archiveLink.VolumePaths.Size() > 1) | |
| 707 { | |
| 708 errorInfo.SystemError = (DWORD)E_NOTIMPL; | |
| 709 errorInfo.Message = L"Updating for multivolume archives is not implemented
"; | |
| 710 return E_NOTIMPL; | |
| 711 } | |
| 712 archive = archiveLink.GetArchive(); | |
| 713 defaultItemName = archiveLink.GetDefaultItemName(); | |
| 714 } | |
| 715 else | |
| 716 { | |
| 717 /* | |
| 718 if (archiveType.IsEmpty()) | |
| 719 throw "type of archive is not specified"; | |
| 720 */ | |
| 721 } | |
| 722 | |
| 723 CDirItems dirItems; | |
| 724 if (options.StdInMode) | |
| 725 { | |
| 726 CDirItem di; | |
| 727 di.Name = options.StdInFileName; | |
| 728 di.Size = (UInt64)(Int64)-1; | |
| 729 di.Attrib = 0; | |
| 730 NTime::GetCurUtcFileTime(di.MTime); | |
| 731 di.CTime = di.ATime = di.MTime; | |
| 732 dirItems.Items.Add(di); | |
| 733 } | |
| 734 else | |
| 735 { | |
| 736 bool needScanning = false; | |
| 737 for(int i = 0; i < options.Commands.Size(); i++) | |
| 738 if (options.Commands[i].ActionSet.NeedScanning()) | |
| 739 needScanning = true; | |
| 740 if (needScanning) | |
| 741 { | |
| 742 CEnumDirItemUpdateCallback enumCallback; | |
| 743 enumCallback.Callback = callback; | |
| 744 RINOK(callback->StartScanning()); | |
| 745 UStringVector errorPaths; | |
| 746 CRecordVector<DWORD> errorCodes; | |
| 747 HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths,
errorCodes); | |
| 748 for (int i = 0; i < errorPaths.Size(); i++) | |
| 749 { | |
| 750 RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i])); | |
| 751 } | |
| 752 if (res != S_OK) | |
| 753 { | |
| 754 if (res != E_ABORT) | |
| 755 errorInfo.Message = L"Scanning error"; | |
| 756 // errorInfo.FileName = errorPath; | |
| 757 return res; | |
| 758 } | |
| 759 RINOK(callback->FinishScanning()); | |
| 760 } | |
| 761 } | |
| 762 | |
| 763 UString tempDirPrefix; | |
| 764 bool usesTempDir = false; | |
| 765 | |
| 766 #ifdef _WIN32 | |
| 767 NDirectory::CTempDirectoryW tempDirectory; | |
| 768 if (options.EMailMode && options.EMailRemoveAfter) | |
| 769 { | |
| 770 tempDirectory.Create(kTempFolderPrefix); | |
| 771 tempDirPrefix = tempDirectory.GetPath(); | |
| 772 NormalizeDirPathPrefix(tempDirPrefix); | |
| 773 usesTempDir = true; | |
| 774 } | |
| 775 #endif | |
| 776 | |
| 777 CTempFiles tempFiles; | |
| 778 | |
| 779 bool createTempFile = false; | |
| 780 if(!options.StdOutMode && options.UpdateArchiveItself) | |
| 781 { | |
| 782 CArchivePath &ap = options.Commands[0].ArchivePath; | |
| 783 ap = options.ArchivePath; | |
| 784 // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty()) | |
| 785 if ((archive != 0 || !options.WorkingDir.IsEmpty()) && !usesTempDir && optio
ns.VolumesSizes.Size() == 0) | |
| 786 { | |
| 787 createTempFile = true; | |
| 788 ap.Temp = true; | |
| 789 if (!options.WorkingDir.IsEmpty()) | |
| 790 { | |
| 791 ap.TempPrefix = options.WorkingDir; | |
| 792 NormalizeDirPathPrefix(ap.TempPrefix); | |
| 793 } | |
| 794 } | |
| 795 } | |
| 796 | |
| 797 for(int i = 0; i < options.Commands.Size(); i++) | |
| 798 { | |
| 799 CArchivePath &ap = options.Commands[i].ArchivePath; | |
| 800 if (usesTempDir) | |
| 801 { | |
| 802 // Check it | |
| 803 ap.Prefix = tempDirPrefix; | |
| 804 // ap.Temp = true; | |
| 805 // ap.TempPrefix = tempDirPrefix; | |
| 806 } | |
| 807 if (i > 0 || !createTempFile) | |
| 808 { | |
| 809 const UString &path = ap.GetFinalPath(); | |
| 810 if (NFind::DoesFileExist(path)) | |
| 811 { | |
| 812 errorInfo.SystemError = 0; | |
| 813 errorInfo.Message = L"File already exists"; | |
| 814 errorInfo.FileName = path; | |
| 815 return E_FAIL; | |
| 816 } | |
| 817 } | |
| 818 } | |
| 819 | |
| 820 CObjectVector<CArcItem> arcItems; | |
| 821 if (archive != NULL) | |
| 822 { | |
| 823 RINOK(EnumerateInArchiveItems(censor, | |
| 824 archive, defaultItemName, archiveFileInfo, arcItems)); | |
| 825 } | |
| 826 | |
| 827 RINOK(UpdateWithItemLists(codecs, options, archive, arcItems, dirItems, | |
| 828 tempFiles, errorInfo, callback)); | |
| 829 | |
| 830 if (archive != NULL) | |
| 831 { | |
| 832 RINOK(archiveLink.Close()); | |
| 833 archiveLink.Release(); | |
| 834 } | |
| 835 | |
| 836 tempFiles.Paths.Clear(); | |
| 837 if(createTempFile) | |
| 838 { | |
| 839 try | |
| 840 { | |
| 841 CArchivePath &ap = options.Commands[0].ArchivePath; | |
| 842 const UString &tempPath = ap.GetTempPath(); | |
| 843 if (archive != NULL) | |
| 844 if (!NDirectory::DeleteFileAlways(archiveName)) | |
| 845 { | |
| 846 errorInfo.SystemError = ::GetLastError(); | |
| 847 errorInfo.Message = L"delete file error"; | |
| 848 errorInfo.FileName = archiveName; | |
| 849 return E_FAIL; | |
| 850 } | |
| 851 if (!NDirectory::MyMoveFile(tempPath, archiveName)) | |
| 852 { | |
| 853 errorInfo.SystemError = ::GetLastError(); | |
| 854 errorInfo.Message = L"move file error"; | |
| 855 errorInfo.FileName = tempPath; | |
| 856 errorInfo.FileName2 = archiveName; | |
| 857 return E_FAIL; | |
| 858 } | |
| 859 } | |
| 860 catch(...) | |
| 861 { | |
| 862 throw; | |
| 863 } | |
| 864 } | |
| 865 | |
| 866 #ifdef _WIN32 | |
| 867 if (options.EMailMode) | |
| 868 { | |
| 869 NDLL::CLibrary mapiLib; | |
| 870 if (!mapiLib.Load(TEXT("Mapi32.dll"))) | |
| 871 { | |
| 872 errorInfo.SystemError = ::GetLastError(); | |
| 873 errorInfo.Message = L"can not load Mapi32.dll"; | |
| 874 return E_FAIL; | |
| 875 } | |
| 876 MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS) | |
| 877 mapiLib.GetProcAddress("MAPISendDocuments"); | |
| 878 if (fnSend == 0) | |
| 879 { | |
| 880 errorInfo.SystemError = ::GetLastError(); | |
| 881 errorInfo.Message = L"can not find MAPISendDocuments function"; | |
| 882 return E_FAIL; | |
| 883 } | |
| 884 UStringVector fullPaths; | |
| 885 int i; | |
| 886 for(i = 0; i < options.Commands.Size(); i++) | |
| 887 { | |
| 888 CArchivePath &ap = options.Commands[i].ArchivePath; | |
| 889 UString arcPath; | |
| 890 if(!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath)) | |
| 891 { | |
| 892 errorInfo.SystemError = ::GetLastError(); | |
| 893 return E_FAIL; | |
| 894 } | |
| 895 fullPaths.Add(arcPath); | |
| 896 } | |
| 897 CCurrentDirRestorer curDirRestorer; | |
| 898 for(i = 0; i < fullPaths.Size(); i++) | |
| 899 { | |
| 900 UString arcPath = fullPaths[i]; | |
| 901 UString fileName = ExtractFileNameFromPath(arcPath); | |
| 902 AString path = GetAnsiString(arcPath); | |
| 903 AString name = GetAnsiString(fileName); | |
| 904 // Warning!!! MAPISendDocuments function changes Current directory | |
| 905 fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); | |
| 906 } | |
| 907 } | |
| 908 #endif | |
| 909 return S_OK; | |
| 910 } | |
| 911 | |
| OLD | NEW |