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 |