diff options
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp | 1136 |
1 files changed, 720 insertions, 416 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp index 0db4a87f0d4..27625aebbe4 100644 --- a/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp +++ b/3rdparty/lzma/CPP/7zip/UI/Common/Update.cpp @@ -2,9 +2,10 @@ #include "StdAfx.h" +// #include <stdio.h> + #include "Update.h" -#include "../../../Common/IntToString.h" #include "../../../Common/StringConvert.h" #include "../../../Windows/DLL.h" @@ -17,6 +18,8 @@ #include "../../Common/FileStreams.h" #include "../../Common/LimitedStreams.h" +#include "../../Common/MultiOutStream.h" +#include "../../Common/StreamUtils.h" #include "../../Compress/CopyCoder.h" @@ -30,17 +33,21 @@ #include "TempFiles.h" #include "UpdateCallback.h" -static const char *kUpdateIsNotSupoorted = +static const char * const kUpdateIsNotSupoorted = "update operations are not supported for this archive"; +static const char * const kUpdateIsNotSupported_MultiVol = + "Updating for multivolume archives is not implemented"; + using namespace NWindows; using namespace NCOM; using namespace NFile; using namespace NDir; using namespace NName; -static CFSTR kTempFolderPrefix = FTEXT("7zE"); - +#ifdef _WIN32 +static CFSTR const kTempFolderPrefix = FTEXT("7zE"); +#endif void CUpdateErrorInfo::SetFromLastError(const char *message) { @@ -55,228 +62,55 @@ HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &f return Get_HRESULT_Error(); } -static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path) +HRESULT CUpdateErrorInfo::SetFromError_DWORD(const char *message, const FString &fileName, DWORD error) { - 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); + Message = message; + FileNames.Add(fileName); + SystemError = error; + return Get_HRESULT_Error(); } using namespace NUpdateArchive; -class COutMultiVolStream: - public IOutStream, - public CMyUnknownImp +struct CMultiOutStream_Rec { - unsigned _streamIndex; // required stream - UInt64 _offsetPos; // offset from start of _streamIndex index - UInt64 _absPos; - UInt64 _length; - - struct CAltStreamInfo - { - COutFileStream *StreamSpec; - CMyComPtr<IOutStream> Stream; - FString Name; - UInt64 Pos; - UInt64 RealSize; - }; - CObjectVector<CAltStreamInfo> Streams; -public: - // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback; - CRecordVector<UInt64> Sizes; - FString Prefix; - CTempFiles *TempFiles; - - void Init() - { - _streamIndex = 0; - _offsetPos = 0; - _absPos = 0; - _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); - STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); - STDMETHOD(SetSize)(UInt64 newSize); + CMultiOutStream *Spec; + CMyComPtr<IOutStream> Ref; }; -// static NSynchronization::CCriticalSection g_TempPathsCS; - -HRESULT COutMultiVolStream::Close() +struct CMultiOutStream_Bunch { - HRESULT res = S_OK; - FOR_VECTOR (i, Streams) - { - COutFileStream *s = Streams[i].StreamSpec; - if (s) - { - HRESULT res2 = s->Close(); - if (res2 != S_OK) - res = res2; - } - } - 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) - *processedSize = 0; - while (size > 0) + CObjectVector<CMultiOutStream_Rec> Items; + + HRESULT Destruct() { - if (_streamIndex >= Streams.Size()) + HRESULT hres = S_OK; + FOR_VECTOR (i, Items) { - CAltStreamInfo altStream; - - FChar temp[16]; - ConvertUInt32ToString(_streamIndex + 1, temp); - 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(); + CMultiOutStream_Rec &rec = Items[i]; + if (rec.Ref) { - // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS); - TempFiles->Paths.Add(name); + const HRESULT hres2 = rec.Spec->Destruct(); + if (hres == S_OK) + hres = hres2; } - - altStream.Pos = 0; - altStream.RealSize = 0; - altStream.Name = name; - Streams.Add(altStream); - continue; } - CAltStreamInfo &altStream = Streams[_streamIndex]; - - unsigned index = _streamIndex; - if (index >= Sizes.Size()) - index = Sizes.Size() - 1; - UInt64 volSize = Sizes[index]; - - if (_offsetPos >= volSize) - { - _offsetPos -= volSize; - _streamIndex++; - continue; - } - if (_offsetPos != altStream.Pos) - { - // CMyComPtr<IOutStream> outStream; - // 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 - altStream.Pos); - UInt32 realProcessed; - RINOK(altStream.Stream->Write(data, curSize, &realProcessed)); - data = (void *)((Byte *)data + realProcessed); - size -= realProcessed; - altStream.Pos += realProcessed; - _offsetPos += realProcessed; - _absPos += realProcessed; - if (_absPos > _length) - _length = _absPos; - if (_offsetPos > altStream.RealSize) - altStream.RealSize = _offsetPos; - if (processedSize != NULL) - *processedSize += realProcessed; - if (altStream.Pos == volSize) - { - _streamIndex++; - _offsetPos = 0; - } - if (realProcessed == 0 && curSize != 0) - return E_FAIL; - break; + Items.Clear(); + return hres; } - return S_OK; -} -STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) -{ - if (seekOrigin >= 3) - return STG_E_INVALIDFUNCTION; - switch (seekOrigin) - { - 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) - *newPosition = _absPos; - _streamIndex = 0; - return S_OK; -} - -STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize) -{ - unsigned i = 0; - while (i < Streams.Size()) - { - CAltStreamInfo &altStream = Streams[i++]; - if ((UInt64)newSize < altStream.RealSize) - { - RINOK(altStream.Stream->SetSize(newSize)); - altStream.RealSize = newSize; - break; - } - newSize -= altStream.RealSize; - } - while (i < Streams.Size()) + void DisableDeletion() { + FOR_VECTOR (i, Items) { - CAltStreamInfo &altStream = Streams.Back(); - altStream.Stream.Release(); - DeleteFileAlways(altStream.Name); + CMultiOutStream_Rec &rec = Items[i]; + if (rec.Ref) + rec.Spec->NeedDelete = false; } - Streams.DeleteBack(); } - _offsetPos = _absPos; - _streamIndex = 0; - _length = newSize; - return S_OK; -} +}; + void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) { @@ -286,29 +120,27 @@ void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode) 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)) + if (mode != k_ArcNameMode_Exact) { - BaseExtension = ext; - Name.DeleteFrom(dotPos); + int dotPos = Name.ReverseFind_Dot(); + if (dotPos < 0) + return; + if ((unsigned)dotPos == Name.Len() - 1) + Name.DeleteBack(); + else + { + const UString ext = Name.Ptr((unsigned)(dotPos + 1)); + if (BaseExtension.IsEqualTo_NoCase(ext)) + { + BaseExtension = ext; + Name.DeleteFrom((unsigned)dotPos); + return; + } + } } - else - BaseExtension.Empty(); + + BaseExtension.Empty(); } UString CArchivePath::GetFinalPath() const @@ -316,7 +148,7 @@ UString CArchivePath::GetFinalPath() const UString path = GetPathWithoutExt(); if (!BaseExtension.IsEmpty()) { - path += L'.'; + path.Add_Dot(); path += BaseExtension; } return path; @@ -325,9 +157,10 @@ UString CArchivePath::GetFinalPath() const UString CArchivePath::GetFinalVolPath() const { UString path = GetPathWithoutExt(); + // if BaseExtension is empty, we must ignore VolExtension also. if (!BaseExtension.IsEmpty()) { - path += L'.'; + path.Add_Dot(); path += VolExtension; } return path; @@ -339,17 +172,17 @@ FString CArchivePath::GetTempPath() const path += us2fs(Name); if (!BaseExtension.IsEmpty()) { - path += FTEXT('.'); + path.Add_Dot(); path += us2fs(BaseExtension); } - path.AddAscii(".tmp"); + path += ".tmp"; path += TempPostfix; return path; } -static const wchar_t *kDefaultArcType = L"7z"; -static const wchar_t *kDefaultArcExt = L"7z"; -static const char *kSFXExtension = +static const char * const kDefaultArcType = "7z"; +static const char * const kDefaultArcExt = "7z"; +static const char * const kSFXExtension = #ifdef _WIN32 "exe"; #else @@ -391,14 +224,14 @@ bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) } else { - const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; if (!arcInfo.UpdateEnabled) return false; typeExt = arcInfo.GetMainExt(); } UString ext = typeExt; if (SfxMode) - ext.SetFromAscii(kSFXExtension); + ext = kSFXExtension; ArchivePath.BaseExtension = ext; ArchivePath.VolExtension = typeExt; ArchivePath.ParseFromPath(arcPath, ArcNameMode); @@ -412,19 +245,43 @@ bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath) return true; } -struct CUpdateProduceCallbackImp: public IUpdateProduceCallback + +struct CUpdateProduceCallbackImp Z7_final: public IUpdateProduceCallback { const CObjectVector<CArcItem> *_arcItems; + CDirItemsStat *_stat; IUpdateCallbackUI *_callback; - CUpdateProduceCallbackImp(const CObjectVector<CArcItem> *a, - IUpdateCallbackUI *callback): _arcItems(a), _callback(callback) {} - virtual HRESULT ShowDeleteFile(unsigned arcIndex); + CUpdateProduceCallbackImp( + const CObjectVector<CArcItem> *a, + CDirItemsStat *stat, + IUpdateCallbackUI *callback): + _arcItems(a), + _stat(stat), + _callback(callback) {} + + virtual HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override; }; + HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex) { const CArcItem &ai = (*_arcItems)[arcIndex]; + { + CDirItemsStat &stat = *_stat; + if (ai.IsDir) + stat.NumDirs++; + else if (ai.IsAltStream) + { + stat.NumAltStreams++; + stat.AltStreamsSize += ai.Size; + } + else + { + stat.NumFiles++; + stat.FilesSize += ai.Size; + } + } return _callback->ShowDeleteFile(ai.Name, ai.IsDir); } @@ -485,6 +342,8 @@ bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) c int FindAltStreamColon_in_Path(const wchar_t *path); #endif + + static HRESULT Compress( const CUpdateOptions &options, bool isUpdatingItself, @@ -497,6 +356,7 @@ static HRESULT Compress( const CDirItems &dirItems, const CDirItem *parentDirItem, CTempFiles &tempFiles, + CMultiOutStream_Bunch &multiStreams, CUpdateErrorInfo &errorInfo, IUpdateCallbackUI *callback, CFinishArchiveStat &st) @@ -516,28 +376,63 @@ static HRESULT Compress( } else { - RINOK(codecs->CreateOutArchive(formatIndex, outArchive)); + RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive)) - #ifdef EXTERNAL_CODECS + #ifdef Z7_EXTERNAL_CODECS { CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo; outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo); if (setCompressCodecsInfo) { - RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)); + RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs)) } } #endif } - if (outArchive == 0) + if (!outArchive) throw kUpdateIsNotSupoorted; - + + // we need to set properties to get fileTimeType. + RINOK(SetProperties(outArchive, options.MethodMode.Properties)) + NFileTimeType::EEnum fileTimeType; { + /* + how we compare file_in_archive::MTime with dirItem.MTime + for GetUpdatePairInfoList(): + + if (kpidMTime is not defined), external MTime of archive is used. + + before 22.00: + if (kpidTimeType is defined) + { + kpidTimeType is used as precision. + (kpidTimeType > kDOS) is not allowed. + } + else GetFileTimeType() value is used as precision. + + 22.00: + if (kpidMTime is defined) + { + if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision. + else + { + if (kpidTimeType is defined), kpidTimeType is used as precision. + else GetFileTimeType() value is used as precision. + } + } + else external MTime of archive is used as precision. + */ + UInt32 value; - RINOK(outArchive->GetFileTimeType(&value)); + RINOK(outArchive->GetFileTimeType(&value)) + + // we support any future fileType here. + fileTimeType = (NFileTimeType::EEnum)value; + /* + old 21.07 code: switch (value) { case NFileTimeType::kWindows: @@ -548,13 +443,28 @@ static HRESULT Compress( default: return E_FAIL; } + */ } + // bool noTimestampExpected = false; { - const CArcInfoEx &arcInfo = codecs->Formats[formatIndex]; + const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex]; + + // if (arcInfo.Flags_KeepName()) noTimestampExpected = true; + if (arcInfo.Is_Xz() || + arcInfo.Is_BZip2()) + { + /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2, + but we want to set timestamp without reduction to unix. */ + // noTimestampExpected = true; + fileTimeType = NFileTimeType::kNotDefined; // it means not defined + } + if (options.AltStreams.Val && !arcInfo.Flags_AltStreams()) return E_NOTIMPL; - if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure()) + if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity()) + return E_NOTIMPL; + if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler()) return E_NOTIMPL; } @@ -562,6 +472,8 @@ static HRESULT Compress( UStringVector newNames; + CArcToDoStat stat2; + if (options.RenamePairs.Size() != 0) { FOR_VECTOR (i, arcItems) @@ -587,7 +499,7 @@ static HRESULT Compress( int colonPos = FindAltStreamColon_in_Path(ai.Name); if (colonPos >= 0) { - UString mainName = ai.Name.Left(colonPos); + UString mainName = ai.Name.Left((unsigned)colonPos); /* actually we must improve that code to support cases with folder renaming like: rn arc dir1\ dir2\ @@ -595,8 +507,8 @@ static HRESULT Compress( if (rp.GetNewPath(false, mainName, dest)) { needRename = true; - dest += L':'; - dest += ai.Name.Ptr(colonPos + 1); + dest += ':'; + dest += ai.Name.Ptr((unsigned)(colonPos + 1)); break; } } @@ -610,8 +522,8 @@ static HRESULT Compress( if (needRename) { up2.NewProps = true; - RINOK(arc->IsItemAnti(i, up2.IsAnti)); - up2.NewNameIndex = newNames.Add(dest); + RINOK(arc->IsItem_Anti(i, up2.IsAnti)) + up2.NewNameIndex = (int)newNames.Add(dest); } updatePairs2.Add(up2); } @@ -620,23 +532,97 @@ static HRESULT Compress( { CRecordVector<CUpdatePair> updatePairs; GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!! - CUpdateProduceCallbackImp upCallback(&arcItems, callback); + CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback); UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL); } { - UInt32 numItems = 0; FOR_VECTOR (i, updatePairs2) - if (updatePairs2[i].NewData) - numItems++; - RINOK(callback->SetNumItems(numItems)); + { + const CUpdatePair2 &up = updatePairs2[i]; + + // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases)) + + if (up.NewData && !up.UseArcProps) + { + if (up.ExistOnDisk()) + { + CDirItemsStat2 &stat = stat2.NewData; + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (di.IsDir()) + { + if (up.IsAnti) + stat.Anti_NumDirs++; + else + stat.NumDirs++; + } + #ifdef _WIN32 + else if (di.IsAltStream) + { + if (up.IsAnti) + stat.Anti_NumAltStreams++; + else + { + stat.NumAltStreams++; + stat.AltStreamsSize += di.Size; + } + } + #endif + else + { + if (up.IsAnti) + stat.Anti_NumFiles++; + else + { + stat.NumFiles++; + stat.FilesSize += di.Size; + } + } + } + } + else if (up.ArcIndex >= 0) + { + CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData); + const CArcItem &ai = arcItems[(unsigned)up.ArcIndex]; + if (ai.IsDir) + { + if (up.IsAnti) + stat.Anti_NumDirs++; + else + stat.NumDirs++; + } + else if (ai.IsAltStream) + { + if (up.IsAnti) + stat.Anti_NumAltStreams++; + else + { + stat.NumAltStreams++; + stat.AltStreamsSize += ai.Size; + } + } + else + { + if (up.IsAnti) + stat.Anti_NumFiles++; + else + { + stat.NumFiles++; + stat.FilesSize += ai.Size; + } + } + } + } + RINOK(callback->SetNumItems(stat2)) } CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback; CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec); + updateCallbackSpec->PreserveATime = options.PreserveATime; updateCallbackSpec->ShareForWrite = options.OpenShareForWrite; + updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError; updateCallbackSpec->StdInMode = options.StdInMode; updateCallbackSpec->Callback = callback; @@ -652,6 +638,8 @@ static HRESULT Compress( updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val; updateCallbackSpec->StoreHardLinks = options.HardLinks.Val; updateCallbackSpec->StoreSymLinks = options.SymLinks.Val; + updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val; + updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val; updateCallbackSpec->Arc = arc; updateCallbackSpec->ArcItems = &arcItems; @@ -659,9 +647,20 @@ static HRESULT Compress( updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses; + { + const UString arcPath = archivePath.GetFinalPath(); + updateCallbackSpec->ArcFileName = ExtractFileNameFromPath(arcPath); + } + if (options.RenamePairs.Size() != 0) updateCallbackSpec->NewNames = &newNames; + if (options.SetArcMTime) + { + // updateCallbackSpec->Need_ArcMTime_Report = true; + updateCallbackSpec->Need_LatestMTime = true; + } + CMyComPtr<IOutStream> outSeekStream; CMyComPtr<ISequentialOutStream> outStream; @@ -675,7 +674,7 @@ static HRESULT Compress( COutFileStream *outStreamSpec = NULL; CStdOutFileStream *stdOutFileStreamSpec = NULL; - COutMultiVolStream *volStreamSpec = NULL; + CMultiOutStream *volStreamSpec = NULL; if (options.VolumesSizes.Size() == 0) { @@ -698,9 +697,8 @@ static HRESULT Compress( { if (i > 0) { - FChar s[16]; - ConvertUInt32ToString(i, s); - archivePath.TempPostfix = s; + archivePath.TempPostfix.Empty(); + archivePath.TempPostfix.Add_UInt32(i); } realPath = archivePath.GetTempPath(); } @@ -729,25 +727,26 @@ static HRESULT Compress( if (arc && arc->GetGlobalOffset() > 0) return E_NOTIMPL; - volStreamSpec = new COutMultiVolStream; + volStreamSpec = new CMultiOutStream(); outSeekStream = volStreamSpec; outStream = outSeekStream; - volStreamSpec->Sizes = options.VolumesSizes; volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath()); - volStreamSpec->Prefix += FTEXT('.'); - volStreamSpec->TempFiles = &tempFiles; - volStreamSpec->Init(); + volStreamSpec->Prefix.Add_Dot(); + volStreamSpec->Init(options.VolumesSizes); + { + CMultiOutStream_Rec &rec = multiStreams.Items.AddNew(); + rec.Spec = volStreamSpec; + rec.Ref = rec.Spec; + } /* updateCallbackSpec->VolumesSizes = volumesSizes; updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name; if (!archivePath.VolExtension.IsEmpty()) - updateCallbackSpec->VolExt = UString(L'.') + archivePath.VolExtension; + updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension; */ } - RINOK(SetProperties(outArchive, options.MethodMode.Properties)); - if (options.SfxMode) { CInFileStream *sfxStreamSpec = new CInFileStream; @@ -763,22 +762,22 @@ static HRESULT Compress( { outStreamSpec2 = new COutFileStream; sfxOutStream = outStreamSpec2; - FString realPath = us2fs(archivePath.GetFinalPath()); + const FString realPath = us2fs(archivePath.GetFinalPath()); if (!outStreamSpec2->Create(realPath, false)) return errorInfo.SetFromLastError("cannot open file", realPath); } { UInt64 sfxSize; - RINOK(sfxStreamSpec->GetSize(&sfxSize)); - RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)); + RINOK(sfxStreamSpec->GetSize(&sfxSize)) + RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize)) } - RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)); + RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL)) if (outStreamSpec2) { - RINOK(outStreamSpec2->Close()); + RINOK(outStreamSpec2->Close()) } } @@ -789,8 +788,8 @@ static HRESULT Compress( else { // Int64 globalOffset = arc->GetGlobalOffset(); - RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL)); - RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)); + RINOK(InStream_SeekToBegin(arc->InStream)) + RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL)) if (options.StdOutMode) tailStream = outStream; else @@ -803,10 +802,57 @@ static HRESULT Compress( } } + CFiTime ft; + FiTime_Clear(ft); + bool ft_Defined = false; + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &pair2 = updatePairs2[i]; + CFiTime ft2; + FiTime_Clear(ft2); + bool ft2_Defined = false; + /* we use full precision of dirItem, if dirItem is defined + and (dirItem will be used or dirItem is sameTime in dir and arc */ + if (pair2.DirIndex >= 0 && + (pair2.NewProps || pair2.IsSameTime)) + { + ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime; + ft2_Defined = true; + } + else if (pair2.UseArcProps && pair2.ArcIndex >= 0) + { + const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex]; + if (arcItem.MTime.Def) + { + arcItem.MTime.Write_To_FiTime(ft2); + ft2_Defined = true; + } + } + if (ft2_Defined) + { + if (!ft_Defined || Compare_FiTime(&ft, &ft2) < 0) + { + ft = ft2; + ft_Defined = true; + } + } + } + /* + if (fileTimeType != NFileTimeType::kNotDefined) + FiTime_Normalize_With_Prec(ft, fileTimeType); + */ + } + + if (volStreamSpec && options.SetArcMTime && ft_Defined) + { + volStreamSpec->MTime = ft; + volStreamSpec->MTime_Defined = true; + } HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback); // callback->Finalize(); - RINOK(result); + RINOK(result) if (!updateCallbackSpec->AreAllFilesClosed()) { @@ -817,29 +863,43 @@ static HRESULT Compress( if (options.SetArcMTime) { - FILETIME ft; - ft.dwLowDateTime = 0; - ft.dwHighDateTime = 0; - FOR_VECTOR (i, updatePairs2) + // bool needNormalizeAfterStream; + // needParse; + /* + if (updateCallbackSpec->ArcMTime_WasReported) { - 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) + isDefined = updateCallbackSpec->Reported_ArcMTime.Def; + if (isDefined) + updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft); + else + fileTimeType = NFileTimeType::kNotDefined; + } + if (!isDefined) + */ + { + if (updateCallbackSpec->LatestMTime_Defined) { - if (::CompareFileTime(&ft, ft2) < 0) - ft = *ft2; + // CArcTime at = StreamCallback_ArcMTime; + // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft); + // we must normalize with precision from archive; + if (!ft_Defined || Compare_FiTime(&ft, &updateCallbackSpec->LatestMTime) < 0) + ft = updateCallbackSpec->LatestMTime; + ft_Defined = true; } + /* + if (fileTimeType != NFileTimeType::kNotDefined) + FiTime_Normalize_With_Prec(ft, fileTimeType); + */ } - if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0) + if (ft_Defined) { + // we ignore set time errors here. + // note that user could move some finished volumes to another folder. if (outStreamSpec) outStreamSpec->SetMTime(&ft); else if (volStreamSpec) - volStreamSpec->SetMTime(&ft);; + volStreamSpec->SetMTime_Final(ft); } } @@ -859,10 +919,43 @@ static HRESULT Compress( if (outStreamSpec) result = outStreamSpec->Close(); else if (volStreamSpec) - result = volStreamSpec->Close(); + { + result = volStreamSpec->FinalFlush_and_CloseFiles(st.NumVolumes); + st.IsMultiVolMode = true; + } + + RINOK(result) + + if (processedItemsStatuses) + { + FOR_VECTOR (i, updatePairs2) + { + const CUpdatePair2 &up = updatePairs2[i]; + if (up.NewData && up.DirIndex >= 0) + { + const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex]; + if (di.AreReparseData() || (!di.IsDir() && di.Size == 0)) + processedItemsStatuses[(unsigned)up.DirIndex] = 1; + } + } + } + return result; } + + +static bool Censor_AreAllAllowed(const NWildcard::CCensor &censor) +{ + if (censor.Pairs.Size() != 1) + return false; + const NWildcard::CPair &pair = censor.Pairs[0]; + /* Censor_CheckPath() ignores (CPair::Prefix). + So we also ignore (CPair::Prefix) here */ + // if (!pair.Prefix.IsEmpty()) return false; + return pair.Head.AreAllAllowed(); +} + bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include); static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item) @@ -870,9 +963,13 @@ static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcIte bool finded = false; FOR_VECTOR (i, censor.Pairs) { + /* (CPair::Prefix) in not used for matching items in archive. + So we ignore (CPair::Prefix) here */ bool include; if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include)) { + // Check it and FIXME !!!! + // here we can exclude item via some Pair, that is still allowed by another Pair if (!include) return false; finded = true; @@ -890,16 +987,18 @@ static HRESULT EnumerateInArchiveItems( arcItems.Clear(); UInt32 numItems; IInArchive *archive = arc.Archive; - RINOK(archive->GetNumberOfItems(&numItems)); + RINOK(archive->GetNumberOfItems(&numItems)) arcItems.ClearAndReserve(numItems); CReadArcItem item; + const bool allFilesAreAllowed = Censor_AreAllAllowed(censor); + for (UInt32 i = 0; i < numItems; i++) { CArcItem ai; - RINOK(arc.GetItem(i, item)); + RINOK(arc.GetItem(i, item)) ai.Name = item.Path; ai.IsDir = item.IsDir; ai.IsAltStream = @@ -913,28 +1012,14 @@ static HRESULT EnumerateInArchiveItems( if (!storeStreamsMode && ai.IsAltStream) continue; */ - ai.Censored = Censor_CheckPath(censor, item); + if (allFilesAreAllowed) + ai.Censored = true; + else + ai.Censored = Censor_CheckPath(censor, item); - RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined)); - RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined)); - - { - CPropVariant prop; - RINOK(archive->GetProperty(i, kpidTimeType, &prop)); - if (prop.vt == VT_UI4) - { - ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal; - switch (ai.TimeType) - { - case NFileTimeType::kWindows: - case NFileTimeType::kUnix: - case NFileTimeType::kDOS: - break; - default: - return E_FAIL; - } - } - } + // ai.MTime will be set to archive MTime, if not present in archive item + RINOK(arc.GetItem_MTime(i, ai.MTime)) + RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined)) ai.IndexInServer = i; arcItems.AddInReserved(ai); @@ -944,39 +1029,72 @@ static HRESULT EnumerateInArchiveItems( #if defined(_WIN32) && !defined(UNDER_CE) +#if defined(__MINGW32__) || defined(__MINGW64__) #include <mapi.h> - +#else +#include <MAPI.h> #endif -struct CRefSortPair -{ - unsigned Len; - unsigned Index; -}; +extern "C" { -#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; } +#ifdef MAPI_FORCE_UNICODE -static int CompareRefSortPair(const CRefSortPair *a1, const CRefSortPair *a2, void *) -{ - RINOZ(-MyCompare(a1->Len, a2->Len)); - return MyCompare(a1->Index, a2->Index); -} +#define Z7_WIN_LPMAPISENDMAILW LPMAPISENDMAILW +#define Z7_WIN_MapiFileDescW MapiFileDescW +#define Z7_WIN_MapiMessageW MapiMessageW +#define Z7_WIN_MapiRecipDescW MapiRecipDescW + +#else -static unsigned GetNumSlashes(const FChar *s) +typedef struct { - for (unsigned numSlashes = 0;;) - { - FChar c = *s++; - if (c == 0) - return numSlashes; - if (IS_PATH_SEPAR(c)) - numSlashes++; - } + ULONG ulReserved; + ULONG ulRecipClass; + PWSTR lpszName; + PWSTR lpszAddress; + ULONG ulEIDSize; + PVOID lpEntryID; +} Z7_WIN_MapiRecipDescW, *Z7_WIN_lpMapiRecipDescW; + +typedef struct +{ + ULONG ulReserved; + ULONG flFlags; + ULONG nPosition; + PWSTR lpszPathName; + PWSTR lpszFileName; + PVOID lpFileType; +} Z7_WIN_MapiFileDescW, *Z7_WIN_lpMapiFileDescW; + +typedef struct +{ + ULONG ulReserved; + PWSTR lpszSubject; + PWSTR lpszNoteText; + PWSTR lpszMessageType; + PWSTR lpszDateReceived; + PWSTR lpszConversationID; + FLAGS flFlags; + Z7_WIN_lpMapiRecipDescW lpOriginator; + ULONG nRecipCount; + Z7_WIN_lpMapiRecipDescW lpRecips; + ULONG nFileCount; + Z7_WIN_lpMapiFileDescW lpFiles; +} Z7_WIN_MapiMessageW, *Z7_WIN_lpMapiMessageW; + +typedef ULONG (FAR PASCAL Z7_WIN_MAPISENDMAILW)( + LHANDLE lhSession, + ULONG_PTR ulUIParam, + Z7_WIN_lpMapiMessageW lpMessage, + FLAGS flFlags, + ULONG ulReserved +); +typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW; + +#endif // MAPI_FORCE_UNICODE } +#endif // _WIN32 -#ifdef _WIN32 -void ConvertToLongNames(NWildcard::CCensor &censor); -#endif HRESULT UpdateArchive( CCodecs *codecs, @@ -1007,7 +1125,7 @@ HRESULT UpdateArchive( if (options.Commands.Size() != 1) return E_NOTIMPL; const CActionSet &as = options.Commands[0].ActionSet; - for (int i = 2; i < NPairState::kNumValues; i++) + for (unsigned i = 2; i < NPairState::kNumValues; i++) if (as.StateActions[i] != NPairAction::kCompress) return E_NOTIMPL; } @@ -1025,7 +1143,7 @@ HRESULT UpdateArchive( if (options.SfxMode) { CProperty property; - property.Name.SetFromAscii("rsfx"); + property.Name = "rsfx"; options.MethodMode.Properties.Add(property); if (options.SfxModule.IsEmpty()) { @@ -1036,7 +1154,7 @@ HRESULT UpdateArchive( if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0) { const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule; - if (NFind::DoesFileExist(fullName)) + if (NFind::DoesFileExist_FollowLink(fullName)) { options.SfxModule = fullName; found = true; @@ -1044,7 +1162,7 @@ HRESULT UpdateArchive( } if (!found) { - if (!NFind::DoesFileExist(options.SfxModule)) + if (!NFind::DoesFileExist_FollowLink(options.SfxModule)) return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule); } } @@ -1058,7 +1176,14 @@ HRESULT UpdateArchive( !options.SetArcPath(codecs, cmdArcPath2)) return E_NOTIMPL; } - const UString arcPath = options.ArchivePath.GetFinalPath(); + + UString arcPath = options.ArchivePath.GetFinalPath(); + + if (!options.VolumesSizes.IsEmpty()) + { + arcPath = options.ArchivePath.GetFinalVolPath(); + arcPath += ".001"; + } if (cmdArcPath2.IsEmpty()) { @@ -1068,10 +1193,10 @@ HRESULT UpdateArchive( else { NFind::CFileInfo fi; - if (!fi.Find(us2fs(arcPath))) + if (!fi.Find_FollowLink(us2fs(arcPath))) { if (renameMode) - throw "can't find archive";; + throw "can't find archive"; if (options.MethodMode.Type.FormatIndex < 0) { if (!options.SetArcPath(codecs, cmdArcPath2)) @@ -1081,11 +1206,39 @@ HRESULT UpdateArchive( else { if (fi.IsDir()) - throw "there is no such archive"; + return errorInfo.SetFromError_DWORD("There is a folder with the name of archive", + us2fs(arcPath), + #ifdef _WIN32 + ERROR_ACCESS_DENIED + #else + EISDIR + #endif + ); + #ifdef _WIN32 if (fi.IsDevice) return E_NOTIMPL; + #endif + + if (!options.StdOutMode && options.UpdateArchiveItself) + if (fi.IsReadOnly()) + { + return errorInfo.SetFromError_DWORD("The file is read-only", + us2fs(arcPath), + #ifdef _WIN32 + ERROR_ACCESS_DENIED + #else + EACCES + #endif + ); + } + if (options.VolumesSizes.Size() > 0) + { + errorInfo.FileNames.Add(us2fs(arcPath)); + // errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = kUpdateIsNotSupported_MultiVol; return E_NOTIMPL; + } CObjectVector<COpenType> types2; // change it. if (options.MethodMode.Type_Defined) @@ -1094,7 +1247,7 @@ HRESULT UpdateArchive( CIntVector excl; COpenOptions op; - #ifndef _SFX + #ifndef Z7_SFX op.props = &options.MethodMode.Properties; #endif op.codecs = codecs; @@ -1104,7 +1257,7 @@ HRESULT UpdateArchive( op.stream = NULL; op.filePath = arcPath; - RINOK(callback->StartOpenArchive(arcPath)); + RINOK(callback->StartOpenArchive(arcPath)) HRESULT result = arcLink.Open_Strict(op, openCallback); @@ -1116,23 +1269,29 @@ HRESULT UpdateArchive( if (result == S_FALSE) return E_FAIL; */ - RINOK(res2); - RINOK(result); + RINOK(res2) + RINOK(result) if (arcLink.VolumePaths.Size() > 1) { - errorInfo.SystemError = (DWORD)E_NOTIMPL; - errorInfo.Message = "Updating for multivolume archives is not implemented"; + // errorInfo.SystemError = (DWORD)E_NOTIMPL; + errorInfo.Message = kUpdateIsNotSupported_MultiVol; return E_NOTIMPL; } CArc &arc = arcLink.Arcs.Back(); - arc.MTimeDefined = !fi.IsDevice; - arc.MTime = fi.MTime; + arc.MTime.Def = + #ifdef _WIN32 + !fi.IsDevice; + #else + true; + #endif + if (arc.MTime.Def) + arc.MTime.Set_From_FiTime(fi.MTime); if (arc.ErrorInfo.ThereIsTail) { - errorInfo.SystemError = (DWORD)E_NOTIMPL; + // errorInfo.SystemError = (DWORD)E_NOTIMPL; errorInfo.Message = "There is some data block after the end of the archive"; return E_NOTIMPL; } @@ -1147,7 +1306,7 @@ HRESULT UpdateArchive( if (options.MethodMode.Type.FormatIndex < 0) { - options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArcType); + options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType); if (options.MethodMode.Type.FormatIndex < 0) return E_NOTIMPL; } @@ -1172,10 +1331,11 @@ HRESULT UpdateArchive( if (options.StdInMode) { CDirItem di; + di.ClearBase(); di.Name = options.StdInFileName; di.Size = (UInt64)(Int64)-1; - di.Attrib = 0; - NTime::GetCurUtcFileTime(di.MTime); + di.SetAsFile(); + NTime::GetCurUtc_FiTime(di.MTime); di.CTime = di.ATime = di.MTime; dirItems.Items.Add(di); } @@ -1190,7 +1350,7 @@ HRESULT UpdateArchive( if (needScanning) { - RINOK(callback->StartScanning()); + RINOK(callback->StartScanning()) dirItems.SymLinks = options.SymLinks.Val; @@ -1199,10 +1359,18 @@ HRESULT UpdateArchive( #endif dirItems.ScanAltStreams = options.AltStreams.Val; + dirItems.ExcludeDirItems = censor.ExcludeDirItems; + dirItems.ExcludeFileItems = censor.ExcludeFileItems; + + dirItems.ShareForWrite = options.OpenShareForWrite; + + #ifndef _WIN32 + dirItems.StoreOwnerName = options.StoreOwnerName.Val; + #endif - HRESULT res = EnumerateItems(censor, + const HRESULT res = EnumerateItems(censor, options.PathMode, - options.AddPathPrefix, + UString(), // options.AddPathPrefix, dirItems); if (res != S_OK) @@ -1212,13 +1380,15 @@ HRESULT UpdateArchive( return res; } - RINOK(callback->FinishScanning(dirItems.Stat)); + RINOK(callback->FinishScanning(dirItems.Stat)) + // 22.00: we don't need parent folder, if absolute path mode + if (options.PathMode != NWildcard::k_AbsPath) if (censor.Pairs.Size() == 1) { NFind::CFileInfo fi; FString prefix = us2fs(censor.Pairs[0].Prefix); - prefix += FTEXT('.'); + prefix.Add_Dot(); // UString prefix = censor.Pairs[0].Prefix; /* if (prefix.Back() == WCHAR_PATH_SEPARATOR) @@ -1229,11 +1399,7 @@ HRESULT UpdateArchive( 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.Copy_From_FileInfoBase(fi); parentDirItem_Ptr = &parentDirItem; int secureIndex = -1; @@ -1242,8 +1408,6 @@ HRESULT UpdateArchive( dirItems.AddSecurityItem(prefix, secureIndex); #endif parentDirItem.SecureIndex = secureIndex; - - parentDirItem_Ptr = &parentDirItem; } } } @@ -1286,6 +1450,31 @@ HRESULT UpdateArchive( unsigned ci; + + // self including protection + if (options.DeleteAfterCompressing) + { + for (ci = 0; ci < options.Commands.Size(); ci++) + { + CArchivePath &ap = options.Commands[ci].ArchivePath; + const FString path = us2fs(ap.GetFinalPath()); + // maybe we must compare absolute paths path here + FOR_VECTOR (i, dirItems.Items) + { + const FString phyPath = dirItems.GetPhyPath(i); + if (phyPath == path) + { + UString s; + s = "It is not allowed to include archive to itself"; + s.Add_LF(); + s += fs2us(path); + throw s; + } + } + } + } + + for (ci = 0; ci < options.Commands.Size(); ci++) { CArchivePath &ap = options.Commands[ci].ArchivePath; @@ -1315,7 +1504,7 @@ HRESULT UpdateArchive( { RINOK(EnumerateInArchiveItems( // options.StoreAltStreams, - censor, arcLink.Arcs.Back(), arcItems)); + censor, arcLink.Arcs.Back(), arcItems)) } /* @@ -1328,14 +1517,16 @@ HRESULT UpdateArchive( CByteBuffer processedItems; if (options.DeleteAfterCompressing) { - unsigned num = dirItems.Items.Size(); + const unsigned num = dirItems.Items.Size(); processedItems.Alloc(num); for (unsigned i = 0; i < num; i++) processedItems[i] = 0; } + CMultiOutStream_Bunch multiStreams; + /* - #ifndef _NO_CRYPTO + #ifndef Z7_NO_CRYPTO if (arcLink.PasswordWasAsked) { // We set password, if open have requested password @@ -1353,7 +1544,7 @@ HRESULT UpdateArchive( if (options.StdOutMode) { - name.SetFromAscii("stdout"); + name = "stdout"; isUpdating = thereIsInArchive; } else @@ -1379,18 +1570,22 @@ HRESULT UpdateArchive( parentDirItem_Ptr, tempFiles, - errorInfo, callback, st)); + multiStreams, + errorInfo, callback, st)) - RINOK(callback->FinishArchive(st)); + RINOK(callback->FinishArchive(st)) } if (thereIsInArchive) { - RINOK(arcLink.Close()); + RINOK(arcLink.Close()) arcLink.Release(); } + multiStreams.DisableDeletion(); + RINOK(multiStreams.Destruct()) + tempFiles.Paths.Clear(); if (createTempFile) { @@ -1399,9 +1594,13 @@ HRESULT UpdateArchive( CArchivePath &ap = options.Commands[0].ArchivePath; const FString &tempPath = ap.GetTempPath(); + // DWORD attrib = 0; if (thereIsInArchive) + { + // attrib = NFind::GetFileAttrib(us2fs(arcPath)); if (!DeleteFileAlways(us2fs(arcPath))) return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath)); + } if (!MyMoveFile(tempPath, us2fs(arcPath))) { @@ -1409,6 +1608,15 @@ HRESULT UpdateArchive( errorInfo.FileNames.Add(us2fs(arcPath)); return errorInfo.Get_HRESULT_Error(); } + + /* + if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) + { + DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath)); + if (attrib2 != INVALID_FILE_ATTRIBUTES) + NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY); + } + */ } catch(...) { @@ -1428,6 +1636,19 @@ HRESULT UpdateArchive( return errorInfo.Get_HRESULT_Error(); } + FStringVector fullPaths; + unsigned i; + + for (i = 0; i < options.Commands.Size(); i++) + { + CArchivePath &ap = options.Commands[i].ArchivePath; + const FString finalPath = us2fs(ap.GetFinalPath()); + FString arcPath2; + if (!MyGetFullPathName(finalPath, arcPath2)) + return errorInfo.SetFromLastError("GetFullPathName error", finalPath); + fullPaths.Add(arcPath2); + } + /* LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments"); if (fnSend == 0) @@ -1436,69 +1657,128 @@ HRESULT UpdateArchive( return errorInfo.Get_HRESULT_Error(); } */ + const + Z7_WIN_LPMAPISENDMAILW sendMailW = Z7_GET_PROC_ADDRESS( + Z7_WIN_LPMAPISENDMAILW, mapiLib.Get_HMODULE(), + "MAPISendMailW"); + if (sendMailW) + { + + CCurrentDirRestorer curDirRestorer; + + UStringVector paths; + UStringVector names; - LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail"); - if (sendMail == 0) + for (i = 0; i < fullPaths.Size(); i++) { - errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); - return errorInfo.Get_HRESULT_Error();; + const UString arcPath2 = fs2us(fullPaths[i]); + const UString fileName = ExtractFileNameFromPath(arcPath2); + paths.Add(arcPath2); + names.Add(fileName); + // Warning!!! MAPISendDocuments function changes Current directory + // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); } - FStringVector fullPaths; - unsigned i; + CRecordVector<Z7_WIN_MapiFileDescW> files; + files.ClearAndSetSize(paths.Size()); - for (i = 0; i < options.Commands.Size(); i++) + for (i = 0; i < paths.Size(); i++) { - CArchivePath &ap = options.Commands[i].ArchivePath; - FString finalPath = us2fs(ap.GetFinalPath()); - FString arcPath2; - if (!MyGetFullPathName(finalPath, arcPath2)) - return errorInfo.SetFromLastError("GetFullPathName error", finalPath); - fullPaths.Add(arcPath2); + Z7_WIN_MapiFileDescW &f = files[i]; + memset(&f, 0, sizeof(f)); + f.nPosition = 0xFFFFFFFF; + f.lpszPathName = paths[i].Ptr_non_const(); + f.lpszFileName = names[i].Ptr_non_const(); + } + + { + Z7_WIN_MapiMessageW m; + memset(&m, 0, sizeof(m)); + m.nFileCount = files.Size(); + m.lpFiles = &files.Front(); + + const UString addr (options.EMailAddress); + Z7_WIN_MapiRecipDescW rec; + if (!addr.IsEmpty()) + { + memset(&rec, 0, sizeof(rec)); + rec.ulRecipClass = MAPI_TO; + rec.lpszAddress = addr.Ptr_non_const(); + m.nRecipCount = 1; + m.lpRecips = &rec; + } + + sendMailW((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); + } + } + else + { + const + LPMAPISENDMAIL sendMail = Z7_GET_PROC_ADDRESS( + LPMAPISENDMAIL, mapiLib.Get_HMODULE(), + "MAPISendMail"); + if (!sendMail) + { + errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function"); + return errorInfo.Get_HRESULT_Error(); } CCurrentDirRestorer curDirRestorer; + + AStringVector paths; + AStringVector names; for (i = 0; i < fullPaths.Size(); i++) { - UString arcPath2 = fs2us(fullPaths[i]); - UString fileName = ExtractFileNameFromPath(arcPath2); - AString path = GetAnsiString(arcPath2); - AString name = GetAnsiString(fileName); + const UString arcPath2 = fs2us(fullPaths[i]); + const UString fileName = ExtractFileNameFromPath(arcPath2); + paths.Add(GetAnsiString(arcPath2)); + names.Add(GetAnsiString(fileName)); + // const AString path (GetAnsiString(arcPath2)); + // const AString name (GetAnsiString(fileName)); // Warning!!! MAPISendDocuments function changes Current directory // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0); + } - MapiFileDesc f; + CRecordVector<MapiFileDesc> files; + files.ClearAndSetSize(paths.Size()); + + for (i = 0; i < paths.Size(); i++) + { + MapiFileDesc &f = files[i]; memset(&f, 0, sizeof(f)); f.nPosition = 0xFFFFFFFF; - f.lpszPathName = (char *)(const char *)path; - f.lpszFileName = (char *)(const char *)name; - + f.lpszPathName = paths[i].Ptr_non_const(); + f.lpszFileName = names[i].Ptr_non_const(); + } + + { MapiMessage m; memset(&m, 0, sizeof(m)); - m.nFileCount = 1; - m.lpFiles = &f; + m.nFileCount = files.Size(); + m.lpFiles = &files.Front(); - const AString addr = GetAnsiString(options.EMailAddress); + 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; + rec.lpszAddress = addr.Ptr_non_const(); m.nRecipCount = 1; m.lpRecips = &rec; } sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0); } + } } #endif if (options.DeleteAfterCompressing) { - CRecordVector<CRefSortPair> pairs; + CRecordVector<CDirPathSortPair> pairs; FStringVector foldersNames; unsigned i; @@ -1506,47 +1786,71 @@ HRESULT UpdateArchive( for (i = 0; i < dirItems.Items.Size(); i++) { const CDirItem &dirItem = dirItems.Items[i]; - FString phyPath = dirItems.GetPhyPath(i); + const FString phyPath = dirItems.GetPhyPath(i); if (dirItem.IsDir()) { - CRefSortPair pair; + CDirPathSortPair pair; pair.Index = i; - pair.Len = GetNumSlashes(phyPath); + pair.SetNumSlashes(phyPath); pairs.Add(pair); } else { - if (processedItems[i] != 0 || dirItem.Size == 0) + // 21.04: we have set processedItems[*] before for all required items + if (processedItems[i] != 0 + // || dirItem.Size == 0 + // || dirItem.AreReparseData() + ) { - RINOK(callback->DeletingAfterArchiving(phyPath, false)); - DeleteFileAlways(phyPath); + NFind::CFileInfo fileInfo; + /* if (!SymLinks), we follow link here, similar to (dirItem) filling */ + if (fileInfo.Find(phyPath, !options.SymLinks.Val)) + { + bool is_SameSize = false; + if (options.SymLinks.Val && dirItem.AreReparseData()) + { + /* (dirItem.Size = dirItem.ReparseData.Size()) was set before. + So we don't compare sizes for that case here */ + is_SameSize = fileInfo.IsOsSymLink(); + } + else + is_SameSize = (fileInfo.Size == dirItem.Size); + + if (is_SameSize + && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0 + && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0) + { + RINOK(callback->DeletingAfterArchiving(phyPath, false)) + DeleteFileAlways(phyPath); + } + } } else { - // file was skipped + // file was skipped by some reason. We can throw error for debug: /* errorInfo.SystemError = 0; errorInfo.Message = "file was not processed"; - errorInfo.FileName = phyPath; + errorInfo.FileNames.Add(phyPath); return E_FAIL; */ } } } - pairs.Sort(CompareRefSortPair, NULL); + pairs.Sort2(); for (i = 0; i < pairs.Size(); i++) { - FString phyPath = dirItems.GetPhyPath(pairs[i].Index); + const FString phyPath = dirItems.GetPhyPath(pairs[i].Index); if (NFind::DoesDirExist(phyPath)) { - RINOK(callback->DeletingAfterArchiving(phyPath, true)); + RINOK(callback->DeletingAfterArchiving(phyPath, true)) RemoveDir(phyPath); } } - RINOK(callback->FinishDeletingAfterArchiving()); + RINOK(callback->FinishDeletingAfterArchiving()) } return S_OK; |