Source code

Revision control

Copy as Markdown

Other Tools

// ArchiveExtractCallback.cpp↩
#include "StdAfx.h"
#undef sprintf↩
#undef printf↩
// #include <stdio.h>↩
// #include "../../../../C/CpuTicks.h"↩
#include "../../../../C/Alloc.h"
#include "../../../../C/CpuArch.h"
#include "../../../Common/ComTry.h"
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/FileDir.h"
#include "../../../Windows/FileFind.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)↩
#define _USE_SECURITY_CODE↩
#include "../../../Windows/SecurityUtils.h"
#endif
#include "../../Common/FilePathAutoRename.h"
// #include "../../Common/StreamUtils.h"↩
#include "../Common/ExtractingFilePath.h"
#include "../Common/PropIDUtils.h"
#include "ArchiveExtractCallback.h"
using namespace NWindows;↩
using namespace NFile;↩
using namespace NDir;↩
static const char * const kCantAutoRename = "Can not create file with auto name";↩
static const char * const kCantRenameFile = "Can not rename existing file";↩
static const char * const kCantDeleteOutputFile = "Can not delete output file";↩
static const char * const kCantDeleteOutputDir = "Can not delete output folder";↩
static const char * const kCantCreateHardLink = "Can not create hard link";↩
static const char * const kCantCreateSymLink = "Can not create symbolic link";↩
static const char * const kCantOpenOutFile = "Can not open output file";↩
static const char * const kCantSetFileLen = "Can not set length for output file";↩
#ifndef _SFX↩
STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)↩
{↩
HRESULT result = S_OK;↩
if (_stream)↩
result = _stream->Write(data, size, &size);↩
if (_calculate)↩
_hash->Update(data, size);↩
_size += size;↩
if (processedSize)↩
*processedSize = size;↩
return result;↩
}↩
#endif
#ifdef _USE_SECURITY_CODE↩
bool InitLocalPrivileges()↩
{↩
NSecurity::CAccessToken token;↩
if (!token.OpenProcessToken(GetCurrentProcess(),↩
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES))↩
return false;↩
TOKEN_PRIVILEGES tp;↩
tp.PrivilegeCount = 1;↩
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;↩
if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid))↩
return false;↩
if (!token.AdjustPrivileges(&tp))↩
return false;↩
return (GetLastError() == ERROR_SUCCESS);↩
}↩
#endif
#ifdef SUPPORT_LINKS↩
int CHardLinkNode::Compare(const CHardLinkNode &a) const
{↩
if (StreamId < a.StreamId) return -1;↩
if (StreamId > a.StreamId) return 1;↩
return MyCompare(INode, a.INode);↩
}↩
static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined)↩
{↩
h.INode = 0;↩
h.StreamId = (UInt64)(Int64)-1;↩
defined = false;↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidINode, &prop));↩
if (!ConvertPropVariantToUInt64(prop, h.INode))↩
return S_OK;↩
}↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidStreamId, &prop));↩
ConvertPropVariantToUInt64(prop, h.StreamId);↩
}↩
defined = true;↩
return S_OK;↩
}↩
HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *realIndices)↩
{↩
_hardLinks.Clear();↩
if (!_arc->Ask_INode)↩
return S_OK;↩
IInArchive *archive = _arc->Archive;↩
CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;↩
{↩
UInt32 numItems;↩
if (realIndices)↩
numItems = realIndices->Size();↩
else
{↩
RINOK(archive->GetNumberOfItems(&numItems));↩
}↩
for (UInt32 i = 0; i < numItems; i++)↩
{↩
CHardLinkNode h;↩
bool defined;↩
UInt32 realIndex = realIndices ? (*realIndices)[i] : i;↩
RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined));↩
if (defined)↩
{↩
bool isAltStream = false;↩
RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream));↩
if (!isAltStream)↩
hardIDs.Add(h);↩
}↩
}↩
}↩
hardIDs.Sort2();↩
{↩
// wee keep only items that have 2 or more items↩
unsigned k = 0;↩
unsigned numSame = 1;↩
for (unsigned i = 1; i < hardIDs.Size(); i++)↩
{↩
if (hardIDs[i].Compare(hardIDs[i - 1]) != 0)↩
numSame = 1;↩
else if (++numSame == 2)↩
{↩
if (i - 1 != k)↩
hardIDs[k] = hardIDs[i - 1];↩
k++;↩
}↩
}↩
hardIDs.DeleteFrom(k);↩
}↩
_hardLinks.PrepareLinks();↩
return S_OK;↩
}↩
#endif
CArchiveExtractCallback::CArchiveExtractCallback():↩
_arc(NULL),↩
WriteCTime(true),↩
WriteATime(true),↩
WriteMTime(true),↩
_multiArchives(false)↩
{↩
LocalProgressSpec = new CLocalProgress();↩
_localProgress = LocalProgressSpec;↩
#ifdef _USE_SECURITY_CODE↩
_saclEnabled = InitLocalPrivileges();↩
#endif
}↩
void CArchiveExtractCallback::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)↩
{↩
ClearExtractedDirsInfo();↩
_outFileStream.Release();↩
#ifdef SUPPORT_LINKS↩
_hardLinks.Clear();↩
#endif
#ifdef SUPPORT_ALT_STREAMS↩
_renamedFiles.Clear();↩
#endif
_ntOptions = ntOptions;↩
_wildcardCensor = wildcardCensor;↩
_stdOutMode = stdOutMode;↩
_testMode = testMode;↩
// _progressTotal = 0;↩
// _progressTotal_Defined = false;↩
_packTotal = packSize;↩
_progressTotal = packSize;↩
_progressTotal_Defined = true;↩
_extractCallback2 = extractCallback2;↩
_compressProgress.Release();↩
_extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);↩
_extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage);↩
_extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);↩
#ifndef _SFX↩
_extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);↩
if (ExtractToStreamCallback)↩
{↩
Int32 useStreams = 0;↩
if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)↩
useStreams = 0;↩
if (useStreams == 0)↩
ExtractToStreamCallback.Release();↩
}↩
#endif
LocalProgressSpec->Init(extractCallback2, true);↩
LocalProgressSpec->SendProgress = false;↩
_removePathParts = removePathParts;↩
_removePartsForAltStreams = removePartsForAltStreams;↩
#ifndef _SFX↩
_baseParentFolder = (UInt32)(Int32)-1;↩
_use_baseParentFolder_mode = false;↩
#endif
_arc = arc;↩
_dirPathPrefix = directoryPath;↩
_dirPathPrefix_Full = directoryPath;↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
if (!NName::IsAltPathPrefix(_dirPathPrefix))↩
#endif
{↩
NName::NormalizeDirPathPrefix(_dirPathPrefix);↩
NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full);↩
NName::NormalizeDirPathPrefix(_dirPathPrefix_Full);↩
}↩
}↩
STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)↩
{↩
COM_TRY_BEGIN↩
_progressTotal = size;↩
_progressTotal_Defined = true;↩
if (!_multiArchives && _extractCallback2)↩
return _extractCallback2->SetTotal(size);↩
return S_OK;↩
COM_TRY_END↩
}↩
static void NormalizeVals(UInt64 &v1, UInt64 &v2)↩
{↩
const UInt64 kMax = (UInt64)1 << 31;↩
while (v1 > kMax)↩
{↩
v1 >>= 1;↩
v2 >>= 1;↩
}↩
}↩
static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)↩
{↩
NormalizeVals(packTotal, unpTotal);↩
NormalizeVals(unpCur, unpTotal);↩
if (unpTotal == 0)↩
unpTotal = 1;↩
return unpCur * packTotal / unpTotal;↩
}↩
STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)↩
{↩
COM_TRY_BEGIN↩
if (!_extractCallback2)↩
return S_OK;↩
UInt64 packCur;↩
if (_multiArchives)↩
{↩
packCur = LocalProgressSpec->InSize;↩
if (completeValue && _progressTotal_Defined)↩
packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);↩
completeValue = &packCur;↩
}↩
return _extractCallback2->SetCompleted(completeValue);↩
COM_TRY_END↩
}↩
STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)↩
{↩
COM_TRY_BEGIN↩
return _localProgress->SetRatioInfo(inSize, outSize);↩
COM_TRY_END↩
}↩
void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath)↩
{↩
bool isAbsPath = false;↩
if (!dirPathParts.IsEmpty())↩
{↩
const UString &s = dirPathParts[0];↩
if (s.IsEmpty())↩
isAbsPath = true;↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
else
{↩
if (NName::IsDrivePath2(s))↩
isAbsPath = true;↩
}↩
#endif
}↩
if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath)↩
fullPath.Empty();↩
else
fullPath = _dirPathPrefix;↩
FOR_VECTOR (i, dirPathParts)↩
{↩
if (i != 0)↩
fullPath.Add_PathSepar();↩
const UString &s = dirPathParts[i];↩
fullPath += us2fs(s);↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
if (_pathMode == NExtract::NPathMode::kAbsPaths)↩
if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))↩
continue;↩
#endif
CreateDir(fullPath);↩
}↩
}↩
HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)↩
{↩
filetimeIsDefined = false;↩
filetime.dwLowDateTime = 0;↩
filetime.dwHighDateTime = 0;↩
NCOM::CPropVariant prop;↩
RINOK(_arc->Archive->GetProperty(index, propID, &prop));↩
if (prop.vt == VT_FILETIME)↩
{↩
filetime = prop.filetime;↩
filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);↩
}↩
else if (prop.vt != VT_EMPTY)↩
return E_FAIL;↩
return S_OK;↩
}↩
HRESULT CArchiveExtractCallback::GetUnpackSize()↩
{↩
return _arc->GetItemSize(_index, _curSize, _curSizeDefined);↩
}↩
static void AddPathToMessage(UString &s, const FString &path)↩
{↩
s += " : ";↩
s += fs2us(path);↩
}↩
HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)↩
{↩
UString s (message);↩
AddPathToMessage(s, path);↩
return _extractCallback2->MessageError(s);↩
}↩
HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)↩
{↩
DWORD errorCode = GetLastError();↩
UString s (message);↩
if (errorCode != 0)↩
{↩
s += " : ";↩
s += NError::MyFormatMessage(errorCode);↩
}↩
AddPathToMessage(s, path);↩
return _extractCallback2->MessageError(s);↩
}↩
HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2)↩
{↩
UString s (message);↩
AddPathToMessage(s, path1);↩
AddPathToMessage(s, path2);↩
return _extractCallback2->MessageError(s);↩
}↩
#ifndef _SFX↩
STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value)↩
{↩
/*↩
if (propID == kpidName)↩
{↩
COM_TRY_BEGIN↩
NCOM::CPropVariant prop = Name;↩
prop.Detach(value);↩
return S_OK;↩
COM_TRY_END↩
}↩
*/
return Arc->Archive->GetProperty(IndexInArc, propID, value);↩
}↩
#endif
#ifdef SUPPORT_LINKS↩
static UString GetDirPrefixOf(const UString &src)↩
{↩
UString s (src);↩
if (!s.IsEmpty())↩
{↩
if (IsPathSepar(s.Back()))↩
s.DeleteBack();↩
int pos = s.ReverseFind_PathSepar();↩
s.DeleteFrom(pos + 1);↩
}↩
return s;↩
}↩
#endif
bool IsSafePath(const UString &path)↩
{↩
if (NName::IsAbsolutePath(path))↩
return false;↩
UStringVector parts;↩
SplitPathToParts(path, parts);↩
unsigned level = 0;↩
FOR_VECTOR (i, parts)↩
{↩
const UString &s = parts[i];↩
if (s.IsEmpty())↩
{↩
if (i == 0)↩
return false;↩
continue;↩
}↩
if (s == L".")↩
continue;↩
if (s == L"..")↩
{↩
if (level == 0)↩
return false;↩
level--;↩
}↩
else
level++;↩
}↩
return level > 0;↩
}↩
bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)↩
{↩
bool found = false;↩
if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include))↩
{↩
if (!include)↩
return true;↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!item.IsAltStream)↩
return true;↩
#endif
found = true;↩
}↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!item.IsAltStream)↩
return false;↩
UStringVector pathParts2 = item.PathParts;↩
if (pathParts2.IsEmpty())↩
pathParts2.AddNew();↩
UString &back = pathParts2.Back();↩
back += ':';↩
back += item.AltStreamName;↩
bool include2;↩
if (node.CheckPathVect(pathParts2,↩
true, // isFile,↩
include2))↩
{↩
include = include2;↩
return true;↩
}↩
#endif
return found;↩
}↩
bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item)↩
{↩
bool include;↩
if (CensorNode_CheckPath2(node, item, include))↩
return include;↩
return false;↩
}↩
static FString MakePath_from_2_Parts(const FString &prefix, const FString &path)↩
{↩
FString s (prefix);↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back()))↩
{↩
if (!NName::IsDriveRootPath_SuperAllowed(prefix))↩
s.DeleteBack();↩
}↩
#endif
s += path;↩
return s;↩
}↩
/*↩
#ifdef SUPPORT_LINKS↩
struct CTempMidBuffer↩
{↩
void *Buf;↩
CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); }↩
~CTempMidBuffer() { ::MidFree(Buf); }↩
};↩
HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)↩
{↩
const size_t kBufSize = 1 << 16;↩
CTempMidBuffer buf(kBufSize);↩
if (!buf.Buf)↩
return E_OUTOFMEMORY;↩
NIO::CInFile inFile;↩
NIO::COutFile outFile;↩
if (!inFile.Open(_CopyFile_Path))↩
return SendMessageError_with_LastError("Open error", _CopyFile_Path);↩
for (;;)↩
{↩
UInt32 num;↩
if (!inFile.Read(buf.Buf, kBufSize, num))↩
return SendMessageError_with_LastError("Read error", _CopyFile_Path);↩
if (num == 0)↩
return S_OK;↩
RINOK(WriteStream(outStream, buf.Buf, num));↩
}↩
}↩
#endif↩
*/
STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)↩
{↩
COM_TRY_BEGIN↩
*outStream = NULL;↩
#ifndef _SFX↩
if (_hashStream)↩
_hashStreamSpec->ReleaseStream();↩
_hashStreamWasUsed = false;↩
#endif
_outFileStream.Release();↩
_encrypted = false;↩
_position = 0;↩
_isSplit = false;↩
_curSize = 0;↩
_curSizeDefined = false;↩
_fileLengthWasSet = false;↩
_index = index;↩
_diskFilePath.Empty();↩
// _fi.Clear();↩
#ifdef SUPPORT_LINKS↩
// _CopyFile_Path.Empty();↩
linkPath.Empty();↩
#endif
IInArchive *archive = _arc->Archive;↩
#ifndef _SFX↩
_item._use_baseParentFolder_mode = _use_baseParentFolder_mode;↩
if (_use_baseParentFolder_mode)↩
{↩
_item._baseParentFolder = _baseParentFolder;↩
if (_pathMode == NExtract::NPathMode::kFullPaths ||↩
_pathMode == NExtract::NPathMode::kAbsPaths)↩
_item._baseParentFolder = -1;↩
}↩
#endif
#ifdef SUPPORT_ALT_STREAMS↩
_item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon;↩
#endif
RINOK(_arc->GetItem(index, _item));↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidPosition, &prop));↩
if (prop.vt != VT_EMPTY)↩
{↩
if (prop.vt != VT_UI8)↩
return E_FAIL;↩
_position = prop.uhVal.QuadPart;↩
_isSplit = true;↩
}↩
}↩
#ifdef SUPPORT_LINKS↩
// bool isCopyLink = false;↩
bool isHardLink = false;↩
bool isJunction = false;↩
bool isRelative = false;↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidHardLink, &prop));↩
if (prop.vt == VT_BSTR)↩
{↩
isHardLink = true;↩
// isCopyLink = false;↩
isRelative = false; // RAR5, TAR: hard links are from root folder of archive↩
linkPath.SetFromBstr(prop.bstrVal);↩
}↩
else if (prop.vt != VT_EMPTY)↩
return E_FAIL;↩
}↩
/*↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidCopyLink, &prop));↩
if (prop.vt == VT_BSTR)↩
{↩
isHardLink = false;↩
isCopyLink = true;↩
isRelative = false; // RAR5: copy links are from root folder of archive↩
linkPath.SetFromBstr(prop.bstrVal);↩
}↩
else if (prop.vt != VT_EMPTY)↩
return E_FAIL;↩
}↩
*/
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidSymLink, &prop));↩
if (prop.vt == VT_BSTR)↩
{↩
isHardLink = false;↩
// isCopyLink = false;↩
isRelative = true; // RAR5, TAR: symbolic links can be relative↩
linkPath.SetFromBstr(prop.bstrVal);↩
}↩
else if (prop.vt != VT_EMPTY)↩
return E_FAIL;↩
}↩
bool isOkReparse = false;↩
if (linkPath.IsEmpty() && _arc->GetRawProps)↩
{↩
const void *data;↩
UInt32 dataSize;↩
UInt32 propType;↩
_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);↩
if (dataSize != 0)↩
{↩
if (propType != NPropDataType::kRaw)↩
return E_FAIL;↩
UString s;↩
CReparseAttr reparse;↩
DWORD errorCode = 0;↩
isOkReparse = reparse.Parse((const Byte *)data, dataSize, errorCode);↩
if (isOkReparse)↩
{↩
isHardLink = false;↩
// isCopyLink = false;↩
linkPath = reparse.GetPath();↩
isJunction = reparse.IsMountPoint();↩
isRelative = reparse.IsRelative();↩
#ifndef _WIN32↩
linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);↩
#endif
}↩
}↩
}↩
if (!linkPath.IsEmpty())↩
{↩
#ifdef _WIN32↩
linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);↩
#endif
// rar5 uses "\??\" prefix for absolute links↩
if (linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))↩
{↩
isRelative = false;↩
linkPath.DeleteFrontal(4);↩
}↩
for (;;)↩
// while (NName::IsAbsolutePath(linkPath))↩
{↩
unsigned n = NName::GetRootPrefixSize(linkPath);↩
if (n == 0)↩
break;↩
isRelative = false;↩
linkPath.DeleteFrontal(n);↩
}↩
}↩
if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0)↩
{↩
UStringVector pathParts;↩
SplitPathToParts(linkPath, pathParts);↩
bool badPrefix = false;↩
FOR_VECTOR (i, _removePathParts)↩
{↩
if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)↩
{↩
badPrefix = true;↩
break;↩
}↩
}↩
if (!badPrefix)↩
pathParts.DeleteFrontal(_removePathParts.Size());↩
linkPath = MakePathFromParts(pathParts);↩
}↩
#endif
RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted));↩
RINOK(GetUnpackSize());↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!_ntOptions.AltStreams.Val && _item.IsAltStream)↩
return S_OK;↩
#endif
UStringVector &pathParts = _item.PathParts;↩
if (_wildcardCensor)↩
{↩
if (!CensorNode_CheckPath(*_wildcardCensor, _item))↩
return S_OK;↩
}↩
#ifndef _SFX↩
if (_use_baseParentFolder_mode)↩
{↩
if (!pathParts.IsEmpty())↩
{↩
unsigned numRemovePathParts = 0;↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream)↩
numRemovePathParts = pathParts.Size();↩
else
#endif
if (_pathMode == NExtract::NPathMode::kNoPaths ||↩
_pathMode == NExtract::NPathMode::kNoPathsAlt)↩
numRemovePathParts = pathParts.Size() - 1;↩
pathParts.DeleteFrontal(numRemovePathParts);↩
}↩
}↩
else
#endif
{↩
if (pathParts.IsEmpty())↩
{↩
if (_item.IsDir)↩
return S_OK;↩
/*↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!_item.IsAltStream)↩
#endif↩
return E_FAIL;↩
*/
}↩
unsigned numRemovePathParts = 0;↩
switch (_pathMode)↩
{↩
case NExtract::NPathMode::kFullPaths:↩
case NExtract::NPathMode::kCurPaths:↩
{↩
if (_removePathParts.IsEmpty())↩
break;↩
bool badPrefix = false;↩
if (pathParts.Size() < _removePathParts.Size())↩
badPrefix = true;↩
else
{↩
if (pathParts.Size() == _removePathParts.Size())↩
{↩
if (_removePartsForAltStreams)↩
{↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!_item.IsAltStream)↩
#endif
badPrefix = true;↩
}↩
else
{↩
if (!_item.MainIsDir)↩
badPrefix = true;↩
}↩
}↩
if (!badPrefix)↩
FOR_VECTOR (i, _removePathParts)↩
{↩
if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)↩
{↩
badPrefix = true;↩
break;↩
}↩
}↩
}↩
if (badPrefix)↩
{↩
if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)↩
return E_FAIL;↩
}↩
else
numRemovePathParts = _removePathParts.Size();↩
break;↩
}↩
case NExtract::NPathMode::kNoPaths:↩
{↩
if (!pathParts.IsEmpty())↩
numRemovePathParts = pathParts.Size() - 1;↩
break;↩
}↩
case NExtract::NPathMode::kNoPathsAlt:↩
{↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_item.IsAltStream)↩
numRemovePathParts = pathParts.Size();↩
else
#endif
if (!pathParts.IsEmpty())↩
numRemovePathParts = pathParts.Size() - 1;↩
break;↩
}↩
/*↩
case NExtract::NPathMode::kFullPaths:↩
case NExtract::NPathMode::kAbsPaths:↩
break;↩
*/
}↩
pathParts.DeleteFrontal(numRemovePathParts);↩
}↩
#ifndef _SFX↩
if (ExtractToStreamCallback)↩
{↩
if (!GetProp)↩
{↩
GetProp_Spec = new CGetProp;↩
GetProp = GetProp_Spec;↩
}↩
GetProp_Spec->Arc = _arc;↩
GetProp_Spec->IndexInArc = index;↩
UString name (MakePathFromParts(pathParts));↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_item.IsAltStream)↩
{↩
if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt))↩
name += ':';↩
name += _item.AltStreamName;↩
}↩
#endif
return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);↩
}↩
#endif
CMyComPtr<ISequentialOutStream> outStreamLoc;↩
if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)↩
{↩
if (_stdOutMode)↩
{↩
outStreamLoc = new CStdOutFileStream;↩
}↩
else
{↩
{↩
NCOM::CPropVariant prop;↩
RINOK(archive->GetProperty(index, kpidAttrib, &prop));↩
if (prop.vt == VT_UI4)↩
{↩
_fi.Attrib = prop.ulVal;↩
_fi.AttribDefined = true;↩
}↩
else if (prop.vt == VT_EMPTY)↩
_fi.AttribDefined = false;↩
else
return E_FAIL;↩
}↩
RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));↩
RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));↩
RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));↩
bool isAnti = false;↩
RINOK(_arc->IsItemAnti(index, isAnti));↩
#ifdef SUPPORT_ALT_STREAMS↩
if (!_item.IsAltStream↩
|| !pathParts.IsEmpty()↩
|| !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt))↩
#endif
Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, _keepAndReplaceEmptyDirPrefixes, pathParts, _item.MainIsDir);↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_item.IsAltStream)↩
{↩
UString s (_item.AltStreamName);↩
Correct_AltStream_Name(s);↩
bool needColon = true;↩
if (pathParts.IsEmpty())↩
{↩
pathParts.AddNew();↩
if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)↩
needColon = false;↩
}↩
else if (_pathMode == NExtract::NPathMode::kAbsPaths &&↩
NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())↩
pathParts.AddNew();↩
UString &name = pathParts.Back();↩
if (needColon)↩
name += (char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':');↩
name += s;↩
}↩
#endif
UString processedPath (MakePathFromParts(pathParts));↩
if (!isAnti)↩
{↩
if (!_item.IsDir)↩
{↩
if (!pathParts.IsEmpty())↩
pathParts.DeleteBack();↩
}↩
if (!pathParts.IsEmpty())↩
{↩
FString fullPathNew;↩
CreateComplexDirectory(pathParts, fullPathNew);↩
if (_item.IsDir)↩
{↩
CDirPathTime &pt = _extractedFolders.AddNew();↩
pt.CTime = _fi.CTime;↩
pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined);↩
pt.ATime = _fi.ATime;↩
pt.ATimeDefined = (WriteATime && _fi.ATimeDefined);↩
pt.MTimeDefined = false;↩
if (WriteMTime)↩
{↩
if (_fi.MTimeDefined)↩
{↩
pt.MTime = _fi.MTime;↩
pt.MTimeDefined = true;↩
}↩
else if (_arc->MTimeDefined)↩
{↩
pt.MTime = _arc->MTime;↩
pt.MTimeDefined = true;↩
}↩
}↩
pt.Path = fullPathNew;↩
pt.SetDirTime();↩
}↩
}↩
}↩
FString fullProcessedPath (us2fs(processedPath));↩
if (_pathMode != NExtract::NPathMode::kAbsPaths↩
|| !NName::IsAbsolutePath(processedPath))↩
{↩
fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath);↩
}↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)↩
{↩
int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));↩
if (renIndex >= 0)↩
{↩
const CIndexToPathPair &pair = _renamedFiles[renIndex];↩
fullProcessedPath = pair.Path;↩
fullProcessedPath += ':';↩
UString s (_item.AltStreamName);↩
Correct_AltStream_Name(s);↩
fullProcessedPath += us2fs(s);↩
}↩
}↩
#endif
bool isRenamed = false;↩
if (_item.IsDir)↩
{↩
_diskFilePath = fullProcessedPath;↩
if (isAnti)↩
RemoveDir(_diskFilePath);↩
#ifdef SUPPORT_LINKS↩
if (linkPath.IsEmpty())↩
#endif
return S_OK;↩
}↩
else if (!_isSplit)↩
{↩
// ----- Is file (not split) -----↩
NFind::CFileInfo fileInfo;↩
if (fileInfo.Find(fullProcessedPath))↩
{↩
switch (_overwriteMode)↩
{↩
case NExtract::NOverwriteMode::kSkip:↩
return S_OK;↩
case NExtract::NOverwriteMode::kAsk:↩
{↩
int slashPos = fullProcessedPath.ReverseFind_PathSepar();↩
FString realFullProcessedPath (fullProcessedPath.Left(slashPos + 1) + fileInfo.Name);↩
Int32 overwriteResult;↩
RINOK(_extractCallback2->AskOverwrite(↩
fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path,↩
_fi.MTimeDefined ? &_fi.MTime : NULL,↩
_curSizeDefined ? &_curSize : NULL,↩
&overwriteResult))↩
switch (overwriteResult)↩
{↩
case NOverwriteAnswer::kCancel: return E_ABORT;↩
case NOverwriteAnswer::kNo: return S_OK;↩
case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;↩
case NOverwriteAnswer::kYes: break;↩
case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break;↩
case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break;↩
default:↩
return E_FAIL;↩
}↩
}↩
}↩
if (_overwriteMode == NExtract::NOverwriteMode::kRename)↩
{↩
if (!AutoRenamePath(fullProcessedPath))↩
{↩
RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));↩
return E_FAIL;↩
}↩
isRenamed = true;↩
}↩
else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting)↩
{↩
FString existPath (fullProcessedPath);↩
if (!AutoRenamePath(existPath))↩
{↩
RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));↩
return E_FAIL;↩
}↩
// MyMoveFile can raname folders. So it's OK to use it for folders too↩
if (!MyMoveFile(fullProcessedPath, existPath))↩
{↩
RINOK(SendMessageError2(kCantRenameFile, existPath, fullProcessedPath));↩
return E_FAIL;↩
}↩
}↩
else
{↩
if (fileInfo.IsDir())↩
{↩
// do we need to delete all files in folder?↩
if (!RemoveDir(fullProcessedPath))↩
{↩
RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath));↩
return S_OK;↩
}↩
}↩
else
{↩
bool needDelete = true;↩
if (needDelete)↩
{↩
if (!DeleteFileAlways(fullProcessedPath))↩
{↩
RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath));↩
return S_OK;↩
// return E_FAIL;↩
}↩
}↩
}↩
}↩
}↩
else // not Find(fullProcessedPath)↩
{↩
// we need to clear READ-ONLY of parent before creating alt stream↩
#if defined(_WIN32) && !defined(UNDER_CE)↩
int colonPos = NName::FindAltStreamColon(fullProcessedPath);↩
if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)↩
{↩
FString parentFsPath (fullProcessedPath);↩
parentFsPath.DeleteFrom(colonPos);↩
NFind::CFileInfo parentFi;↩
if (parentFi.Find(parentFsPath))↩
{↩
if (parentFi.IsReadOnly())↩
SetFileAttrib(parentFsPath, parentFi.Attrib & ~FILE_ATTRIBUTE_READONLY);↩
}↩
}↩
#endif
}↩
// ----- END of code for Is file (not split) -----↩
}↩
_diskFilePath = fullProcessedPath;↩
if (!isAnti)↩
{↩
#ifdef SUPPORT_LINKS↩
if (!linkPath.IsEmpty())↩
{↩
#ifndef UNDER_CE↩
UString relatPath;↩
if (isRelative)↩
relatPath = GetDirPrefixOf(_item.Path);↩
relatPath += linkPath;↩
if (!IsSafePath(relatPath))↩
{↩
RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath)));↩
}↩
else
{↩
FString existPath;↩
if (isHardLink /* || isCopyLink */ || !isRelative)↩
{↩
if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))↩
{↩
RINOK(SendMessageError("Incorrect path", us2fs(relatPath)));↩
}↩
}↩
else
{↩
existPath = us2fs(linkPath);↩
}↩
if (!existPath.IsEmpty())↩
{↩
if (isHardLink /* || isCopyLink */)↩
{↩
// if (isHardLink)↩
{↩
if (!MyCreateHardLink(fullProcessedPath, existPath))↩
{↩
RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, existPath));↩
// return S_OK;↩
}↩
}↩
/*↩
else↩
{↩
NFind::CFileInfo fi;↩
if (!fi.Find(existPath))↩
{↩
RINOK(SendMessageError2("Can not find the file for copying", existPath, fullProcessedPath));↩
}↩
else↩
{↩
if (_curSizeDefined && _curSize == fi.Size)↩
_CopyFile_Path = existPath;↩
else↩
{↩
RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));↩
}↩
// RINOK(MyCopyFile(existPath, fullProcessedPath));↩
}↩
}↩
*/
}↩
else if (_ntOptions.SymLinks.Val)↩
{↩
// bool isSymLink = true; // = false for junction↩
if (_item.IsDir && !isRelative)↩
{↩
// if it's before Vista we use Junction Point↩
// isJunction = true;↩
// convertToAbs = true;↩
}↩
CByteBuffer data;↩
if (FillLinkData(data, fs2us(existPath), !isJunction))↩
{↩
CReparseAttr attr;↩
DWORD errorCode = 0;↩
if (!attr.Parse(data, data.Size(), errorCode))↩
{↩
RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)));↩
// return E_FAIL;↩
}↩
else
if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))↩
{↩
RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath));↩
}↩
}↩
}↩
}↩
}↩
#endif
}↩
if (linkPath.IsEmpty() /* || !_CopyFile_Path.IsEmpty() */)↩
#endif // SUPPORT_LINKS↩
{↩
bool needWriteFile = true;↩
#ifdef SUPPORT_LINKS↩
if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream)↩
{↩
CHardLinkNode h;↩
bool defined;↩
RINOK(Archive_Get_HardLinkNode(archive, index, h, defined));↩
if (defined)↩
{↩
{↩
int linkIndex = _hardLinks.IDs.FindInSorted2(h);↩
if (linkIndex >= 0)↩
{↩
FString &hl = _hardLinks.Links[linkIndex];↩
if (hl.IsEmpty())↩
hl = fullProcessedPath;↩
else
{↩
if (!MyCreateHardLink(fullProcessedPath, hl))↩
{↩
RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, hl));↩
return S_OK;↩
}↩
needWriteFile = false;↩
}↩
}↩
}↩
}↩
}↩
#endif
if (needWriteFile)↩
{↩
_outFileStreamSpec = new COutFileStream;↩
CMyComPtr<ISequentialOutStream> outStreamLoc2(_outFileStreamSpec);↩
if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))↩
{↩
// if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)↩
{↩
RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath));↩
return S_OK;↩
}↩
}↩
if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSizeDefined && _curSize > (1 << 12))↩
{↩
// UInt64 ticks = GetCpuTicks();↩
bool res = _outFileStreamSpec->File.SetLength(_curSize);↩
_fileLengthWasSet = res;↩
_outFileStreamSpec->File.SeekToBegin();↩
// ticks = GetCpuTicks() - ticks;↩
// printf("\nticks = %10d\n", (unsigned)ticks);↩
if (!res)↩
{↩
RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath));↩
}↩
}↩
#ifdef SUPPORT_ALT_STREAMS↩
if (isRenamed && !_item.IsAltStream)↩
{↩
CIndexToPathPair pair(index, fullProcessedPath);↩
unsigned oldSize = _renamedFiles.Size();↩
unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair);↩
if (oldSize == _renamedFiles.Size())↩
_renamedFiles[insertIndex].Path = fullProcessedPath;↩
}↩
#endif
if (_isSplit)↩
{↩
RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));↩
}↩
_outFileStream = outStreamLoc2;↩
}↩
}↩
}↩
outStreamLoc = _outFileStream;↩
}↩
}↩
#ifndef _SFX↩
if (_hashStream)↩
{↩
if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||↩
askExtractMode == NArchive::NExtract::NAskMode::kTest)↩
{↩
_hashStreamSpec->SetStream(outStreamLoc);↩
outStreamLoc = _hashStream;↩
_hashStreamSpec->Init(true);↩
_hashStreamWasUsed = true;↩
}↩
}↩
#endif
if (outStreamLoc)↩
{↩
/*↩
#ifdef SUPPORT_LINKS↩
if (!_CopyFile_Path.IsEmpty())↩
{↩
RINOK(PrepareOperation(askExtractMode));↩
RINOK(MyCopyFile(outStreamLoc));↩
return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);↩
}↩
if (isCopyLink && _testMode)↩
return S_OK;↩
#endif↩
*/
*outStream = outStreamLoc.Detach();↩
}↩
return S_OK;↩
COM_TRY_END↩
}↩
STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)↩
{↩
COM_TRY_BEGIN↩
#ifndef _SFX↩
if (ExtractToStreamCallback)↩
return ExtractToStreamCallback->PrepareOperation7(askExtractMode);↩
#endif
_extractMode = false;↩
switch (askExtractMode)↩
{↩
case NArchive::NExtract::NAskMode::kExtract:↩
if (_testMode)↩
askExtractMode = NArchive::NExtract::NAskMode::kTest;↩
else
_extractMode = true;↩
break;↩
};↩
return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir),↩
askExtractMode, _isSplit ? &_position: 0);↩
COM_TRY_END↩
}↩
HRESULT CArchiveExtractCallback::CloseFile()↩
{↩
if (!_outFileStream)↩
return S_OK;↩
HRESULT hres = S_OK;↩
_outFileStreamSpec->SetTime(↩
(WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,↩
(WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,↩
(WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));↩
const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;↩
if (_fileLengthWasSet && _curSize > processedSize)↩
{↩
bool res = _outFileStreamSpec->File.SetLength(processedSize);↩
_fileLengthWasSet = res;↩
if (!res)↩
hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));↩
}↩
_curSize = processedSize;↩
_curSizeDefined = true;↩
RINOK(_outFileStreamSpec->Close());↩
_outFileStream.Release();↩
return hres;↩
}↩
STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)↩
{↩
COM_TRY_BEGIN↩
#ifndef _SFX↩
if (ExtractToStreamCallback)↩
return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted));↩
#endif
#ifndef _SFX↩
if (_hashStreamWasUsed)↩
{↩
_hashStreamSpec->_hash->Final(_item.IsDir,↩
#ifdef SUPPORT_ALT_STREAMS↩
_item.IsAltStream↩
#else
false
#endif
, _item.Path);↩
_curSize = _hashStreamSpec->GetSize();↩
_curSizeDefined = true;↩
_hashStreamSpec->ReleaseStream();↩
_hashStreamWasUsed = false;↩
}↩
#endif
RINOK(CloseFile());↩
#ifdef _USE_SECURITY_CODE↩
if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)↩
{↩
const void *data;↩
UInt32 dataSize;↩
UInt32 propType;↩
_arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType);↩
if (dataSize != 0)↩
{↩
if (propType != NPropDataType::kRaw)↩
return E_FAIL;↩
if (CheckNtSecure((const Byte *)data, dataSize))↩
{↩
SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;↩
if (_saclEnabled)↩
securInfo |= SACL_SECURITY_INFORMATION;↩
::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data);↩
}↩
}↩
}↩
#endif
if (!_curSizeDefined)↩
GetUnpackSize();↩
if (_curSizeDefined)↩
{↩
#ifdef SUPPORT_ALT_STREAMS↩
if (_item.IsAltStream)↩
AltStreams_UnpackSize += _curSize;↩
else
#endif
UnpackSize += _curSize;↩
}↩
if (_item.IsDir)↩
NumFolders++;↩
#ifdef SUPPORT_ALT_STREAMS↩
else if (_item.IsAltStream)↩
NumAltStreams++;↩
#endif
else
NumFiles++;↩
if (!_stdOutMode && _extractMode && _fi.AttribDefined)↩
SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib);↩
RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)));↩
return S_OK;↩
COM_TRY_END↩
}↩
STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)↩
{↩
if (_folderArchiveExtractCallback2)↩
{↩
bool isEncrypted = false;↩
UString s;↩
if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1)↩
{↩
CReadArcItem item;↩
RINOK(_arc->GetItem(index, item));↩
s = item.Path;↩
RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted));↩
}↩
else
{↩
s = '#';↩
s.Add_UInt32(index);↩
// if (indexType == NArchive::NEventIndexType::kBlockIndex) {}↩
}↩
return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s);↩
}↩
return S_OK;↩
}↩
STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)↩
{↩
COM_TRY_BEGIN↩
if (!_cryptoGetTextPassword)↩
{↩
RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,↩
&_cryptoGetTextPassword));↩
}↩
return _cryptoGetTextPassword->CryptoGetTextPassword(password);↩
COM_TRY_END↩
}↩
void CDirPathSortPair::SetNumSlashes(const FChar *s)↩
{↩
for (unsigned numSlashes = 0;;)↩
{↩
FChar c = *s++;↩
if (c == 0)↩
{↩
Len = numSlashes;↩
return;↩
}↩
if (IS_PATH_SEPAR(c))↩
numSlashes++;↩
}↩
}↩
bool CDirPathTime::SetDirTime()↩
{↩
return NDir::SetDirTime(Path,↩
CTimeDefined ? &CTime : NULL,↩
ATimeDefined ? &ATime : NULL,↩
MTimeDefined ? &MTime : NULL);↩
}↩
HRESULT CArchiveExtractCallback::SetDirsTimes()↩
{↩
if (!_arc)↩
return S_OK;↩
CRecordVector<CDirPathSortPair> pairs;↩
pairs.ClearAndSetSize(_extractedFolders.Size());↩
unsigned i;↩
for (i = 0; i < _extractedFolders.Size(); i++)↩
{↩
CDirPathSortPair &pair = pairs[i];↩
pair.Index = i;↩
pair.SetNumSlashes(_extractedFolders[i].Path);↩
}↩
pairs.Sort2();↩
for (i = 0; i < pairs.Size(); i++)↩
{↩
_extractedFolders[pairs[i].Index].SetDirTime();↩
// if (!) return GetLastError();↩
}↩
ClearExtractedDirsInfo();↩
return S_OK;↩
}↩
HRESULT CArchiveExtractCallback::CloseArc()↩
{↩
HRESULT res = CloseFile();↩
HRESULT res2 = SetDirsTimes();↩
if (res == S_OK)↩
res = res2;↩
_arc = NULL;↩
return res;↩
}↩