用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

524 lines
16 KiB

10 months ago
#include "ArchiveExtractCallback.h"
#include "PropVariant2.h"
#include "FileSys.h"
#include "OutStreamWrapper.h"
#include <comdef.h>
#include "../CPP/Common/MyCom.h"
namespace SevenZip
{
namespace intl
{
const TString EmptyFileAlias = _T("[Content]");
ArchiveExtractCallback::ArchiveExtractCallback(
const CMyComPtr< IInArchive >& archiveHandler,
const TString& directory,
OverwriteModeEnum mode,
ProgressCallback* callback)
: m_refCount(0)
, m_archiveHandler(archiveHandler)
, m_directory(directory)
, m_callback(callback)
, m_overwriteMode(mode)
, m_totalSize(0)
, PasswordIsDefined(false)
{
if (*m_directory.rbegin() != L'\\' && *m_directory.rbegin() != L'/')
m_directory +=L'\\';
}
ArchiveExtractCallback::~ArchiveExtractCallback()
{
}
STDMETHODIMP ArchiveExtractCallback::QueryInterface(REFIID iid, void** ppvObject)
{
if (iid == __uuidof(IUnknown))
{
*ppvObject = reinterpret_cast<IUnknown*>(this);
AddRef();
return S_OK;
}
if (iid == IID_IArchiveExtractCallback)
{
*ppvObject = static_cast<IArchiveExtractCallback*>(this);
AddRef();
return S_OK;
}
if (iid == IID_ICryptoGetTextPassword)
{
*ppvObject = static_cast<ICryptoGetTextPassword*>(this);
AddRef();
return S_OK;
}
if (iid == IID_ICompressProgressInfo)
{
*ppvObject = static_cast<ICompressProgressInfo*>(this);
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) ArchiveExtractCallback::AddRef()
{
return static_cast<ULONG>(InterlockedIncrement(&m_refCount));
}
STDMETHODIMP_(ULONG) ArchiveExtractCallback::Release()
{
ULONG res = static_cast<ULONG>(InterlockedDecrement(&m_refCount));
if (res == 0)
{
delete this;
}
return res;
}
STDMETHODIMP ArchiveExtractCallback::SetTotal(UInt64 size)
{
#ifdef _DEBUG
wprintf_s(L"SetTotal:%llu\n", size);
#endif // _DEBUG
m_totalSize = size;
// - SetTotal is never called for ZIP and 7z formats
if (m_callback)
{
m_callback->OnStart(m_absPath, size);
}
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::SetCompleted(const UInt64* completeValue)
{
#ifdef _DEBUG
wprintf_s(L"SetCompleted:%llu\n", *completeValue);
#endif // _DEBUG
completeValue;
//Callback Event calls
/*
NB:
- For ZIP format SetCompleted only called once per 1000 files in central directory and once per 100 in local ones.
- For 7Z format SetCompleted is never called.
*/
if (m_callback)
{
//Don't call this directly, it will be called per file which is more consistent across archive types
//TODO: incorporate better progress tracking
//m_callback->OnProgress(m_absPath, *completeValue);
}
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
{
#ifdef _DEBUG
wprintf_s(L"SetRatioInfo:%llu-%llu\n", *inSize, *outSize);
#endif // _DEBUG
if (m_callback)
m_callback->OnRadio(*inSize, *outSize);
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream** outStream, Int32 askExtractMode)
{
try
{
// Retrieve all the various properties for the file at this index.
GetPropertyFilePath(index);
if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
{
return S_OK;
}
GetPropertyAttributes(index);
GetPropertyIsDir(index);
GetPropertyModifiedTime(index);
GetPropertyCreatedTime(index);
GetPropertyAccessedTime(index);
GetPropertySize(index);
}
catch (_com_error& ex)
{
wprintf_s(L"获取数据失败\n");
return ex.Error();
}
// TODO: m_directory could be a relative path as "..\"
m_absPath = FileSys::AppendPath(m_directory, m_relPath);
if (m_isDir)
{
wprintf_s(L"DirBegin:%s\n", m_absPath.c_str());
FileSys::CreateDirectoryTree(m_absPath);
*outStream = NULL;
return S_OK;
}
if (m_callback)
{
if (!m_callback->OnFileBegin(m_directory, m_relPath))
{
//stop decompress
return E_FAIL;
}
//Skip file
if (m_relPath.empty())
{
*outStream = NULL;
return S_OK;
}
}
wprintf_s(L"FileBegin:%s\n", m_absPath.c_str());
if (m_overwriteMode == OverwriteMode::kRollBack)
{
TString BackupPath;
if (FileSys::PathExists(m_absPath))
{
BackupPath = FileSys::GetUniquePath(m_absPath);
if (!FileSys::BackupFile(m_absPath, BackupPath))
return HRESULT_FROM_WIN32(GetLastError());
}
RollBack_Info info;
info.backup_path = BackupPath;
info.original_path = m_absPath;
m_rollbacks.push_back(info);
}
else if (FileSys::PathExists(m_absPath))
{
if (m_overwriteMode == OverwriteMode::kSkipExisting)
{
*outStream = NULL;
return S_OK;
}
else if (m_overwriteMode == OverwriteMode::kAutoRename)
{
m_absPath = FileSys::GetUniquePath(m_absPath);
}
else if (m_overwriteMode == OverwriteMode::kAutoRenameExisting)
{
TString rename_path = FileSys::GetUniquePath(m_absPath);
if (!FileSys::RenameFile(m_absPath, rename_path))
{
wprintf_s(L"重命名文件失败:%s-%s\n", m_absPath.c_str(), rename_path.c_str());
return HRESULT_FROM_WIN32(GetLastError());
}
}
else if (m_overwriteMode == OverwriteMode::kWithoutPrompt)
{
if (!FileSys::RemovePath(m_absPath))
{
wprintf_s(L"移除路径失败:%s\n", m_absPath.c_str());
return HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
wprintf_s(L"文件已存在:%s\n", m_absPath.c_str());
return ERROR_FILE_EXISTS;
}
}
TString absDir = FileSys::GetPath(m_absPath);
if (!FileSys::CreateDirectoryTree(absDir))
{
wprintf_s(L"创建目录失败:%s\n", absDir.c_str());
return ERROR_CREATE_FAILED;
}
CMyComPtr< IStream > fileStream = FileSys::OpenFileToWrite(m_absPath);
if (fileStream == NULL)
{
wprintf_s(L"创建文件失败:%s\n", m_absPath.c_str());
m_absPath.clear();
return HRESULT_FROM_WIN32(GetLastError());
}
OutStreamWrapper* stream = new OutStreamWrapper(fileStream);
if (!stream)
{
wprintf_s(L"内存不足\n");
return E_OUTOFMEMORY;
}
CMyComPtr< OutStreamWrapper > wrapperStream = stream;
*outStream = wrapperStream.Detach();
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::PrepareOperation(Int32 /*askExtractMode*/)
{
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::SetOperationResult(Int32 operationResult)
{
if (m_overwriteMode == OverwriteMode::kRollBack && operationResult != S_OK)
{
_ASSERT_EXPR(FALSE,L"begin rollback");
bool succ = ProcessRollBack(); succ;
_ASSERT_EXPR(succ, L"rollback error!");
return E_FAIL;
}
if (m_absPath.empty())
{
wprintf_s(L"AllDone\n");
if (m_callback)
m_callback->OnEnd(m_directory);
return S_OK;
}
if (m_hasModifiedTime || m_hasAccessedTime || m_hasCreatedTime)
{
HANDLE fileHandle = CreateFile(m_absPath.c_str(), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fileHandle != INVALID_HANDLE_VALUE)
{
SetFileTime(fileHandle,
m_hasCreatedTime ? &m_createdTime : NULL,
m_hasAccessedTime ? &m_accessedTime : NULL,
m_hasModifiedTime ? &m_modifiedTime : NULL);
CloseHandle(fileHandle);
}
}
if (m_hasAttrib)
{
SetFileAttributes(m_absPath.c_str(), m_attrib);
}
wprintf_s(L"FileDone:%s\n", m_absPath.c_str());
if (m_callback)
{
if(!m_callback->OnFileDone(m_absPath, m_newFileSize))
return E_FAIL;
m_callback->OnProgress(m_absPath, m_newFileSize);
}
return S_OK;
}
STDMETHODIMP ArchiveExtractCallback::CryptoGetTextPassword(BSTR* password)
{
if (!PasswordIsDefined)
{
// You can ask real password here from user
// Password = GetPassword(OutStream);
// PasswordIsDefined = true;
printf("Password is not defined");
return E_ABORT;
}
return StringToBstr(Password, password);
}
void ArchiveExtractCallback::GetPropertyFilePath(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidPath, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if ( prop.vt == VT_EMPTY )
{
m_relPath = EmptyFileAlias;
}
else if (prop.vt != VT_BSTR)
{
_com_issue_error(E_FAIL);
}
else
{
_bstr_t bstr = prop.bstrVal;
#ifdef _UNICODE
m_relPath = bstr;
#else
char relPath[MAX_PATH];
int size = WideCharToMultiByte(CP_UTF8, 0, bstr, bstr.length(), relPath, MAX_PATH, NULL, NULL);
m_relPath.assign(relPath, size);
#endif
}
}
void ArchiveExtractCallback::GetPropertyAttributes(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidAttrib, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if (prop.vt == VT_EMPTY)
{
m_attrib = 0;
m_hasAttrib = false;
}
else if (prop.vt != VT_UI4)
{
_com_issue_error(E_FAIL);
}
else
{
m_attrib = prop.ulVal;
m_hasAttrib = true;
}
}
void ArchiveExtractCallback::GetPropertyIsDir(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidIsDir, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if (prop.vt == VT_EMPTY)
{
m_isDir = false;
}
else if (prop.vt != VT_BOOL)
{
_com_issue_error(E_FAIL);
}
else
{
m_isDir = prop.boolVal != VARIANT_FALSE;
}
}
void ArchiveExtractCallback::GetPropertyModifiedTime(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidMTime, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if (prop.vt == VT_EMPTY)
{
m_hasModifiedTime = false;
}
else if (prop.vt != VT_FILETIME)
{
_com_issue_error(E_FAIL);
}
else
{
m_modifiedTime = prop.filetime;
m_hasModifiedTime = true;
}
}
void ArchiveExtractCallback::GetPropertyAccessedTime(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidATime, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if (prop.vt == VT_EMPTY)
{
m_hasAccessedTime = false;
}
else if (prop.vt != VT_FILETIME)
{
_com_issue_error(E_FAIL);
}
else
{
m_accessedTime = prop.filetime;
m_hasAccessedTime = true;
}
}
void ArchiveExtractCallback::GetPropertyCreatedTime(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidCTime, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
if (prop.vt == VT_EMPTY)
{
m_hasCreatedTime = false;
}
else if (prop.vt != VT_FILETIME)
{
_com_issue_error(E_FAIL);
}
else
{
m_createdTime = prop.filetime;
m_hasCreatedTime = true;
}
}
void ArchiveExtractCallback::GetPropertySize(UInt32 index)
{
CPropVariant prop;
HRESULT hr = m_archiveHandler->GetProperty(index, kpidSize, &prop);
if (hr != S_OK)
{
_com_issue_error(hr);
}
switch (prop.vt)
{
case VT_EMPTY:
m_hasNewFileSize = false;
return;
case VT_UI1:
m_newFileSize = prop.bVal;
break;
case VT_UI2:
m_newFileSize = prop.uiVal;
break;
case VT_UI4:
m_newFileSize = prop.ulVal;
break;
case VT_UI8:
m_newFileSize = (UInt64)prop.uhVal.QuadPart;
break;
default:
_com_issue_error(E_FAIL);
}
m_hasNewFileSize = true;
}
bool ArchiveExtractCallback::ProcessRollBack()
{
bool succ = true;
for (size_t i = 0;i<m_rollbacks.size();++i)
{
RollBack_Info& a = m_rollbacks[i];
if (m_callback)
m_callback->OnRollBack(a.original_path);
if (a.backup_path.empty())
FileSys::RemovePath(a.original_path);
else
succ = FileSys::RenameFile(a.backup_path, a.original_path);
}
return succ;
}
}
}