Update.cpp 22 KB

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