📄 update.cpp
字号:
// Update.cpp
#include "StdAfx.h"
#ifdef _WIN32
#include <mapi.h>
#endif
#include "Update.h"
#include "Common/IntToString.h"
#include "Common/StringConvert.h"
#include "Common/CommandLineParser.h"
#ifdef _WIN32
#include "Windows/DLL.h"
#endif
#include "Windows/Defs.h"
#include "Windows/FileDir.h"
#include "Windows/FileFind.h"
#include "Windows/FileName.h"
#include "Windows/PropVariant.h"
#include "Windows/PropVariantConversions.h"
// #include "Windows/Synchronization.h"
#include "../../Common/FileStreams.h"
#include "../../Compress/Copy/CopyCoder.h"
#include "../Common/DirItem.h"
#include "../Common/EnumDirItems.h"
#include "../Common/UpdateProduce.h"
#include "../Common/OpenArchive.h"
#include "TempFiles.h"
#include "UpdateCallback.h"
#include "EnumDirItems.h"
#include "SetProperties.h"
static const char *kUpdateIsNotSupoorted =
"update operations are not supported for this archive";
using namespace NCommandLineParser;
using namespace NWindows;
using namespace NCOM;
using namespace NFile;
using namespace NName;
static const wchar_t *kTempFolderPrefix = L"7zE";
using namespace NUpdateArchive;
static HRESULT CopyBlock(ISequentialInStream *inStream, ISequentialOutStream *outStream)
{
CMyComPtr<ICompressCoder> copyCoder = new NCompress::CCopyCoder;
return copyCoder->Code(inStream, outStream, NULL, NULL, NULL);
}
class COutMultiVolStream:
public IOutStream,
public CMyUnknownImp
{
int _streamIndex; // required stream
UInt64 _offsetPos; // offset from start of _streamIndex index
UInt64 _absPos;
UInt64 _length;
struct CSubStreamInfo
{
COutFileStream *StreamSpec;
CMyComPtr<IOutStream> Stream;
UString Name;
UInt64 Pos;
UInt64 RealSize;
};
CObjectVector<CSubStreamInfo> Streams;
public:
// CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
CRecordVector<UInt64> Sizes;
UString Prefix;
CTempFiles *TempFiles;
void Init()
{
_streamIndex = 0;
_offsetPos = 0;
_absPos = 0;
_length = 0;
}
HRESULT Close();
MY_UNKNOWN_IMP1(IOutStream)
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
STDMETHOD(SetSize)(Int64 newSize);
};
// static NSynchronization::CCriticalSection g_TempPathsCS;
HRESULT COutMultiVolStream::Close()
{
HRESULT res = S_OK;
for (int i = 0; i < Streams.Size(); i++)
{
CSubStreamInfo &s = Streams[i];
if (s.StreamSpec)
{
HRESULT res2 = s.StreamSpec->Close();
if (res2 != S_OK)
res = res2;
}
}
return res;
}
STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
{
if(processedSize != NULL)
*processedSize = 0;
while(size > 0)
{
if (_streamIndex >= Streams.Size())
{
CSubStreamInfo subStream;
wchar_t temp[32];
ConvertUInt64ToString(_streamIndex + 1, temp);
UString res = temp;
while (res.Length() < 3)
res = UString(L'0') + res;
UString name = Prefix + res;
subStream.StreamSpec = new COutFileStream;
subStream.Stream = subStream.StreamSpec;
if(!subStream.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);
continue;
}
CSubStreamInfo &subStream = Streams[_streamIndex];
int index = _streamIndex;
if (index >= Sizes.Size())
index = Sizes.Size() - 1;
UInt64 volSize = Sizes[index];
if (_offsetPos >= volSize)
{
_offsetPos -= volSize;
_streamIndex++;
continue;
}
if (_offsetPos != subStream.Pos)
{
// CMyComPtr<IOutStream> outStream;
// RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
RINOK(subStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
subStream.Pos = _offsetPos;
}
UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - subStream.Pos);
UInt32 realProcessed;
RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
data = (void *)((Byte *)data + realProcessed);
size -= realProcessed;
subStream.Pos += realProcessed;
_offsetPos += realProcessed;
_absPos += realProcessed;
if (_absPos > _length)
_length = _absPos;
if (_offsetPos > subStream.RealSize)
subStream.RealSize = _offsetPos;
if(processedSize != NULL)
*processedSize += realProcessed;
if (subStream.Pos == volSize)
{
_streamIndex++;
_offsetPos = 0;
}
if (realProcessed == 0 && curSize != 0)
return E_FAIL;
break;
}
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(Int64 newSize)
{
if (newSize < 0)
return E_INVALIDARG;
int i = 0;
while (i < Streams.Size())
{
CSubStreamInfo &subStream = Streams[i++];
if ((UInt64)newSize < subStream.RealSize)
{
RINOK(subStream.Stream->SetSize(newSize));
subStream.RealSize = newSize;
break;
}
newSize -= subStream.RealSize;
}
while (i < Streams.Size())
{
{
CSubStreamInfo &subStream = Streams.Back();
subStream.Stream.Release();
NDirectory::DeleteFileAlways(subStream.Name);
}
Streams.DeleteBack();
}
_offsetPos = _absPos;
_streamIndex = 0;
_length = newSize;
return S_OK;
}
static const wchar_t *kDefaultArchiveType = L"7z";
static const wchar_t *kSFXExtension =
#ifdef _WIN32
L"exe";
#else
L"";
#endif
bool CUpdateOptions::Init(const CCodecs *codecs, const UString &arcPath, const UString &arcType)
{
if (!arcType.IsEmpty())
MethodMode.FormatIndex = codecs->FindFormatForArchiveType(arcType);
else
{
MethodMode.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
if (MethodMode.FormatIndex < 0)
MethodMode.FormatIndex = codecs->FindFormatForArchiveType(kDefaultArchiveType);
}
if (MethodMode.FormatIndex < 0)
return false;
const CArcInfoEx &arcInfo = codecs->Formats[MethodMode.FormatIndex];
UString typeExt = arcInfo.GetMainExt();
UString ext = typeExt;
if (SfxMode)
ext = kSFXExtension;
ArchivePath.BaseExtension = ext;
ArchivePath.VolExtension = typeExt;
ArchivePath.ParseFromPath(arcPath);
for (int i = 0; i < Commands.Size(); i++)
{
CUpdateArchiveCommand &uc = Commands[i];
uc.ArchivePath.BaseExtension = ext;
uc.ArchivePath.VolExtension = typeExt;
uc.ArchivePath.ParseFromPath(uc.UserArchivePath);
}
return true;
}
static HRESULT Compress(
CCodecs *codecs,
const CActionSet &actionSet,
IInArchive *archive,
const CCompressionMethodMode &compressionMethod,
CArchivePath &archivePath,
const CObjectVector<CArchiveItem> &archiveItems,
bool shareForWrite,
bool stdInMode,
/* const UString & stdInFileName, */
bool stdOutMode,
const CObjectVector<CDirItem> &dirItems,
bool sfxMode,
const UString &sfxModule,
const CRecordVector<UInt64> &volumesSizes,
CTempFiles &tempFiles,
CUpdateErrorInfo &errorInfo,
IUpdateCallbackUI *callback)
{
CMyComPtr<IOutArchive> outArchive;
if(archive != NULL)
{
CMyComPtr<IInArchive> archive2 = archive;
HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
if(result != S_OK)
throw kUpdateIsNotSupoorted;
}
else
{
RINOK(codecs->CreateOutArchive(compressionMethod.FormatIndex, outArchive));
#ifdef EXTERNAL_CODECS
{
CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
if (setCompressCodecsInfo)
{
RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
}
}
#endif
}
if (outArchive == 0)
throw kUpdateIsNotSupoorted;
NFileTimeType::EEnum fileTimeType;
UInt32 value;
RINOK(outArchive->GetFileTimeType(&value));
switch(value)
{
case NFileTimeType::kWindows:
case NFileTimeType::kDOS:
case NFileTimeType::kUnix:
fileTimeType = NFileTimeType::EEnum(value);
break;
default:
return E_FAIL;
}
CObjectVector<CUpdatePair> updatePairs;
GetUpdatePairInfoList(dirItems, archiveItems, fileTimeType, updatePairs); // must be done only once!!!
CObjectVector<CUpdatePair2> updatePairs2;
UpdateProduce(updatePairs, actionSet, updatePairs2);
UInt32 numFiles = 0;
for (int i = 0; i < updatePairs2.Size(); i++)
if (updatePairs2[i].NewData)
numFiles++;
RINOK(callback->SetNumFiles(numFiles));
CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
updateCallbackSpec->ShareForWrite = shareForWrite;
updateCallbackSpec->StdInMode = stdInMode;
updateCallbackSpec->Callback = callback;
updateCallbackSpec->DirItems = &dirItems;
updateCallbackSpec->ArchiveItems = &archiveItems;
updateCallbackSpec->UpdatePairs = &updatePairs2;
CMyComPtr<ISequentialOutStream> outStream;
const UString &archiveName = archivePath.GetFinalPath();
if (!stdOutMode)
{
UString resultPath;
int pos;
if(!NFile::NDirectory::MyGetFullPathName(archiveName, resultPath, pos))
throw 1417161;
NFile::NDirectory::CreateComplexDirectory(resultPath.Left(pos));
}
COutFileStream *outStreamSpec = NULL;
COutMultiVolStream *volStreamSpec = NULL;
if (volumesSizes.Size() == 0)
{
if (stdOutMode)
outStream = new CStdOutFileStream;
else
{
outStreamSpec = new COutFileStream;
outStream = outStreamSpec;
bool isOK = false;
UString realPath;
for (int i = 0; i < (1 << 16); i++)
{
if (archivePath.Temp)
{
if (i > 0)
{
wchar_t s[32];
ConvertUInt64ToString(i, s);
archivePath.TempPostfix = s;
}
realPath = archivePath.GetTempPath();
}
else
realPath = archivePath.GetFinalPath();
if (outStreamSpec->Create(realPath, false))
{
tempFiles.Paths.Add(realPath);
isOK = true;
break;
}
if (::GetLastError() != ERROR_FILE_EXISTS)
break;
if (!archivePath.Temp)
break;
}
if (!isOK)
{
errorInfo.SystemError = ::GetLastError();
errorInfo.FileName = realPath;
errorInfo.Message = L"Can not open file";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -