diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp | 1272 |
1 files changed, 960 insertions, 312 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp index e740e8a70f7..2dfb210458d 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp @@ -4,18 +4,19 @@ #include "Update.h" -#include "Common/IntToString.h" -#include "Common/StringConvert.h" +#include "../../../Common/IntToString.h" +#include "../../../Common/StringConvert.h" -#include "Windows/DLL.h" -#include "Windows/FileDir.h" -#include "Windows/FileFind.h" -#include "Windows/FileName.h" -#include "Windows/PropVariant.h" -#include "Windows/PropVariantConversions.h" -#include "Windows/Time.h" +#include "../../../Windows/DLL.h" +#include "../../../Windows/FileDir.h" +#include "../../../Windows/FileFind.h" +#include "../../../Windows/FileName.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/PropVariantConv.h" +#include "../../../Windows/TimeUtils.h" #include "../../Common/FileStreams.h" +#include "../../Common/LimitedStreams.h" #include "../../Compress/CopyCoder.h" @@ -35,22 +36,59 @@ static const char *kUpdateIsNotSupoorted = using namespace NWindows; using namespace NCOM; using namespace NFile; +using namespace NDir; using namespace NName; static CFSTR kTempFolderPrefix = FTEXT("7zE"); + +void CUpdateErrorInfo::SetFromLastError(const char *message) +{ + SystemError = ::GetLastError(); + Message = message; +} + +HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName) +{ + SetFromLastError(message); + FileNames.Add(fileName); + return Get_HRESULT_Error(); +} + +static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) +{ + NFind::CFileInfo fileInfo; + FString pathPrefix = path + FCHAR_PATH_SEPARATOR; + { + NFind::CEnumerator enumerator(pathPrefix + FCHAR_ANY_MASK); + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDir()) + if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name)) + return false; + } + } + /* + // we don't need clear read-only for folders + if (!MySetFileAttributes(path, 0)) + return false; + */ + return RemoveDir(path); +} + + using namespace NUpdateArchive; class COutMultiVolStream: public IOutStream, public CMyUnknownImp { - int _streamIndex; // required stream + unsigned _streamIndex; // required stream UInt64 _offsetPos; // offset from start of _streamIndex index UInt64 _absPos; UInt64 _length; - struct CSubStreamInfo + struct CAltStreamInfo { COutFileStream *StreamSpec; CMyComPtr<IOutStream> Stream; @@ -58,7 +96,7 @@ class COutMultiVolStream: UInt64 Pos; UInt64 RealSize; }; - CObjectVector<CSubStreamInfo> Streams; + CObjectVector<CAltStreamInfo> Streams; public: // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; CRecordVector<UInt64> Sizes; @@ -73,8 +111,11 @@ public: _length = 0; } + bool SetMTime(const FILETIME *mTime); HRESULT Close(); + UInt64 GetSize() const { return _length; } + MY_UNKNOWN_IMP1(IOutStream) STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); @@ -87,12 +128,12 @@ public: HRESULT COutMultiVolStream::Close() { HRESULT res = S_OK; - for (int i = 0; i < Streams.Size(); i++) + FOR_VECTOR (i, Streams) { - CSubStreamInfo &s = Streams[i]; - if (s.StreamSpec) + COutFileStream *s = Streams[i].StreamSpec; + if (s) { - HRESULT res2 = s.StreamSpec->Close(); + HRESULT res2 = s->Close(); if (res2 != S_OK) res = res2; } @@ -100,6 +141,19 @@ HRESULT COutMultiVolStream::Close() return res; } +bool COutMultiVolStream::SetMTime(const FILETIME *mTime) +{ + bool res = true; + FOR_VECTOR (i, Streams) + { + COutFileStream *s = Streams[i].StreamSpec; + if (s) + if (!s->SetMTime(mTime)) + res = false; + } + return res; +} + STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize) { if (processedSize != NULL) @@ -108,32 +162,32 @@ STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *pr { if (_streamIndex >= Streams.Size()) { - CSubStreamInfo subStream; + CAltStreamInfo altStream; FChar temp[16]; ConvertUInt32ToString(_streamIndex + 1, temp); - FString res = temp; - while (res.Length() < 3) - res = FString(FTEXT('0')) + res; - FString name = Prefix + res; - subStream.StreamSpec = new COutFileStream; - subStream.Stream = subStream.StreamSpec; - if (!subStream.StreamSpec->Create(name, false)) + FString name = temp; + while (name.Len() < 3) + name.InsertAtFront(FTEXT('0')); + name.Insert(0, Prefix); + altStream.StreamSpec = new COutFileStream; + altStream.Stream = altStream.StreamSpec; + if (!altStream.StreamSpec->Create(name, false)) return ::GetLastError(); { // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); TempFiles->Paths.Add(name); } - subStream.Pos = 0; - subStream.RealSize = 0; - subStream.Name = name; - Streams.Add(subStream); + altStream.Pos = 0; + altStream.RealSize = 0; + altStream.Name = name; + Streams.Add(altStream); continue; } - CSubStreamInfo &subStream = Streams[_streamIndex]; + CAltStreamInfo &altStream = Streams[_streamIndex]; - int index = _streamIndex; + unsigned index = _streamIndex; if (index >= Sizes.Size()) index = Sizes.Size() - 1; UInt64 volSize = Sizes[index]; @@ -144,29 +198,29 @@ STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *pr _streamIndex++; continue; } - if (_offsetPos != subStream.Pos) + if (_offsetPos != altStream.Pos) { // CMyComPtr<IOutStream> outStream; - // RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream)); - RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); - subStream.Pos = _offsetPos; + // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream)); + RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL)); + altStream.Pos = _offsetPos; } - UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos); + UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos); UInt32 realProcessed; - RINOK(subStream.Stream->Write(data, curSize, &realProcessed)); + RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); data = (void *)((Byte *)data + realProcessed); size -= realProcessed; - subStream.Pos += realProcessed; + altStream.Pos += realProcessed; _offsetPos += realProcessed; _absPos += realProcessed; if (_absPos > _length) _length = _absPos; - if (_offsetPos > subStream.RealSize) - subStream.RealSize = _offsetPos; + if (_offsetPos > altStream.RealSize) + altStream.RealSize = _offsetPos; if (processedSize != NULL) *processedSize += realProcessed; - if (subStream.Pos == volSize) + if (altStream.Pos == volSize) { _streamIndex++; _offsetPos = 0; @@ -182,17 +236,11 @@ STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *n { if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION; - switch(seekOrigin) + switch (seekOrigin) { - case STREAM_SEEK_SET: - _absPos = offset; - break; - case STREAM_SEEK_CUR: - _absPos += offset; - break; - case STREAM_SEEK_END: - _absPos = _length + offset; - break; + case STREAM_SEEK_SET: _absPos = offset; break; + case STREAM_SEEK_CUR: _absPos += offset; break; + case STREAM_SEEK_END: _absPos = _length + offset; break; } _offsetPos = _absPos; if (newPosition != NULL) @@ -205,24 +253,24 @@ STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) { if (newSize < 0) return E_INVALIDARG; - int i = 0; + unsigned i = 0; while (i < Streams.Size()) { - CSubStreamInfo &subStream = Streams[i++]; - if ((UInt64)newSize < subStream.RealSize) + CAltStreamInfo &altStream = Streams[i++]; + if ((UInt64)newSize < altStream.RealSize) { - RINOK(subStream.Stream->SetSize(newSize)); - subStream.RealSize = newSize; + RINOK(altStream.Stream->SetSize(newSize)); + altStream.RealSize = newSize; break; } - newSize -= subStream.RealSize; + newSize -= altStream.RealSize; } while (i < Streams.Size()) { { - CSubStreamInfo &subStream = Streams.Back(); - subStream.Stream.Release(); - NDirectory::DeleteFileAlways(subStream.Name); + CAltStreamInfo &altStream = Streams.Back(); + altStream.Stream.Release(); + DeleteFileAlways(altStream.Name); } Streams.DeleteBack(); } @@ -232,53 +280,140 @@ STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) return S_OK; } -static const wchar_t *kDefaultArchiveType = L"7z"; -static const wchar_t *kSFXExtension = +void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) +{ + OriginalPath = path; + + SplitPathToParts_2(path, Prefix, Name); + + if (mode == k_ArcNameMode_Add) + return; + if (mode == k_ArcNameMode_Exact) + { + BaseExtension.Empty(); + return; + } + + int dotPos = Name.ReverseFind_Dot(); + if (dotPos < 0) + return; + if ((unsigned)dotPos == Name.Len() - 1) + { + Name.DeleteBack(); + BaseExtension.Empty(); + return; + } + const UString ext = Name.Ptr(dotPos + 1); + if (BaseExtension.IsEqualTo_NoCase(ext)) + { + BaseExtension = ext; + Name.DeleteFrom(dotPos); + } + else + BaseExtension.Empty(); +} + +UString CArchivePath::GetFinalPath() const +{ + UString path = GetPathWithoutExt(); + if (!BaseExtension.IsEmpty()) + { + path += L'.'; + path += BaseExtension; + } + return path; +} + +UString CArchivePath::GetFinalVolPath() const +{ + UString path = GetPathWithoutExt(); + if (!BaseExtension.IsEmpty()) + { + path += L'.'; + path += VolExtension; + } + return path; +} + +FString CArchivePath::GetTempPath() const +{ + FString path = TempPrefix; + path += us2fs(Name); + if (!BaseExtension.IsEmpty()) + { + path += FTEXT('.'); + path += us2fs(BaseExtension); + } + path.AddAscii(".tmp"); + path += TempPostfix; + return path; +} + +static const wchar_t *kDefaultArcType = L"7z"; +static const wchar_t *kDefaultArcExt = L"7z"; +static const char *kSFXExtension = #ifdef _WIN32 - L"exe"; + "exe"; #else - L""; + ""; #endif -bool CUpdateOptions::Init(const CCodecs *codecs, const CIntVector &formatIndices, const UString &arcPath) +bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs, + const CObjectVector<COpenType> &types, const UString &arcPath) { - if (formatIndices.Size() > 1) + if (types.Size() > 1) return false; - int arcTypeIndex = -1; - if (formatIndices.Size() != 0) - arcTypeIndex = formatIndices[0]; - if (arcTypeIndex >= 0) - MethodMode.FormatIndex = arcTypeIndex; + // int arcTypeIndex = -1; + if (types.Size() != 0) + { + MethodMode.Type = types[0]; + MethodMode.Type_Defined = true; + } + if (MethodMode.Type.FormatIndex < 0) + { + // MethodMode.Type = -1; + MethodMode.Type = COpenType(); + if (ArcNameMode != k_ArcNameMode_Add) + { + MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath); + if (MethodMode.Type.FormatIndex >= 0) + MethodMode.Type_Defined = true; + } + } + return true; +} + +bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) +{ + UString typeExt; + int formatIndex = MethodMode.Type.FormatIndex; + if (formatIndex < 0) + { + typeExt = kDefaultArcExt; + } else { - MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath); - // It works incorrectly for update command if archive has some non-default extension! - if (MethodMode.FormatIndex < 0) - MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType); + const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + if (!arcInfo.UpdateEnabled) + return false; + typeExt = arcInfo.GetMainExt(); } - if (MethodMode.FormatIndex < 0) - return false; - const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex]; - if (!arcInfo.UpdateEnabled) - return false; - UString typeExt = arcInfo.GetMainExt(); UString ext = typeExt; if (SfxMode) - ext = kSFXExtension; + ext.SetFromAscii(kSFXExtension); ArchivePath.BaseExtension = ext; ArchivePath.VolExtension = typeExt; - ArchivePath.ParseFromPath(arcPath); - for (int i = 0; i < Commands.Size(); i++) + ArchivePath.ParseFromPath(arcPath, ArcNameMode); + FOR_VECTOR (i, Commands) { CUpdateArchiveCommand &uc = Commands[i]; uc.ArchivePath.BaseExtension = ext; uc.ArchivePath.VolExtension = typeExt; - uc.ArchivePath.ParseFromPath(uc.UserArchivePath); + uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode); } return true; } -/* struct CUpdateProduceCallbackImp: public IUpdateProduceCallback { const CObjectVector<CArcItem> *_arcItems; @@ -286,45 +421,104 @@ struct CUpdateProduceCallbackImp: public IUpdateProduceCallback CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a, IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} - virtual HRESULT ShowDeleteFile(int arcIndex); + virtual HRESULT ShowDeleteFile(unsigned arcIndex); }; -HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(int arcIndex) +HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex) +{ + const CArcItem &ai = (*_arcItems)[arcIndex]; + return _callback->ShowDeleteFile(ai.Name, ai.IsDir); +} + +bool CRenamePair::Prepare() +{ + if (RecursedType != NRecursedType::kNonRecursed) + return false; + if (!WildcardParsing) + return true; + return !DoesNameContainWildcard(OldName); +} + +extern bool g_CaseSensitive; + +static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2) +{ + for (unsigned i = 0;; i++) + { + wchar_t c1 = s1[i]; + wchar_t c2 = s2[i]; + if (c1 == 0 || c2 == 0) + return i; + if (c1 == c2) + continue; + if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2))) + continue; + if (IsPathSepar(c1) && IsPathSepar(c2)) + continue; + return i; + } +} + +bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const { - return _callback->ShowDeleteFile((*_arcItems)[arcIndex].Name); + unsigned num = CompareTwoNames(OldName, src); + if (OldName[num] == 0) + { + if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1])) + return false; + } + else + { + // OldName[num] != 0 + // OldName = "1\1a.txt" + // src = "1" + + if (!isFolder + || src[num] != 0 + || !IsPathSepar(OldName[num]) + || OldName[num + 1] != 0) + return false; + } + dest = NewName + src.Ptr(num); + return true; } -*/ + +#ifdef SUPPORT_ALT_STREAMS +int FindAltStreamColon_in_Path(const wchar_t *path); +#endif static HRESULT Compress( + const CUpdateOptions &options, + bool isUpdatingItself, CCodecs *codecs, const CActionSet &actionSet, - IInArchive *archive, - const CCompressionMethodMode &compressionMethod, + const CArc *arc, CArchivePath &archivePath, const CObjectVector<CArcItem> &arcItems, - bool shareForWrite, - bool stdInMode, - /* const UString & stdInFileName, */ - bool stdOutMode, + Byte *processedItemsStatuses, const CDirItems &dirItems, - bool sfxMode, - const FString &sfxModule, - const CRecordVector<UInt64> &volumesSizes, + const CDirItem *parentDirItem, CTempFiles &tempFiles, CUpdateErrorInfo &errorInfo, - IUpdateCallbackUI *callback) + IUpdateCallbackUI *callback, + CFinishArchiveStat &st) { CMyComPtr<IOutArchive> outArchive; - if (archive != NULL) + int formatIndex = options.MethodMode.Type.FormatIndex; + + if (arc) { - CMyComPtr<IInArchive> archive2 = archive; + formatIndex = arc->FormatIndex; + if (formatIndex < 0) + return E_NOTIMPL; + CMyComPtr<IInArchive> archive2 = arc->Archive; HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive); if (result != S_OK) throw kUpdateIsNotSupoorted; } else { - RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive)); + RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); #ifdef EXTERNAL_CODECS { @@ -337,75 +531,170 @@ static HRESULT Compress( } #endif } + if (outArchive == 0) throw kUpdateIsNotSupoorted; NFileTimeType::EEnum fileTimeType; - UInt32 value; - RINOK(outArchive->GetFileTimeType(&value)); + { + UInt32 value; + RINOK(outArchive->GetFileTimeType(&value)); + + switch (value) + { + case NFileTimeType::kWindows: + case NFileTimeType::kUnix: + case NFileTimeType::kDOS: + fileTimeType = (NFileTimeType::EEnum)value; + break; + default: + return E_FAIL; + } + } - switch(value) { - case NFileTimeType::kWindows: - case NFileTimeType::kUnix: - case NFileTimeType::kDOS: - fileTimeType = (NFileTimeType::EEnum)value; - break; - default: - return E_FAIL; + const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) + return E_NOTIMPL; + if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) + return E_NOTIMPL; } CRecordVector<CUpdatePair2> updatePairs2; + UStringVector newNames; + + if (options.RenamePairs.Size() != 0) + { + FOR_VECTOR (i, arcItems) + { + const CArcItem &ai = arcItems[i]; + bool needRename = false; + UString dest; + + if (ai.Censored) + { + FOR_VECTOR (j, options.RenamePairs) + { + const CRenamePair &rp = options.RenamePairs[j]; + if (rp.GetNewPath(ai.IsDir, ai.Name, dest)) + { + needRename = true; + break; + } + + #ifdef SUPPORT_ALT_STREAMS + if (ai.IsAltStream) + { + int colonPos = FindAltStreamColon_in_Path(ai.Name); + if (colonPos >= 0) + { + UString mainName = ai.Name.Left(colonPos); + /* + actually we must improve that code to support cases + with folder renaming like: rn arc dir1\ dir2\ + */ + if (rp.GetNewPath(false, mainName, dest)) + { + needRename = true; + dest += L':'; + dest += ai.Name.Ptr(colonPos + 1); + break; + } + } + } + #endif + } + } + + CUpdatePair2 up2; + up2.SetAs_NoChangeArcItem(ai.IndexInServer); + if (needRename) + { + up2.NewProps = true; + RINOK(arc->IsItemAnti(i, up2.IsAnti)); + up2.NewNameIndex = newNames.Add(dest); + } + updatePairs2.Add(up2); + } + } + else { CRecordVector<CUpdatePair> updatePairs; GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! - // CUpdateProduceCallbackImp upCallback(&arcItems, callback); - UpdateProduce(updatePairs, actionSet, updatePairs2, NULL /* &upCallback */); + CUpdateProduceCallbackImp upCallback(&arcItems, callback); + + UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL); } - UInt32 numFiles = 0; - for (int i = 0; i < updatePairs2.Size(); i++) - if (updatePairs2[i].NewData) - numFiles++; - - RINOK(callback->SetNumFiles(numFiles)); - + { + UInt32 numItems = 0; + FOR_VECTOR (i, updatePairs2) + if (updatePairs2[i].NewData) + numItems++; + RINOK(callback->SetNumItems(numItems)); + } CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); - updateCallbackSpec->ShareForWrite = shareForWrite; - updateCallbackSpec->StdInMode = stdInMode; + updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; + updateCallbackSpec->StdInMode = options.StdInMode; updateCallbackSpec->Callback = callback; + + if (arc) + { + // we set Archive to allow to transfer GetProperty requests back to DLL. + updateCallbackSpec->Archive = arc->Archive; + } + updateCallbackSpec->DirItems = &dirItems; + updateCallbackSpec->ParentDirItem = parentDirItem; + + updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; + updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; + updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; + + updateCallbackSpec->Arc = arc; updateCallbackSpec->ArcItems = &arcItems; updateCallbackSpec->UpdatePairs = &updatePairs2; + updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; + + if (options.RenamePairs.Size() != 0) + updateCallbackSpec->NewNames = &newNames; + + CMyComPtr<IOutStream> outSeekStream; CMyComPtr<ISequentialOutStream> outStream; - if (!stdOutMode) + if (!options.StdOutMode) { FString dirPrefix; - if (!NFile::NDirectory::GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) + if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix)) throw 1417161; - NFile::NDirectory::CreateComplexDirectory(dirPrefix); + CreateComplexDir(dirPrefix); } COutFileStream *outStreamSpec = NULL; + CStdOutFileStream *stdOutFileStreamSpec = NULL; COutMultiVolStream *volStreamSpec = NULL; - if (volumesSizes.Size() == 0) + if (options.VolumesSizes.Size() == 0) { - if (stdOutMode) - outStream = new CStdOutFileStream; + if (options.StdOutMode) + { + stdOutFileStreamSpec = new CStdOutFileStream; + outStream = stdOutFileStreamSpec; + } else { outStreamSpec = new COutFileStream; - outStream = outStreamSpec; + outSeekStream = outStreamSpec; + outStream = outSeekStream; bool isOK = false; FString realPath; - for (int i = 0; i < (1 << 16); i++) + + for (unsigned i = 0; i < (1 << 16); i++) { if (archivePath.Temp) { @@ -430,23 +719,24 @@ static HRESULT Compress( if (!archivePath.Temp) break; } + if (!isOK) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.FileName = realPath; - errorInfo.Message = L"7-Zip cannot open file"; - return E_FAIL; - } + return errorInfo.SetFromLastError("cannot open file", realPath); } } else { - if (stdOutMode) + if (options.StdOutMode) return E_FAIL; + if (arc && arc->GetGlobalOffset() > 0) + return E_NOTIMPL; + volStreamSpec = new COutMultiVolStream; - outStream = volStreamSpec; - volStreamSpec->Sizes = volumesSizes; - volStreamSpec->Prefix = us2fs(archivePath.GetFinalPath() + L"."); + outSeekStream = volStreamSpec; + outStream = outSeekStream; + volStreamSpec->Sizes = options.VolumesSizes; + volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath()); + volStreamSpec->Prefix += FTEXT('.'); volStreamSpec->TempFiles = &tempFiles; volStreamSpec->Init(); @@ -458,23 +748,18 @@ static HRESULT Compress( */ } - RINOK(SetProperties(outArchive, compressionMethod.Properties)); + RINOK(SetProperties(outArchive, options.MethodMode.Properties)); - if (sfxMode) + if (options.SfxMode) { CInFileStream *sfxStreamSpec = new CInFileStream; CMyComPtr<IInStream> sfxStream(sfxStreamSpec); - if (!sfxStreamSpec->Open(sfxModule)) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot open SFX module"; - errorInfo.FileName = sfxModule; - return E_FAIL; - } + if (!sfxStreamSpec->Open(options.SfxModule)) + return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule); CMyComPtr<ISequentialOutStream> sfxOutStream; COutFileStream *outStreamSpec = NULL; - if (volumesSizes.Size() == 0) + if (options.VolumesSizes.Size() == 0) sfxOutStream = outStream; else { @@ -482,23 +767,97 @@ static HRESULT Compress( sfxOutStream = outStreamSpec; FString realPath = us2fs(archivePath.GetFinalPath()); if (!outStreamSpec->Create(realPath, false)) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.FileName = realPath; - errorInfo.Message = L"7-Zip cannot open file"; - return E_FAIL; - } + return errorInfo.SetFromLastError("cannot open file", realPath); + } + + { + UInt64 sfxSize; + RINOK(sfxStreamSpec->GetSize(&sfxSize)); + RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)); } + RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); + if (outStreamSpec) { RINOK(outStreamSpec->Close()); } } - HRESULT result = outArchive->UpdateItems(outStream, updatePairs2.Size(), updateCallback); - callback->Finilize(); + CMyComPtr<ISequentialOutStream> tailStream; + + if (options.SfxMode || !arc || arc->ArcStreamOffset == 0) + tailStream = outStream; + else + { + // Int64 globalOffset = arc->GetGlobalOffset(); + RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); + RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); + if (options.StdOutMode) + tailStream = outStream; + else + { + CTailOutStream *tailStreamSpec = new CTailOutStream; + tailStream = tailStreamSpec; + tailStreamSpec->Stream = outSeekStream; + tailStreamSpec->Offset = arc->ArcStreamOffset; + tailStreamSpec->Init(); + } + } + + + HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); + // callback->Finalize(); RINOK(result); + + if (!updateCallbackSpec->AreAllFilesClosed()) + { + errorInfo.Message = "There are unclosed input file:"; + errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths; + return E_FAIL; + } + + if (options.SetArcMTime) + { + FILETIME ft; + ft.dwLowDateTime = 0; + ft.dwHighDateTime = 0; + FOR_VECTOR (i, updatePairs2) + { + CUpdatePair2 &pair2 = updatePairs2[i]; + const FILETIME *ft2 = NULL; + if (pair2.NewProps && pair2.DirIndex >= 0) + ft2 = &dirItems.Items[pair2.DirIndex].MTime; + else if (pair2.UseArcProps && pair2.ArcIndex >= 0) + ft2 = &arcItems[pair2.ArcIndex].MTime; + if (ft2) + { + if (::CompareFileTime(&ft, ft2) < 0) + ft = *ft2; + } + } + if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + { + if (outStreamSpec) + outStreamSpec->SetMTime(&ft); + else if (volStreamSpec) + volStreamSpec->SetMTime(&ft);; + } + } + + if (callback) + { + UInt64 size = 0; + if (outStreamSpec) + outStreamSpec->GetSize(&size); + else if (stdOutFileStreamSpec) + size = stdOutFileStreamSpec->GetSize(); + else + size = volStreamSpec->GetSize(); + + st.OutArcFileSize = size; + } + if (outStreamSpec) result = outStreamSpec->Close(); else if (volStreamSpec) @@ -506,7 +865,27 @@ static HRESULT Compress( return result; } -HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, +bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); + +static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) +{ + bool finded = false; + FOR_VECTOR (i, censor.Pairs) + { + bool include; + if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) + { + if (!include) + return false; + finded = true; + } + } + return finded; +} + +static HRESULT EnumerateInArchiveItems( + // bool storeStreamsMode, + const NWildcard::CCensor &censor, const CArc &arc, CObjectVector<CArcItem> &arcItems) { @@ -514,14 +893,30 @@ HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, UInt32 numItems; IInArchive *archive = arc.Archive; RINOK(archive->GetNumberOfItems(&numItems)); - arcItems.Reserve(numItems); + arcItems.ClearAndReserve(numItems); + + CReadArcItem item; + for (UInt32 i = 0; i < numItems; i++) { CArcItem ai; - RINOK(arc.GetItemPath(i, ai.Name)); - RINOK(IsArchiveItemFolder(archive, i, ai.IsDir)); - ai.Censored = censor.CheckPath(ai.Name, !ai.IsDir); + RINOK(arc.GetItem(i, item)); + ai.Name = item.Path; + ai.IsDir = item.IsDir; + ai.IsAltStream = + #ifdef SUPPORT_ALT_STREAMS + item.IsAltStream; + #else + false; + #endif + + /* + if (!storeStreamsMode && ai.IsAltStream) + continue; + */ + ai.Censored = Censor_CheckPath(censor, item); + RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); @@ -531,7 +926,7 @@ HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, if (prop.vt == VT_UI4) { ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; - switch(ai.TimeType) + switch (ai.TimeType) { case NFileTimeType::kWindows: case NFileTimeType::kUnix: @@ -544,110 +939,99 @@ HRESULT EnumerateInArchiveItems(const NWildcard::CCensor &censor, } ai.IndexInServer = i; - arcItems.Add(ai); + arcItems.AddInReserved(ai); } return S_OK; } +#if defined(_WIN32) && !defined(UNDER_CE) -static HRESULT UpdateWithItemLists( - CCodecs *codecs, - CUpdateOptions &options, - IInArchive *archive, - const CObjectVector<CArcItem> &arcItems, - CDirItems &dirItems, - CTempFiles &tempFiles, - CUpdateErrorInfo &errorInfo, - IUpdateCallbackUI2 *callback) -{ - for(int i = 0; i < options.Commands.Size(); i++) - { - CUpdateArchiveCommand &command = options.Commands[i]; - if (options.StdOutMode) - { - RINOK(callback->StartArchive(L"stdout", archive != 0)); - } - else - { - RINOK(callback->StartArchive(command.ArchivePath.GetFinalPath(), - i == 0 && options.UpdateArchiveItself && archive != 0)); - } +#include <mapi.h> - RINOK(Compress( - codecs, - command.ActionSet, archive, - options.MethodMode, - command.ArchivePath, - arcItems, - options.OpenShareForWrite, - options.StdInMode, - /* options.StdInFileName, */ - options.StdOutMode, - dirItems, - options.SfxMode, options.SfxModule, - options.VolumesSizes, - tempFiles, - errorInfo, callback)); - - RINOK(callback->FinishArchive()); - } - return S_OK; -} +#endif -#if defined(_WIN32) && !defined(UNDER_CE) -class CCurrentDirRestorer +struct CRefSortPair { - FString _path; -public: - CCurrentDirRestorer() { NFile::NDirectory::MyGetCurrentDirectory(_path); } - ~CCurrentDirRestorer() { RestoreDirectory();} - bool RestoreDirectory() const { return BOOLToBool(NFile::NDirectory::MySetCurrentDirectory(_path)); } + unsigned Len; + unsigned Index; }; -#endif -struct CEnumDirItemUpdateCallback: public IEnumDirItemCallback +#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } + +static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *) +{ + RINOZ(-MyCompare(a1->Len, a2->Len)); + return MyCompare(a1->Index, a2->Index); +} + +static unsigned GetNumSlashes(const FChar *s) { - IUpdateCallbackUI2 *Callback; - HRESULT ScanProgress(UInt64 numFolders, UInt64 numFiles, const wchar_t *path) + for (unsigned numSlashes = 0;;) { - return Callback->ScanProgress(numFolders, numFiles, path); + FChar c = *s++; + if (c == 0) + return numSlashes; + if (IS_PATH_SEPAR(c)) + numSlashes++; } -}; +} #ifdef _WIN32 -typedef ULONG (FAR PASCAL MY_MAPISENDDOCUMENTS)( - ULONG_PTR ulUIParam, - LPSTR lpszDelimChar, - LPSTR lpszFilePaths, - LPSTR lpszFileNames, - ULONG ulReserved -); -typedef MY_MAPISENDDOCUMENTS FAR *MY_LPMAPISENDDOCUMENTS; +void ConvertToLongNames(NWildcard::CCensor &censor); #endif HRESULT UpdateArchive( CCodecs *codecs, - const NWildcard::CCensor &censor, + const CObjectVector<COpenType> &types, + const UString &cmdArcPath2, + NWildcard::CCensor &censor, CUpdateOptions &options, CUpdateErrorInfo &errorInfo, IOpenCallbackUI *openCallback, - IUpdateCallbackUI2 *callback) + IUpdateCallbackUI2 *callback, + bool needSetPath) { if (options.StdOutMode && options.EMailMode) return E_FAIL; - if (options.VolumesSizes.Size() > 0 && (options.EMailMode || options.SfxMode)) + if (types.Size() > 1) + return E_NOTIMPL; + + bool renameMode = !options.RenamePairs.IsEmpty(); + if (renameMode) + { + if (options.Commands.Size() != 1) + return E_FAIL; + } + + if (options.DeleteAfterCompressing) + { + if (options.Commands.Size() != 1) + return E_NOTIMPL; + const CActionSet &as = options.Commands[0].ActionSet; + for (int i = 2; i < NPairState::kNumValues; i++) + if (as.StateActions[i] != NPairAction::kCompress) + return E_NOTIMPL; + } + + censor.AddPathsToCensor(options.PathMode); + #ifdef _WIN32 + ConvertToLongNames(censor); + #endif + censor.ExtendExclude(); + + + if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */)) return E_NOTIMPL; if (options.SfxMode) { CProperty property; - property.Name = L"rsfx"; - property.Value = L"on"; + property.Name.SetFromAscii("rsfx"); options.MethodMode.Properties.Add(property); if (options.SfxModule.IsEmpty()) { - errorInfo.Message = L"SFX file is not specified"; + errorInfo.Message = "SFX file is not specified"; return E_FAIL; } bool found = false; @@ -663,57 +1047,133 @@ HRESULT UpdateArchive( if (!found) { if (!NFind::DoesFileExist(options.SfxModule)) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot find specified SFX module"; - errorInfo.FileName = options.SfxModule; - return E_FAIL; - } + return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule); } } - CArchiveLink arcLink; - const UString arcPath = options.ArchivePath.GetFinalPath(); - if (!options.ArchivePath.OriginalPath.IsEmpty()) + + if (needSetPath) + { + if (!options.InitFormatIndex(codecs, types, cmdArcPath2) || + !options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + UString arcPath = options.ArchivePath.GetFinalPath(); + + if (cmdArcPath2.IsEmpty()) + { + if (options.MethodMode.Type.FormatIndex < 0) + throw "type of archive is not specified"; + } + else { NFind::CFileInfo fi; - if (fi.Find(us2fs(arcPath))) + if (!fi.Find(us2fs(arcPath))) + { + if (renameMode) + throw "can't find archive";; + if (options.MethodMode.Type.FormatIndex < 0) + { + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } + } + else { if (fi.IsDir()) throw "there is no such archive"; + if (fi.IsDevice) + return E_NOTIMPL; if (options.VolumesSizes.Size() > 0) return E_NOTIMPL; - CIntVector formatIndices; - if (options.MethodMode.FormatIndex >= 0) - formatIndices.Add(options.MethodMode.FormatIndex); - HRESULT result = arcLink.Open2(codecs, formatIndices, false, NULL, arcPath, openCallback); + CObjectVector<COpenType> types; + // change it. + if (options.MethodMode.Type_Defined) + types.Add(options.MethodMode.Type); + // We need to set Properties to open archive only in some cases (WIM archives). + + CIntVector excl; + COpenOptions op; + #ifndef _SFX + op.props = &options.MethodMode.Properties; + #endif + op.codecs = codecs; + op.types = &types; + op.excludedFormats = ! + op.stdInMode = false; + op.stream = NULL; + op.filePath = arcPath; + + RINOK(callback->StartOpenArchive(arcPath)); + + HRESULT result = arcLink.Open3(op, openCallback); + if (result == E_ABORT) return result; - RINOK(callback->OpenResult(arcPath, result)); + + if (result == S_OK && arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0) + result = S_FALSE; + + HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result); + /* + if (result == S_FALSE) + return E_FAIL; + */ + RINOK(res2); RINOK(result); + if (arcLink.VolumePaths.Size() > 1) { errorInfo.SystemError = (DWORD)E_NOTIMPL; - errorInfo.Message = L"Updating for multivolume archives is not implemented"; + errorInfo.Message = "Updating for multivolume archives is not implemented"; return E_NOTIMPL; } CArc &arc = arcLink.Arcs.Back(); arc.MTimeDefined = !fi.IsDevice; arc.MTime = fi.MTime; + + if (arc.ErrorInfo.ThereIsTail) + { + errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = "There is some data block after the end of the archive"; + return E_NOTIMPL; + } + if (options.MethodMode.Type.FormatIndex < 0) + { + options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex; + if (!options.SetArcPath(codecs, cmdArcPath2)) + return E_NOTIMPL; + } } } - else + + if (options.MethodMode.Type.FormatIndex < 0) { - /* - if (archiveType.IsEmpty()) - throw "type of archive is not specified"; - */ + options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArcType); + if (options.MethodMode.Type.FormatIndex < 0) + return E_NOTIMPL; } + bool thereIsInArchive = arcLink.IsOpen; + if (!thereIsInArchive && renameMode) + return E_FAIL; + CDirItems dirItems; + dirItems.Callback = callback; + + CDirItem parentDirItem; + CDirItem *parentDirItem_Ptr = NULL; + + /* + FStringVector requestedPaths; + FStringVector *requestedPaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + requestedPaths_Ptr = &requestedPaths; + */ + if (options.StdInMode) { CDirItem di; @@ -727,28 +1187,70 @@ HRESULT UpdateArchive( else { bool needScanning = false; - for(int i = 0; i < options.Commands.Size(); i++) + + if (!renameMode) + FOR_VECTOR (i, options.Commands) if (options.Commands[i].ActionSet.NeedScanning()) needScanning = true; + if (needScanning) { - CEnumDirItemUpdateCallback enumCallback; - enumCallback.Callback = callback; RINOK(callback->StartScanning()); - FStringVector errorPaths; - CRecordVector<DWORD> errorCodes; - HRESULT res = EnumerateItems(censor, dirItems, &enumCallback, errorPaths, errorCodes); - for (int i = 0; i < errorPaths.Size(); i++) - { - RINOK(callback->CanNotFindError(fs2us(errorPaths[i]), errorCodes[i])); - } + + dirItems.SymLinks = options.SymLinks.Val; + + #if defined(_WIN32) && !defined(UNDER_CE) + dirItems.ReadSecure = options.NtSecurity.Val; + #endif + + dirItems.ScanAltStreams = options.AltStreams.Val; + + HRESULT res = EnumerateItems(censor, + options.PathMode, + options.AddPathPrefix, + dirItems); + if (res != S_OK) { if (res != E_ABORT) - errorInfo.Message = L"Scanning error"; + errorInfo.Message = "Scanning error"; return res; } - RINOK(callback->FinishScanning()); + + RINOK(callback->FinishScanning(dirItems.Stat)); + + if (censor.Pairs.Size() == 1) + { + NFind::CFileInfo fi; + FString prefix = us2fs(censor.Pairs[0].Prefix); + prefix += FTEXT('.'); + // UString prefix = censor.Pairs[0].Prefix; + /* + if (prefix.Back() == WCHAR_PATH_SEPARATOR) + { + prefix.DeleteBack(); + } + */ + if (fi.Find(prefix)) + if (fi.IsDir()) + { + parentDirItem.Size = fi.Size; + parentDirItem.CTime = fi.CTime; + parentDirItem.ATime = fi.ATime; + parentDirItem.MTime = fi.MTime; + parentDirItem.Attrib = fi.Attrib; + parentDirItem_Ptr = &parentDirItem; + + int secureIndex = -1; + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.NtSecurity.Val) + dirItems.AddSecurityItem(prefix, secureIndex); + #endif + parentDirItem.SecureIndex = secureIndex; + + parentDirItem_Ptr = &parentDirItem; + } + } } } @@ -756,7 +1258,7 @@ HRESULT UpdateArchive( bool usesTempDir = false; #ifdef _WIN32 - NDirectory::CTempDir tempDirectory; + CTempDir tempDirectory; if (options.EMailMode && options.EMailRemoveAfter) { tempDirectory.Create(kTempFolderPrefix); @@ -770,8 +1272,6 @@ HRESULT UpdateArchive( bool createTempFile = false; - bool thereIsInArchive = arcLink.IsOpen; - if (!options.StdOutMode && options.UpdateArchiveItself) { CArchivePath &ap = options.Commands[0].ArchivePath; @@ -782,14 +1282,15 @@ HRESULT UpdateArchive( createTempFile = true; ap.Temp = true; if (!options.WorkingDir.IsEmpty()) - { ap.TempPrefix = options.WorkingDir; - NormalizeDirPathPrefix(ap.TempPrefix); - } + else + ap.TempPrefix = us2fs(ap.Prefix); + NormalizeDirPathPrefix(ap.TempPrefix); } } - for (int i = 0; i < options.Commands.Size(); i++) + unsigned i; + for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; if (usesTempDir) @@ -805,10 +1306,10 @@ HRESULT UpdateArchive( const FString path = us2fs(ap.GetFinalPath()); if (NFind::DoesFileOrDirExist(path)) { - errorInfo.SystemError = 0; - errorInfo.Message = L"The file already exists"; - errorInfo.FileName = path; - return E_FAIL; + errorInfo.SystemError = ERROR_FILE_EXISTS; + errorInfo.Message = "The file already exists"; + errorInfo.FileNames.Add(path); + return errorInfo.Get_HRESULT_Error(); } } } @@ -816,13 +1317,77 @@ HRESULT UpdateArchive( CObjectVector<CArcItem> arcItems; if (thereIsInArchive) { - RINOK(EnumerateInArchiveItems(censor, arcLink.Arcs.Back(), arcItems)); + RINOK(EnumerateInArchiveItems( + // options.StoreAltStreams, + censor, arcLink.Arcs.Back(), arcItems)); + } + + /* + FStringVector processedFilePaths; + FStringVector *processedFilePaths_Ptr = NULL; + if (options.DeleteAfterCompressing) + processedFilePaths_Ptr = &processedFilePaths; + */ + + CByteBuffer processedItems; + if (options.DeleteAfterCompressing) + { + unsigned num = dirItems.Items.Size(); + processedItems.Alloc(num); + for (i = 0; i < num; i++) + processedItems[i] = 0; + } + + /* + #ifndef _NO_CRYPTO + if (arcLink.PasswordWasAsked) + { + // We set password, if open have requested password + RINOK(callback->SetPassword(arcLink.Password)); + } + #endif + */ + + for (i = 0; i < options.Commands.Size(); i++) + { + const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL; + CUpdateArchiveCommand &command = options.Commands[i]; + UString name; + bool isUpdating; + + if (options.StdOutMode) + { + name.SetFromAscii("stdout"); + isUpdating = thereIsInArchive; + } + else + { + name = command.ArchivePath.GetFinalPath(); + isUpdating = (i == 0 && options.UpdateArchiveItself && thereIsInArchive); + } + + RINOK(callback->StartArchive(name, isUpdating)) + + CFinishArchiveStat st; + + RINOK(Compress(options, + isUpdating, + codecs, + command.ActionSet, + arc, + command.ArchivePath, + arcItems, + options.DeleteAfterCompressing ? (Byte *)processedItems : NULL, + + dirItems, + parentDirItem_Ptr, + + tempFiles, + errorInfo, callback, st)); + + RINOK(callback->FinishArchive(st)); } - RINOK(UpdateWithItemLists(codecs, options, - thereIsInArchive ? arcLink.GetArchive() : 0, - arcItems, dirItems, - tempFiles, errorInfo, callback)); if (thereIsInArchive) { @@ -837,21 +1402,16 @@ HRESULT UpdateArchive( { CArchivePath &ap = options.Commands[0].ArchivePath; const FString &tempPath = ap.GetTempPath(); + if (thereIsInArchive) - if (!NDirectory::DeleteFileAlways(us2fs(arcPath))) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot delete the file"; - errorInfo.FileName = us2fs(arcPath); - return E_FAIL; - } - if (!NDirectory::MyMoveFile(tempPath, us2fs(arcPath))) + if (!DeleteFileAlways(us2fs(arcPath))) + return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); + + if (!MyMoveFile(tempPath, us2fs(arcPath))) { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot move the file"; - errorInfo.FileName = tempPath; - errorInfo.FileName2 = us2fs(arcPath); - return E_FAIL; + errorInfo.SetFromLastError("cannot move the file", tempPath); + errorInfo.FileNames.Add(us2fs(arcPath)); + return errorInfo.Get_HRESULT_Error(); } } catch(...) @@ -860,38 +1420,49 @@ HRESULT UpdateArchive( } } + #if defined(_WIN32) && !defined(UNDER_CE) + if (options.EMailMode) { NDLL::CLibrary mapiLib; if (!mapiLib.Load(FTEXT("Mapi32.dll"))) { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot load Mapi32.dll"; - return E_FAIL; + errorInfo.SetFromLastError("cannot load Mapi32.dll"); + return errorInfo.Get_HRESULT_Error(); } - MY_LPMAPISENDDOCUMENTS fnSend = (MY_LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); + + /* + LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); if (fnSend == 0) { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"7-Zip cannot find MAPISendDocuments function"; - return E_FAIL; + errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function"); + return errorInfo.Get_HRESULT_Error(); + } + */ + + LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); + if (sendMail == 0) + { + errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); + return errorInfo.Get_HRESULT_Error();; } + FStringVector fullPaths; - int i; + unsigned i; + for (i = 0; i < options.Commands.Size(); i++) { CArchivePath &ap = options.Commands[i].ArchivePath; + FString finalPath = us2fs(ap.GetFinalPath()); FString arcPath; - if (!NFile::NDirectory::MyGetFullPathName(us2fs(ap.GetFinalPath()), arcPath)) - { - errorInfo.SystemError = ::GetLastError(); - errorInfo.Message = L"GetFullPathName error"; - return E_FAIL; - } + if (!MyGetFullPathName(finalPath, arcPath)) + return errorInfo.SetFromLastError("GetFullPathName error", finalPath); fullPaths.Add(arcPath); } + CCurrentDirRestorer curDirRestorer; + for (i = 0; i < fullPaths.Size(); i++) { UString arcPath = fs2us(fullPaths[i]); @@ -899,9 +1470,86 @@ HRESULT UpdateArchive( AString path = GetAnsiString(arcPath); AString name = GetAnsiString(fileName); // Warning!!! MAPISendDocuments function changes Current directory - fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); + // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); + + MapiFileDesc f; + memset(&f, 0, sizeof(f)); + f.nPosition = 0xFFFFFFFF; + f.lpszPathName = (char *)(const char *)path; + f.lpszFileName = (char *)(const char *)name; + + MapiMessage m; + memset(&m, 0, sizeof(m)); + m.nFileCount = 1; + m.lpFiles = &f; + + const AString addr = GetAnsiString(options.EMailAddress); + MapiRecipDesc rec; + if (!addr.IsEmpty()) + { + memset(&rec, 0, sizeof(rec)); + rec.ulRecipClass = MAPI_TO; + rec.lpszAddress = (char *)(const char *)addr; + m.nRecipCount = 1; + m.lpRecips = &rec; + } + + sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); } } + #endif + + if (options.DeleteAfterCompressing) + { + CRecordVector<CRefSortPair> pairs; + FStringVector foldersNames; + + for (i = 0; i < dirItems.Items.Size(); i++) + { + const CDirItem &dirItem = dirItems.Items[i]; + FString phyPath = dirItems.GetPhyPath(i); + if (dirItem.IsDir()) + { + CRefSortPair pair; + pair.Index = i; + pair.Len = GetNumSlashes(phyPath); + pairs.Add(pair); + } + else + { + if (processedItems[i] != 0 || dirItem.Size == 0) + { + RINOK(callback->DeletingAfterArchiving(phyPath, false)); + DeleteFileAlways(phyPath); + } + else + { + // file was skipped + /* + errorInfo.SystemError = 0; + errorInfo.Message = "file was not processed"; + errorInfo.FileName = phyPath; + return E_FAIL; + */ + } + } + } + + pairs.Sort(CompareRefSortPair, NULL); + + for (i = 0; i < pairs.Size(); i++) + { + FString phyPath = dirItems.GetPhyPath(pairs[i].Index); + if (NFind::DoesDirExist(phyPath)) + { + RINOK(callback->DeletingAfterArchiving(phyPath, true)); + RemoveDir(phyPath); + } + } + + RINOK(callback->FinishDeletingAfterArchiving()); + } + return S_OK; } |