Initialer Commit

This commit is contained in:
Tino Reichardt
2016-06-25 21:15:50 +02:00
commit c3967fe27a
1199 changed files with 290375 additions and 0 deletions

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
// ArchiveCommandLine.h
#ifndef __ARCHIVE_COMMAND_LINE_H
#define __ARCHIVE_COMMAND_LINE_H
#include "../../../Common/CommandLineParser.h"
#include "../../../Common/Wildcard.h"
#include "Extract.h"
#include "HashCalc.h"
#include "Update.h"
struct CArcCmdLineException: public UString
{
CArcCmdLineException(const char *a, const wchar_t *u = NULL);
};
namespace NCommandType { enum EEnum
{
kAdd = 0,
kUpdate,
kDelete,
kTest,
kExtract,
kExtractFull,
kList,
kBenchmark,
kInfo,
kHash,
kRename
};}
struct CArcCommand
{
NCommandType::EEnum CommandType;
bool IsFromExtractGroup() const;
bool IsFromUpdateGroup() const;
bool IsTestCommand() const { return CommandType == NCommandType::kTest; }
NExtract::NPathMode::EEnum GetPathMode() const;
};
enum
{
k_OutStream_disabled = 0,
k_OutStream_stdout = 1,
k_OutStream_stderr = 2
};
struct CArcCmdLineOptions
{
bool HelpMode;
bool LargePages;
bool CaseSensitiveChange;
bool CaseSensitive;
bool IsInTerminal;
bool IsStdOutTerminal;
bool IsStdErrTerminal;
bool StdInMode;
bool StdOutMode;
bool EnableHeaders;
bool YesToAll;
bool ShowDialog;
NWildcard::CCensor Censor;
CArcCommand Command;
UString ArchiveName;
#ifndef _NO_CRYPTO
bool PasswordEnabled;
UString Password;
#endif
bool TechMode;
bool ShowTime;
UStringVector HashMethods;
bool AppendName;
// UStringVector ArchivePathsSorted;
// UStringVector ArchivePathsFullSorted;
NWildcard::CCensor arcCensor;
UString ArcName_for_StdInMode;
CObjectVector<CProperty> Properties;
CExtractOptionsBase ExtractOptions;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
CUpdateOptions UpdateOptions;
CHashOptions HashOptions;
UString ArcType;
UStringVector ExcludedArcTypes;
unsigned Number_for_Out;
unsigned Number_for_Errors;
unsigned Number_for_Percents;
unsigned LogLevel;
// bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; }
// Benchmark
UInt32 NumIterations;
CArcCmdLineOptions():
LargePages(false),
CaseSensitiveChange(false),
CaseSensitive(false),
StdInMode(false),
StdOutMode(false),
Number_for_Out(k_OutStream_stdout),
Number_for_Errors(k_OutStream_stderr),
Number_for_Percents(k_OutStream_stdout),
LogLevel(0)
{
};
};
class CArcCmdLineParser
{
NCommandLineParser::CParser parser;
public:
CArcCmdLineParser();
void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options);
void Parse2(CArcCmdLineOptions &options);
};
HRESULT EnumerateDirItemsAndSort(
NWildcard::CCensor &censor,
NWildcard::ECensorPathMode pathMode,
const UString &addPathPrefix,
UStringVector &sortedPaths,
UStringVector &sortedFullPaths,
CDirItemsStat &st,
IDirItemsCallback *callback);
#endif

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
// ArchiveExtractCallback.h
#ifndef __ARCHIVE_EXTRACT_CALLBACK_H
#define __ARCHIVE_EXTRACT_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../../Common/Wildcard.h"
#include "../../IPassword.h"
#include "../../Common/FileStreams.h"
#include "../../Common/ProgressUtils.h"
#include "../../Archive/IArchive.h"
#include "ExtractMode.h"
#include "IFileExtractCallback.h"
#include "OpenArchive.h"
#include "HashCalc.h"
#ifndef _SFX
class COutStreamWithHash:
public ISequentialOutStream,
public CMyUnknownImp
{
CMyComPtr<ISequentialOutStream> _stream;
UInt64 _size;
bool _calculate;
public:
IHashCalc *_hash;
MY_UNKNOWN_IMP
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
void SetStream(ISequentialOutStream *stream) { _stream = stream; }
void ReleaseStream() { _stream.Release(); }
void Init(bool calculate = true)
{
InitCRC();
_size = 0;
_calculate = calculate;
}
void EnableCalc(bool calculate) { _calculate = calculate; }
void InitCRC() { _hash->InitForNewFile(); }
UInt64 GetSize() const { return _size; }
};
#endif
struct CExtractNtOptions
{
CBoolPair NtSecurity;
CBoolPair SymLinks;
CBoolPair HardLinks;
CBoolPair AltStreams;
bool ReplaceColonForAltStream;
bool WriteToAltStreamIfColon;
CExtractNtOptions():
ReplaceColonForAltStream(false),
WriteToAltStreamIfColon(false)
{
SymLinks.Val = true;
HardLinks.Val = true;
AltStreams.Val = true;
}
};
#ifndef _SFX
class CGetProp:
public IGetProp,
public CMyUnknownImp
{
public:
const CArc *Arc;
UInt32 IndexInArc;
// UString Name; // relative path
MY_UNKNOWN_IMP1(IGetProp)
INTERFACE_IGetProp(;)
};
#endif
#ifndef _SFX
#ifndef UNDER_CE
#define SUPPORT_LINKS
#endif
#endif
#ifdef SUPPORT_LINKS
struct CHardLinkNode
{
UInt64 StreamId;
UInt64 INode;
int Compare(const CHardLinkNode &a) const;
};
class CHardLinks
{
public:
CRecordVector<CHardLinkNode> IDs;
CObjectVector<FString> Links;
void Clear()
{
IDs.Clear();
Links.Clear();
}
void PrepareLinks()
{
while (Links.Size() < IDs.Size())
Links.AddNew();
}
};
#endif
#ifdef SUPPORT_ALT_STREAMS
struct CIndexToPathPair
{
UInt32 Index;
FString Path;
CIndexToPathPair(UInt32 index): Index(index) {}
CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {}
int Compare(const CIndexToPathPair &pair) const
{
return MyCompare(Index, pair.Index);
}
};
#endif
class CArchiveExtractCallback:
public IArchiveExtractCallback,
public IArchiveExtractCallbackMessage,
public ICryptoGetTextPassword,
public ICompressProgressInfo,
public CMyUnknownImp
{
const CArc *_arc;
CExtractNtOptions _ntOptions;
const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
CMyComPtr<ICompressProgressInfo> _compressProgress;
CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
CMyComPtr<IArchiveExtractCallbackMessage> _callbackMessage;
CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
FString _dirPathPrefix;
FString _dirPathPrefix_Full;
NExtract::NPathMode::EEnum _pathMode;
NExtract::NOverwriteMode::EEnum _overwriteMode;
#ifndef _SFX
CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
CGetProp *GetProp_Spec;
CMyComPtr<IGetProp> GetProp;
#endif
CReadArcItem _item;
FString _diskFilePath;
UInt64 _position;
bool _isSplit;
bool _extractMode;
bool WriteCTime;
bool WriteATime;
bool WriteMTime;
bool _encrypted;
struct CProcessedFileInfo
{
FILETIME CTime;
FILETIME ATime;
FILETIME MTime;
UInt32 Attrib;
bool CTimeDefined;
bool ATimeDefined;
bool MTimeDefined;
bool AttribDefined;
} _fi;
UInt32 _index;
UInt64 _curSize;
bool _curSizeDefined;
COutFileStream *_outFileStreamSpec;
CMyComPtr<ISequentialOutStream> _outFileStream;
#ifndef _SFX
COutStreamWithHash *_hashStreamSpec;
CMyComPtr<ISequentialOutStream> _hashStream;
bool _hashStreamWasUsed;
#endif
bool _removePartsForAltStreams;
UStringVector _removePathParts;
#ifndef _SFX
bool _use_baseParentFolder_mode;
UInt32 _baseParentFolder;
#endif
bool _stdOutMode;
bool _testMode;
bool _multiArchives;
CMyComPtr<ICompressProgressInfo> _localProgress;
UInt64 _packTotal;
UInt64 _progressTotal;
bool _progressTotal_Defined;
FStringVector _extractedFolderPaths;
CRecordVector<UInt32> _extractedFolderIndices;
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
bool _saclEnabled;
#endif
void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
HRESULT GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
HRESULT GetUnpackSize();
HRESULT SendMessageError(const char *message, const FString &path);
HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2);
public:
CLocalProgress *LocalProgressSpec;
UInt64 NumFolders;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 UnpackSize;
UInt64 AltStreams_UnpackSize;
MY_UNKNOWN_IMP3(IArchiveExtractCallbackMessage, ICryptoGetTextPassword, ICompressProgressInfo)
INTERFACE_IArchiveExtractCallback(;)
INTERFACE_IArchiveExtractCallbackMessage(;)
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
CArchiveExtractCallback();
void InitForMulti(bool multiArchives,
NExtract::NPathMode::EEnum pathMode,
NExtract::NOverwriteMode::EEnum overwriteMode)
{
_multiArchives = multiArchives;
_pathMode = pathMode;
_overwriteMode = overwriteMode;
NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
}
#ifndef _SFX
void SetHashMethods(IHashCalc *hash)
{
if (!hash)
return;
_hashStreamSpec = new COutStreamWithHash;
_hashStream = _hashStreamSpec;
_hashStreamSpec->_hash = hash;
}
#endif
void Init(
const CExtractNtOptions &ntOptions,
const NWildcard::CCensorNode *wildcardCensor,
const CArc *arc,
IFolderArchiveExtractCallback *extractCallback2,
bool stdOutMode, bool testMode,
const FString &directoryPath,
const UStringVector &removePathParts, bool removePartsForAltStreams,
UInt64 packSize);
#ifdef SUPPORT_LINKS
private:
CHardLinks _hardLinks;
UString linkPath;
// FString _CopyFile_Path;
// HRESULT MyCopyFile(ISequentialOutStream *outStream);
public:
// call PrepareHardLinks() after Init()
HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
#endif
#ifdef SUPPORT_ALT_STREAMS
CObjectVector<CIndexToPathPair> _renamedFiles;
#endif
// call it after Init()
#ifndef _SFX
void SetBaseParentFolderIndex(UInt32 indexInArc)
{
_baseParentFolder = indexInArc;
_use_baseParentFolder_mode = true;
}
#endif
HRESULT SetDirsTimes();
};
bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
#endif

View File

@@ -0,0 +1,78 @@
// ArchiveName.cpp
#include "StdAfx.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "ExtractingFilePath.h"
#include "ArchiveName.h"
using namespace NWindows;
using namespace NFile;
UString CreateArchiveName(const NFind::CFileInfo &fi, bool keepName)
{
FString resultName = fi.Name;
if (!fi.IsDir() && !keepName)
{
int dotPos = resultName.ReverseFind_Dot();
if (dotPos > 0)
{
FString archiveName2 = resultName.Left(dotPos);
if (archiveName2.ReverseFind_Dot() < 0)
resultName = archiveName2;
}
}
return Get_Correct_FsFile_Name(fs2us(resultName));
}
static FString CreateArchiveName2(const FString &path, bool fromPrev, bool keepName)
{
FString resultName = FTEXT("Archive");
if (fromPrev)
{
FString dirPrefix;
if (NDir::GetOnlyDirPrefix(path, dirPrefix))
{
if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))
{
#if defined(_WIN32) && !defined(UNDER_CE)
if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))
resultName = dirPrefix[dirPrefix.Len() - 3]; // only letter
else
#endif
{
dirPrefix.DeleteBack();
NFind::CFileInfo fi;
if (fi.Find(dirPrefix))
resultName = fi.Name;
}
}
}
}
else
{
NFind::CFileInfo fi;
if (fi.Find(path))
{
resultName = fi.Name;
if (!fi.IsDir() && !keepName)
{
int dotPos = resultName.ReverseFind_Dot();
if (dotPos > 0)
{
FString name2 = resultName.Left(dotPos);
if (name2.ReverseFind_Dot() < 0)
resultName = name2;
}
}
}
}
return resultName;
}
UString CreateArchiveName(const UString &path, bool fromPrev, bool keepName)
{
return Get_Correct_FsFile_Name(fs2us(CreateArchiveName2(us2fs(path), fromPrev, keepName)));
}

View File

@@ -0,0 +1,13 @@
// ArchiveName.h
#ifndef __ARCHIVE_NAME_H
#define __ARCHIVE_NAME_H
#include "../../../Common/MyString.h"
#include "../../../Windows/FileFind.h"
UString CreateArchiveName(const UString &path, bool fromPrev, bool keepName);
UString CreateArchiveName(const NWindows::NFile::NFind::CFileInfo &fileInfo, bool keepName);
#endif

View File

@@ -0,0 +1,154 @@
// ArchiveOpenCallback.cpp
#include "StdAfx.h"
#include "../../../Common/ComTry.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/PropVariant.h"
#include "../../Common/FileStreams.h"
#include "ArchiveOpenCallback.h"
using namespace NWindows;
STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
{
COM_TRY_BEGIN
if (ReOpenCallback)
return ReOpenCallback->SetTotal(files, bytes);
if (!Callback)
return S_OK;
return Callback->Open_SetTotal(files, bytes);
COM_TRY_END
}
STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
{
COM_TRY_BEGIN
if (ReOpenCallback)
return ReOpenCallback->SetCompleted(files, bytes);
if (!Callback)
return S_OK;
return Callback->Open_SetCompleted(files, bytes);
COM_TRY_END
}
STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
NCOM::CPropVariant prop;
if (_subArchiveMode)
switch (propID)
{
case kpidName: prop = _subArchiveName; break;
// case kpidSize: prop = _subArchiveSize; break; // we don't use it now
}
else
switch (propID)
{
case kpidName: prop = _fileInfo.Name; break;
case kpidIsDir: prop = _fileInfo.IsDir(); break;
case kpidSize: prop = _fileInfo.Size; break;
case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break;
case kpidCTime: prop = _fileInfo.CTime; break;
case kpidATime: prop = _fileInfo.ATime; break;
case kpidMTime: prop = _fileInfo.MTime; break;
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
struct CInFileStreamVol: public CInFileStream
{
int FileNameIndex;
COpenCallbackImp *OpenCallbackImp;
CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
~CInFileStreamVol()
{
if (OpenCallbackRef)
OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false;
}
};
// from ArchiveExtractCallback.cpp
bool IsSafePath(const UString &path);
STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
{
COM_TRY_BEGIN
*inStream = NULL;
if (_subArchiveMode)
return S_FALSE;
if (Callback)
{
RINOK(Callback->Open_CheckBreak());
}
UString name2 = name;
#ifndef _SFX
#ifdef _WIN32
name2.Replace(L'/', WCHAR_PATH_SEPARATOR);
#endif
// if (!allowAbsVolPaths)
if (!IsSafePath(name2))
return S_FALSE;
#endif
FString fullPath;
if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))
return S_FALSE;
if (!_fileInfo.Find(fullPath))
return S_FALSE;
if (_fileInfo.IsDir())
return S_FALSE;
CInFileStreamVol *inFile = new CInFileStreamVol;
CMyComPtr<IInStream> inStreamTemp = inFile;
if (!inFile->Open(fullPath))
{
DWORD lastError = ::GetLastError();
if (lastError == 0)
return E_FAIL;
return HRESULT_FROM_WIN32(lastError);
}
FileSizes.Add(_fileInfo.Size);
FileNames.Add(name2);
inFile->FileNameIndex = FileNames_WasUsed.Add(true);
inFile->OpenCallbackImp = this;
inFile->OpenCallbackRef = this;
// TotalSize += _fileInfo.Size;
*inStream = inStreamTemp.Detach();
return S_OK;
COM_TRY_END
}
#ifndef _NO_CRYPTO
STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
{
COM_TRY_BEGIN
if (ReOpenCallback)
{
CMyComPtr<ICryptoGetTextPassword> getTextPassword;
ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
if (getTextPassword)
return getTextPassword->CryptoGetTextPassword(password);
}
if (!Callback)
return E_NOTIMPL;
PasswordWasAsked = true;
return Callback->Open_CryptoGetTextPassword(password);
COM_TRY_END
}
#endif

View File

@@ -0,0 +1,112 @@
// ArchiveOpenCallback.h
#ifndef __ARCHIVE_OPEN_CALLBACK_H
#define __ARCHIVE_OPEN_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../../Windows/FileFind.h"
#ifndef _NO_CRYPTO
#include "../../IPassword.h"
#endif
#include "../../Archive/IArchive.h"
#ifdef _NO_CRYPTO
#define INTERFACE_IOpenCallbackUI_Crypto(x)
#else
#define INTERFACE_IOpenCallbackUI_Crypto(x) \
virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \
/* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x; */ \
/* virtual bool Open_WasPasswordAsked() x; */ \
/* virtual void Open_Clear_PasswordWasAsked_Flag() x; */ \
#endif
#define INTERFACE_IOpenCallbackUI(x) \
virtual HRESULT Open_CheckBreak() x; \
virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \
virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \
virtual HRESULT Open_Finished() x; \
INTERFACE_IOpenCallbackUI_Crypto(x)
struct IOpenCallbackUI
{
INTERFACE_IOpenCallbackUI(=0)
};
class COpenCallbackImp:
public IArchiveOpenCallback,
public IArchiveOpenVolumeCallback,
public IArchiveOpenSetSubArchiveName,
#ifndef _NO_CRYPTO
public ICryptoGetTextPassword,
#endif
public CMyUnknownImp
{
public:
MY_QUERYINTERFACE_BEGIN2(IArchiveOpenVolumeCallback)
MY_QUERYINTERFACE_ENTRY(IArchiveOpenSetSubArchiveName)
#ifndef _NO_CRYPTO
MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
#endif
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
INTERFACE_IArchiveOpenCallback(;)
INTERFACE_IArchiveOpenVolumeCallback(;)
#ifndef _NO_CRYPTO
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
#endif
STDMETHOD(SetSubArchiveName(const wchar_t *name))
{
_subArchiveMode = true;
_subArchiveName = name;
// TotalSize = 0;
return S_OK;
}
private:
FString _folderPrefix;
NWindows::NFile::NFind::CFileInfo _fileInfo;
bool _subArchiveMode;
UString _subArchiveName;
public:
UStringVector FileNames;
CBoolVector FileNames_WasUsed;
CRecordVector<UInt64> FileSizes;
bool PasswordWasAsked;
IOpenCallbackUI *Callback;
CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
// UInt64 TotalSize;
COpenCallbackImp(): Callback(NULL), _subArchiveMode(false) {}
void Init(const FString &folderPrefix, const FString &fileName)
{
_folderPrefix = folderPrefix;
if (!_fileInfo.Find(_folderPrefix + fileName))
throw 20121118;
FileNames.Clear();
FileNames_WasUsed.Clear();
FileSizes.Clear();
_subArchiveMode = false;
// TotalSize = 0;
PasswordWasAsked = false;
}
bool SetSecondFileInfo(CFSTR newName)
{
return _fileInfo.Find(newName) && !_fileInfo.IsDir();
}
};
#endif

3100
CPP/7zip/UI/Common/Bench.cpp Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
// Bench.h
#ifndef __7ZIP_BENCH_H
#define __7ZIP_BENCH_H
#include "../../Common/CreateCoder.h"
#include "../../UI/Common/Property.h"
struct CBenchInfo
{
UInt64 GlobalTime;
UInt64 GlobalFreq;
UInt64 UserTime;
UInt64 UserFreq;
UInt64 UnpackSize;
UInt64 PackSize;
UInt64 NumIterations;
CBenchInfo(): NumIterations(0) {}
UInt64 GetUsage() const;
UInt64 GetRatingPerUsage(UInt64 rating) const;
UInt64 GetSpeed(UInt64 numCommands) const;
};
struct IBenchCallback
{
virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0;
virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
};
UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);
const unsigned kBenchMinDicLogSize = 18;
UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench = false);
struct IBenchPrintCallback
{
virtual void Print(const char *s) = 0;
virtual void NewLine() = 0;
virtual HRESULT CheckBreak() = 0;
};
HRESULT Bench(
DECL_EXTERNAL_CODECS_LOC_VARS
IBenchPrintCallback *printCallback,
IBenchCallback *benchCallback,
const CObjectVector<CProperty> &props,
UInt32 numIterations,
bool multiDict
);
#endif

View File

@@ -0,0 +1,295 @@
// CompressCall.cpp
#include "StdAfx.h"
#include <wchar.h>
#include "../../../Common/IntToString.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/Random.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileMapping.h"
#include "../../../Windows/ProcessUtils.h"
#include "../../../Windows/Synchronization.h"
#include "../FileManager/RegistryUtils.h"
#include "CompressCall.h"
using namespace NWindows;
#define MY_TRY_BEGIN try {
#define MY_TRY_FINISH } \
catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; }
#define MY_TRY_FINISH_VOID } \
catch(...) { ErrorMessageHRESULT(E_FAIL); }
static const char *k7zGui = "7zG.exe";
static const char *kShowDialogSwitch = " -ad";
static const char *kEmailSwitch = " -seml.";
static const char *kIncludeSwitch = " -i";
static const char *kArchiveTypeSwitch = " -t";
static const char *kArcIncludeSwitches = " -an -ai";
static const char *kHashIncludeSwitches = " -i";
static const char *kStopSwitchParsing = " --";
static const char *kLargePagesDisable = " -slp-";
extern HWND g_HWND;
UString GetQuotedString(const UString &s)
{
UString s2 = L'\"';
s2 += s;
s2 += L'\"';
return s2;
}
static void ErrorMessage(LPCWSTR message)
{
MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK);
}
static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL)
{
UString s2 = NError::MyFormatMessage(res);
if (s)
{
s2.Add_LF();
s2 += s;
}
ErrorMessage(s2);
}
static HRESULT Call7zGui(const UString &params,
// LPCWSTR curDir,
bool waitFinish,
NSynchronization::CBaseEvent *event)
{
UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix());
imageName.AddAscii(k7zGui);
CProcess process;
WRes res = process.Create(imageName, params, NULL); // curDir);
if (res != 0)
{
ErrorMessageHRESULT(res, imageName);
return res;
}
if (waitFinish)
process.Wait();
else if (event != NULL)
{
HANDLE handles[] = { process, *event };
::WaitForMultipleObjects(ARRAY_SIZE(handles), handles, FALSE, INFINITE);
}
return S_OK;
}
static void AddLagePagesSwitch(UString &params)
{
if (!ReadLockMemoryEnable())
params.AddAscii(kLargePagesDisable);
}
class CRandNameGenerator
{
CRandom _random;
public:
CRandNameGenerator() { _random.Init(); }
void GenerateName(UString &s, const char *prefix)
{
s.AddAscii(prefix);
char temp[16];
ConvertUInt32ToString((UInt32)(unsigned)_random.Generate(), temp);
s.AddAscii(temp);
}
};
static HRESULT CreateMap(const UStringVector &names,
CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event,
UString &params)
{
size_t totalSize = 1;
{
FOR_VECTOR (i, names)
totalSize += (names[i].Len() + 1);
}
totalSize *= sizeof(wchar_t);
CRandNameGenerator random;
UString mappingName;
for (;;)
{
random.GenerateName(mappingName, "7zMap");
WRes res = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName));
if (fileMapping.IsCreated() && res == 0)
break;
if (res != ERROR_ALREADY_EXISTS)
return res;
fileMapping.Close();
}
UString eventName;
for (;;)
{
random.GenerateName(eventName, "7zEvent");
WRes res = event.CreateWithName(false, GetSystemString(eventName));
if (event.IsCreated() && res == 0)
break;
if (res != ERROR_ALREADY_EXISTS)
return res;
event.Close();
}
params += L'#';
params += mappingName;
params += L':';
char temp[32];
ConvertUInt64ToString(totalSize, temp);
params.AddAscii(temp);
params += L':';
params += eventName;
LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize);
if (!data)
return E_FAIL;
CFileUnmapper unmapper(data);
{
wchar_t *cur = (wchar_t *)data;
*cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32)
FOR_VECTOR (i, names)
{
const UString &s = names[i];
unsigned len = s.Len() + 1;
wmemcpy(cur, (const wchar_t *)s, len);
cur += len;
}
}
return S_OK;
}
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool waitFinish)
{
MY_TRY_BEGIN
UString params = L'a';
CFileMapping fileMapping;
NSynchronization::CManualResetEvent event;
params.AddAscii(kIncludeSwitch);
RINOK(CreateMap(names, fileMapping, event, params));
if (!arcType.IsEmpty())
{
params.AddAscii(kArchiveTypeSwitch);
params += arcType;
}
if (email)
params.AddAscii(kEmailSwitch);
if (showDialog)
params.AddAscii(kShowDialogSwitch);
AddLagePagesSwitch(params);
if (arcName.IsEmpty())
params.AddAscii(" -an");
if (addExtension)
params.AddAscii(" -saa");
else
params.AddAscii(" -sae");
params.AddAscii(kStopSwitchParsing);
params.Add_Space();
if (!arcName.IsEmpty())
{
params += GetQuotedString(
// #ifdef UNDER_CE
arcPathPrefix +
// #endif
arcName);
}
return Call7zGui(params,
// (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix),
waitFinish, &event);
MY_TRY_FINISH
}
static void ExtractGroupCommand(const UStringVector &arcPaths, UString &params, bool isHash)
{
AddLagePagesSwitch(params);
params.AddAscii(isHash ? kHashIncludeSwitches : kArcIncludeSwitches);
CFileMapping fileMapping;
NSynchronization::CManualResetEvent event;
HRESULT result = CreateMap(arcPaths, fileMapping, event, params);
if (result == S_OK)
result = Call7zGui(params, false, &event);
if (result != S_OK)
ErrorMessageHRESULT(result);
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup)
{
MY_TRY_BEGIN
UString params = L'x';
if (!outFolder.IsEmpty())
{
params.AddAscii(" -o");
params += GetQuotedString(outFolder);
}
if (elimDup)
params.AddAscii(" -spe");
if (showDialog)
params.AddAscii(kShowDialogSwitch);
ExtractGroupCommand(arcPaths, params, false);
MY_TRY_FINISH_VOID
}
void TestArchives(const UStringVector &arcPaths)
{
MY_TRY_BEGIN
UString params = L't';
ExtractGroupCommand(arcPaths, params, false);
MY_TRY_FINISH_VOID
}
void CalcChecksum(const UStringVector &paths, const UString &methodName)
{
MY_TRY_BEGIN
UString params = L'h';
if (!methodName.IsEmpty())
{
params.AddAscii(" -scrc");
params += methodName;
}
ExtractGroupCommand(paths, params, true);
MY_TRY_FINISH_VOID
}
void Benchmark(bool totalMode)
{
MY_TRY_BEGIN
HRESULT result = Call7zGui(totalMode ? L"b -mm=*" : L"b", false, NULL);
if (result != S_OK)
ErrorMessageHRESULT(result);
MY_TRY_FINISH_VOID
}

View File

@@ -0,0 +1,23 @@
// CompressCall.h
#ifndef __COMPRESS_CALL_H
#define __COMPRESS_CALL_H
#include "../../../Common/MyString.h"
UString GetQuotedString(const UString &s);
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool waitFinish);
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup);
void TestArchives(const UStringVector &arcPaths);
void CalcChecksum(const UStringVector &paths, const UString &methodName);
void Benchmark(bool totalMode);
#endif

View File

@@ -0,0 +1,270 @@
// CompressCall.cpp
#include "StdAfx.h"
#include "../../../Common/MyException.h"
#include "../../UI/common/ArchiveCommandLine.h"
#include "../../UI/GUI/BenchmarkDialog.h"
#include "../../UI/GUI/ExtractGUI.h"
#include "../../UI/GUI/UpdateGUI.h"
#include "../../UI/GUI/HashGUI.h"
#include "../../UI/GUI/ExtractRes.h"
#include "CompressCall.h"
extern HWND g_HWND;
#define MY_TRY_BEGIN HRESULT result; try {
#define MY_TRY_FINISH } \
catch(CSystemException &e) { result = e.ErrorCode; } \
catch(...) { result = E_FAIL; } \
if (result != S_OK && result != E_ABORT) \
ErrorMessageHRESULT(result);
static void ThrowException_if_Error(HRESULT res)
{
if (res != S_OK)
throw CSystemException(res);
}
#ifdef EXTERNAL_CODECS
#define CREATE_CODECS \
CCodecs *codecs = new CCodecs; \
CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs; \
ThrowException_if_Error(codecs->Load());
#define LOAD_EXTERNAL_CODECS \
CExternalCodecs __externalCodecs; \
__externalCodecs.GetCodecs = codecs; \
__externalCodecs.GetHashers = codecs; \
ThrowException_if_Error(__externalCodecs.Load());
#else
#define CREATE_CODECS \
CCodecs *codecs = new CCodecs; \
CMyComPtr<IUnknown> compressCodecsInfo = codecs; \
ThrowException_if_Error(codecs->Load());
#define LOAD_EXTERNAL_CODECS
#endif
UString GetQuotedString(const UString &s)
{
UString s2 = L'\"';
s2 += s;
s2 += L'\"';
return s2;
}
static void ErrorMessage(LPCWSTR message)
{
MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR);
}
static void ErrorMessageHRESULT(HRESULT res)
{
ErrorMessage(HResultToMessage(res));
}
static void ErrorLangMessage(UINT resourceID)
{
ErrorMessage(LangString(resourceID));
}
HRESULT CompressFiles(
const UString &arcPathPrefix,
const UString &arcName,
const UString &arcType,
bool addExtension,
const UStringVector &names,
bool email, bool showDialog, bool /* waitFinish */)
{
MY_TRY_BEGIN
CREATE_CODECS
CUpdateCallbackGUI callback;
callback.Init();
CUpdateOptions uo;
uo.EMailMode = email;
uo.SetActionCommand_Add();
uo.ArcNameMode = (addExtension ? k_ArcNameMode_Add : k_ArcNameMode_Exact);
CObjectVector<COpenType> formatIndices;
if (!ParseOpenTypes(*codecs, arcType, formatIndices))
{
ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
return E_FAIL;
}
const UString arcPath = arcPathPrefix + arcName;
if (!uo.InitFormatIndex(codecs, formatIndices, arcPath) ||
!uo.SetArcPath(codecs, arcPath))
{
ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED);
return E_FAIL;
}
NWildcard::CCensor censor;
FOR_VECTOR (i, names)
{
censor.AddPreItem(names[i]);
}
bool messageWasDisplayed = false;
result = UpdateGUI(codecs,
formatIndices, arcPath,
censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return E_FAIL;
throw CSystemException(result);
}
if (callback.FailedFiles.Size() > 0)
{
if (!messageWasDisplayed)
throw CSystemException(E_FAIL);
return E_FAIL;
}
MY_TRY_FINISH
return S_OK;
}
static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
bool showDialog, const UString &outFolder, bool testMode, bool elimDup = false)
{
MY_TRY_BEGIN
CREATE_CODECS
CExtractOptions eo;
eo.OutputDir = us2fs(outFolder);
eo.TestMode = testMode;
eo.ElimDup.Val = elimDup;
eo.ElimDup.Def = elimDup;
CExtractCallbackImp *ecs = new CExtractCallbackImp;
CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
ecs->Init();
// eo.CalcCrc = options.CalcCrc;
UStringVector arcPathsSorted;
UStringVector arcFullPathsSorted;
{
NWildcard::CCensor arcCensor;
FOR_VECTOR (i, arcPaths)
{
arcCensor.AddPreItem(arcPaths[i]);
}
arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
CDirItemsStat st;
EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(),
arcPathsSorted, arcFullPathsSorted,
st,
NULL // &scan: change it!!!!
);
}
CObjectVector<COpenType> formatIndices;
NWildcard::CCensor censor;
{
censor.AddPreItem_Wildcard();
}
censor.AddPathsToCensor(NWildcard::k_RelatPath);
bool messageWasDisplayed = false;
result = ExtractGUI(codecs,
formatIndices, CIntVector(),
arcPathsSorted, arcFullPathsSorted,
censor.Pairs.Front().Head, eo, NULL, showDialog, messageWasDisplayed, ecs, g_HWND);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return E_FAIL;
throw CSystemException(result);
}
return ecs->IsOK() ? S_OK : E_FAIL;
MY_TRY_FINISH
return result;
}
void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup)
{
ExtractGroupCommand(arcPaths, showDialog, outFolder, false, elimDup);
}
void TestArchives(const UStringVector &arcPaths)
{
ExtractGroupCommand(arcPaths, true, UString(), true);
}
void CalcChecksum(const UStringVector &paths, const UString &methodName)
{
MY_TRY_BEGIN
CREATE_CODECS
LOAD_EXTERNAL_CODECS
NWildcard::CCensor censor;
FOR_VECTOR (i, paths)
{
censor.AddPreItem(paths[i]);
}
censor.AddPathsToCensor(NWildcard::k_RelatPath);
bool messageWasDisplayed = false;
CHashOptions options;
options.Methods.Add(methodName);
result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed);
if (result != S_OK)
{
if (result != E_ABORT && messageWasDisplayed)
return; // E_FAIL;
throw CSystemException(result);
}
MY_TRY_FINISH
return; // result;
}
void Benchmark(bool totalMode)
{
MY_TRY_BEGIN
CREATE_CODECS
LOAD_EXTERNAL_CODECS
CObjectVector<CProperty> props;
if (totalMode)
{
CProperty prop;
prop.Name = L"m";
prop.Value = L"*";
props.Add(prop);
}
result = Benchmark(EXTERNAL_CODECS_VARS_L props, g_HWND);
MY_TRY_FINISH
}

View File

@@ -0,0 +1,37 @@
// DefaultName.cpp
#include "StdAfx.h"
#include "DefaultName.h"
static UString GetDefaultName3(const UString &fileName,
const UString &extension, const UString &addSubExtension)
{
const unsigned extLen = extension.Len();
const unsigned fileNameLen = fileName.Len();
if (fileNameLen > extLen + 1)
{
const unsigned dotPos = fileNameLen - (extLen + 1);
if (fileName[dotPos] == '.')
if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1)))
return fileName.Left(dotPos) + addSubExtension;
}
int dotPos = fileName.ReverseFind_Dot();
if (dotPos > 0)
return fileName.Left(dotPos) + addSubExtension;
if (addSubExtension.IsEmpty())
return fileName + L'~';
else
return fileName + addSubExtension;
}
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension)
{
UString name = GetDefaultName3(fileName, extension, addSubExtension);
name.TrimRight();
return name;
}

View File

@@ -0,0 +1,11 @@
// DefaultName.h
#ifndef __DEFAULT_NAME_H
#define __DEFAULT_NAME_H
#include "../../../Common/MyString.h"
UString GetDefaultName2(const UString &fileName,
const UString &extension, const UString &addSubExtension);
#endif

View File

@@ -0,0 +1,157 @@
// DirItem.h
#ifndef __DIR_ITEM_H
#define __DIR_ITEM_H
#include "../../../Common/MyString.h"
#include "../../../Windows/FileFind.h"
#include "../../Common/UniqBlocks.h"
#include "../../Archive/IArchive.h"
struct CDirItemsStat
{
UInt64 NumDirs;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 FilesSize;
UInt64 AltStreamsSize;
UInt64 NumErrors;
// UInt64 GetTotalItems() const { return NumDirs + NumFiles + NumAltStreams; }
UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; }
CDirItemsStat():
NumDirs(0),
NumFiles(0),
NumAltStreams(0),
FilesSize(0),
AltStreamsSize(0),
NumErrors(0)
{}
};
#define INTERFACE_IDirItemsCallback(x) \
virtual HRESULT ScanError(const FString &path, DWORD systemError) x; \
virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x; \
struct IDirItemsCallback
{
INTERFACE_IDirItemsCallback(=0)
};
struct CDirItem
{
UInt64 Size;
FILETIME CTime;
FILETIME ATime;
FILETIME MTime;
UString Name;
#if defined(_WIN32) && !defined(UNDER_CE)
// UString ShortName;
CByteBuffer ReparseData;
CByteBuffer ReparseData2; // fixed (reduced) absolute links
bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }
#endif
UInt32 Attrib;
int PhyParent;
int LogParent;
int SecureIndex;
bool IsAltStream;
CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {}
bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
};
class CDirItems
{
UStringVector Prefixes;
CIntVector PhyParents;
CIntVector LogParents;
UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix);
public:
CObjectVector<CDirItem> Items;
bool SymLinks;
bool ScanAltStreams;
CDirItemsStat Stat;
#ifndef UNDER_CE
HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi,
const FString &phyPrefix);
#endif
#if defined(_WIN32) && !defined(UNDER_CE)
CUniqBlocks SecureBlocks;
CByteBuffer TempSecureBuf;
bool _saclEnabled;
bool ReadSecure;
HRESULT AddSecurityItem(const FString &path, int &secureIndex);
#endif
IDirItemsCallback *Callback;
CDirItems();
void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
const NWindows::NFile::NFind::CFileInfo &fi);
HRESULT AddError(const FString &path, DWORD errorCode);
HRESULT AddError(const FString &path);
HRESULT ScanProgress(const FString &path);
// unsigned GetNumFolders() const { return Prefixes.Size(); }
FString GetPhyPath(unsigned index) const;
UString GetLogPath(unsigned index) const;
unsigned AddPrefix(int phyParent, int logParent, const UString &prefix);
void DeleteLastPrefix();
HRESULT EnumerateItems2(
const FString &phyPrefix,
const UString &logPrefix,
const FStringVector &filePaths,
FStringVector *requestedPaths);
#if defined(_WIN32) && !defined(UNDER_CE)
void FillFixedReparse();
#endif
void ReserveDown();
};
struct CArcItem
{
UInt64 Size;
FILETIME MTime;
UString Name;
bool IsDir;
bool IsAltStream;
bool SizeDefined;
bool MTimeDefined;
bool Censored;
UInt32 IndexInServer;
int TimeType;
CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {}
};
#endif

View File

@@ -0,0 +1,898 @@
// EnumDirItems.cpp
#include "StdAfx.h"
#include <wchar.h>
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/FileName.h"
#if defined(_WIN32) && !defined(UNDER_CE)
#define _USE_SECURITY_CODE
#include "../../../Windows/SecurityUtils.h"
#endif
#include "EnumDirItems.h"
using namespace NWindows;
using namespace NFile;
using namespace NName;
void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,
const NFind::CFileInfo &fi)
{
CDirItem di;
di.Size = fi.Size;
di.CTime = fi.CTime;
di.ATime = fi.ATime;
di.MTime = fi.MTime;
di.Attrib = fi.Attrib;
di.IsAltStream = fi.IsAltStream;
di.PhyParent = phyParent;
di.LogParent = logParent;
di.SecureIndex = secureIndex;
di.Name = fs2us(fi.Name);
#if defined(_WIN32) && !defined(UNDER_CE)
// di.ShortName = fs2us(fi.ShortName);
#endif
Items.Add(di);
if (fi.IsDir())
Stat.NumDirs++;
else if (fi.IsAltStream)
{
Stat.NumAltStreams++;
Stat.AltStreamsSize += fi.Size;
}
else
{
Stat.NumFiles++;
Stat.FilesSize += fi.Size;
}
}
HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)
{
Stat.NumErrors++;
if (Callback)
return Callback->ScanError(path, errorCode);
return S_OK;
}
HRESULT CDirItems::AddError(const FString &path)
{
return AddError(path, ::GetLastError());
}
static const unsigned kScanProgressStepMask = (1 << 12) - 1;
HRESULT CDirItems::ScanProgress(const FString &dirPath)
{
if (Callback)
return Callback->ScanProgress(Stat, dirPath, true);
return S_OK;
}
UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
{
UString path;
unsigned len = name.Len();
int i;
for (i = index; i >= 0; i = parents[i])
len += Prefixes[i].Len();
wchar_t *p = path.GetBuf_SetEnd(len) + len;
p -= name.Len();
wmemcpy(p, (const wchar_t *)name, name.Len());
for (i = index; i >= 0; i = parents[i])
{
const UString &s = Prefixes[i];
p -= s.Len();
wmemcpy(p, (const wchar_t *)s, s.Len());
}
return path;
}
FString CDirItems::GetPhyPath(unsigned index) const
{
const CDirItem &di = Items[index];
return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name));
}
UString CDirItems::GetLogPath(unsigned index) const
{
const CDirItem &di = Items[index];
return GetPrefixesPath(LogParents, di.LogParent, di.Name);
}
void CDirItems::ReserveDown()
{
Prefixes.ReserveDown();
PhyParents.ReserveDown();
LogParents.ReserveDown();
Items.ReserveDown();
}
unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
{
PhyParents.Add(phyParent);
LogParents.Add(logParent);
return Prefixes.Add(prefix);
}
void CDirItems::DeleteLastPrefix()
{
PhyParents.DeleteBack();
LogParents.DeleteBack();
Prefixes.DeleteBack();
}
bool InitLocalPrivileges();
CDirItems::CDirItems():
SymLinks(false),
ScanAltStreams(false)
#ifdef _USE_SECURITY_CODE
, ReadSecure(false)
#endif
, Callback(NULL)
{
#ifdef _USE_SECURITY_CODE
_saclEnabled = InitLocalPrivileges();
#endif
}
#ifdef _USE_SECURITY_CODE
HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
{
secureIndex = -1;
SECURITY_INFORMATION securInfo =
DACL_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION |
OWNER_SECURITY_INFORMATION;
if (_saclEnabled)
securInfo |= SACL_SECURITY_INFORMATION;
DWORD errorCode = 0;
DWORD secureSize;
BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
if (res)
{
if (secureSize == 0)
return S_OK;
if (secureSize > TempSecureBuf.Size())
errorCode = ERROR_INVALID_FUNCTION;
}
else
{
errorCode = GetLastError();
if (errorCode == ERROR_INSUFFICIENT_BUFFER)
{
if (secureSize <= TempSecureBuf.Size())
errorCode = ERROR_INVALID_FUNCTION;
else
{
TempSecureBuf.Alloc(secureSize);
res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
if (res)
{
if (secureSize != TempSecureBuf.Size())
errorCode = ERROR_INVALID_FUNCTION;;
}
else
errorCode = GetLastError();
}
}
}
if (res)
{
secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);
return S_OK;
}
if (errorCode == 0)
errorCode = ERROR_INVALID_FUNCTION;
return AddError(path, errorCode);
}
#endif
HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
{
RINOK(ScanProgress(phyPrefix));
NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
for (unsigned ttt = 0; ; ttt++)
{
NFind::CFileInfo fi;
bool found;
if (!enumerator.Next(fi, found))
{
return AddError(phyPrefix);
}
if (!found)
return S_OK;
int secureIndex = -1;
#ifdef _USE_SECURITY_CODE
if (ReadSecure)
{
RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex));
}
#endif
AddDirFileInfo(phyParent, logParent, secureIndex, fi);
if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
{
RINOK(ScanProgress(phyPrefix));
}
if (fi.IsDir())
{
const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));
RINOK(EnumerateDir(parent, parent, phyPrefix + name2));
}
}
}
HRESULT CDirItems::EnumerateItems2(
const FString &phyPrefix,
const UString &logPrefix,
const FStringVector &filePaths,
FStringVector *requestedPaths)
{
int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix));
int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
FOR_VECTOR (i, filePaths)
{
const FString &filePath = filePaths[i];
NFind::CFileInfo fi;
const FString phyPath = phyPrefix + filePath;
if (!fi.Find(phyPath))
{
RINOK(AddError(phyPath));
continue;
}
if (requestedPaths)
requestedPaths->Add(phyPath);
int delimiter = filePath.ReverseFind_PathSepar();
FString phyPrefixCur;
int phyParentCur = phyParent;
if (delimiter >= 0)
{
phyPrefixCur.SetFrom(filePath, delimiter + 1);
phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
}
int secureIndex = -1;
#ifdef _USE_SECURITY_CODE
if (ReadSecure)
{
RINOK(AddSecurityItem(phyPath, secureIndex));
}
#endif
AddDirFileInfo(phyParentCur, logParent, secureIndex, fi);
if (fi.IsDir())
{
const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
RINOK(EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2));
}
}
ReserveDown();
return S_OK;
}
static HRESULT EnumerateDirItems(
const NWildcard::CCensorNode &curNode,
int phyParent, int logParent, const FString &phyPrefix,
const UStringVector &addArchivePrefix,
CDirItems &dirItems,
bool enterToSubFolders);
static HRESULT EnumerateDirItems_Spec(
const NWildcard::CCensorNode &curNode,
int phyParent, int logParent, const FString &curFolderName,
const FString &phyPrefix,
const UStringVector &addArchivePrefix,
CDirItems &dirItems,
bool enterToSubFolders)
{
const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;
unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
unsigned numItems = dirItems.Items.Size();
HRESULT res = EnumerateDirItems(
curNode, parent, parent, phyPrefix + name2,
addArchivePrefix, dirItems, enterToSubFolders);
if (numItems == dirItems.Items.Size())
dirItems.DeleteLastPrefix();
return res;
}
#ifndef UNDER_CE
#ifdef _WIN32
static HRESULT EnumerateAltStreams(
const NFind::CFileInfo &fi,
const NWildcard::CCensorNode &curNode,
int phyParent, int logParent, const FString &fullPath,
const UStringVector &addArchivePrefix, // prefix from curNode
CDirItems &dirItems)
{
NFind::CStreamEnumerator enumerator(fullPath);
for (;;)
{
NFind::CStreamInfo si;
bool found;
if (!enumerator.Next(si, found))
{
return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL
}
if (!found)
return S_OK;
if (si.IsMainStream())
continue;
UStringVector addArchivePrefixNew = addArchivePrefix;
UString reducedName = si.GetReducedName();
addArchivePrefixNew.Back() += reducedName;
if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))
continue;
NFind::CFileInfo fi2 = fi;
fi2.Name += us2fs(reducedName);
fi2.Size = si.Size;
fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
fi2.IsAltStream = true;
dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);
}
}
#endif
HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
const FString &phyPrefix)
{
if (!SymLinks || !fi.HasReparsePoint())
return S_OK;
const FString path = phyPrefix + fi.Name;
CByteBuffer &buf = dirItem.ReparseData;
if (NIO::GetReparseData(path, buf))
{
CReparseAttr attr;
if (attr.Parse(buf, buf.Size()))
return S_OK;
}
DWORD res = ::GetLastError();
buf.Free();
return AddError(path , res);
}
#endif
static HRESULT EnumerateForItem(
NFind::CFileInfo &fi,
const NWildcard::CCensorNode &curNode,
int phyParent, int logParent, const FString &phyPrefix,
const UStringVector &addArchivePrefix, // prefix from curNode
CDirItems &dirItems,
bool enterToSubFolders)
{
const UString name = fs2us(fi.Name);
bool enterToSubFolders2 = enterToSubFolders;
UStringVector addArchivePrefixNew = addArchivePrefix;
addArchivePrefixNew.Add(name);
{
UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
return S_OK;
}
int dirItemIndex = -1;
if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
{
int secureIndex = -1;
#ifdef _USE_SECURITY_CODE
if (dirItems.ReadSecure)
{
RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex));
}
#endif
dirItemIndex = dirItems.Items.Size();
dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
if (fi.IsDir())
enterToSubFolders2 = true;
}
#ifndef UNDER_CE
if (dirItems.ScanAltStreams)
{
RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
phyPrefix + fi.Name,
addArchivePrefixNew, dirItems));
}
if (dirItemIndex >= 0)
{
CDirItem &dirItem = dirItems.Items[dirItemIndex];
RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
if (dirItem.ReparseData.Size() != 0)
return S_OK;
}
#endif
if (!fi.IsDir())
return S_OK;
const NWildcard::CCensorNode *nextNode = 0;
if (addArchivePrefix.IsEmpty())
{
int index = curNode.FindSubNode(name);
if (index >= 0)
nextNode = &curNode.SubNodes[index];
}
if (!enterToSubFolders2 && nextNode == 0)
return S_OK;
addArchivePrefixNew = addArchivePrefix;
if (nextNode == 0)
{
nextNode = &curNode;
addArchivePrefixNew.Add(name);
}
return EnumerateDirItems_Spec(
*nextNode, phyParent, logParent, fi.Name, phyPrefix,
addArchivePrefixNew,
dirItems,
enterToSubFolders2);
}
static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)
{
FOR_VECTOR (i, curNode.IncludeItems)
{
const NWildcard::CItem &item = curNode.IncludeItems[i];
if (item.Recursive || item.PathParts.Size() != 1)
return false;
const UString &name = item.PathParts.Front();
/*
if (name.IsEmpty())
return false;
*/
/* Windows doesn't support file name with wildcard
But if another system supports file name with wildcard,
and wildcard mode is disabled, we can ignore wildcard in name */
/*
if (!item.WildcardParsing)
continue;
*/
if (DoesNameContainWildcard(name))
return false;
}
return true;
}
#if defined(_WIN32) && !defined(UNDER_CE)
static bool IsVirtualFsFolder(const FString &prefix, const UString &name)
{
UString s = fs2us(prefix);
s += name;
s.Add_PathSepar();
return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0;
}
#endif
static HRESULT EnumerateDirItems(
const NWildcard::CCensorNode &curNode,
int phyParent, int logParent, const FString &phyPrefix,
const UStringVector &addArchivePrefix, // prefix from curNode
CDirItems &dirItems,
bool enterToSubFolders)
{
if (!enterToSubFolders)
if (curNode.NeedCheckSubDirs())
enterToSubFolders = true;
RINOK(dirItems.ScanProgress(phyPrefix));
// try direct_names case at first
if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
{
if (CanUseFsDirect(curNode))
{
// all names are direct (no wildcards)
// so we don't need file_system's dir enumerator
CRecordVector<bool> needEnterVector;
unsigned i;
for (i = 0; i < curNode.IncludeItems.Size(); i++)
{
const NWildcard::CItem &item = curNode.IncludeItems[i];
const UString &name = item.PathParts.Front();
FString fullPath = phyPrefix + us2fs(name);
#if defined(_WIN32) && !defined(UNDER_CE)
bool needAltStreams = true;
#endif
#ifdef _USE_SECURITY_CODE
bool needSecurity = true;
#endif
if (phyPrefix.IsEmpty())
{
if (!item.ForFile)
{
/* we don't like some names for alt streams inside archive:
":sname" for "\"
"c:::sname" for "C:\"
So we ignore alt streams for these cases */
if (name.IsEmpty())
{
#if defined(_WIN32) && !defined(UNDER_CE)
needAltStreams = false;
#endif
/*
// do we need to ignore security info for "\\" folder ?
#ifdef _USE_SECURITY_CODE
needSecurity = false;
#endif
*/
fullPath = FCHAR_PATH_SEPARATOR;
}
#if defined(_WIN32) && !defined(UNDER_CE)
else if (item.IsDriveItem())
{
needAltStreams = false;
fullPath.Add_PathSepar();
}
#endif
}
}
NFind::CFileInfo fi;
#if defined(_WIN32) && !defined(UNDER_CE)
if (IsVirtualFsFolder(phyPrefix, name))
{
fi.SetAsDir();
fi.Name = us2fs(name);
}
else
#endif
if (!fi.Find(fullPath))
{
RINOK(dirItems.AddError(fullPath));
continue;
}
bool isDir = fi.IsDir();
if (isDir && !item.ForDir || !isDir && !item.ForFile)
{
RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
continue;
}
{
UStringVector pathParts;
pathParts.Add(fs2us(fi.Name));
if (curNode.CheckPathToRoot(false, pathParts, !isDir))
continue;
}
int secureIndex = -1;
#ifdef _USE_SECURITY_CODE
if (needSecurity && dirItems.ReadSecure)
{
RINOK(dirItems.AddSecurityItem(fullPath, secureIndex));
}
#endif
dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
#ifndef UNDER_CE
{
CDirItem &dirItem = dirItems.Items.Back();
RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
if (dirItem.ReparseData.Size() != 0)
{
if (fi.IsAltStream)
dirItems.Stat.AltStreamsSize -= fi.Size;
else
dirItems.Stat.FilesSize -= fi.Size;
continue;
}
}
#endif
#ifndef UNDER_CE
if (needAltStreams && dirItems.ScanAltStreams)
{
UStringVector pathParts;
pathParts.Add(fs2us(fi.Name));
RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
fullPath, pathParts, dirItems));
}
#endif
if (!isDir)
continue;
UStringVector addArchivePrefixNew;
const NWildcard::CCensorNode *nextNode = 0;
int index = curNode.FindSubNode(name);
if (index >= 0)
{
for (int t = needEnterVector.Size(); t <= index; t++)
needEnterVector.Add(true);
needEnterVector[index] = false;
nextNode = &curNode.SubNodes[index];
}
else
{
nextNode = &curNode;
addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
}
RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
addArchivePrefixNew, dirItems, true));
}
for (i = 0; i < curNode.SubNodes.Size(); i++)
{
if (i < needEnterVector.Size())
if (!needEnterVector[i])
continue;
const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
FString fullPath = phyPrefix + us2fs(nextNode.Name);
NFind::CFileInfo fi;
if (phyPrefix.IsEmpty())
{
{
if (nextNode.Name.IsEmpty())
fullPath = FCHAR_PATH_SEPARATOR;
#ifdef _WIN32
else if (NWildcard::IsDriveColonName(nextNode.Name))
fullPath.Add_PathSepar();
#endif
}
}
// we don't want to call fi.Find() for root folder or virtual folder
if (phyPrefix.IsEmpty() && nextNode.Name.IsEmpty()
#if defined(_WIN32) && !defined(UNDER_CE)
|| IsVirtualFsFolder(phyPrefix, nextNode.Name)
#endif
)
{
fi.SetAsDir();
fi.Name = us2fs(nextNode.Name);
}
else
{
if (!fi.Find(fullPath))
{
if (!nextNode.AreThereIncludeItems())
continue;
RINOK(dirItems.AddError(fullPath));
continue;
}
if (!fi.IsDir())
{
RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
continue;
}
}
RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
UStringVector(), dirItems, false));
}
return S_OK;
}
}
#ifdef _WIN32
#ifndef UNDER_CE
// scan drives, if wildcard is "*:\"
if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0)
{
unsigned i;
for (i = 0; i < curNode.IncludeItems.Size(); i++)
{
const NWildcard::CItem &item = curNode.IncludeItems[i];
if (item.PathParts.Size() < 1)
break;
const UString &name = item.PathParts.Front();
if (name.Len() != 2 || name[1] != ':')
break;
if (item.PathParts.Size() == 1)
if (item.ForFile || !item.ForDir)
break;
if (NWildcard::IsDriveColonName(name))
continue;
if (name[0] != '*' && name[0] != '?')
break;
}
if (i == curNode.IncludeItems.Size())
{
FStringVector driveStrings;
NFind::MyGetLogicalDriveStrings(driveStrings);
for (i = 0; i < driveStrings.Size(); i++)
{
FString driveName = driveStrings[i];
if (driveName.Len() < 3 || driveName.Back() != '\\')
return E_FAIL;
driveName.DeleteBack();
NFind::CFileInfo fi;
fi.SetAsDir();
fi.Name = driveName;
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
addArchivePrefix, dirItems, enterToSubFolders));
}
return S_OK;
}
}
#endif
#endif
NFind::CEnumerator enumerator(phyPrefix + FCHAR_ANY_MASK);
for (unsigned ttt = 0; ; ttt++)
{
NFind::CFileInfo fi;
bool found;
if (!enumerator.Next(fi, found))
{
RINOK(dirItems.AddError(phyPrefix));
break;
}
if (!found)
break;
if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
{
RINOK(dirItems.ScanProgress(phyPrefix));
}
RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
addArchivePrefix, dirItems, enterToSubFolders));
}
return S_OK;
}
HRESULT EnumerateItems(
const NWildcard::CCensor &censor,
const NWildcard::ECensorPathMode pathMode,
const UString &addPathPrefix,
CDirItems &dirItems)
{
FOR_VECTOR (i, censor.Pairs)
{
const NWildcard::CPair &pair = censor.Pairs[i];
int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
int logParent = -1;
if (pathMode == NWildcard::k_AbsPath)
logParent = phyParent;
else
{
if (!addPathPrefix.IsEmpty())
logParent = dirItems.AddPrefix(-1, -1, addPathPrefix);
}
RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(),
dirItems,
false // enterToSubFolders
));
}
dirItems.ReserveDown();
#if defined(_WIN32) && !defined(UNDER_CE)
dirItems.FillFixedReparse();
#endif
return S_OK;
}
#if defined(_WIN32) && !defined(UNDER_CE)
void CDirItems::FillFixedReparse()
{
/* imagex/WIM reduces absolute pathes in links (raparse data),
if we archive non root folder. We do same thing here */
if (!SymLinks)
return;
FOR_VECTOR(i, Items)
{
CDirItem &item = Items[i];
if (item.ReparseData.Size() == 0)
continue;
CReparseAttr attr;
if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
continue;
if (attr.IsRelative())
continue;
const UString &link = attr.GetPath();
if (!IsDrivePath(link))
continue;
// maybe we need to support networks paths also ?
FString fullPathF;
if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF))
continue;
UString fullPath = fs2us(fullPathF);
const UString logPath = GetLogPath(i);
if (logPath.Len() >= fullPath.Len())
continue;
if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0)
continue;
const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len());
if (!IsPathSepar(prefix.Back()))
continue;
unsigned rootPrefixSize = GetRootPrefixSize(prefix);
if (rootPrefixSize == 0)
continue;
if (rootPrefixSize == prefix.Len())
continue; // simple case: paths are from root
if (link.Len() <= prefix.Len())
continue;
if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
continue;
UString newLink = prefix.Left(rootPrefixSize);
newLink += link.Ptr(prefix.Len());
CByteBuffer data;
if (!FillLinkData(data, newLink, attr.IsSymLink()))
continue;
item.ReparseData2 = data;
}
}
#endif

View File

@@ -0,0 +1,21 @@
// EnumDirItems.h
#ifndef __ENUM_DIR_ITEMS_H
#define __ENUM_DIR_ITEMS_H
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileFind.h"
#include "DirItem.h"
void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems);
HRESULT EnumerateItems(
const NWildcard::CCensor &censor,
NWildcard::ECensorPathMode pathMode,
const UString &addPathPrefix,
CDirItems &dirItems);
#endif

View File

@@ -0,0 +1,27 @@
// ExitCode.h
#ifndef __EXIT_CODE_H
#define __EXIT_CODE_H
namespace NExitCode {
enum EEnum {
kSuccess = 0, // Successful operation
kWarning = 1, // Non fatal error(s) occurred
kFatalError = 2, // A fatal error occurred
// kCRCError = 3, // A CRC error occurred when unpacking
// kLockedArchive = 4, // Attempt to modify an archive previously locked
// kWriteError = 5, // Write to disk error
// kOpenError = 6, // Open file error
kUserError = 7, // Command line option error
kMemoryError = 8, // Not enough memory for operation
// kCreateFileError = 9, // Create file error
kUserBreak = 255 // User stopped the process
};
}
#endif

View File

@@ -0,0 +1,477 @@
// Extract.cpp
#include "StdAfx.h"
#include "../../../../C/Sort.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
#include "../Common/ExtractingFilePath.h"
#include "Extract.h"
#include "SetProperties.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
static HRESULT DecompressArchive(
CCodecs *codecs,
const CArchiveLink &arcLink,
UInt64 packSize,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
bool calcCrc,
IExtractCallbackUI *callback,
CArchiveExtractCallback *ecs,
UString &errorMessage,
UInt64 &stdInProcessed)
{
const CArc &arc = arcLink.Arcs.Back();
stdInProcessed = 0;
IInArchive *archive = arc.Archive;
CRecordVector<UInt32> realIndices;
UStringVector removePathParts;
FString outDir = options.OutputDir;
UString replaceName = arc.DefaultName;
if (arcLink.Arcs.Size() > 1)
{
// Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1".
// So it extracts different archives to one folder.
// We will use top level archive name
const CArc &arc0 = arcLink.Arcs[0];
if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe"))
replaceName = arc0.DefaultName;
}
outDir.Replace(FSTRING_ANY_MASK, us2fs(Get_Correct_FsFile_Name(replaceName)));
bool elimIsPossible = false;
UString elimPrefix; // only pure name without dir delimiter
FString outDirReduced = outDir;
if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths)
{
UString dirPrefix;
SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix);
if (!elimPrefix.IsEmpty())
{
if (IsPathSepar(elimPrefix.Back()))
elimPrefix.DeleteBack();
if (!elimPrefix.IsEmpty())
{
outDirReduced = us2fs(dirPrefix);
elimIsPossible = true;
}
}
}
bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
if (!options.StdInMode)
{
UInt32 numItems;
RINOK(archive->GetNumberOfItems(&numItems));
CReadArcItem item;
for (UInt32 i = 0; i < numItems; i++)
{
if (elimIsPossible || !allFilesAreAllowed)
{
RINOK(arc.GetItem(i, item));
}
else
{
#ifdef SUPPORT_ALT_STREAMS
item.IsAltStream = false;
if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream)
{
RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream));
}
#endif
}
#ifdef SUPPORT_ALT_STREAMS
if (!options.NtOptions.AltStreams.Val && item.IsAltStream)
continue;
#endif
if (elimIsPossible)
{
const UString &s =
#ifdef SUPPORT_ALT_STREAMS
item.MainPath;
#else
item.Path;
#endif
if (!IsPath1PrefixedByPath2(s, elimPrefix))
elimIsPossible = false;
else
{
wchar_t c = s[elimPrefix.Len()];
if (c == 0)
{
if (!item.MainIsDir)
elimIsPossible = false;
}
else if (!IsPathSepar(c))
elimIsPossible = false;
}
}
if (!allFilesAreAllowed)
{
if (!CensorNode_CheckPath(wildcardCensor, item))
continue;
}
realIndices.Add(i);
}
if (realIndices.Size() == 0)
{
callback->ThereAreNoFiles();
return callback->ExtractResult(S_OK);
}
}
if (elimIsPossible)
{
removePathParts.Add(elimPrefix);
// outDir = outDirReduced;
}
#ifdef _WIN32
// GetCorrectFullFsPath doesn't like "..".
// outDir.TrimRight();
// outDir = GetCorrectFullFsPath(outDir);
#endif
if (outDir.IsEmpty())
outDir = FTEXT(".") FSTRING_PATH_SEPARATOR;
/*
#ifdef _WIN32
else if (NName::IsAltPathPrefix(outDir)) {}
#endif
*/
else if (!CreateComplexDir(outDir))
{
HRESULT res = ::GetLastError();
if (res == S_OK)
res = E_FAIL;
errorMessage.SetFromAscii("Can not create output directory: ");
errorMessage += fs2us(outDir);
return res;
}
ecs->Init(
options.NtOptions,
options.StdInMode ? &wildcardCensor : NULL,
&arc,
callback,
options.StdOutMode, options.TestMode,
outDir,
removePathParts, false,
packSize);
#ifdef SUPPORT_LINKS
if (!options.StdInMode &&
!options.TestMode &&
options.NtOptions.HardLinks.Val)
{
RINOK(ecs->PrepareHardLinks(&realIndices));
}
#endif
HRESULT result;
Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0;
if (options.StdInMode)
{
result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
NCOM::CPropVariant prop;
if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
ConvertPropVariantToUInt64(prop, stdInProcessed);
}
else
result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
if (result == S_OK && !options.StdInMode)
result = ecs->SetDirsTimes();
return callback->ExtractResult(result);
}
/* v9.31: BUG was fixed:
Sorted list for file paths was sorted with case insensitive compare function.
But FindInSorted function did binary search via case sensitive compare function */
int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name)
{
unsigned left = 0, right = fileName.Size();
while (left != right)
{
unsigned mid = (left + right) / 2;
const UString &midValue = fileName[mid];
int compare = CompareFileNames(name, midValue);
if (compare == 0)
return mid;
if (compare < 0)
right = mid;
else
left = mid + 1;
}
return -1;
}
HRESULT Extract(
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const CIntVector &excludedFormats,
UStringVector &arcPaths, UStringVector &arcPathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback,
#ifndef _SFX
IHashCalc *hash,
#endif
UString &errorMessage,
CDecompressStat &st)
{
st.Clear();
UInt64 totalPackSize = 0;
CRecordVector<UInt64> arcSizes;
unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size();
unsigned i;
for (i = 0; i < numArcs; i++)
{
NFind::CFileInfo fi;
fi.Size = 0;
if (!options.StdInMode)
{
const FString &arcPath = us2fs(arcPaths[i]);
if (!fi.Find(arcPath))
throw "there is no such archive";
if (fi.IsDir())
throw "can't decompress folder";
}
arcSizes.Add(fi.Size);
totalPackSize += fi.Size;
}
CBoolArr skipArcs(numArcs);
for (i = 0; i < numArcs; i++)
skipArcs[i] = false;
CArchiveExtractCallback *ecs = new CArchiveExtractCallback;
CMyComPtr<IArchiveExtractCallback> ec(ecs);
bool multi = (numArcs > 1);
ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode);
#ifndef _SFX
ecs->SetHashMethods(hash);
#endif
if (multi)
{
RINOK(extractCallback->SetTotal(totalPackSize));
}
UInt64 totalPackProcessed = 0;
bool thereAreNotOpenArcs = false;
for (i = 0; i < numArcs; i++)
{
if (skipArcs[i])
continue;
const UString &arcPath = arcPaths[i];
NFind::CFileInfo fi;
if (options.StdInMode)
{
fi.Size = 0;
fi.Attrib = 0;
}
else
{
if (!fi.Find(us2fs(arcPath)) || fi.IsDir())
throw "there is no such archive";
}
/*
#ifndef _NO_CRYPTO
openCallback->Open_Clear_PasswordWasAsked_Flag();
#endif
*/
RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode));
CArchiveLink arcLink;
CObjectVector<COpenType> types2 = types;
/*
#ifndef _SFX
if (types.IsEmpty())
{
int pos = arcPath.ReverseFind(L'.');
if (pos >= 0)
{
UString s = arcPath.Ptr(pos + 1);
int index = codecs->FindFormatForExtension(s);
if (index >= 0 && s == L"001")
{
s = arcPath.Left(pos);
pos = s.ReverseFind(L'.');
if (pos >= 0)
{
int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1));
if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0
{
types2.Add(index2);
types2.Add(index);
}
}
}
}
}
#endif
*/
COpenOptions op;
#ifndef _SFX
op.props = &options.Properties;
#endif
op.codecs = codecs;
op.types = &types2;
op.excludedFormats = &excludedFormats;
op.stdInMode = options.StdInMode;
op.stream = NULL;
op.filePath = arcPath;
HRESULT result = arcLink.Open3(op, openCallback);
if (result == E_ABORT)
return result;
if (result == S_OK && arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
result = S_FALSE;
// arcLink.Set_ErrorsText();
RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result));
if (result != S_OK)
{
thereAreNotOpenArcs = true;
if (!options.StdInMode)
{
NFind::CFileInfo fi2;
if (fi2.Find(us2fs(arcPath)))
if (!fi2.IsDir())
totalPackProcessed += fi2.Size;
}
continue;
}
if (!options.StdInMode)
{
// numVolumes += arcLink.VolumePaths.Size();
// arcLink.VolumesSize;
// totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes);
// numArcs = arcPaths.Size();
if (arcLink.VolumePaths.Size() != 0)
{
Int64 correctionSize = arcLink.VolumesSize;
FOR_VECTOR (v, arcLink.VolumePaths)
{
int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
if (index >= 0)
{
if ((unsigned)index > i)
{
skipArcs[(unsigned)index] = true;
correctionSize -= arcSizes[(unsigned)index];
}
}
}
if (correctionSize != 0)
{
Int64 newPackSize = (Int64)totalPackSize + correctionSize;
if (newPackSize < 0)
newPackSize = 0;
totalPackSize = newPackSize;
RINOK(extractCallback->SetTotal(totalPackSize));
}
}
}
/*
// Now openCallback and extractCallback use same object. So we don't need to send password.
#ifndef _NO_CRYPTO
bool passwordIsDefined;
UString password;
RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password));
if (passwordIsDefined)
{
RINOK(extractCallback->SetPassword(password));
}
#endif
*/
CArc &arc = arcLink.Arcs.Back();
arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);
arc.MTime = fi.MTime;
UInt64 packProcessed;
bool calcCrc =
#ifndef _SFX
(hash != NULL);
#else
false;
#endif
RINOK(DecompressArchive(
codecs,
arcLink,
fi.Size + arcLink.VolumesSize,
wildcardCensor,
options,
calcCrc,
extractCallback, ecs, errorMessage, packProcessed));
if (!options.StdInMode)
packProcessed = fi.Size + arcLink.VolumesSize;
totalPackProcessed += packProcessed;
ecs->LocalProgressSpec->InSize += packProcessed;
ecs->LocalProgressSpec->OutSize = ecs->UnpackSize;
if (!errorMessage.IsEmpty())
return E_FAIL;
}
if (multi || thereAreNotOpenArcs)
{
RINOK(extractCallback->SetTotal(totalPackSize));
RINOK(extractCallback->SetCompleted(&totalPackProcessed));
}
st.NumFolders = ecs->NumFolders;
st.NumFiles = ecs->NumFiles;
st.NumAltStreams = ecs->NumAltStreams;
st.UnpackSize = ecs->UnpackSize;
st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize;
st.NumArchives = arcPaths.Size();
st.PackSize = ecs->LocalProgressSpec->InSize;
return S_OK;
}

View File

@@ -0,0 +1,94 @@
// Extract.h
#ifndef __EXTRACT_H
#define __EXTRACT_H
#include "../../../Windows/FileFind.h"
#include "../../Archive/IArchive.h"
#include "ArchiveExtractCallback.h"
#include "ArchiveOpenCallback.h"
#include "ExtractMode.h"
#include "Property.h"
#include "../Common/LoadCodecs.h"
struct CExtractOptionsBase
{
CBoolPair ElimDup;
bool PathMode_Force;
bool OverwriteMode_Force;
NExtract::NPathMode::EEnum PathMode;
NExtract::NOverwriteMode::EEnum OverwriteMode;
FString OutputDir;
CExtractNtOptions NtOptions;
CExtractOptionsBase():
PathMode_Force(false),
OverwriteMode_Force(false),
PathMode(NExtract::NPathMode::kFullPaths),
OverwriteMode(NExtract::NOverwriteMode::kAsk)
{}
};
struct CExtractOptions: public CExtractOptionsBase
{
bool StdInMode;
bool StdOutMode;
bool YesToAll;
bool TestMode;
// bool ShowDialog;
// bool PasswordEnabled;
// UString Password;
#ifndef _SFX
CObjectVector<CProperty> Properties;
#endif
#ifdef EXTERNAL_CODECS
CCodecs *Codecs;
#endif
CExtractOptions():
TestMode(false),
StdInMode(false),
StdOutMode(false),
YesToAll(false)
{}
};
struct CDecompressStat
{
UInt64 NumArchives;
UInt64 UnpackSize;
UInt64 AltStreams_UnpackSize;
UInt64 PackSize;
UInt64 NumFolders;
UInt64 NumFiles;
UInt64 NumAltStreams;
void Clear()
{
NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0;
}
};
HRESULT Extract(
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const CIntVector &excludedFormats,
UStringVector &archivePaths, UStringVector &archivePathsFull,
const NWildcard::CCensorNode &wildcardCensor,
const CExtractOptions &options,
IOpenCallbackUI *openCallback,
IExtractCallbackUI *extractCallback,
#ifndef _SFX
IHashCalc *hash,
#endif
UString &errorMessage,
CDecompressStat &st);
#endif

View File

@@ -0,0 +1,34 @@
// ExtractMode.h
#ifndef __EXTRACT_MODE_H
#define __EXTRACT_MODE_H
namespace NExtract {
namespace NPathMode
{
enum EEnum
{
kFullPaths,
kCurPaths,
kNoPaths,
kAbsPaths,
kNoPathsAlt // alt streams must be extracted without name of base file
};
}
namespace NOverwriteMode
{
enum EEnum
{
kAsk,
kOverwrite,
kSkip,
kRename,
kRenameExisting
};
}
}
#endif

View File

@@ -0,0 +1,237 @@
// ExtractingFilePath.cpp
#include "StdAfx.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileName.h"
#include "ExtractingFilePath.h"
static void ReplaceIncorrectChars(UString &s)
{
{
for (unsigned i = 0; i < s.Len(); i++)
{
wchar_t c = s[i];
if (
#ifdef _WIN32
c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
|| c == '/'
// || c == 0x202E // RLO
||
#endif
c == WCHAR_PATH_SEPARATOR)
s.ReplaceOneCharAtPos(i, '_');
}
}
#ifdef _WIN32
{
for (unsigned i = s.Len(); i != 0;)
{
wchar_t c = s[--i];
if (c != '.' && c != ' ')
break;
s.ReplaceOneCharAtPos(i, '_');
}
}
#endif
}
#ifdef _WIN32
/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
But colon in postfix ":$DATA" is allowed.
WIN32 functions don't allow empty alt stream name "name:" */
void Correct_AltStream_Name(UString &s)
{
unsigned len = s.Len();
const unsigned kPostfixSize = 6;
if (s.Len() >= kPostfixSize
&& StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
len -= kPostfixSize;
for (unsigned i = 0; i < len; i++)
{
wchar_t c = s[i];
if (c == ':' || c == '\\' || c == '/'
|| c == 0x202E // RLO
)
s.ReplaceOneCharAtPos(i, '_');
}
if (s.IsEmpty())
s = L'_';
}
static const unsigned g_ReservedWithNum_Index = 4;
static const char * const g_ReservedNames[] =
{
"CON", "PRN", "AUX", "NUL",
"COM", "LPT"
};
static bool IsSupportedName(const UString &name)
{
for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
{
const char *reservedName = g_ReservedNames[i];
unsigned len = MyStringLen(reservedName);
if (name.Len() < len)
continue;
if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
continue;
if (i >= g_ReservedWithNum_Index)
{
wchar_t c = name[len];
if (c < L'0' || c > L'9')
continue;
len++;
}
for (;;)
{
wchar_t c = name[len++];
if (c == 0 || c == '.')
return false;
if (c != ' ')
break;
}
}
return true;
}
static void CorrectUnsupportedName(UString &name)
{
if (!IsSupportedName(name))
name.InsertAtFront(L'_');
}
#endif
static void Correct_PathPart(UString &s)
{
// "." and ".."
if (s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0))
s.Empty();
#ifdef _WIN32
else
ReplaceIncorrectChars(s);
#endif
}
// static const wchar_t *k_EmptyReplaceName = L"[]";
static const wchar_t k_EmptyReplaceName = L'_';
UString Get_Correct_FsFile_Name(const UString &name)
{
UString res = name;
Correct_PathPart(res);
#ifdef _WIN32
CorrectUnsupportedName(res);
#endif
if (res.IsEmpty())
res = k_EmptyReplaceName;
return res;
}
void Correct_FsPath(bool absIsAllowed, UStringVector &parts, bool isDir)
{
unsigned i = 0;
if (absIsAllowed)
{
#if defined(_WIN32) && !defined(UNDER_CE)
bool isDrive = false;
#endif
if (parts[0].IsEmpty())
{
i = 1;
#if defined(_WIN32) && !defined(UNDER_CE)
if (parts.Size() > 1 && parts[1].IsEmpty())
{
i = 2;
if (parts.Size() > 2 && parts[2] == L"?")
{
i = 3;
if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
{
isDrive = true;
i = 4;
}
}
}
#endif
}
#if defined(_WIN32) && !defined(UNDER_CE)
else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
{
isDrive = true;
i = 1;
}
if (isDrive)
{
// we convert "c:name" to "c:\name", if absIsAllowed path.
const UString &ds = parts[i - 1];
if (ds.Len() != 2)
{
UString s = ds.Ptr(2);
parts.Insert(i, s);
}
}
#endif
}
for (; i < parts.Size();)
{
UString &s = parts[i];
Correct_PathPart(s);
if (s.IsEmpty())
{
if (isDir || i != parts.Size() - 1)
{
parts.Delete(i);
continue;
}
s = k_EmptyReplaceName;
}
else
{
#ifdef _WIN32
CorrectUnsupportedName(s);
#endif
}
i++;
}
if (!isDir)
{
if (parts.IsEmpty())
parts.Add(k_EmptyReplaceName);
else
{
UString &s = parts.Back();
if (s.IsEmpty())
s = k_EmptyReplaceName;
}
}
}
UString MakePathFromParts(const UStringVector &parts)
{
UString s;
FOR_VECTOR (i, parts)
{
if (i != 0)
s.Add_PathSepar();
s += parts[i];
}
return s;
}

View File

@@ -0,0 +1,19 @@
// ExtractingFilePath.h
#ifndef __EXTRACTING_FILE_PATH_H
#define __EXTRACTING_FILE_PATH_H
#include "../../../Common/MyString.h"
#ifdef _WIN32
void Correct_AltStream_Name(UString &s);
#endif
// replaces unsuported characters, and replaces "." , ".." and "" to "[]"
UString Get_Correct_FsFile_Name(const UString &name);
void Correct_FsPath(bool absIsAllowed, UStringVector &parts, bool isDir);
UString MakePathFromParts(const UStringVector &parts);
#endif

View File

@@ -0,0 +1,351 @@
// HashCalc.cpp
#include "StdAfx.h"
#include "../../../../C/Alloc.h"
#include "../../../Common/StringToInt.h"
#include "../../Common/FileStreams.h"
#include "../../Common/StreamUtils.h"
#include "EnumDirItems.h"
#include "HashCalc.h"
using namespace NWindows;
class CHashMidBuf
{
void *_data;
public:
CHashMidBuf(): _data(0) {}
operator void *() { return _data; }
bool Alloc(size_t size)
{
if (_data != 0)
return false;
_data = ::MidAlloc(size);
return _data != 0;
}
~CHashMidBuf() { ::MidFree(_data); }
};
static const char *k_DefaultHashMethod = "CRC32";
HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
{
UStringVector names = hashMethods;
if (names.IsEmpty())
{
UString s;
s.SetFromAscii(k_DefaultHashMethod);
names.Add(s);
}
CRecordVector<CMethodId> ids;
CObjectVector<COneMethodInfo> methods;
unsigned i;
for (i = 0; i < names.Size(); i++)
{
COneMethodInfo m;
RINOK(m.ParseMethodFromString(names[i]));
if (m.MethodName.IsEmpty())
m.MethodName = k_DefaultHashMethod;
if (m.MethodName == "*")
{
CRecordVector<CMethodId> tempMethods;
GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
methods.Clear();
ids.Clear();
FOR_VECTOR (t, tempMethods)
{
unsigned index = ids.AddToUniqueSorted(tempMethods[t]);
if (ids.Size() != methods.Size())
methods.Insert(index, m);
}
break;
}
else
{
// m.MethodName.RemoveChar(L'-');
CMethodId id;
if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id))
return E_NOTIMPL;
unsigned index = ids.AddToUniqueSorted(id);
if (ids.Size() != methods.Size())
methods.Insert(index, m);
}
}
for (i = 0; i < ids.Size(); i++)
{
CMyComPtr<IHasher> hasher;
AString name;
RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher));
if (!hasher)
throw "Can't create hasher";
const COneMethodInfo &m = methods[i];
{
CMyComPtr<ICompressSetCoderProperties> scp;
hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
if (scp)
RINOK(m.SetCoderProps(scp, NULL));
}
UInt32 digestSize = hasher->GetDigestSize();
if (digestSize > k_HashCalc_DigestSize_Max)
return E_NOTIMPL;
CHasherState &h = Hashers.AddNew();
h.Hasher = hasher;
h.Name = name;
h.DigestSize = digestSize;
for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)
memset(h.Digests[k], 0, digestSize);
}
return S_OK;
}
void CHashBundle::InitForNewFile()
{
CurSize = 0;
FOR_VECTOR (i, Hashers)
{
CHasherState &h = Hashers[i];
h.Hasher->Init();
memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize);
}
}
void CHashBundle::Update(const void *data, UInt32 size)
{
CurSize += size;
FOR_VECTOR (i, Hashers)
Hashers[i].Hasher->Update(data, size);
}
void CHashBundle::SetSize(UInt64 size)
{
CurSize = size;
}
static void AddDigests(Byte *dest, const Byte *src, UInt32 size)
{
unsigned next = 0;
for (UInt32 i = 0; i < size; i++)
{
next += (unsigned)dest[i] + (unsigned)src[i];
dest[i] = (Byte)next;
next >>= 8;
}
}
void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path)
{
if (isDir)
NumDirs++;
else if (isAltStream)
{
NumAltStreams++;
AltStreamsSize += CurSize;
}
else
{
NumFiles++;
FilesSize += CurSize;
}
Byte pre[16];
memset(pre, 0, sizeof(pre));
if (isDir)
pre[0] = 1;
FOR_VECTOR (i, Hashers)
{
CHasherState &h = Hashers[i];
if (!isDir)
{
h.Hasher->Final(h.Digests[0]);
if (!isAltStream)
AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize);
}
h.Hasher->Init();
h.Hasher->Update(pre, sizeof(pre));
h.Hasher->Update(h.Digests[0], h.DigestSize);
for (unsigned k = 0; k < path.Len(); k++)
{
wchar_t c = path[k];
Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) };
h.Hasher->Update(temp, 2);
}
Byte tempDigest[k_HashCalc_DigestSize_Max];
h.Hasher->Final(tempDigest);
if (!isAltStream)
AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize);
AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize);
}
}
HRESULT HashCalc(
DECL_EXTERNAL_CODECS_LOC_VARS
const NWildcard::CCensor &censor,
const CHashOptions &options,
AString &errorInfo,
IHashCallbackUI *callback)
{
CDirItems dirItems;
dirItems.Callback = callback;
if (options.StdInMode)
{
CDirItem di;
di.Size = (UInt64)(Int64)-1;
di.Attrib = 0;
di.MTime.dwLowDateTime = 0;
di.MTime.dwHighDateTime = 0;
di.CTime = di.ATime = di.MTime;
dirItems.Items.Add(di);
}
else
{
RINOK(callback->StartScanning());
dirItems.ScanAltStreams = options.AltStreamsMode;
HRESULT res = EnumerateItems(censor,
options.PathMode,
UString(),
dirItems);
if (res != S_OK)
{
if (res != E_ABORT)
errorInfo = "Scanning error";
return res;
}
RINOK(callback->FinishScanning(dirItems.Stat));
}
unsigned i;
CHashBundle hb;
RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods));
hb.Init();
hb.NumErrors = dirItems.Stat.NumErrors;
if (options.StdInMode)
{
RINOK(callback->SetNumFiles(1));
}
else
{
RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes()));
}
const UInt32 kBufSize = 1 << 15;
CHashMidBuf buf;
if (!buf.Alloc(kBufSize))
return E_OUTOFMEMORY;
UInt64 completeValue = 0;
RINOK(callback->BeforeFirstFile(hb));
for (i = 0; i < dirItems.Items.Size(); i++)
{
CMyComPtr<ISequentialInStream> inStream;
UString path;
bool isDir = false;
bool isAltStream = false;
if (options.StdInMode)
{
inStream = new CStdInFileStream;
}
else
{
CInFileStream *inStreamSpec = new CInFileStream;
inStream = inStreamSpec;
const CDirItem &dirItem = dirItems.Items[i];
isDir = dirItem.IsDir();
isAltStream = dirItem.IsAltStream;
path = dirItems.GetLogPath(i);
if (!isDir)
{
FString phyPath = dirItems.GetPhyPath(i);
if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))
{
HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());
hb.NumErrors++;
if (res != S_FALSE)
return res;
continue;
}
}
}
RINOK(callback->GetStream(path, isDir));
UInt64 fileSize = 0;
hb.InitForNewFile();
if (!isDir)
{
for (UInt32 step = 0;; step++)
{
if ((step & 0xFF) == 0)
RINOK(callback->SetCompleted(&completeValue));
UInt32 size;
RINOK(inStream->Read(buf, kBufSize, &size));
if (size == 0)
break;
hb.Update(buf, size);
fileSize += size;
completeValue += size;
}
}
hb.Final(isDir, isAltStream, path);
RINOK(callback->SetOperationResult(fileSize, hb, !isDir));
RINOK(callback->SetCompleted(&completeValue));
}
return callback->AfterLastFile(hb);
}
static inline char GetHex(unsigned v)
{
return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
}
void AddHashHexToString(char *dest, const Byte *data, UInt32 size)
{
dest[size * 2] = 0;
if (!data)
{
for (UInt32 i = 0; i < size; i++)
{
dest[0] = ' ';
dest[1] = ' ';
dest += 2;
}
return;
}
int step = 2;
if (size <= 8)
{
step = -2;
dest += size * 2 - 2;
}
for (UInt32 i = 0; i < size; i++)
{
unsigned b = data[i];
dest[0] = GetHex((b >> 4) & 0xF);
dest[1] = GetHex(b & 0xF);
dest += step;
}
}

View File

@@ -0,0 +1,107 @@
// HashCalc.h
#ifndef __HASH_CALC_H
#define __HASH_CALC_H
#include "../../../Common/Wildcard.h"
#include "../../Common/CreateCoder.h"
#include "../../Common/MethodProps.h"
#include "DirItem.h"
#include "Property.h"
const unsigned k_HashCalc_DigestSize_Max = 64;
const unsigned k_HashCalc_NumGroups = 4;
enum
{
k_HashCalc_Index_Current,
k_HashCalc_Index_DataSum,
k_HashCalc_Index_NamesSum,
k_HashCalc_Index_StreamsSum
};
struct CHasherState
{
CMyComPtr<IHasher> Hasher;
AString Name;
UInt32 DigestSize;
Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max];
};
struct IHashCalc
{
virtual void InitForNewFile() = 0;
virtual void Update(const void *data, UInt32 size) = 0;
virtual void SetSize(UInt64 size) = 0;
virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0;
};
struct CHashBundle: public IHashCalc
{
CObjectVector<CHasherState> Hashers;
UInt64 NumDirs;
UInt64 NumFiles;
UInt64 NumAltStreams;
UInt64 FilesSize;
UInt64 AltStreamsSize;
UInt64 NumErrors;
UInt64 CurSize;
HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods);
void Init()
{
NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0;
}
void InitForNewFile();
void Update(const void *data, UInt32 size);
void SetSize(UInt64 size);
void Final(bool isDir, bool isAltStream, const UString &path);
};
#define INTERFACE_IHashCallbackUI(x) \
INTERFACE_IDirItemsCallback(x) \
virtual HRESULT StartScanning() x; \
virtual HRESULT FinishScanning(const CDirItemsStat &st) x; \
virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
virtual HRESULT SetTotal(UInt64 size) x; \
virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
virtual HRESULT CheckBreak() x; \
virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x; \
virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x; \
virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x; \
virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \
virtual HRESULT AfterLastFile(const CHashBundle &hb) x; \
struct IHashCallbackUI: public IDirItemsCallback
{
INTERFACE_IHashCallbackUI(=0)
};
struct CHashOptions
{
UStringVector Methods;
bool OpenShareForWrite;
bool StdInMode;
bool AltStreamsMode;
NWildcard::ECensorPathMode PathMode;
CHashOptions(): StdInMode(false), OpenShareForWrite(false), AltStreamsMode(false), PathMode(NWildcard::k_RelatPath) {};
};
HRESULT HashCalc(
DECL_EXTERNAL_CODECS_LOC_VARS
const NWildcard::CCensor &censor,
const CHashOptions &options,
AString &errorInfo,
IHashCallbackUI *callback);
void AddHashHexToString(char *dest, const Byte *data, UInt32 size);
#endif

View File

@@ -0,0 +1,114 @@
// IFileExtractCallback.h
#ifndef __I_FILE_EXTRACT_CALLBACK_H
#define __I_FILE_EXTRACT_CALLBACK_H
#include "../../../Common/MyString.h"
#include "../../IDecl.h"
#include "LoadCodecs.h"
#include "OpenArchive.h"
namespace NOverwriteAnswer
{
enum EEnum
{
kYes,
kYesToAll,
kNo,
kNoToAll,
kAutoRename,
kCancel
};
}
/* ---------- IFolderArchiveExtractCallback ----------
is implemented by
Console/ExtractCallbackConsole.h CExtractCallbackConsole
FileManager/ExtractCallback.h CExtractCallbackImp
FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported)
IID_IFolderArchiveExtractCallback is requested by:
- Agent/ArchiveFolder.cpp
CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback)
is sent to IArchiveFolder::Extract()
- FileManager/PanelCopy.cpp
CPanel::CopyTo(), if (options->testMode)
is sent to IArchiveFolder::Extract()
IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp
*/
#define INTERFACE_IFolderArchiveExtractCallback(x) \
STDMETHOD(AskOverwrite)( \
const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \
const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \
Int32 *answer) x; \
STDMETHOD(PrepareOperation)(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position) x; \
STDMETHOD(MessageError)(const wchar_t *message) x; \
STDMETHOD(SetOperationResult)(Int32 opRes, Int32 encrypted) x; \
DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
{
INTERFACE_IFolderArchiveExtractCallback(PURE)
};
#define INTERFACE_IFolderArchiveExtractCallback2(x) \
STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 encrypted, const wchar_t *name) x; \
DECL_INTERFACE_SUB(IFolderArchiveExtractCallback2, IUnknown, 0x01, 0x08)
{
INTERFACE_IFolderArchiveExtractCallback2(PURE)
};
/* ---------- IExtractCallbackUI ----------
is implemented by
Console/ExtractCallbackConsole.h CExtractCallbackConsole
FileManager/ExtractCallback.h CExtractCallbackImp
*/
#ifdef _NO_CRYPTO
#define INTERFACE_IExtractCallbackUI_Crypto(x)
#else
#define INTERFACE_IExtractCallbackUI_Crypto(x) \
virtual HRESULT SetPassword(const UString &password) x;
#endif
#define INTERFACE_IExtractCallbackUI(x) \
virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) x; \
virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x; \
virtual HRESULT ThereAreNoFiles() x; \
virtual HRESULT ExtractResult(HRESULT result) x; \
INTERFACE_IExtractCallbackUI_Crypto(x)
struct IExtractCallbackUI: IFolderArchiveExtractCallback
{
INTERFACE_IExtractCallbackUI(PURE)
};
#define INTERFACE_IGetProp(x) \
STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \
DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20)
{
INTERFACE_IGetProp(PURE)
};
#define INTERFACE_IFolderExtractToStreamCallback(x) \
STDMETHOD(UseExtractToStream)(Int32 *res) x; \
STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \
STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \
STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, Int32 encrypted) x; \
DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30)
{
INTERFACE_IFolderExtractToStreamCallback(PURE)
};
#endif

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,424 @@
// LoadCodecs.h
#ifndef __LOAD_CODECS_H
#define __LOAD_CODECS_H
/*
Client application uses LoadCodecs.* to load plugins to
CCodecs object, that contains 3 lists of plugins:
1) Formats - internal and external archive handlers
2) Codecs - external codecs
3) Hashers - external hashers
EXTERNAL_CODECS
---------------
if EXTERNAL_CODECS is defined, then the code tries to load external
plugins from DLL files (shared libraries).
There are two types of executables in 7-Zip:
1) Executable that uses external plugins must be compiled
with EXTERNAL_CODECS defined:
- 7z.exe, 7zG.exe, 7zFM.exe
Note: EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h
that code is used in plugin module (7z.dll).
2) Standalone modules are compiled without EXTERNAL_CODECS:
- SFX modules: 7z.sfx, 7zCon.sfx
- standalone versions of console 7-Zip: 7za.exe, 7zr.exe
if EXTERNAL_CODECS is defined, CCodecs class implements interfaces:
- ICompressCodecsInfo : for Codecs
- IHashers : for Hashers
The client application can send CCodecs object to each plugin module.
And plugin module can use ICompressCodecsInfo or IHashers interface to access
another plugins.
There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin
1) for old versions:
a) request ISetCompressCodecsInfo from created archive handler.
b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo)
2) for new versions:
a) request "SetCodecs" function from DLL file
b) call SetCodecs(compressCodecsInfo) function from DLL file
*/
#include "../../../Common/MyBuffer.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/MyString.h"
#include "../../../Common/ComTry.h"
#ifdef EXTERNAL_CODECS
#include "../../../Windows/DLL.h"
#endif
#include "../../ICoder.h"
#include "../../Archive/IArchive.h"
#ifdef EXTERNAL_CODECS
struct CDllCodecInfo
{
unsigned LibIndex;
UInt32 CodecIndex;
bool EncoderIsAssigned;
bool DecoderIsAssigned;
CLSID Encoder;
CLSID Decoder;
};
struct CDllHasherInfo
{
unsigned LibIndex;
UInt32 HasherIndex;
};
#endif
struct CArcExtInfo
{
UString Ext;
UString AddExt;
CArcExtInfo() {}
CArcExtInfo(const UString &ext): Ext(ext) {}
CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
};
struct CArcInfoEx
{
UInt32 Flags;
Func_CreateInArchive CreateInArchive;
Func_IsArc IsArcFunc;
UString Name;
CObjectVector<CArcExtInfo> Exts;
#ifndef _SFX
Func_CreateOutArchive CreateOutArchive;
bool UpdateEnabled;
bool NewInterface;
// UInt32 Version;
UInt32 SignatureOffset;
CObjectVector<CByteBuffer> Signatures;
#ifdef NEW_FOLDER_INTERFACE
UStringVector AssociateExts;
#endif
#endif
#ifdef EXTERNAL_CODECS
int LibIndex;
UInt32 FormatIndex;
CLSID ClassID;
#endif
bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
UString GetMainExt() const
{
if (Exts.IsEmpty())
return UString();
return Exts[0].Ext;
}
int FindExtension(const UString &ext) const;
/*
UString GetAllExtensions() const
{
UString s;
for (int i = 0; i < Exts.Size(); i++)
{
if (i > 0)
s += ' ';
s += Exts[i].Ext;
}
return s;
}
*/
void AddExts(const UString &ext, const UString &addExt);
bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
// bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
CArcInfoEx():
Flags(0),
CreateInArchive(NULL),
IsArcFunc(NULL)
#ifndef _SFX
, CreateOutArchive(NULL)
, UpdateEnabled(false)
, NewInterface(false)
// , Version(0)
, SignatureOffset(0)
#endif
#ifdef EXTERNAL_CODECS
, LibIndex(-1)
#endif
{}
};
#ifdef NEW_FOLDER_INTERFACE
struct CCodecIcons
{
struct CIconPair
{
UString Ext;
int IconIndex;
};
CObjectVector<CIconPair> IconPairs;
void LoadIcons(HMODULE m);
bool FindIconIndex(const UString &ext, int &iconIndex) const;
};
#endif
#ifdef EXTERNAL_CODECS
struct CCodecLib
#ifdef NEW_FOLDER_INTERFACE
: public CCodecIcons
#endif
{
NWindows::NDLL::CLibrary Lib;
FString Path;
Func_CreateObject CreateObject;
Func_GetMethodProperty GetMethodProperty;
Func_CreateDecoder CreateDecoder;
Func_CreateEncoder CreateEncoder;
Func_SetCodecs SetCodecs;
CMyComPtr<IHashers> ComHashers;
#ifdef NEW_FOLDER_INTERFACE
void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
#endif
CCodecLib():
CreateObject(NULL),
GetMethodProperty(NULL),
CreateDecoder(NULL),
CreateEncoder(NULL),
SetCodecs(NULL)
{}
};
#endif
class CCodecs:
#ifdef EXTERNAL_CODECS
public ICompressCodecsInfo,
public IHashers,
#else
public IUnknown,
#endif
public CMyUnknownImp
{
CLASS_NO_COPY(CCodecs);
public:
#ifdef EXTERNAL_CODECS
CObjectVector<CCodecLib> Libs;
FString MainDll_ErrorPath;
void CloseLibs();
class CReleaser
{
CLASS_NO_COPY(CReleaser);
/* CCodecsReleaser object releases CCodecs links.
1) CCodecs is COM object that is deleted when all links to that object will be released/
2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
CCodecs *_codecs;
public:
CReleaser(): _codecs(NULL) {}
void Set(CCodecs *codecs) { _codecs = codecs; }
~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
};
bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
HRESULT LoadCodecs();
HRESULT LoadFormats();
HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
HRESULT LoadDllsFromFolder(const FString &folderPrefix);
HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
{
return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
}
#endif
#ifdef NEW_FOLDER_INTERFACE
CCodecIcons InternalIcons;
#endif
CObjectVector<CArcInfoEx> Formats;
#ifdef EXTERNAL_CODECS
CRecordVector<CDllCodecInfo> Codecs;
CRecordVector<CDllHasherInfo> Hashers;
#endif
bool CaseSensitiveChange;
bool CaseSensitive;
CCodecs():
#ifdef EXTERNAL_CODECS
NeedSetLibCodecs(true),
#endif
CaseSensitiveChange(false),
CaseSensitive(false)
{}
~CCodecs()
{
// OutputDebugStringA("~CCodecs");
}
const wchar_t *GetFormatNamePtr(int formatIndex) const
{
return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name;
}
HRESULT Load();
#ifndef _SFX
int FindFormatForArchiveName(const UString &arcPath) const;
int FindFormatForExtension(const UString &ext) const;
int FindFormatForArchiveType(const UString &arcType) const;
bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
#endif
#ifdef EXTERNAL_CODECS
MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers)
STDMETHOD(GetNumMethods)(UInt32 *numMethods);
STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder);
STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder);
STDMETHOD_(UInt32, GetNumHashers)();
STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
#else
MY_UNKNOWN_IMP
#endif // EXTERNAL_CODECS
#ifdef EXTERNAL_CODECS
int GetCodec_LibIndex(UInt32 index) const;
bool GetCodec_DecoderIsAssigned(UInt32 index) const;
bool GetCodec_EncoderIsAssigned(UInt32 index) const;
UInt32 GetCodec_NumStreams(UInt32 index);
HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
AString GetCodec_Name(UInt32 index);
int GetHasherLibIndex(UInt32 index);
UInt64 GetHasherId(UInt32 index);
AString GetHasherName(UInt32 index);
UInt32 GetHasherDigestSize(UInt32 index);
#endif
HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
{
const CArcInfoEx &ai = Formats[formatIndex];
#ifdef EXTERNAL_CODECS
if (ai.LibIndex < 0)
#endif
{
COM_TRY_BEGIN
archive = ai.CreateInArchive();
return S_OK;
COM_TRY_END
}
#ifdef EXTERNAL_CODECS
return CreateArchiveHandler(ai, false, (void **)&archive);
#endif
}
#ifndef _SFX
HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
{
const CArcInfoEx &ai = Formats[formatIndex];
#ifdef EXTERNAL_CODECS
if (ai.LibIndex < 0)
#endif
{
COM_TRY_BEGIN
archive = ai.CreateOutArchive();
return S_OK;
COM_TRY_END
}
#ifdef EXTERNAL_CODECS
return CreateArchiveHandler(ai, true, (void **)&archive);
#endif
}
int FindOutFormatFromName(const UString &name) const
{
FOR_VECTOR (i, Formats)
{
const CArcInfoEx &arc = Formats[i];
if (!arc.UpdateEnabled)
continue;
if (arc.Name.IsEqualTo_NoCase(name))
return i;
}
return -1;
}
#endif // _SFX
};
#ifdef EXTERNAL_CODECS
#define CREATE_CODECS_OBJECT \
CCodecs *codecs = new CCodecs; \
CExternalCodecs __externalCodecs; \
__externalCodecs.GetCodecs = codecs; \
__externalCodecs.GetHashers = codecs; \
CCodecs::CReleaser codecsReleaser; \
codecsReleaser.Set(codecs);
#else
#define CREATE_CODECS_OBJECT \
CCodecs *codecs = new CCodecs; \
CMyComPtr<IUnknown> __codecsRef = codecs;
#endif
#endif

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,409 @@
// OpenArchive.h
#ifndef __OPEN_ARCHIVE_H
#define __OPEN_ARCHIVE_H
#include "../../../Windows/PropVariant.h"
#include "ArchiveOpenCallback.h"
#include "LoadCodecs.h"
#include "Property.h"
#ifndef _SFX
#define SUPPORT_ALT_STREAMS
#endif
HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw();
HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw();
#ifdef SUPPORT_ALT_STREAMS
int FindAltStreamColon_in_Path(const wchar_t *path);
#endif
/*
struct COptionalOpenProperties
{
UString FormatName;
CObjectVector<CProperty> Props;
};
*/
#ifdef _SFX
#define OPEN_PROPS_DECL
#else
#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props
#endif
struct COpenSpecFlags
{
// bool CanReturnFull;
bool CanReturnFrontal;
bool CanReturnTail;
bool CanReturnMid;
bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; }
COpenSpecFlags():
// CanReturnFull(true),
CanReturnFrontal(false),
CanReturnTail(false),
CanReturnMid(false)
{}
};
struct COpenType
{
int FormatIndex;
COpenSpecFlags SpecForcedType;
COpenSpecFlags SpecMainType;
COpenSpecFlags SpecWrongExt;
COpenSpecFlags SpecUnknownExt;
bool Recursive;
bool CanReturnArc;
bool CanReturnParser;
bool EachPos;
// bool SkipSfxStub;
// bool ExeAsUnknown;
bool ZerosTailIsAllowed;
bool MaxStartOffset_Defined;
UInt64 MaxStartOffset;
const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const
{
return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt));
}
COpenType():
FormatIndex(-1),
Recursive(true),
EachPos(false),
CanReturnArc(true),
CanReturnParser(false),
// SkipSfxStub(true),
// ExeAsUnknown(true),
ZerosTailIsAllowed(false),
MaxStartOffset_Defined(false),
MaxStartOffset(0)
{
SpecForcedType.CanReturnFrontal = true;
SpecForcedType.CanReturnTail = true;
SpecForcedType.CanReturnMid = true;
SpecMainType.CanReturnFrontal = true;
SpecUnknownExt.CanReturnTail = true; // for sfx
SpecUnknownExt.CanReturnMid = true;
SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad
// ZerosTailIsAllowed = true;
}
};
struct COpenOptions
{
CCodecs *codecs;
COpenType openType;
const CObjectVector<COpenType> *types;
const CIntVector *excludedFormats;
IInStream *stream;
ISequentialInStream *seqStream;
IArchiveOpenCallback *callback;
COpenCallbackImp *callbackSpec;
OPEN_PROPS_DECL
// bool openOnlySpecifiedByExtension,
bool stdInMode;
UString filePath;
COpenOptions():
codecs(NULL),
types(NULL),
excludedFormats(NULL),
stream(NULL),
seqStream(NULL),
callback(NULL),
callbackSpec(NULL),
stdInMode(false)
{}
};
UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL);
struct CArcErrorInfo
{
bool ThereIsTail;
bool UnexpecedEnd;
bool IgnoreTail; // all are zeros
// bool NonZerosTail;
bool ErrorFlags_Defined;
UInt32 ErrorFlags;
UInt32 WarningFlags;
int ErrorFormatIndex; // - 1 means no Error.
// if FormatIndex == ErrorFormatIndex, the archive is open with offset
UInt64 TailSize;
/* if CArc is Open OK with some format:
- ErrorFormatIndex shows error format index, if extension is incorrect
- other variables show message and warnings of archive that is open */
UString ErrorMessage;
UString WarningMessage;
// call IsArc_After_NonOpen only if Open returns S_FALSE
bool IsArc_After_NonOpen() const
{
return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0);
}
CArcErrorInfo():
ThereIsTail(false),
UnexpecedEnd(false),
IgnoreTail(false),
// NonZerosTail(false),
ErrorFlags_Defined(false),
ErrorFlags(0),
WarningFlags(0),
ErrorFormatIndex(-1),
TailSize(0)
{}
void ClearErrors();
void ClearErrors_Full()
{
ErrorFormatIndex = -1;
ClearErrors();
}
bool IsThereErrorOrWarning() const
{
return ErrorFlags != 0
|| WarningFlags != 0
|| NeedTailWarning()
|| UnexpecedEnd
|| !ErrorMessage.IsEmpty()
|| !WarningMessage.IsEmpty();
}
bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; }
bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); }
bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; }
UInt32 GetWarningFlags() const
{
UInt32 a = WarningFlags;
if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0)
a |= kpv_ErrorFlags_DataAfterEnd;
return a;
}
UInt32 GetErrorFlags() const
{
UInt32 a = ErrorFlags;
if (UnexpecedEnd)
a |= kpv_ErrorFlags_UnexpectedEnd;
return a;
}
};
struct CReadArcItem
{
UString Path; // Path from root (including alt stream name, if alt stream)
UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode
#ifdef SUPPORT_ALT_STREAMS
UString MainPath;
/* MainPath = Path for non-AltStream,
MainPath = Path of parent, if there is parent for AltStream. */
UString AltStreamName;
bool IsAltStream;
bool WriteToAltStreamIfColon;
#endif
bool IsDir;
bool MainIsDir;
UInt32 ParentIndex; // use it, if IsAltStream
#ifndef _SFX
bool _use_baseParentFolder_mode;
int _baseParentFolder;
#endif
CReadArcItem()
{
#ifdef SUPPORT_ALT_STREAMS
WriteToAltStreamIfColon = false;
#endif
#ifndef _SFX
_use_baseParentFolder_mode = false;
_baseParentFolder = -1;
#endif
}
};
class CArc
{
HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
HRESULT OpenStream2(const COpenOptions &options);
#ifndef _SFX
// parts.Back() can contain alt stream name "nams:AltName"
HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
#endif
public:
CMyComPtr<IInArchive> Archive;
CMyComPtr<IInStream> InStream;
// we use InStream in 2 cases (ArcStreamOffset != 0):
// 1) if we use additional cache stream
// 2) we reopen sfx archive with CTailInStream
CMyComPtr<IArchiveGetRawProps> GetRawProps;
CMyComPtr<IArchiveGetRootProps> GetRootProps;
CArcErrorInfo ErrorInfo; // for OK archives
CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)
UString Path;
UString filePath;
UString DefaultName;
int FormatIndex; // - 1 means Parser.
int SubfileIndex;
FILETIME MTime;
bool MTimeDefined;
Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
UInt64 PhySize;
// UInt64 OkPhySize;
bool PhySizeDefined;
// bool OkPhySize_Defined;
UInt64 FileSize;
UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
// bool offsetDefined;
UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; }
UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive
// AString ErrorFlagsText;
bool IsParseArc;
bool IsTree;
bool IsReadOnly;
bool Ask_Deleted;
bool Ask_AltStream;
bool Ask_Aux;
bool Ask_INode;
bool IgnoreSplit; // don't try split handler
// void Set_ErrorFlagsText();
CArc():
MTimeDefined(false),
IsTree(false),
IsReadOnly(false),
Ask_Deleted(false),
Ask_AltStream(false),
Ask_Aux(false),
Ask_INode(false),
IgnoreSplit(false)
{}
HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes);
// ~CArc();
HRESULT Close()
{
InStream.Release();
return Archive->Close();
}
HRESULT GetItemPath(UInt32 index, UString &result) const;
HRESULT GetDefaultItemPath(UInt32 index, UString &result) const;
// GetItemPath2 adds [DELETED] dir prefix for deleted items.
HRESULT GetItemPath2(UInt32 index, UString &result) const;
HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const;
HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;
HRESULT IsItemAnti(UInt32 index, bool &result) const
{ return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
HRESULT OpenStream(const COpenOptions &options);
HRESULT OpenStreamOrFile(COpenOptions &options);
HRESULT ReOpen(const COpenOptions &options);
HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);
};
struct CArchiveLink
{
CObjectVector<CArc> Arcs;
UStringVector VolumePaths;
UInt64 VolumesSize;
bool IsOpen;
bool PasswordWasAsked;
// UString Password;
// int NonOpenErrorFormatIndex; // - 1 means no Error.
UString NonOpen_ArcPath;
CArcErrorInfo NonOpen_ErrorInfo;
// UString ErrorsText;
// void Set_ErrorsText();
CArchiveLink():
VolumesSize(0),
IsOpen(false),
PasswordWasAsked(false)
{}
void KeepModeForNextOpen();
HRESULT Close();
void Release();
~CArchiveLink() { Release(); }
const CArc *GetArc() const { return &Arcs.Back(); }
IInArchive *GetArchive() const { return Arcs.Back().Archive; }
IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; }
IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; }
HRESULT Open(COpenOptions &options);
HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI);
HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI);
HRESULT ReOpen(COpenOptions &options);
};
bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
#endif

View File

@@ -0,0 +1,574 @@
// PropIDUtils.cpp
#include "StdAfx.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileIO.h"
#include "../../../Windows/PropVariantConv.h"
#include "../../PropID.h"
#include "PropIDUtils.h"
#define Get16(x) GetUi16(x)
#define Get32(x) GetUi32(x)
using namespace NWindows;
static const char g_WinAttribChars[16 + 1] = "RHS8DAdNTsLCOnE_";
/*
0 READONLY
1 HIDDEN
2 SYSTEM
4 DIRECTORY
5 ARCHIVE
6 DEVICE
7 NORMAL
8 TEMPORARY
9 SPARSE_FILE
10 REPARSE_POINT
11 COMPRESSED
12 OFFLINE
13 NOT_CONTENT_INDEXED
14 ENCRYPTED
16 VIRTUAL
*/
static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
#define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-';
static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
{
s[0] = kPosixTypes[(a >> 12) & 0xF];
for (int i = 6; i >= 0; i -= 3)
{
s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
}
if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S');
if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S');
if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T');
s[10] = 0;
a &= ~(UInt32)0xFFFF;
if (a != 0)
{
s[10] = ' ';
ConvertUInt32ToHex8Digits(a, s + 11);
}
}
void ConvertWinAttribToString(char *s, UInt32 wa) throw()
{
for (int i = 0; i < 16; i++)
if ((wa & (1 << i)) && i != 7)
*s++ = g_WinAttribChars[i];
*s = 0;
// we support p7zip trick that stores posix attributes in high 16 bits, and 0x8000 flag
// we also support ZIP archives created in Unix, that store posix attributes in high 16 bits without 0x8000 flag
// if (wa & 0x8000)
if ((wa >> 16) != 0)
{
*s++ = ' ';
ConvertPosixAttribToString(s, wa >> 16);
}
}
void ConvertPropertyToShortString(char *dest, const PROPVARIANT &prop, PROPID propID, bool full) throw()
{
*dest = 0;
if (prop.vt == VT_FILETIME)
{
FILETIME localFileTime;
if ((prop.filetime.dwHighDateTime == 0 &&
prop.filetime.dwLowDateTime == 0) ||
!::FileTimeToLocalFileTime(&prop.filetime, &localFileTime))
return;
ConvertFileTimeToString(localFileTime, dest, true, full);
return;
}
switch (propID)
{
case kpidCRC:
{
if (prop.vt != VT_UI4)
break;
ConvertUInt32ToHex8Digits(prop.ulVal, dest);
return;
}
case kpidAttrib:
{
if (prop.vt != VT_UI4)
break;
UInt32 a = prop.ulVal;
/*
if ((a & 0x8000) && (a & 0x7FFF) == 0)
ConvertPosixAttribToString(dest, a >> 16);
else
*/
ConvertWinAttribToString(dest, a);
return;
}
case kpidPosixAttrib:
{
if (prop.vt != VT_UI4)
break;
ConvertPosixAttribToString(dest, prop.ulVal);
return;
}
case kpidINode:
{
if (prop.vt != VT_UI8)
break;
ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
dest += strlen(dest);
*dest++ = '-';
UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
ConvertUInt64ToString(low, dest);
return;
}
case kpidVa:
{
UInt64 v = 0;
if (prop.vt == VT_UI4)
v = prop.ulVal;
else if (prop.vt == VT_UI8)
v = (UInt64)prop.uhVal.QuadPart;
else
break;
dest[0] = '0';
dest[1] = 'x';
ConvertUInt64ToHex(v, dest + 2);
return;
}
}
ConvertPropVariantToShortString(prop, dest);
}
void ConvertPropertyToString(UString &dest, const PROPVARIANT &prop, PROPID propID, bool full)
{
if (prop.vt == VT_BSTR)
{
dest.SetFromBstr(prop.bstrVal);
return;
}
char temp[64];
ConvertPropertyToShortString(temp, prop, propID, full);
dest.SetFromAscii(temp);
}
static inline unsigned GetHex(unsigned v)
{
return (v < 10) ? ('0' + v) : ('A' + (v - 10));
}
#ifndef _SFX
static inline void AddHexToString(AString &res, unsigned v)
{
res += (char)GetHex(v >> 4);
res += (char)GetHex(v & 0xF);
res += ' ';
}
/*
static AString Data_To_Hex(const Byte *data, size_t size)
{
AString s;
for (size_t i = 0; i < size; i++)
AddHexToString(s, data[i]);
return s;
}
*/
static const char * const sidNames[] =
{
"0"
, "Dialup"
, "Network"
, "Batch"
, "Interactive"
, "Logon" // S-1-5-5-X-Y
, "Service"
, "Anonymous"
, "Proxy"
, "EnterpriseDC"
, "Self"
, "AuthenticatedUsers"
, "RestrictedCode"
, "TerminalServer"
, "RemoteInteractiveLogon"
, "ThisOrganization"
, "16"
, "IUserIIS"
, "LocalSystem"
, "LocalService"
, "NetworkService"
, "Domains"
};
struct CSecID2Name
{
UInt32 n;
const char *sz;
};
static const CSecID2Name sid_32_Names[] =
{
{ 544, "Administrators" },
{ 545, "Users" },
{ 546, "Guests" },
{ 547, "PowerUsers" },
{ 548, "AccountOperators" },
{ 549, "ServerOperators" },
{ 550, "PrintOperators" },
{ 551, "BackupOperators" },
{ 552, "Replicators" },
{ 553, "Backup Operators" },
{ 554, "PreWindows2000CompatibleAccess" },
{ 555, "RemoteDesktopUsers" },
{ 556, "NetworkConfigurationOperators" },
{ 557, "IncomingForestTrustBuilders" },
{ 558, "PerformanceMonitorUsers" },
{ 559, "PerformanceLogUsers" },
{ 560, "WindowsAuthorizationAccessGroup" },
{ 561, "TerminalServerLicenseServers" },
{ 562, "DistributedCOMUsers" },
{ 569, "CryptographicOperators" },
{ 573, "EventLogReaders" },
{ 574, "CertificateServiceDCOMAccess" }
};
static const CSecID2Name sid_21_Names[] =
{
{ 500, "Administrator" },
{ 501, "Guest" },
{ 502, "KRBTGT" },
{ 512, "DomainAdmins" },
{ 513, "DomainUsers" },
{ 515, "DomainComputers" },
{ 516, "DomainControllers" },
{ 517, "CertPublishers" },
{ 518, "SchemaAdmins" },
{ 519, "EnterpriseAdmins" },
{ 520, "GroupPolicyCreatorOwners" },
{ 553, "RASandIASServers" },
{ 553, "RASandIASServers" },
{ 571, "AllowedRODCPasswordReplicationGroup" },
{ 572, "DeniedRODCPasswordReplicationGroup" }
};
struct CServicesToName
{
UInt32 n[5];
const char *sz;
};
static const CServicesToName services_to_name[] =
{
{ { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
};
static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
{
sidSize = 0;
if (lim < 8)
{
s += "ERROR";
return;
}
UInt32 rev = p[0];
if (rev != 1)
{
s += "UNSUPPORTED";
return;
}
UInt32 num = p[1];
if (8 + num * 4 > lim)
{
s += "ERROR";
return;
}
sidSize = 8 + num * 4;
UInt32 authority = GetBe32(p + 4);
if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
{
UInt32 v0 = Get32(p + 8);
if (v0 < ARRAY_SIZE(sidNames))
{
s += sidNames[v0];
return;
}
if (v0 == 32 && num == 2)
{
UInt32 v1 = Get32(p + 12);
for (unsigned i = 0; i < ARRAY_SIZE(sid_32_Names); i++)
if (sid_32_Names[i].n == v1)
{
s += sid_32_Names[i].sz;
return;
}
}
if (v0 == 21 && num == 5)
{
UInt32 v4 = Get32(p + 8 + 4 * 4);
for (unsigned i = 0; i < ARRAY_SIZE(sid_21_Names); i++)
if (sid_21_Names[i].n == v4)
{
s += sid_21_Names[i].sz;
return;
}
}
if (v0 == 80 && num == 6)
{
for (unsigned i = 0; i < ARRAY_SIZE(services_to_name); i++)
{
const CServicesToName &sn = services_to_name[i];
int j;
for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
if (j == 5)
{
s += sn.sz;
return;
}
}
}
}
char sz[16];
s += "S-1-";
if (p[2] == 0 && p[3] == 0)
{
ConvertUInt32ToString(authority, sz);
s += sz;
}
else
{
s += "0x";
for (int i = 2; i < 8; i++)
AddHexToString(s, p[i]);
}
for (UInt32 i = 0; i < num; i++)
{
s += '-';
ConvertUInt32ToString(Get32(p + 8 + i * 4), sz);
s += sz;
}
}
static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
{
if (pos > size)
{
s += "ERROR";
return;
}
UInt32 sidSize = 0;
ParseSid(s, p + pos, size - pos, sidSize);
}
static void AddUInt32ToString(AString &s, UInt32 val)
{
char sz[16];
ConvertUInt32ToString(val, sz);
s += sz;
}
static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
{
UInt32 control = Get16(p + 2);
if ((flags & control) == 0)
return;
UInt32 pos = Get32(p + offset);
s += ' ';
s += strName;
if (pos >= size)
return;
p += pos;
size -= pos;
if (size < 8)
return;
if (Get16(p) != 2) // revision
return;
UInt32 num = Get32(p + 4);
AddUInt32ToString(s, num);
/*
UInt32 aclSize = Get16(p + 2);
if (num >= (1 << 16))
return;
if (aclSize > size)
return;
size = aclSize;
size -= 8;
p += 8;
for (UInt32 i = 0 ; i < num; i++)
{
if (size <= 8)
return;
// Byte type = p[0];
// Byte flags = p[1];
// UInt32 aceSize = Get16(p + 2);
// UInt32 mask = Get32(p + 4);
p += 8;
size -= 8;
UInt32 sidSize = 0;
s += ' ';
ParseSid(s, p, size, sidSize);
if (sidSize == 0)
return;
p += sidSize;
size -= sidSize;
}
// the tail can contain zeros. So (size != 0) is not ERROR
// if (size != 0) s += " ERROR";
*/
}
#define MY_SE_OWNER_DEFAULTED (0x0001)
#define MY_SE_GROUP_DEFAULTED (0x0002)
#define MY_SE_DACL_PRESENT (0x0004)
#define MY_SE_DACL_DEFAULTED (0x0008)
#define MY_SE_SACL_PRESENT (0x0010)
#define MY_SE_SACL_DEFAULTED (0x0020)
#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
#define MY_SE_DACL_AUTO_INHERITED (0x0400)
#define MY_SE_SACL_AUTO_INHERITED (0x0800)
#define MY_SE_DACL_PROTECTED (0x1000)
#define MY_SE_SACL_PROTECTED (0x2000)
#define MY_SE_RM_CONTROL_VALID (0x4000)
#define MY_SE_SELF_RELATIVE (0x8000)
void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
{
s.Empty();
if (size < 20 || size > (1 << 18))
{
s += "ERROR";
return;
}
if (Get16(data) != 1) // revision
{
s += "UNSUPPORTED";
return;
}
ParseOwner(s, data, size, Get32(data + 4));
s += ' ';
ParseOwner(s, data, size, Get32(data + 8));
ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
s += ' ';
AddUInt32ToString(s, size);
// s += '\n';
// s += Data_To_Hex(data, size);
}
#ifdef _WIN32
static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()
{
if (pos >= size)
return false;
size -= pos;
if (size < 8)
return false;
UInt32 rev = data[pos];
if (rev != 1)
return false;
UInt32 num = data[pos + 1];
return (8 + num * 4 <= size);
}
static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()
{
UInt32 control = Get16(p + 2);
if ((flags & control) == 0)
return true;
UInt32 pos = Get32(p + offset);
if (pos >= size)
return false;
p += pos;
size -= pos;
if (size < 8)
return false;
UInt32 aclSize = Get16(p + 2);
return (aclSize <= size);
}
bool CheckNtSecure(const Byte *data, UInt32 size) throw()
{
if (size < 20)
return false;
if (Get16(data) != 1) // revision
return true; // windows function can handle such error, so we allow it
if (size > (1 << 18))
return false;
if (!CheckSid(data, size, Get32(data + 4))) return false;
if (!CheckSid(data, size, Get32(data + 8))) return false;
if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
return true;
}
#endif
bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
{
s.Empty();
NFile::CReparseAttr attr;
if (attr.Parse(data, size))
{
if (!attr.IsSymLink())
s.AddAscii("Junction: ");
s += attr.GetPath();
if (!attr.IsOkNamePair())
{
s.AddAscii(" : ");
s += attr.PrintName;
}
return true;
}
if (size < 8)
return false;
UInt32 tag = Get32(data);
UInt32 len = Get16(data + 4);
if (len + 8 > size)
return false;
if (Get16(data + 6) != 0) // padding
return false;
char hex[16];
ConvertUInt32ToHex8Digits(tag, hex);
s.AddAscii(hex);
s.Add_Space();
data += 8;
for (UInt32 i = 0; i < len; i++)
{
unsigned b = ((const Byte *)data)[i];
s += (wchar_t)GetHex((b >> 4) & 0xF);
s += (wchar_t)GetHex(b & 0xF);
}
return true;
}
#endif

View File

@@ -0,0 +1,18 @@
// PropIDUtils.h
#ifndef __PROPID_UTILS_H
#define __PROPID_UTILS_H
#include "../../../Common/MyString.h"
// provide at least 64 bytes for buffer including zero-end
void ConvertPropertyToShortString(char *dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true) throw();
void ConvertPropertyToString(UString &dest, const PROPVARIANT &propVariant, PROPID propID, bool full = true);
bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s);
void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s);
bool CheckNtSecure(const Byte *data, UInt32 size) throw();;
void ConvertWinAttribToString(char *s, UInt32 wa) throw();
#endif

View File

@@ -0,0 +1,14 @@
// Property.h
#ifndef __7Z_PROPERTY_H
#define __7Z_PROPERTY_H
#include "../../../Common/MyString.h"
struct CProperty
{
UString Name;
UString Value;
};
#endif

View File

@@ -0,0 +1,80 @@
// SetProperties.cpp
#include "StdAfx.h"
#include "../../../Common/MyCom.h"
#include "../../../Common/MyString.h"
#include "../../../Common/StringToInt.h"
#include "../../../Windows/PropVariant.h"
#include "../../Archive/IArchive.h"
#include "SetProperties.h"
using namespace NWindows;
using namespace NCOM;
static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
{
const wchar_t *end;
UInt64 result = ConvertStringToUInt64(s, &end);
if (*end != 0 || s.IsEmpty())
prop = s;
else if (result <= (UInt32)0xFFFFFFFF)
prop = (UInt32)result;
else
prop = result;
}
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
{
if (properties.IsEmpty())
return S_OK;
CMyComPtr<ISetProperties> setProperties;
unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
if (!setProperties)
return S_OK;
UStringVector realNames;
CPropVariant *values = new CPropVariant[properties.Size()];
try
{
unsigned i;
for (i = 0; i < properties.Size(); i++)
{
const CProperty &property = properties[i];
NCOM::CPropVariant propVariant;
UString name = property.Name;
if (property.Value.IsEmpty())
{
if (!name.IsEmpty())
{
wchar_t c = name.Back();
if (c == L'-')
propVariant = false;
else if (c == L'+')
propVariant = true;
if (propVariant.vt != VT_EMPTY)
name.DeleteBack();
}
}
else
ParseNumberString(property.Value, propVariant);
realNames.Add(name);
values[i] = propVariant;
}
CRecordVector<const wchar_t *> names;
for (i = 0; i < realNames.Size(); i++)
names.Add((const wchar_t *)realNames[i]);
RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
}
catch(...)
{
delete []values;
throw;
}
delete []values;
return S_OK;
}

View File

@@ -0,0 +1,10 @@
// SetProperties.h
#ifndef __SETPROPERTIES_H
#define __SETPROPERTIES_H
#include "Property.h"
HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
#endif

View File

@@ -0,0 +1,25 @@
// SortUtils.cpp
#include "StdAfx.h"
#include "../../../Common/Wildcard.h"
#include "SortUtils.h"
static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param)
{
const UStringVector &strings = *(const UStringVector *)param;
return CompareFileNames(strings[*p1], strings[*p2]);
}
void SortFileNames(const UStringVector &strings, CUIntVector &indices)
{
const unsigned numItems = strings.Size();
indices.ClearAndSetSize(numItems);
if (numItems == 0)
return;
unsigned *vals = &indices[0];
for (unsigned i = 0; i < numItems; i++)
vals[i] = i;
indices.Sort(CompareStrings, (void *)&strings);
}

View File

@@ -0,0 +1,10 @@
// SortUtils.h
#ifndef __SORT_UTLS_H
#define __SORT_UTLS_H
#include "../../../Common/MyString.h"
void SortFileNames(const UStringVector &strings, CUIntVector &indices);
#endif

View File

@@ -0,0 +1,8 @@
// StdAfx.h
#ifndef __STDAFX_H
#define __STDAFX_H
#include "../../../Common/Common.h"
#endif

View File

@@ -0,0 +1,19 @@
// TempFiles.cpp
#include "StdAfx.h"
#include "../../../Windows/FileDir.h"
#include "TempFiles.h"
using namespace NWindows;
using namespace NFile;
void CTempFiles::Clear()
{
while (!Paths.IsEmpty())
{
NDir::DeleteFileAlways(Paths.Back());
Paths.DeleteBack();
}
}

View File

@@ -0,0 +1,16 @@
// TempFiles.h
#ifndef __TEMP_FILES_H
#define __TEMP_FILES_H
#include "../../../Common/MyString.h"
class CTempFiles
{
void Clear();
public:
FStringVector Paths;
~CTempFiles() { Clear(); }
};
#endif

View File

File diff suppressed because it is too large Load Diff

198
CPP/7zip/UI/Common/Update.h Normal file
View File

@@ -0,0 +1,198 @@
// Update.h
#ifndef __COMMON_UPDATE_H
#define __COMMON_UPDATE_H
#include "../../../Common/Wildcard.h"
#include "ArchiveOpenCallback.h"
#include "LoadCodecs.h"
#include "OpenArchive.h"
#include "Property.h"
#include "UpdateAction.h"
#include "UpdateCallback.h"
#include "DirItem.h"
enum EArcNameMode
{
k_ArcNameMode_Smart,
k_ArcNameMode_Exact,
k_ArcNameMode_Add,
};
struct CArchivePath
{
UString OriginalPath;
UString Prefix; // path(folder) prefix including slash
UString Name; // base name
UString BaseExtension; // archive type extension or "exe" extension
UString VolExtension; // archive type extension for volumes
bool Temp;
FString TempPrefix; // path(folder) for temp location
FString TempPostfix;
CArchivePath(): Temp(false) {};
void ParseFromPath(const UString &path, EArcNameMode mode);
UString GetPathWithoutExt() const { return Prefix + Name; }
UString GetFinalPath() const;
UString GetFinalVolPath() const;
FString GetTempPath() const;
};
struct CUpdateArchiveCommand
{
UString UserArchivePath;
CArchivePath ArchivePath;
NUpdateArchive::CActionSet ActionSet;
};
struct CCompressionMethodMode
{
bool Type_Defined;
COpenType Type;
CObjectVector<CProperty> Properties;
CCompressionMethodMode(): Type_Defined(false) {}
};
namespace NRecursedType { enum EEnum
{
kRecursed,
kWildcardOnlyRecursed,
kNonRecursed
};}
struct CRenamePair
{
UString OldName;
UString NewName;
bool WildcardParsing;
NRecursedType::EEnum RecursedType;
CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {}
bool Prepare();
bool GetNewPath(bool isFolder, const UString &src, UString &dest) const;
};
struct CUpdateOptions
{
CCompressionMethodMode MethodMode;
CObjectVector<CUpdateArchiveCommand> Commands;
bool UpdateArchiveItself;
CArchivePath ArchivePath;
EArcNameMode ArcNameMode;
bool SfxMode;
FString SfxModule;
bool OpenShareForWrite;
bool StdInMode;
UString StdInFileName;
bool StdOutMode;
bool EMailMode;
bool EMailRemoveAfter;
UString EMailAddress;
FString WorkingDir;
NWildcard::ECensorPathMode PathMode;
UString AddPathPrefix;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
bool DeleteAfterCompressing;
bool SetArcMTime;
CObjectVector<CRenamePair> RenamePairs;
bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath);
bool SetArcPath(const CCodecs *codecs, const UString &arcPath);
CUpdateOptions():
UpdateArchiveItself(true),
SfxMode(false),
StdInMode(false),
StdOutMode(false),
EMailMode(false),
EMailRemoveAfter(false),
OpenShareForWrite(false),
ArcNameMode(k_ArcNameMode_Smart),
PathMode(NWildcard::k_RelatPath),
DeleteAfterCompressing(false),
SetArcMTime(false)
{};
void SetActionCommand_Add()
{
Commands.Clear();
CUpdateArchiveCommand c;
c.ActionSet = NUpdateArchive::k_ActionSet_Add;
Commands.Add(c);
}
CRecordVector<UInt64> VolumesSizes;
};
struct CUpdateErrorInfo
{
DWORD SystemError;
AString Message;
FStringVector FileNames;
bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); }
HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); }
void SetFromLastError(const char *message);
HRESULT SetFromLastError(const char *message, const FString &fileName);
CUpdateErrorInfo(): SystemError(0) {};
};
struct CFinishArchiveStat
{
UInt64 OutArcFileSize;
CFinishArchiveStat(): OutArcFileSize(0) {}
};
#define INTERFACE_IUpdateCallbackUI2(x) \
INTERFACE_IUpdateCallbackUI(x) \
INTERFACE_IDirItemsCallback(x) \
virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x; \
virtual HRESULT StartScanning() x; \
virtual HRESULT FinishScanning(const CDirItemsStat &st) x; \
virtual HRESULT StartOpenArchive(const wchar_t *name) x; \
virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x; \
virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x; \
virtual HRESULT FinishDeletingAfterArchiving() x; \
struct IUpdateCallbackUI2: public IUpdateCallbackUI, public IDirItemsCallback
{
INTERFACE_IUpdateCallbackUI2(=0)
};
HRESULT UpdateArchive(
CCodecs *codecs,
const CObjectVector<COpenType> &types,
const UString &cmdArcPath2,
NWildcard::CCensor &censor,
CUpdateOptions &options,
CUpdateErrorInfo &errorInfo,
IOpenCallbackUI *openCallback,
IUpdateCallbackUI2 *callback,
bool needSetPath);
#endif

View File

@@ -0,0 +1,64 @@
// UpdateAction.cpp
#include "StdAfx.h"
#include "UpdateAction.h"
namespace NUpdateArchive {
const CActionSet k_ActionSet_Add =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Update =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Fresh =
{{
NPairAction::kCopy,
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress
}};
const CActionSet k_ActionSet_Sync =
{{
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
NPairAction::kCopy,
NPairAction::kCompress,
}};
const CActionSet k_ActionSet_Delete =
{{
NPairAction::kCopy,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore,
NPairAction::kIgnore
}};
}

View File

@@ -0,0 +1,66 @@
// UpdateAction.h
#ifndef __UPDATE_ACTION_H
#define __UPDATE_ACTION_H
namespace NUpdateArchive {
namespace NPairState
{
const unsigned kNumValues = 7;
enum EEnum
{
kNotMasked = 0,
kOnlyInArchive,
kOnlyOnDisk,
kNewInArchive,
kOldInArchive,
kSameFiles,
kUnknowNewerFiles
};
}
namespace NPairAction
{
enum EEnum
{
kIgnore = 0,
kCopy,
kCompress,
kCompressAsAnti
};
}
struct CActionSet
{
NPairAction::EEnum StateActions[NPairState::kNumValues];
bool IsEqualTo(const CActionSet &a) const
{
for (unsigned i = 0; i < NPairState::kNumValues; i++)
if (StateActions[i] != a.StateActions[i])
return false;
return true;
}
bool NeedScanning() const
{
unsigned i;
for (i = 0; i < NPairState::kNumValues; i++)
if (StateActions[i] == NPairAction::kCompress)
return true;
for (i = 1; i < NPairState::kNumValues; i++)
if (StateActions[i] != NPairAction::kIgnore)
return true;
return false;
}
};
extern const CActionSet k_ActionSet_Add;
extern const CActionSet k_ActionSet_Update;
extern const CActionSet k_ActionSet_Fresh;
extern const CActionSet k_ActionSet_Sync;
extern const CActionSet k_ActionSet_Delete;
}
#endif

View File

@@ -0,0 +1,757 @@
// UpdateCallback.cpp
#include "StdAfx.h"
#ifndef _7ZIP_ST
#include "../../../Windows/Synchronization.h"
#endif
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/PropVariant.h"
#include "../../Common/StreamObjects.h"
#include "UpdateCallback.h"
#if defined(_WIN32) && !defined(UNDER_CE)
#define _USE_SECURITY_CODE
#include "../../../Windows/SecurityUtils.h"
#endif
using namespace NWindows;
using namespace NFile;
#ifndef _7ZIP_ST
static NSynchronization::CCriticalSection g_CriticalSection;
#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
#else
#define MT_LOCK
#endif
#ifdef _USE_SECURITY_CODE
bool InitLocalPrivileges();
#endif
CArchiveUpdateCallback::CArchiveUpdateCallback():
_hardIndex_From((UInt32)(Int32)-1),
Callback(NULL),
DirItems(NULL),
ParentDirItem(NULL),
Arc(NULL),
ArcItems(NULL),
UpdatePairs(NULL),
NewNames(NULL),
ShareForWrite(false),
StdInMode(false),
KeepOriginalItemNames(false),
StoreNtSecurity(false),
StoreHardLinks(false),
StoreSymLinks(false),
ProcessedItemsStatuses(NULL)
{
#ifdef _USE_SECURITY_CODE
_saclEnabled = InitLocalPrivileges();
#endif
}
STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
{
COM_TRY_BEGIN
return Callback->SetTotal(size);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
{
COM_TRY_BEGIN
return Callback->SetCompleted(completeValue);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
{
COM_TRY_BEGIN
return Callback->SetRatioInfo(inSize, outSize);
COM_TRY_END
}
/*
static const CStatProp kProps[] =
{
{ NULL, kpidPath, VT_BSTR},
{ NULL, kpidIsDir, VT_BOOL},
{ NULL, kpidSize, VT_UI8},
{ NULL, kpidCTime, VT_FILETIME},
{ NULL, kpidATime, VT_FILETIME},
{ NULL, kpidMTime, VT_FILETIME},
{ NULL, kpidAttrib, VT_UI4},
{ NULL, kpidIsAnti, VT_BOOL}
};
STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
{
return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);
}
*/
STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
{
COM_TRY_BEGIN
RINOK(Callback->CheckBreak());
const CUpdatePair2 &up = (*UpdatePairs)[index];
if (newData) *newData = BoolToInt(up.NewData);
if (newProps) *newProps = BoolToInt(up.NewProps);
if (indexInArchive)
{
*indexInArchive = (UInt32)(Int32)-1;
if (up.ExistInArchive())
*indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
{
NCOM::CPropVariant prop;
switch (propID)
{
case kpidIsDir: prop = true; break;
case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;
case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break;
case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break;
case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break;
}
prop.Detach(value);
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
{
*parentType = NParentType::kDir;
*parent = (UInt32)(Int32)-1;
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)
{
*numProps = 0;
if (StoreNtSecurity)
*numProps = 1;
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
{
*name = NULL;
*propID = kpidNtSecure;
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID
#ifdef _USE_SECURITY_CODE
propID
#endif
, const void **data, UInt32 *dataSize, UInt32 *propType)
{
*data = 0;
*dataSize = 0;
*propType = 0;
if (!StoreNtSecurity)
return S_OK;
#ifdef _USE_SECURITY_CODE
if (propID == kpidNtSecure)
{
if (StdInMode)
return S_OK;
if (ParentDirItem)
{
if (ParentDirItem->SecureIndex < 0)
return S_OK;
const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex];
*data = buf;
*dataSize = (UInt32)buf.Size();
*propType = NPropDataType::kRaw;
return S_OK;
}
if (Arc && Arc->GetRootProps)
return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
}
#endif
return S_OK;
}
// #ifdef _USE_SECURITY_CODE
// #endif
STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
{
*data = 0;
*dataSize = 0;
*propType = 0;
if (propID == kpidNtSecure ||
propID == kpidNtReparse)
{
if (StdInMode)
return S_OK;
const CUpdatePair2 &up = (*UpdatePairs)[index];
if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
return Arc->GetRawProps->GetRawProp(
ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
propID, data, dataSize, propType);
{
/*
if (!up.NewData)
return E_FAIL;
*/
if (up.IsAnti)
return S_OK;
#ifndef UNDER_CE
const CDirItem &di = DirItems->Items[up.DirIndex];
#endif
#ifdef _USE_SECURITY_CODE
if (propID == kpidNtSecure)
{
if (!StoreNtSecurity)
return S_OK;
if (di.SecureIndex < 0)
return S_OK;
const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];
*data = buf;
*dataSize = (UInt32)buf.Size();
*propType = NPropDataType::kRaw;
}
else
#endif
{
// propID == kpidNtReparse
if (!StoreSymLinks)
return S_OK;
#ifndef UNDER_CE
const CByteBuffer *buf = &di.ReparseData2;
if (buf->Size() == 0)
buf = &di.ReparseData;
if (buf->Size() != 0)
{
*data = *buf;
*dataSize = (UInt32)buf->Size();
*propType = NPropDataType::kRaw;
}
#endif
}
return S_OK;
}
}
return S_OK;
}
#ifndef UNDER_CE
static UString GetRelativePath(const UString &to, const UString &from)
{
UStringVector partsTo, partsFrom;
SplitPathToParts(to, partsTo);
SplitPathToParts(from, partsFrom);
unsigned i;
for (i = 0;; i++)
{
if (i + 1 >= partsFrom.Size() ||
i + 1 >= partsTo.Size())
break;
if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
break;
}
if (i == 0)
{
#ifdef _WIN32
if (NName::IsDrivePath(to) ||
NName::IsDrivePath(from))
return to;
#endif
}
UString s;
unsigned k;
for (k = i + 1; k < partsFrom.Size(); k++)
s += L".." WSTRING_PATH_SEPARATOR;
for (k = i; k < partsTo.Size(); k++)
{
if (k != i)
s.Add_PathSepar();
s += partsTo[k];
}
return s;
}
#endif
STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
{
COM_TRY_BEGIN
const CUpdatePair2 &up = (*UpdatePairs)[index];
NCOM::CPropVariant prop;
if (up.NewData)
{
/*
if (propID == kpidIsHardLink)
{
prop = _isHardLink;
prop.Detach(value);
return S_OK;
}
*/
if (propID == kpidSymLink)
{
if (index == _hardIndex_From)
{
prop.Detach(value);
return S_OK;
}
if (up.DirIndex >= 0)
{
#ifndef UNDER_CE
const CDirItem &di = DirItems->Items[up.DirIndex];
// if (di.IsDir())
{
CReparseAttr attr;
if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
{
UString simpleName = attr.GetPath();
if (attr.IsRelative())
prop = simpleName;
else
{
const FString phyPath = DirItems->GetPhyPath(up.DirIndex);
FString fullPath;
if (NDir::MyGetFullPathName(phyPath, fullPath))
{
prop = GetRelativePath(simpleName, fs2us(fullPath));
}
}
prop.Detach(value);
return S_OK;
}
}
#endif
}
}
else if (propID == kpidHardLink)
{
if (index == _hardIndex_From)
{
const CKeyKeyValPair &pair = _map[_hardIndex_To];
const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
prop = DirItems->GetLogPath(up2.DirIndex);
prop.Detach(value);
return S_OK;
}
if (up.DirIndex >= 0)
{
prop.Detach(value);
return S_OK;
}
}
}
if (up.IsAnti
&& propID != kpidIsDir
&& propID != kpidPath
&& propID != kpidIsAltStream)
{
switch (propID)
{
case kpidSize: prop = (UInt64)0; break;
case kpidIsAnti: prop = true; break;
}
}
else if (propID == kpidPath && up.NewNameIndex >= 0)
prop = (*NewNames)[up.NewNameIndex];
else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
{
// we can generate new ShortName here;
}
else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
&& up.ExistInArchive() && Archive)
return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);
else if (up.ExistOnDisk())
{
const CDirItem &di = DirItems->Items[up.DirIndex];
switch (propID)
{
case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break;
case kpidIsDir: prop = di.IsDir(); break;
case kpidSize: prop = di.IsDir() ? (UInt64)0 : di.Size; break;
case kpidAttrib: prop = di.Attrib; break;
case kpidCTime: prop = di.CTime; break;
case kpidATime: prop = di.ATime; break;
case kpidMTime: prop = di.MTime; break;
case kpidIsAltStream: prop = di.IsAltStream; break;
#if defined(_WIN32) && !defined(UNDER_CE)
// case kpidShortName: prop = di.ShortName; break;
#endif
}
}
prop.Detach(value);
return S_OK;
COM_TRY_END
}
#ifndef _7ZIP_ST
static NSynchronization::CCriticalSection CS;
#endif
STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)
{
COM_TRY_BEGIN
*inStream = NULL;
const CUpdatePair2 &up = (*UpdatePairs)[index];
if (!up.NewData)
return E_FAIL;
RINOK(Callback->CheckBreak());
// RINOK(Callback->Finalize());
bool isDir = IsDir(up);
if (up.IsAnti)
{
UString name;
if (up.ArcIndex >= 0)
name = (*ArcItems)[up.ArcIndex].Name;
else if (up.DirIndex >= 0)
name = DirItems->GetLogPath(up.DirIndex);
RINOK(Callback->GetStream(name, isDir, true, mode));
/* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
so we return empty stream */
if (!isDir)
{
CBufInStream *inStreamSpec = new CBufInStream();
CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
inStreamSpec->Init(NULL, 0);
*inStream = inStreamLoc.Detach();
}
return S_OK;
}
RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode));
if (isDir)
return S_OK;
if (StdInMode)
{
if (mode != NUpdateNotifyOp::kAdd &&
mode != NUpdateNotifyOp::kUpdate)
return S_OK;
CStdInFileStream *inStreamSpec = new CStdInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
*inStream = inStreamLoc.Detach();
}
else
{
CInFileStream *inStreamSpec = new CInFileStream;
CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
inStreamSpec->SupportHardLinks = StoreHardLinks;
inStreamSpec->Callback = this;
inStreamSpec->CallbackRef = index;
const FString path = DirItems->GetPhyPath(up.DirIndex);
_openFiles_Indexes.Add(index);
_openFiles_Paths.Add(path);
#if defined(_WIN32) && !defined(UNDER_CE)
if (DirItems->Items[up.DirIndex].AreReparseData())
{
if (!inStreamSpec->File.OpenReparse(path))
{
return Callback->OpenFileError(path, ::GetLastError());
}
}
else
#endif
if (!inStreamSpec->OpenShared(path, ShareForWrite))
{
return Callback->OpenFileError(path, ::GetLastError());
}
if (StoreHardLinks)
{
CStreamFileProps props;
if (inStreamSpec->GetProps2(&props) == S_OK)
{
if (props.NumLinks > 1)
{
CKeyKeyValPair pair;
pair.Key1 = props.VolID;
pair.Key2 = props.FileID_Low;
pair.Value = index;
unsigned numItems = _map.Size();
unsigned pairIndex = _map.AddToUniqueSorted2(pair);
if (numItems == _map.Size())
{
// const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
_hardIndex_From = index;
_hardIndex_To = pairIndex;
// we could return NULL as stream, but it's better to return real stream
// return S_OK;
}
}
}
}
if (ProcessedItemsStatuses)
{
#ifndef _7ZIP_ST
NSynchronization::CCriticalSectionLock lock(CS);
#endif
ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1;
}
*inStream = inStreamLoc.Detach();
}
return S_OK;
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes)
{
COM_TRY_BEGIN
return Callback->SetOperationResult(opRes);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
{
COM_TRY_BEGIN
return GetStream2(index, inStream,
(*UpdatePairs)[index].ArcIndex < 0 ?
NUpdateNotifyOp::kAdd :
NUpdateNotifyOp::kUpdate);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)
{
COM_TRY_BEGIN
bool isDir = false;
if (indexType == NArchive::NEventIndexType::kOutArcIndex)
{
UString name;
if (index != (UInt32)(Int32)-1)
{
const CUpdatePair2 &up = (*UpdatePairs)[index];
if (up.ExistOnDisk())
{
name = DirItems->GetLogPath(up.DirIndex);
isDir = DirItems->Items[up.DirIndex].IsDir();
}
}
return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
}
wchar_t temp[16];
UString s2;
const wchar_t *s = NULL;
if (indexType == NArchive::NEventIndexType::kInArcIndex)
{
if (index != (UInt32)(Int32)-1)
{
if (ArcItems)
{
const CArcItem &ai = (*ArcItems)[index];
s = ai.Name;
isDir = ai.IsDir;
}
else if (Arc)
{
RINOK(Arc->GetItemPath(index, s2));
s = s2;
RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir));
}
}
}
else if (indexType == NArchive::NEventIndexType::kBlockIndex)
{
temp[0] = '#';
ConvertUInt32ToString(index, temp + 1);
s = temp;
}
if (!s)
s = L"";
return Callback->ReportUpdateOpeartion(op, s, isDir);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
{
COM_TRY_BEGIN
bool isEncrypted = false;
wchar_t temp[16];
UString s2;
const wchar_t *s = NULL;
if (indexType == NArchive::NEventIndexType::kOutArcIndex)
{
/*
UString name;
if (index != (UInt32)(Int32)-1)
{
const CUpdatePair2 &up = (*UpdatePairs)[index];
if (up.ExistOnDisk())
{
s2 = DirItems->GetLogPath(up.DirIndex);
s = s2;
}
}
*/
return E_FAIL;
}
if (indexType == NArchive::NEventIndexType::kInArcIndex)
{
if (index != (UInt32)(Int32)-1)
{
if (ArcItems)
s = (*ArcItems)[index].Name;
else if (Arc)
{
RINOK(Arc->GetItemPath(index, s2));
s = s2;
}
if (Archive)
{
RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted));
}
}
}
else if (indexType == NArchive::NEventIndexType::kBlockIndex)
{
temp[0] = '#';
ConvertUInt32ToString(index, temp + 1);
s = temp;
}
return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
{
if (VolumesSizes.Size() == 0)
return S_FALSE;
if (index >= (UInt32)VolumesSizes.Size())
index = VolumesSizes.Size() - 1;
*size = VolumesSizes[index];
return S_OK;
}
STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
{
COM_TRY_BEGIN
FChar temp[16];
ConvertUInt32ToString(index + 1, temp);
FString res = temp;
while (res.Len() < 2)
res.InsertAtFront(FTEXT('0'));
FString fileName = VolName;
fileName += FTEXT('.');
fileName += res;
fileName += VolExt;
COutFileStream *streamSpec = new COutFileStream;
CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
if (!streamSpec->Create(fileName, false))
return ::GetLastError();
*volumeStream = streamLoc.Detach();
return S_OK;
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
{
COM_TRY_BEGIN
return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
COM_TRY_END
}
STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
{
COM_TRY_BEGIN
return Callback->CryptoGetTextPassword(password);
COM_TRY_END
}
HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
{
if (error == ERROR_LOCK_VIOLATION)
{
MT_LOCK
UInt32 index = (UInt32)val;
FOR_VECTOR(i, _openFiles_Indexes)
{
if (_openFiles_Indexes[i] == index)
{
RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error));
break;
}
}
}
return HRESULT_FROM_WIN32(error);
}
void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val)
{
MT_LOCK
UInt32 index = (UInt32)val;
FOR_VECTOR(i, _openFiles_Indexes)
{
if (_openFiles_Indexes[i] == index)
{
_openFiles_Indexes.Delete(i);
_openFiles_Paths.Delete(i);
return;
}
}
throw 20141125;
}

View File

@@ -0,0 +1,147 @@
// UpdateCallback.h
#ifndef __UPDATE_CALLBACK_H
#define __UPDATE_CALLBACK_H
#include "../../../Common/MyCom.h"
#include "../../Common/FileStreams.h"
#include "../../IPassword.h"
#include "../../ICoder.h"
#include "../Common/UpdatePair.h"
#include "../Common/UpdateProduce.h"
#include "OpenArchive.h"
#define INTERFACE_IUpdateCallbackUI(x) \
virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x; \
virtual HRESULT SetTotal(UInt64 size) x; \
virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
virtual HRESULT CheckBreak() x; \
/* virtual HRESULT Finalize() x; */ \
virtual HRESULT SetNumItems(UInt64 numItems) x; \
virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x; \
virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x; \
virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x; \
virtual HRESULT SetOperationResult(Int32 opRes) x; \
virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x; \
virtual HRESULT ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool isDir) x; \
/* virtual HRESULT SetPassword(const UString &password) x; */ \
virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x; \
/* virtual HRESULT CloseProgress() { return S_OK; } */
struct IUpdateCallbackUI
{
INTERFACE_IUpdateCallbackUI(=0)
};
struct CKeyKeyValPair
{
UInt64 Key1;
UInt64 Key2;
unsigned Value;
int Compare(const CKeyKeyValPair &a) const
{
if (Key1 < a.Key1) return -1;
if (Key1 > a.Key1) return 1;
return MyCompare(Key2, a.Key2);
}
};
class CArchiveUpdateCallback:
public IArchiveUpdateCallback2,
public IArchiveUpdateCallbackFile,
public IArchiveExtractCallbackMessage,
public IArchiveGetRawProps,
public IArchiveGetRootProps,
public ICryptoGetTextPassword2,
public ICryptoGetTextPassword,
public ICompressProgressInfo,
public IInFileStream_Callback,
public CMyUnknownImp
{
#if defined(_WIN32) && !defined(UNDER_CE)
bool _saclEnabled;
#endif
CRecordVector<CKeyKeyValPair> _map;
UInt32 _hardIndex_From;
UInt32 _hardIndex_To;
public:
MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2)
MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile)
MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)
MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps)
MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword2)
MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)
MY_QUERYINTERFACE_END
MY_ADDREF_RELEASE
STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
INTERFACE_IArchiveUpdateCallback2(;)
INTERFACE_IArchiveUpdateCallbackFile(;)
INTERFACE_IArchiveExtractCallbackMessage(;)
INTERFACE_IArchiveGetRawProps(;)
INTERFACE_IArchiveGetRootProps(;)
STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
STDMETHOD(CryptoGetTextPassword)(BSTR *password);
CRecordVector<UInt32> _openFiles_Indexes;
FStringVector _openFiles_Paths;
bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }
virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error);
virtual void InFileStream_On_Destroy(UINT_PTR val);
CRecordVector<UInt64> VolumesSizes;
FString VolName;
FString VolExt;
IUpdateCallbackUI *Callback;
const CDirItems *DirItems;
const CDirItem *ParentDirItem;
const CArc *Arc;
CMyComPtr<IInArchive> Archive;
const CObjectVector<CArcItem> *ArcItems;
const CRecordVector<CUpdatePair2> *UpdatePairs;
const UStringVector *NewNames;
bool ShareForWrite;
bool StdInMode;
bool KeepOriginalItemNames;
bool StoreNtSecurity;
bool StoreHardLinks;
bool StoreSymLinks;
Byte *ProcessedItemsStatuses;
CArchiveUpdateCallback();
bool IsDir(const CUpdatePair2 &up) const
{
if (up.DirIndex >= 0)
return DirItems->Items[up.DirIndex].IsDir();
else if (up.ArcIndex >= 0)
return (*ArcItems)[up.ArcIndex].IsDir;
return false;
}
};
#endif

View File

@@ -0,0 +1,234 @@
// UpdatePair.cpp
#include "StdAfx.h"
#include <time.h>
#include "../../../Common/Wildcard.h"
#include "../../../Windows/TimeUtils.h"
#include "SortUtils.h"
#include "UpdatePair.h"
using namespace NWindows;
using namespace NTime;
static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
{
switch (fileTimeType)
{
case NFileTimeType::kWindows:
return ::CompareFileTime(&time1, &time2);
case NFileTimeType::kUnix:
{
UInt32 unixTime1, unixTime2;
FileTimeToUnixTime(time1, unixTime1);
FileTimeToUnixTime(time2, unixTime2);
return MyCompare(unixTime1, unixTime2);
}
case NFileTimeType::kDOS:
{
UInt32 dosTime1, dosTime2;
FileTimeToDosTime(time1, dosTime1);
FileTimeToDosTime(time2, dosTime2);
return MyCompare(dosTime1, dosTime2);
}
}
throw 4191618;
}
static const char *k_Duplicate_inArc_Message = "Duplicate filename in archive:";
static const char *k_Duplicate_inDir_Message = "Duplicate filename on disk:";
static const char *k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
static void ThrowError(const char *message, const UString &s1, const UString &s2)
{
UString m;
m.SetFromAscii(message);
m.Add_LF(); m += s1;
m.Add_LF(); m += s2;
throw m;
}
static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
{
int res = CompareFileNames(ai1.Name, ai2.Name);
if (res != 0)
return res;
if (ai1.IsDir != ai2.IsDir)
return ai1.IsDir ? -1 : 1;
return 0;
}
static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
{
unsigned i1 = *p1;
unsigned i2 = *p2;
const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
if (res != 0)
return res;
return MyCompare(i1, i2);
}
void GetUpdatePairInfoList(
const CDirItems &dirItems,
const CObjectVector<CArcItem> &arcItems,
NFileTimeType::EEnum fileTimeType,
CRecordVector<CUpdatePair> &updatePairs)
{
CUIntVector dirIndices, arcIndices;
unsigned numDirItems = dirItems.Items.Size();
unsigned numArcItems = arcItems.Size();
CIntArr duplicatedArcItem(numArcItems);
{
int *vals = &duplicatedArcItem[0];
for (unsigned i = 0; i < numArcItems; i++)
vals[i] = 0;
}
{
arcIndices.ClearAndSetSize(numArcItems);
if (numArcItems != 0)
{
unsigned *vals = &arcIndices[0];
for (unsigned i = 0; i < numArcItems; i++)
vals[i] = i;
}
arcIndices.Sort(CompareArcItems, (void *)&arcItems);
for (unsigned i = 0; i + 1 < numArcItems; i++)
if (CompareArcItemsBase(
arcItems[arcIndices[i]],
arcItems[arcIndices[i + 1]]) == 0)
{
duplicatedArcItem[i] = 1;
duplicatedArcItem[i + 1] = -1;
}
}
UStringVector dirNames;
{
dirNames.ClearAndReserve(numDirItems);
unsigned i;
for (i = 0; i < numDirItems; i++)
dirNames.AddInReserved(dirItems.GetLogPath(i));
SortFileNames(dirNames, dirIndices);
for (i = 0; i + 1 < numDirItems; i++)
{
const UString &s1 = dirNames[dirIndices[i]];
const UString &s2 = dirNames[dirIndices[i + 1]];
if (CompareFileNames(s1, s2) == 0)
ThrowError(k_Duplicate_inDir_Message, s1, s2);
}
}
unsigned dirIndex = 0;
unsigned arcIndex = 0;
int prevHostFile = -1;
const UString *prevHostName = NULL;
while (dirIndex < numDirItems || arcIndex < numArcItems)
{
CUpdatePair pair;
int dirIndex2 = -1;
int arcIndex2 = -1;
const CDirItem *di = NULL;
const CArcItem *ai = NULL;
int compareResult = -1;
const UString *name = NULL;
if (dirIndex < numDirItems)
{
dirIndex2 = dirIndices[dirIndex];
di = &dirItems.Items[dirIndex2];
}
if (arcIndex < numArcItems)
{
arcIndex2 = arcIndices[arcIndex];
ai = &arcItems[arcIndex2];
compareResult = 1;
if (dirIndex < numDirItems)
{
compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name);
if (compareResult == 0)
{
if (di->IsDir() != ai->IsDir)
compareResult = (ai->IsDir ? 1 : -1);
}
}
}
if (compareResult < 0)
{
name = &dirNames[dirIndex2];
pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
pair.DirIndex = dirIndex2;
dirIndex++;
}
else if (compareResult > 0)
{
name = &ai->Name;
pair.State = ai->Censored ?
NUpdateArchive::NPairState::kOnlyInArchive:
NUpdateArchive::NPairState::kNotMasked;
pair.ArcIndex = arcIndex2;
arcIndex++;
}
else
{
int dupl = duplicatedArcItem[arcIndex];
if (dupl != 0)
ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name);
name = &dirNames[dirIndex2];
if (!ai->Censored)
ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
pair.DirIndex = dirIndex2;
pair.ArcIndex = arcIndex2;
switch (ai->MTimeDefined ? MyCompareTime(
ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType,
di->MTime, ai->MTime): 0)
{
case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
default:
pair.State = (ai->SizeDefined && di->Size == ai->Size) ?
NUpdateArchive::NPairState::kSameFiles :
NUpdateArchive::NPairState::kUnknowNewerFiles;
}
dirIndex++;
arcIndex++;
}
if ((di && di->IsAltStream) ||
(ai && ai->IsAltStream))
{
if (prevHostName)
{
unsigned hostLen = prevHostName->Len();
if (name->Len() > hostLen)
if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
pair.HostIndex = prevHostFile;
}
}
else
{
prevHostFile = updatePairs.Size();
prevHostName = name;
}
updatePairs.Add(pair);
}
updatePairs.ReserveDown();
}

View File

@@ -0,0 +1,27 @@
// UpdatePair.h
#ifndef __UPDATE_PAIR_H
#define __UPDATE_PAIR_H
#include "DirItem.h"
#include "UpdateAction.h"
#include "../../Archive/IArchive.h"
struct CUpdatePair
{
NUpdateArchive::NPairState::EEnum State;
int ArcIndex;
int DirIndex;
int HostIndex; // >= 0 for alt streams only, contains index of host pair
CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {}
};
void GetUpdatePairInfoList(
const CDirItems &dirItems,
const CObjectVector<CArcItem> &arcItems,
NFileTimeType::EEnum fileTimeType,
CRecordVector<CUpdatePair> &updatePairs);
#endif

View File

@@ -0,0 +1,70 @@
// UpdateProduce.cpp
#include "StdAfx.h"
#include "UpdateProduce.h"
using namespace NUpdateArchive;
static const char *kUpdateActionSetCollision = "Internal collision in update action set";
void UpdateProduce(
const CRecordVector<CUpdatePair> &updatePairs,
const CActionSet &actionSet,
CRecordVector<CUpdatePair2> &operationChain,
IUpdateProduceCallback *callback)
{
FOR_VECTOR (i, updatePairs)
{
const CUpdatePair &pair = updatePairs[i];
CUpdatePair2 up2;
up2.DirIndex = pair.DirIndex;
up2.ArcIndex = pair.ArcIndex;
up2.NewData = up2.NewProps = true;
up2.UseArcProps = false;
switch (actionSet.StateActions[(unsigned)pair.State])
{
case NPairAction::kIgnore:
if (pair.ArcIndex >= 0 && callback)
callback->ShowDeleteFile(pair.ArcIndex);
continue;
case NPairAction::kCopy:
if (pair.State == NPairState::kOnlyOnDisk)
throw kUpdateActionSetCollision;
if (pair.State == NPairState::kOnlyInArchive)
{
if (pair.HostIndex >= 0)
{
/*
ignore alt stream if
1) no such alt stream in Disk
2) there is Host file in disk
*/
if (updatePairs[pair.HostIndex].DirIndex >= 0)
continue;
}
}
up2.NewData = up2.NewProps = false;
up2.UseArcProps = true;
break;
case NPairAction::kCompress:
if (pair.State == NPairState::kOnlyInArchive ||
pair.State == NPairState::kNotMasked)
throw kUpdateActionSetCollision;
break;
case NPairAction::kCompressAsAnti:
up2.IsAnti = true;
up2.UseArcProps = (pair.ArcIndex >= 0);
break;
}
operationChain.Add(up2);
}
operationChain.ReserveDown();
}

View File

@@ -0,0 +1,55 @@
// UpdateProduce.h
#ifndef __UPDATE_PRODUCE_H
#define __UPDATE_PRODUCE_H
#include "UpdatePair.h"
struct CUpdatePair2
{
bool NewData;
bool NewProps;
bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties.
bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status
int DirIndex;
int ArcIndex;
int NewNameIndex;
bool IsMainRenameItem;
void SetAs_NoChangeArcItem(int arcIndex)
{
NewData = NewProps = false;
UseArcProps = true;
IsAnti = false;
ArcIndex = arcIndex;
}
bool ExistOnDisk() const { return DirIndex != -1; }
bool ExistInArchive() const { return ArcIndex != -1; }
CUpdatePair2():
NewData(false),
NewProps(false),
UseArcProps(false),
IsAnti(false),
DirIndex(-1),
ArcIndex(-1),
NewNameIndex(-1),
IsMainRenameItem(false)
{}
};
struct IUpdateProduceCallback
{
virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0;
};
void UpdateProduce(
const CRecordVector<CUpdatePair> &updatePairs,
const NUpdateArchive::CActionSet &actionSet,
CRecordVector<CUpdatePair2> &operationChain,
IUpdateProduceCallback *callback);
#endif

View File

@@ -0,0 +1,94 @@
// WorkDir.cpp
#include "StdAfx.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/FileName.h"
#include "WorkDir.h"
using namespace NWindows;
using namespace NFile;
using namespace NDir;
FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName)
{
NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
#if defined(_WIN32) && !defined(UNDER_CE)
if (workDirInfo.ForRemovableOnly)
{
mode = NWorkDir::NMode::kCurrent;
FString prefix = path.Left(3);
if (prefix[1] == FTEXT(':') && prefix[2] == FTEXT('\\'))
{
UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP));
if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
mode = workDirInfo.Mode;
}
/*
CParsedPath parsedPath;
parsedPath.ParsePath(archiveName);
UINT driveType = GetDriveType(parsedPath.Prefix);
if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
mode = NZipSettings::NWorkDir::NMode::kCurrent;
*/
}
#endif
int pos = path.ReverseFind_PathSepar() + 1;
fileName = path.Ptr(pos);
switch (mode)
{
case NWorkDir::NMode::kCurrent:
{
return path.Left(pos);
}
case NWorkDir::NMode::kSpecified:
{
FString tempDir = workDirInfo.Path;
NName::NormalizeDirPathPrefix(tempDir);
return tempDir;
}
default:
{
FString tempDir;
if (!MyGetTempPath(tempDir))
throw 141717;
return tempDir;
}
}
}
HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
{
NWorkDir::CInfo workDirInfo;
workDirInfo.Load();
FString namePart;
FString workDir = GetWorkDir(workDirInfo, originalPath, namePart);
CreateComplexDir(workDir);
CTempFile tempFile;
_outStreamSpec = new COutFileStream;
OutStream = _outStreamSpec;
if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File))
{
DWORD error = GetLastError();
return error ? error : E_FAIL;
}
_originalPath = originalPath;
return S_OK;
}
HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal)
{
OutStream.Release();
if (!_tempFile.MoveTo(_originalPath, deleteOriginal))
{
DWORD error = GetLastError();
return error ? error : E_FAIL;
}
return S_OK;
}

View File

@@ -0,0 +1,26 @@
// WorkDir.h
#ifndef __WORK_DIR_H
#define __WORK_DIR_H
#include "../../../Windows/FileDir.h"
#include "../../Common/FileStreams.h"
#include "ZipRegistry.h"
FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
class CWorkDirTempFile
{
FString _originalPath;
NWindows::NFile::NDir::CTempFile _tempFile;
COutFileStream *_outStreamSpec;
public:
CMyComPtr<IOutStream> OutStream;
HRESULT CreateTempFile(const FString &originalPath);
HRESULT MoveToOriginal(bool deleteOriginal);
};
#endif

View File

@@ -0,0 +1,399 @@
// ZipRegistry.cpp
#include "StdAfx.h"
#include "../../../Common/IntToString.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/Registry.h"
#include "../../../Windows/Synchronization.h"
#include "ZipRegistry.h"
using namespace NWindows;
using namespace NRegistry;
static NSynchronization::CCriticalSection g_CS;
#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS);
static const TCHAR *kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR);
static CSysString GetKeyPath(const CSysString &path) { return kCuPrefix + path; }
static LONG OpenMainKey(CKey &key, LPCTSTR keyName)
{
return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ);
}
static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
{
return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
}
static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
{
if (b.Def)
key.SetValue(name, b.Val);
}
static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
{
b.Val = false;
b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS);
}
static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b)
{
b.Val = true;
b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS);
}
namespace NExtract
{
static const TCHAR *kKeyName = TEXT("Extraction");
static const TCHAR *kExtractMode = TEXT("ExtractMode");
static const TCHAR *kOverwriteMode = TEXT("OverwriteMode");
static const TCHAR *kShowPassword = TEXT("ShowPassword");
static const TCHAR *kPathHistory = TEXT("PathHistory");
static const TCHAR *kSplitDest = TEXT("SplitDest");
static const TCHAR *kElimDup = TEXT("ElimDup");
// static const TCHAR *kAltStreams = TEXT("AltStreams");
static const TCHAR *kNtSecur = TEXT("Security");
void CInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
if (PathMode_Force)
key.SetValue(kExtractMode, (UInt32)PathMode);
if (OverwriteMode_Force)
key.SetValue(kOverwriteMode, (UInt32)OverwriteMode);
Key_Set_BoolPair(key, kSplitDest, SplitDest);
Key_Set_BoolPair(key, kElimDup, ElimDup);
// Key_Set_BoolPair(key, kAltStreams, AltStreams);
Key_Set_BoolPair(key, kNtSecur, NtSecurity);
Key_Set_BoolPair(key, kShowPassword, ShowPassword);
key.RecurseDeleteKey(kPathHistory);
key.SetValue_Strings(kPathHistory, Paths);
}
void Save_ShowPassword(bool showPassword)
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
key.SetValue(kShowPassword, showPassword);
}
void CInfo::Load()
{
PathMode = NPathMode::kCurPaths;
PathMode_Force = false;
OverwriteMode = NOverwriteMode::kAsk;
OverwriteMode_Force = false;
SplitDest.Val = true;
Paths.Clear();
CS_LOCK
CKey key;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return;
key.GetValue_Strings(kPathHistory, Paths);
UInt32 v;
if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths)
{
PathMode = (NPathMode::EEnum)v;
PathMode_Force = true;
}
if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting)
{
OverwriteMode = (NOverwriteMode::EEnum)v;
OverwriteMode_Force = true;
}
Key_Get_BoolPair_true(key, kSplitDest, SplitDest);
Key_Get_BoolPair(key, kElimDup, ElimDup);
// Key_Get_BoolPair(key, kAltStreams, AltStreams);
Key_Get_BoolPair(key, kNtSecur, NtSecurity);
Key_Get_BoolPair(key, kShowPassword, ShowPassword);
}
bool Read_ShowPassword()
{
CS_LOCK
CKey key;
bool showPassword = false;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return showPassword;
key.GetValue_IfOk(kShowPassword, showPassword);
return showPassword;
}
}
namespace NCompression
{
static const TCHAR *kKeyName = TEXT("Compression");
static const TCHAR *kArcHistory = TEXT("ArcHistory");
static const WCHAR *kArchiver = L"Archiver";
static const TCHAR *kShowPassword = TEXT("ShowPassword");
static const TCHAR *kEncryptHeaders = TEXT("EncryptHeaders");
static const TCHAR *kOptionsKeyName = TEXT("Options");
static const TCHAR *kLevel = TEXT("Level");
static const TCHAR *kDictionary = TEXT("Dictionary");
static const TCHAR *kOrder = TEXT("Order");
static const TCHAR *kBlockSize = TEXT("BlockSize");
static const TCHAR *kNumThreads = TEXT("NumThreads");
static const WCHAR *kMethod = L"Method";
static const WCHAR *kOptions = L"Options";
static const WCHAR *kEncryptionMethod = L"EncryptionMethod";
static const TCHAR *kNtSecur = TEXT("Security");
static const TCHAR *kAltStreams = TEXT("AltStreams");
static const TCHAR *kHardLinks = TEXT("HardLinks");
static const TCHAR *kSymLinks = TEXT("SymLinks");
static void SetRegString(CKey &key, const WCHAR *name, const UString &value)
{
if (value.IsEmpty())
key.DeleteValue(name);
else
key.SetValue(name, value);
}
static void SetRegUInt32(CKey &key, const TCHAR *name, UInt32 value)
{
if (value == (UInt32)(Int32)-1)
key.DeleteValue(name);
else
key.SetValue(name, value);
}
static void GetRegString(CKey &key, const WCHAR *name, UString &value)
{
if (key.QueryValue(name, value) != ERROR_SUCCESS)
value.Empty();
}
static void GetRegUInt32(CKey &key, const TCHAR *name, UInt32 &value)
{
if (key.QueryValue(name, value) != ERROR_SUCCESS)
value = (UInt32)(Int32)-1;
}
void CInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kKeyName);
Key_Set_BoolPair(key, kNtSecur, NtSecurity);
Key_Set_BoolPair(key, kAltStreams, AltStreams);
Key_Set_BoolPair(key, kHardLinks, HardLinks);
Key_Set_BoolPair(key, kSymLinks, SymLinks);
key.SetValue(kShowPassword, ShowPassword);
key.SetValue(kLevel, (UInt32)Level);
key.SetValue(kArchiver, ArcType);
key.SetValue(kShowPassword, ShowPassword);
key.SetValue(kEncryptHeaders, EncryptHeaders);
key.RecurseDeleteKey(kArcHistory);
key.SetValue_Strings(kArcHistory, ArcPaths);
key.RecurseDeleteKey(kOptionsKeyName);
{
CKey optionsKey;
optionsKey.Create(key, kOptionsKeyName);
FOR_VECTOR (i, Formats)
{
const CFormatOptions &fo = Formats[i];
CKey fk;
fk.Create(optionsKey, fo.FormatID);
SetRegUInt32(fk, kLevel, fo.Level);
SetRegUInt32(fk, kDictionary, fo.Dictionary);
SetRegUInt32(fk, kOrder, fo.Order);
SetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
SetRegUInt32(fk, kNumThreads, fo.NumThreads);
SetRegString(fk, kMethod, fo.Method);
SetRegString(fk, kOptions, fo.Options);
SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
}
}
}
void CInfo::Load()
{
ArcPaths.Clear();
Formats.Clear();
Level = 5;
ArcType = L"7z";
ShowPassword = false;
EncryptHeaders = false;
CS_LOCK
CKey key;
if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
return;
Key_Get_BoolPair(key, kNtSecur, NtSecurity);
Key_Get_BoolPair(key, kAltStreams, AltStreams);
Key_Get_BoolPair(key, kHardLinks, HardLinks);
Key_Get_BoolPair(key, kSymLinks, SymLinks);
key.GetValue_Strings(kArcHistory, ArcPaths);
{
CKey optionsKey;
if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS)
{
CSysStringVector formatIDs;
optionsKey.EnumKeys(formatIDs);
FOR_VECTOR (i, formatIDs)
{
CKey fk;
CFormatOptions fo;
fo.FormatID = formatIDs[i];
if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
{
GetRegString(fk, kOptions, fo.Options);
GetRegString(fk, kMethod, fo.Method);
GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
GetRegUInt32(fk, kLevel, fo.Level);
GetRegUInt32(fk, kDictionary, fo.Dictionary);
GetRegUInt32(fk, kOrder, fo.Order);
GetRegUInt32(fk, kBlockSize, fo.BlockLogSize);
GetRegUInt32(fk, kNumThreads, fo.NumThreads);
Formats.Add(fo);
}
}
}
}
UString a;
if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
ArcType = a;
key.GetValue_IfOk(kLevel, Level);
key.GetValue_IfOk(kShowPassword, ShowPassword);
key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders);
}
}
static const TCHAR *kOptionsInfoKeyName = TEXT("Options");
namespace NWorkDir
{
static const TCHAR *kWorkDirType = TEXT("WorkDirType");
static const WCHAR *kWorkDirPath = L"WorkDirPath";
static const TCHAR *kTempRemovableOnly = TEXT("TempRemovableOnly");
void CInfo::Save()const
{
CS_LOCK
CKey key;
CreateMainKey(key, kOptionsInfoKeyName);
key.SetValue(kWorkDirType, (UInt32)Mode);
key.SetValue(kWorkDirPath, fs2us(Path));
key.SetValue(kTempRemovableOnly, ForRemovableOnly);
}
void CInfo::Load()
{
SetDefault();
CS_LOCK
CKey key;
if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
return;
UInt32 dirType;
if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS)
return;
switch (dirType)
{
case NMode::kSystem:
case NMode::kCurrent:
case NMode::kSpecified:
Mode = (NMode::EEnum)dirType;
}
UString pathU;
if (key.QueryValue(kWorkDirPath, pathU) == ERROR_SUCCESS)
Path = us2fs(pathU);
else
{
Path.Empty();
if (Mode == NMode::kSpecified)
Mode = NMode::kSystem;
}
key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly);
}
}
static const TCHAR *kCascadedMenu = TEXT("CascadedMenu");
static const TCHAR *kContextMenu = TEXT("ContextMenu");
static const TCHAR *kMenuIcons = TEXT("MenuIcons");
static const TCHAR *kElimDup = TEXT("ElimDupExtract");
void CContextMenuInfo::Save() const
{
CS_LOCK
CKey key;
CreateMainKey(key, kOptionsInfoKeyName);
Key_Set_BoolPair(key, kCascadedMenu, Cascaded);
Key_Set_BoolPair(key, kMenuIcons, MenuIcons);
Key_Set_BoolPair(key, kElimDup, ElimDup);
if (Flags_Def)
key.SetValue(kContextMenu, Flags);
}
void CContextMenuInfo::Load()
{
Cascaded.Val = true;
Cascaded.Def = false;
MenuIcons.Val = false;
MenuIcons.Def = false;
ElimDup.Val = true;
ElimDup.Def = false;
Flags = (UInt32)(Int32)-1;
Flags_Def = false;
CS_LOCK
CKey key;
if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
return;
Key_Get_BoolPair_true(key, kCascadedMenu, Cascaded);
Key_Get_BoolPair_true(key, kElimDup, ElimDup);
Key_Get_BoolPair(key, kMenuIcons, MenuIcons);
Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
}

View File

@@ -0,0 +1,125 @@
// ZipRegistry.h
#ifndef __ZIP_REGISTRY_H
#define __ZIP_REGISTRY_H
#include "../../../Common/MyTypes.h"
#include "../../../Common/MyString.h"
#include "ExtractMode.h"
namespace NExtract
{
struct CInfo
{
NPathMode::EEnum PathMode;
NOverwriteMode::EEnum OverwriteMode;
bool PathMode_Force;
bool OverwriteMode_Force;
CBoolPair SplitDest;
CBoolPair ElimDup;
// CBoolPair AltStreams;
CBoolPair NtSecurity;
CBoolPair ShowPassword;
UStringVector Paths;
void Save() const;
void Load();
};
void Save_ShowPassword(bool showPassword);
bool Read_ShowPassword();
}
namespace NCompression
{
struct CFormatOptions
{
UInt32 Level;
UInt32 Dictionary;
UInt32 Order;
UInt32 BlockLogSize;
UInt32 NumThreads;
CSysString FormatID;
UString Method;
UString Options;
UString EncryptionMethod;
void ResetForLevelChange()
{
BlockLogSize = NumThreads = Level = Dictionary = Order = UInt32(-1);
Method.Empty();
// Options.Empty();
// EncryptionMethod.Empty();
}
CFormatOptions() { ResetForLevelChange(); }
};
struct CInfo
{
UInt32 Level;
bool ShowPassword;
bool EncryptHeaders;
UString ArcType;
UStringVector ArcPaths;
CObjectVector<CFormatOptions> Formats;
CBoolPair NtSecurity;
CBoolPair AltStreams;
CBoolPair HardLinks;
CBoolPair SymLinks;
void Save() const;
void Load();
};
}
namespace NWorkDir
{
namespace NMode
{
enum EEnum
{
kSystem,
kCurrent,
kSpecified
};
}
struct CInfo
{
NMode::EEnum Mode;
FString Path;
bool ForRemovableOnly;
void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
void SetDefault()
{
Mode = NMode::kSystem;
Path.Empty();
SetForRemovableOnlyDefault();
}
void Save() const;
void Load();
};
}
struct CContextMenuInfo
{
CBoolPair Cascaded;
CBoolPair MenuIcons;
CBoolPair ElimDup;
bool Flags_Def;
UInt32 Flags;
void Save() const;
void Load();
};
#endif