7 #include "Common/IntToString.h"
\r
8 #include "Common/StringConvert.h"
\r
11 #include "Windows/DLL.h"
\r
14 #include "Windows/FileDir.h"
\r
15 #include "Windows/FileFind.h"
\r
16 #include "Windows/FileName.h"
\r
17 #include "Windows/PropVariant.h"
\r
18 #include "Windows/PropVariantConversions.h"
\r
19 #include "Windows/Time.h"
\r
21 #include "../../Common/FileStreams.h"
\r
23 #include "../../Compress/CopyCoder.h"
\r
25 #include "../Common/DirItem.h"
\r
26 #include "../Common/EnumDirItems.h"
\r
27 #include "../Common/OpenArchive.h"
\r
28 #include "../Common/UpdateProduce.h"
\r
30 #include "EnumDirItems.h"
\r
31 #include "SetProperties.h"
\r
32 #include "TempFiles.h"
\r
33 #include "UpdateCallback.h"
\r
35 static const char *kUpdateIsNotSupoorted =
\r
36 "update operations are not supported for this archive";
\r
38 using namespace NWindows;
\r
39 using namespace NCOM;
\r
40 using namespace NFile;
\r
41 using namespace NName;
\r
43 static const wchar_t *kTempFolderPrefix = L"7zE";
\r
45 using namespace NUpdateArchive;
\r
47 class COutMultiVolStream:
\r
49 public CMyUnknownImp
\r
51 int _streamIndex; // required stream
\r
52 UInt64 _offsetPos; // offset from start of _streamIndex index
\r
56 struct CSubStreamInfo
\r
58 COutFileStream *StreamSpec;
\r
59 CMyComPtr<IOutStream> Stream;
\r
64 CObjectVector<CSubStreamInfo> Streams;
\r
66 // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
\r
67 CRecordVector<UInt64> Sizes;
\r
69 CTempFiles *TempFiles;
\r
81 MY_UNKNOWN_IMP1(IOutStream)
\r
83 STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
\r
84 STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
\r
85 STDMETHOD(SetSize)(UInt64 newSize);
\r
88 // static NSynchronization::CCriticalSection g_TempPathsCS;
\r
90 HRESULT COutMultiVolStream::Close()
\r
93 for (int i = 0; i < Streams.Size(); i++)
\r
95 CSubStreamInfo &s = Streams[i];
\r
98 HRESULT res2 = s.StreamSpec->Close();
\r
106 STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
\r
108 if (processedSize != NULL)
\r
109 *processedSize = 0;
\r
112 if (_streamIndex >= Streams.Size())
\r
114 CSubStreamInfo subStream;
\r
117 ConvertUInt32ToString(_streamIndex + 1, temp);
\r
118 UString res = temp;
\r
119 while (res.Length() < 3)
\r
120 res = UString(L'0') + res;
\r
121 UString name = Prefix + res;
\r
122 subStream.StreamSpec = new COutFileStream;
\r
123 subStream.Stream = subStream.StreamSpec;
\r
124 if (!subStream.StreamSpec->Create(name, false))
\r
125 return ::GetLastError();
\r
127 // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
\r
128 TempFiles->Paths.Add(name);
\r
132 subStream.RealSize = 0;
\r
133 subStream.Name = name;
\r
134 Streams.Add(subStream);
\r
137 CSubStreamInfo &subStream = Streams[_streamIndex];
\r
139 int index = _streamIndex;
\r
140 if (index >= Sizes.Size())
\r
141 index = Sizes.Size() - 1;
\r
142 UInt64 volSize = Sizes[index];
\r
144 if (_offsetPos >= volSize)
\r
146 _offsetPos -= volSize;
\r
150 if (_offsetPos != subStream.Pos)
\r
152 // CMyComPtr<IOutStream> outStream;
\r
153 // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
\r
154 RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
\r
155 subStream.Pos = _offsetPos;
\r
158 UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
\r
159 UInt32 realProcessed;
\r
160 RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
\r
161 data = (void *)((Byte *)data + realProcessed);
\r
162 size -= realProcessed;
\r
163 subStream.Pos += realProcessed;
\r
164 _offsetPos += realProcessed;
\r
165 _absPos += realProcessed;
\r
166 if (_absPos > _length)
\r
168 if (_offsetPos > subStream.RealSize)
\r
169 subStream.RealSize = _offsetPos;
\r
170 if (processedSize != NULL)
\r
171 *processedSize += realProcessed;
\r
172 if (subStream.Pos == volSize)
\r
177 if (realProcessed == 0 && curSize != 0)
\r
184 STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
\r
186 if (seekOrigin >= 3)
\r
187 return STG_E_INVALIDFUNCTION;
\r
190 case STREAM_SEEK_SET:
\r
193 case STREAM_SEEK_CUR:
\r
196 case STREAM_SEEK_END:
\r
197 _absPos = _length + offset;
\r
200 _offsetPos = _absPos;
\r
201 if (newPosition != NULL)
\r
202 *newPosition = _absPos;
\r
207 STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)
\r
210 return E_INVALIDARG;
\r
212 while (i < Streams.Size())
\r
214 CSubStreamInfo &subStream = Streams[i++];
\r
215 if ((UInt64)newSize < subStream.RealSize)
\r
217 RINOK(subStream.Stream->SetSize(newSize));
\r
218 subStream.RealSize = newSize;
\r
221 newSize -= subStream.RealSize;
\r
223 while (i < Streams.Size())
\r
226 CSubStreamInfo &subStream = Streams.Back();
\r
227 subStream.Stream.Release();
\r
228 NDirectory::DeleteFileAlways(subStream.Name);
\r
230 Streams.DeleteBack();
\r
232 _offsetPos = _absPos;
\r
238 static const wchar_t *kDefaultArchiveType = L"7z";
\r
239 static const wchar_t *kSFXExtension =
\r
246 bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath)
\r
248 if (formatIndices.Size() > 1)
\r
250 int arcTypeIndex = -1;
\r
251 if (formatIndices.Size() != 0)
\r
252 arcTypeIndex = formatIndices[0];
\r
253 if (arcTypeIndex >= 0)
\r
254 MethodMode.FormatIndex = arcTypeIndex;
\r
257 MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
\r
258 // It works incorrectly for update command if archive has some non-default extension!
\r
259 if (MethodMode.FormatIndex < 0)
\r
260 MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
\r
262 if (MethodMode.FormatIndex < 0)
\r
264 const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
\r
265 if (!arcInfo.UpdateEnabled)
\r
267 UString typeExt = arcInfo.GetMainExt();
\r
268 UString ext = typeExt;
\r
270 ext = kSFXExtension;
\r
271 ArchivePath.BaseExtension = ext;
\r
272 ArchivePath.VolExtension = typeExt;
\r
273 ArchivePath.ParseFromPath(arcPath);
\r
274 for (int i = 0; i < Commands.Size(); i++)
\r
276 CUpdateArchiveCommand &uc = Commands[i];
\r
277 uc.ArchivePath.BaseExtension = ext;
\r
278 uc.ArchivePath.VolExtension = typeExt;
\r
279 uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
\r
285 struct CUpdateProduceCallbackImp: public IUpdateProduceCallback
\r
287 const CObjectVector<CArcItem> *_arcItems;
\r
288 IUpdateCallbackUI *_callback;
\r
290 CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a,
\r
291 IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {}
\r
292 virtual HRESULT ShowDeleteFile(int arcIndex);
\r
295 HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex)
\r
297 return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name);
\r
301 static HRESULT Compress(
\r
303 const CActionSet &actionSet,
\r
304 IInArchive *archive,
\r
305 const CCompressionMethodMode &compressionMethod,
\r
306 CArchivePath &archivePath,
\r
307 const CObjectVector<CArcItem> &arcItems,
\r
308 bool shareForWrite,
\r
310 /* const UString & stdInFileName, */
\r
312 const CDirItems &dirItems,
\r
314 const UString &sfxModule,
\r
315 const CRecordVector<UInt64> &volumesSizes,
\r
316 CTempFiles &tempFiles,
\r
317 CUpdateErrorInfo &errorInfo,
\r
318 IUpdateCallbackUI *callback)
\r
320 CMyComPtr<IOutArchive> outArchive;
\r
321 if (archive != NULL)
\r
323 CMyComPtr<IInArchive> archive2 = archive;
\r
324 HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
\r
325 if (result != S_OK)
\r
326 throw kUpdateIsNotSupoorted;
\r
330 RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
\r
332 #ifdef EXTERNAL_CODECS
\r
334 CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
\r
335 outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
\r
336 if (setCompressCodecsInfo)
\r
338 RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
\r
343 if (outArchive == 0)
\r
344 throw kUpdateIsNotSupoorted;
\r
346 NFileTimeType::EEnum fileTimeType;
\r
348 RINOK(outArchive->GetFileTimeType(&value));
\r
352 case NFileTimeType::kWindows:
\r
353 case NFileTimeType::kUnix:
\r
354 case NFileTimeType::kDOS:
\r
355 fileTimeType = (NFileTimeType::EEnum)value;
\r
361 CRecordVector<CUpdatePair2> updatePairs2;
\r
364 CRecordVector<CUpdatePair> updatePairs;
\r
365 GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!!
\r
366 // CUpdateProduceCallbackImp upCallback(&arcItems, callback);
\r
367 UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */);
\r
370 UInt32 numFiles = 0;
\r
371 for (int i = 0; i < updatePairs2.Size(); i++)
\r
372 if (updatePairs2[i].NewData)
\r
375 RINOK(callback->SetNumFiles(numFiles));
\r
378 CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
\r
379 CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
\r
381 updateCallbackSpec->ShareForWrite = shareForWrite;
\r
382 updateCallbackSpec->StdInMode = stdInMode;
\r
383 updateCallbackSpec->Callback = callback;
\r
384 updateCallbackSpec->DirItems = &dirItems;
\r
385 updateCallbackSpec->ArcItems = &arcItems;
\r
386 updateCallbackSpec->UpdatePairs = &updatePairs2;
\r
388 CMyComPtr<ISequentialOutStream> outStream;
\r
392 UString resultPath;
\r
394 if (!NFile::NDirectory::MyGetFullPathName(archivePath.GetFinalPath(), resultPath, pos))
\r
396 NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
\r
399 COutFileStream *outStreamSpec = NULL;
\r
400 COutMultiVolStream *volStreamSpec = NULL;
\r
402 if (volumesSizes.Size() == 0)
\r
405 outStream = new CStdOutFileStream;
\r
408 outStreamSpec = new COutFileStream;
\r
409 outStream = outStreamSpec;
\r
412 for (int i = 0; i < (1 << 16); i++)
\r
414 if (archivePath.Temp)
\r
419 ConvertUInt32ToString(i, s);
\r
420 archivePath.TempPostfix = s;
\r
422 realPath = archivePath.GetTempPath();
\r
425 realPath = archivePath.GetFinalPath();
\r
426 if (outStreamSpec->Create(realPath, false))
\r
428 tempFiles.Paths.Add(realPath);
\r
432 if (::GetLastError() != ERROR_FILE_EXISTS)
\r
434 if (!archivePath.Temp)
\r
439 errorInfo.SystemError = ::GetLastError();
\r
440 errorInfo.FileName = realPath;
\r
441 errorInfo.Message = L"7-Zip cannot open file";
\r
450 volStreamSpec = new COutMultiVolStream;
\r
451 outStream = volStreamSpec;
\r
452 volStreamSpec->Sizes = volumesSizes;
\r
453 volStreamSpec->Prefix = archivePath.GetFinalPath() + UString(L".");
\r
454 volStreamSpec->TempFiles = &tempFiles;
\r
455 volStreamSpec->Init();
\r
458 updateCallbackSpec->VolumesSizes = volumesSizes;
\r
459 updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
\r
460 if (!archivePath.VolExtension.IsEmpty())
\r
461 updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension;
\r
465 RINOK(SetProperties(outArchive, compressionMethod.Properties));
\r
469 CInFileStream *sfxStreamSpec = new CInFileStream;
\r
470 CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
\r
471 if (!sfxStreamSpec->Open(sfxModule))
\r
473 errorInfo.SystemError = ::GetLastError();
\r
474 errorInfo.Message = L"7-Zip cannot open SFX module";
\r
475 errorInfo.FileName = sfxModule;
\r
479 CMyComPtr<ISequentialOutStream> sfxOutStream;
\r
480 COutFileStream *outStreamSpec = NULL;
\r
481 if (volumesSizes.Size() == 0)
\r
482 sfxOutStream = outStream;
\r
485 outStreamSpec = new COutFileStream;
\r
486 sfxOutStream = outStreamSpec;
\r
487 UString realPath = archivePath.GetFinalPath();
\r
488 if (!outStreamSpec->Create(realPath, false))
\r
490 errorInfo.SystemError = ::GetLastError();
\r
491 errorInfo.FileName = realPath;
\r
492 errorInfo.Message = L"7-Zip cannot open file";
\r
496 RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL));
\r
499 RINOK(outStreamSpec->Close());
\r
503 HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback);
\r
504 callback->Finilize();
\r
507 result = outStreamSpec->Close();
\r
508 else if (volStreamSpec)
\r
509 result = volStreamSpec->Close();
\r
513 HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor,
\r
515 CObjectVector<CArcItem> &arcItems)
\r
519 IInArchive *archive = arc.Archive;
\r
520 RINOK(archive->GetNumberOfItems(&numItems));
\r
521 arcItems.Reserve(numItems);
\r
522 for (UInt32 i = 0; i < numItems; i++)
\r
526 RINOK(arc.GetItemPath(i, ai.Name));
\r
527 RINOK(IsArchiveItemFolder(archive, i, ai.IsDir));
\r
528 ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir);
\r
529 RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined));
\r
533 RINOK(archive->GetProperty(i, kpidSize, &prop));
\r
534 ai.SizeDefined = (prop.vt != VT_EMPTY);
\r
535 if (ai.SizeDefined)
\r
536 ai.Size = ConvertPropVariantToUInt64(prop);
\r
541 RINOK(archive->GetProperty(i, kpidTimeType, &prop));
\r
542 if (prop.vt == VT_UI4)
\r
544 ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
\r
545 switch(ai.TimeType)
\r
547 case NFileTimeType::kWindows:
\r
548 case NFileTimeType::kUnix:
\r
549 case NFileTimeType::kDOS:
\r
557 ai.IndexInServer = i;
\r
564 static HRESULT UpdateWithItemLists(
\r
566 CUpdateOptions &options,
\r
567 IInArchive *archive,
\r
568 const CObjectVector<CArcItem> &arcItems,
\r
569 CDirItems &dirItems,
\r
570 CTempFiles &tempFiles,
\r
571 CUpdateErrorInfo &errorInfo,
\r
572 IUpdateCallbackUI2 *callback)
\r
574 for(int i = 0; i < options.Commands.Size(); i++)
\r
576 CUpdateArchiveCommand &command = options.Commands[i];
\r
577 if (options.StdOutMode)
\r
579 RINOK(callback->StartArchive(L"stdout", archive != 0));
\r
583 RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(),
\r
584 i == 0 && options.UpdateArchiveItself && archive != 0));
\r
589 command.ActionSet, archive,
\r
590 options.MethodMode,
\r
591 command.ArchivePath,
\r
593 options.OpenShareForWrite,
\r
595 /* options.StdInFileName, */
\r
596 options.StdOutMode,
\r
598 options.SfxMode, options.SfxModule,
\r
599 options.VolumesSizes,
\r
601 errorInfo, callback));
\r
603 RINOK(callback->FinishArchive());
\r
608 #if defined(_WIN32) && !defined(UNDER_CE)
\r
609 class CCurrentDirRestorer
\r
613 CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(_path); }
\r
614 ~CCurrentDirRestorer() { RestoreDirectory();}
\r
615 bool RestoreDirectory() { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(_path)); }
\r
619 struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback
\r
621 IUpdateCallbackUI2 *Callback;
\r
622 HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path)
\r
624 return Callback->ScanProgress(numFolders, numFiles, path);
\r
629 typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)(
\r
630 ULONG_PTR ulUIParam,
\r
631 LPSTR lpszDelimChar,
\r
632 LPSTR lpszFilePaths,
\r
633 LPSTR lpszFileNames,
\r
636 typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS;
\r
639 HRESULT UpdateArchive(
\r
641 const NWildcard::CCensor &censor,
\r
642 CUpdateOptions &options,
\r
643 CUpdateErrorInfo &errorInfo,
\r
644 IOpenCallbackUI *openCallback,
\r
645 IUpdateCallbackUI2 *callback)
\r
647 if (options.StdOutMode && options.EMailMode)
\r
650 if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode))
\r
653 if (options.SfxMode)
\r
655 CProperty property;
\r
656 property.Name = L"rsfx";
\r
657 property.Value = L"on";
\r
658 options.MethodMode.Properties.Add(property);
\r
659 if (options.SfxModule.IsEmpty())
\r
661 errorInfo.Message = L"SFX file is not specified";
\r
664 UString name = options.SfxModule;
\r
666 if (!NFind::DoesFileExist(name))
\r
668 if (!NDirectory::MySearchPath(NULL, name, NULL, options.SfxModule))
\r
671 errorInfo.SystemError = ::GetLastError();
\r
672 errorInfo.Message = L"7-Zip cannot find specified SFX module";
\r
673 errorInfo.FileName = name;
\r
679 CArchiveLink arcLink;
\r
680 const UString arcPath = options.ArchivePath.GetFinalPath();
\r
682 if (!options.ArchivePath.OriginalPath.IsEmpty())
\r
684 NFind::CFileInfoW fi;
\r
685 if (fi.Find(arcPath))
\r
688 throw "there is no such archive";
\r
689 if (options.VolumesSizes.Size() > 0)
\r
691 CIntVector formatIndices;
\r
692 if (options.MethodMode.FormatIndex >= 0)
\r
693 formatIndices.Add(options.MethodMode.FormatIndex);
\r
694 HRESULT result = arcLink.Open2(codecs, formatIndices, false, NULL, arcPath, openCallback);
\r
695 if (result == E_ABORT)
\r
697 RINOK(callback->OpenResult(arcPath, result));
\r
699 if (arcLink.VolumePaths.Size() > 1)
\r
701 errorInfo.SystemError = (DWORD)E_NOTIMPL;
\r
702 errorInfo.Message = L"Updating for multivolume archives is not implemented";
\r
706 CArc &arc = arcLink.Arcs.Back();
\r
707 arc.MTimeDefined = !fi.IsDevice;
\r
708 arc.MTime = fi.MTime;
\r
714 if (archiveType.IsEmpty())
\r
715 throw "type of archive is not specified";
\r
719 CDirItems dirItems;
\r
720 if (options.StdInMode)
\r
723 di.Name = options.StdInFileName;
\r
724 di.Size = (UInt64)(Int64)-1;
\r
726 NTime::GetCurUtcFileTime(di.MTime);
\r
727 di.CTime = di.ATime = di.MTime;
\r
728 dirItems.Items.Add(di);
\r
732 bool needScanning = false;
\r
733 for(int i = 0; i < options.Commands.Size(); i++)
\r
734 if (options.Commands[i].ActionSet.NeedScanning())
\r
735 needScanning = true;
\r
738 CEnumDirItemUpdateCallback enumCallback;
\r
739 enumCallback.Callback = callback;
\r
740 RINOK(callback->StartScanning());
\r
741 UStringVector errorPaths;
\r
742 CRecordVector<DWORD> errorCodes;
\r
743 HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes);
\r
744 for (int i = 0; i < errorPaths.Size(); i++)
\r
746 RINOK(callback->CanNotFindError(errorPaths[i], errorCodes[i]));
\r
750 if (res != E_ABORT)
\r
751 errorInfo.Message = L"Scanning error";
\r
754 RINOK(callback->FinishScanning());
\r
758 UString tempDirPrefix;
\r
759 bool usesTempDir = false;
\r
762 NDirectory::CTempDirectoryW tempDirectory;
\r
763 if (options.EMailMode && options.EMailRemoveAfter)
\r
765 tempDirectory.Create(kTempFolderPrefix);
\r
766 tempDirPrefix = tempDirectory.GetPath();
\r
767 NormalizeDirPathPrefix(tempDirPrefix);
\r
768 usesTempDir = true;
\r
772 CTempFiles tempFiles;
\r
774 bool createTempFile = false;
\r
776 bool thereIsInArchive = arcLink.IsOpen;
\r
778 if (!options.StdOutMode && options.UpdateArchiveItself)
\r
780 CArchivePath &ap = options.Commands[0].ArchivePath;
\r
781 ap = options.ArchivePath;
\r
782 // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
\r
783 if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
\r
785 createTempFile = true;
\r
787 if (!options.WorkingDir.IsEmpty())
\r
789 ap.TempPrefix = options.WorkingDir;
\r
790 NormalizeDirPathPrefix(ap.TempPrefix);
\r
795 for(int i = 0; i < options.Commands.Size(); i++)
\r
797 CArchivePath &ap = options.Commands[i].ArchivePath;
\r
801 ap.Prefix = tempDirPrefix;
\r
803 // ap.TempPrefix = tempDirPrefix;
\r
805 if (!options.StdOutMode &&
\r
806 (i > 0 || !createTempFile))
\r
808 const UString &path = ap.GetFinalPath();
\r
809 if (NFind::DoesFileOrDirExist(path))
\r
811 errorInfo.SystemError = 0;
\r
812 errorInfo.Message = L"The file already exists";
\r
813 errorInfo.FileName = path;
\r
819 CObjectVector<CArcItem> arcItems;
\r
820 if (thereIsInArchive)
\r
822 RINOK(EnumerateInArchiveItems(censor, arcLink.Arcs.Back(), arcItems));
\r
825 RINOK(UpdateWithItemLists(codecs, options,
\r
826 thereIsInArchive ? arcLink.GetArchive() : 0,
\r
827 arcItems, dirItems,
\r
828 tempFiles, errorInfo, callback));
\r
830 if (thereIsInArchive)
\r
832 RINOK(arcLink.Close());
\r
836 tempFiles.Paths.Clear();
\r
837 if (createTempFile)
\r
841 CArchivePath &ap = options.Commands[0].ArchivePath;
\r
842 const UString &tempPath = ap.GetTempPath();
\r
843 if (thereIsInArchive)
\r
844 if (!NDirectory::DeleteFileAlways(arcPath))
\r
846 errorInfo.SystemError = ::GetLastError();
\r
847 errorInfo.Message = L"7-Zip cannot delete the file";
\r
848 errorInfo.FileName = arcPath;
\r
851 if (!NDirectory::MyMoveFile(tempPath, arcPath))
\r
853 errorInfo.SystemError = ::GetLastError();
\r
854 errorInfo.Message = L"7-Zip cannot move the file";
\r
855 errorInfo.FileName = tempPath;
\r
856 errorInfo.FileName2 = arcPath;
\r
866 #if defined(_WIN32) && !defined(UNDER_CE)
\r
867 if (options.EMailMode)
\r
869 NDLL::CLibrary mapiLib;
\r
870 if (!mapiLib.Load(TEXT("Mapi32.dll")))
\r
872 errorInfo.SystemError = ::GetLastError();
\r
873 errorInfo.Message = L"7-Zip cannot load Mapi32.dll";
\r
876 MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
\r
879 errorInfo.SystemError = ::GetLastError();
\r
880 errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function";
\r
883 UStringVector fullPaths;
\r
885 for(i = 0; i < options.Commands.Size(); i++)
\r
887 CArchivePath &ap = options.Commands[i].ArchivePath;
\r
889 if (!NFile::NDirectory::MyGetFullPathName(ap.GetFinalPath(), arcPath))
\r
891 errorInfo.SystemError = ::GetLastError();
\r
892 errorInfo.Message = L"GetFullPathName error";
\r
895 fullPaths.Add(arcPath);
\r
897 CCurrentDirRestorer curDirRestorer;
\r
898 for(i = 0; i < fullPaths.Size(); i++)
\r
900 UString arcPath = fullPaths[i];
\r
901 UString fileName = ExtractFileNameFromPath(arcPath);
\r
902 AString path = GetAnsiString(arcPath);
\r
903 AString name = GetAnsiString(fileName);
\r
904 // Warning!!! MAPISendDocuments function changes Current directory
\r
905 fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
\r