summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp')
-rw-r--r--3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp1478
1 files changed, 1315 insertions, 163 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index 9c9c042291d..62da5e9fad4 100644
--- a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -2,63 +2,273 @@
#include "StdAfx.h"
-#include "Common/ComTry.h"
-#include "Common/StringConvert.h"
-#include "Common/Wildcard.h"
+#undef sprintf
+#undef printf
-#include "Windows/FileDir.h"
-#include "Windows/FileFind.h"
-#include "Windows/FileName.h"
-#include "Windows/PropVariant.h"
-#include "Windows/PropVariantConversions.h"
+#include "../../../../C/Alloc.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 *kCantAutoRename = "Can not create file with auto name";
+static const char *kCantRenameFile = "Can not rename existing file";
+static const char *kCantDeleteOutputFile = "Can not delete output file";
+static const char *kCantDeleteOutputDir = "Can not delete output folder";
+
+
+#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;
+}
-static const char *kCantAutoRename = "ERROR: Can not create file with auto name";
-static const char *kCantRenameFile = "ERROR: Can not rename existing file ";
-static const char *kCantDeleteOutputFile = "ERROR: Can not delete output file ";
+#endif
+
+CArchiveExtractCallback::CArchiveExtractCallback():
+ 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, bool crcMode,
+ bool stdOutMode, bool testMode,
const FString &directoryPath,
- const UStringVector &removePathParts,
+ const UStringVector &removePathParts, bool removePartsForAltStreams,
UInt64 packSize)
{
+ _extractedFolderPaths.Clear();
+ _extractedFolderIndices.Clear();
+
+ #ifdef SUPPORT_LINKS
+ _hardLinks.Clear();
+ #endif
+
+ #ifdef SUPPORT_ALT_STREAMS
+ _renamedFiles.Clear();
+ #endif
+
+ _ntOptions = ntOptions;
_wildcardCensor = wildcardCensor;
_stdOutMode = stdOutMode;
_testMode = testMode;
- _crcMode = crcMode;
- _unpTotal = 1;
+
+ // _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;
- _directoryPath = directoryPath;
- NFile::NName::NormalizeDirPathPrefix(_directoryPath);
+ _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
- _unpTotal = size;
+ _progressTotal = size;
+ _progressTotal_Defined = true;
if (!_multiArchives && _extractCallback2)
return _extractCallback2->SetTotal(size);
return S_OK;
@@ -87,18 +297,20 @@ static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
{
COM_TRY_BEGIN
+
if (!_extractCallback2)
return S_OK;
+ UInt64 packCur;
if (_multiArchives)
{
- if (completeValue != NULL)
- {
- UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal);
- return _extractCallback2->SetCompleted(&packCur);
- }
+ packCur = LocalProgressSpec->InSize;
+ if (completeValue && _progressTotal_Defined)
+ packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);
+ completeValue = &packCur;
}
return _extractCallback2->SetCompleted(completeValue);
+
COM_TRY_END
}
@@ -111,13 +323,39 @@ STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const U
void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath)
{
- fullPath = _directoryPath;
- for (int i = 0; i < dirPathParts.Size(); i++)
+ 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 += FCHAR_PATH_SEPARATOR;
- fullPath += us2fs(dirPathParts[i]);
- NFile::NDirectory::MyCreateDirectory(fullPath);
+ 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);
}
}
@@ -141,31 +379,272 @@ HRESULT CArchiveExtractCallback::GetUnpackSize()
return _arc->GetItemSize(_index, _curSize, _curSizeDefined);
}
+static void AddPathToMessage(UString &s, const FString &path)
+{
+ s.AddAscii(" : ");
+ s += fs2us(path);
+}
+
HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)
{
- return _extractCallback2->MessageError(GetUnicodeString(message) + fs2us(path));
+ UString s;
+ s.AddAscii(message);
+ AddPathToMessage(s, path);
+ return _extractCallback2->MessageError(s);
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)
+{
+ DWORD errorCode = GetLastError();
+ UString s;
+ s.AddAscii(message);
+ if (errorCode != 0)
+ {
+ s.AddAscii(" : ");
+ 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;
+ s.AddAscii(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 += L':';
+ 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
- _crcStream.Release();
- *outStream = 0;
+
+ *outStream = NULL;
+
+ #ifndef _SFX
+ if (_hashStream)
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ #endif
+
_outFileStream.Release();
_encrypted = false;
+ _position = 0;
_isSplit = false;
+
_curSize = 0;
_curSizeDefined = false;
_index = index;
- UString fullPath;
+ _diskFilePath.Empty();
+
+ // _fi.Clear();
+
+ #ifdef SUPPORT_LINKS
+ // _CopyFile_Path.Empty();
+ linkPath.Empty();
+ #endif
IInArchive *archive = _arc->Archive;
- RINOK(_arc->GetItemPath(index, fullPath));
- RINOK(IsArchiveItemFolder(archive, index, _fi.IsDir));
- _filePath = fullPath;
+ #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;
@@ -178,26 +657,303 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
_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;
- RINOK(GetArchiveItemBoolProp(archive, index, kpidEncrypted, _encrypted));
+ _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);
+
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ UString s;
+ CReparseAttr reparse;
+ isOkReparse = reparse.Parse((const Byte *)data, dataSize);
+ 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 (!_wildcardCensor->CheckPath(fullPath, !_fi.IsDir))
+ if (!CensorNode_CheckPath(*_wildcardCensor, _item))
return S_OK;
}
- if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ #ifndef _SFX
+ if (_use_baseParentFolder_mode)
{
- if (_stdOutMode)
+ if (!pathParts.IsEmpty())
{
- CMyComPtr<ISequentialOutStream> outStreamLoc = new CStdOutFileStream;
- *outStream = outStreamLoc.Detach();
- return S_OK;
+ 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 += L':';
+ 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));
@@ -219,38 +975,44 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
bool isAnti = false;
RINOK(_arc->IsItemAnti(index, isAnti));
- UStringVector pathParts;
- SplitPathToParts(fullPath, pathParts);
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_item.IsAltStream
+ || !pathParts.IsEmpty()
+ || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt))
+ #endif
+ Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, pathParts, _item.MainIsDir);
+
+ #ifdef SUPPORT_ALT_STREAMS
- if (pathParts.IsEmpty())
- return E_FAIL;
- int numRemovePathParts = 0;
- switch(_pathMode)
+ if (_item.IsAltStream)
{
- case NExtract::NPathMode::kFullPathnames:
- break;
- case NExtract::NPathMode::kCurrentPathnames:
- {
- numRemovePathParts = _removePathParts.Size();
- if (pathParts.Size() <= numRemovePathParts)
- return E_FAIL;
- for (int i = 0; i < numRemovePathParts; i++)
- if (_removePathParts[i].CompareNoCase(pathParts[i]) != 0)
- return E_FAIL;
- break;
- }
- case NExtract::NPathMode::kNoPathnames:
+ UString s = _item.AltStreamName;
+ Correct_AltStream_Name(s);
+ bool needColon = true;
+
+ if (pathParts.IsEmpty())
{
- numRemovePathParts = pathParts.Size() - 1;
- break;
+ 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 += (wchar_t)(_ntOptions.ReplaceColonForAltStream ? L'_' : L':');
+ name += s;
}
- pathParts.Delete(0, numRemovePathParts);
- MakeCorrectPath(pathParts);
- UString processedPath = MakePathNameFromParts(pathParts);
+
+ #endif
+
+ UString processedPath = MakePathFromParts(pathParts);
+
if (!isAnti)
{
- if (!_fi.IsDir)
+ if (!_item.IsDir)
{
if (!pathParts.IsEmpty())
pathParts.DeleteBack();
@@ -260,74 +1022,103 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
{
FString fullPathNew;
CreateComplexDirectory(pathParts, fullPathNew);
- if (_fi.IsDir)
- NFile::NDirectory::SetDirTime(fullPathNew,
+ if (_item.IsDir)
+ {
+ _extractedFolderPaths.Add(fullPathNew);
+ _extractedFolderIndices.Add(index);
+ SetDirTime(fullPathNew,
(WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
(WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
(WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
}
}
- FString fullProcessedPath = _directoryPath + us2fs(processedPath);
+ FString fullProcessedPath = us2fs(processedPath);
+ if (_pathMode != NExtract::NPathMode::kAbsPaths
+ || !NName::IsAbsolutePath(processedPath))
+ {
+ fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath);
+ }
- if (_fi.IsDir)
+ #ifdef SUPPORT_ALT_STREAMS
+
+ if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)
+ {
+ CIndexToPathPair pair(_item.ParentIndex);
+ int renIndex = _renamedFiles.FindInSorted(pair);
+ if (renIndex >= 0)
+ {
+ const CIndexToPathPair &pair = _renamedFiles[renIndex];
+ fullProcessedPath = pair.Path;
+ fullProcessedPath += (FChar)':';
+ UString s = _item.AltStreamName;
+ Correct_AltStream_Name(s);
+ fullProcessedPath += us2fs(s);
+ }
+ }
+
+ #endif
+
+ bool isRenamed = false;
+
+ if (_item.IsDir)
{
_diskFilePath = fullProcessedPath;
if (isAnti)
- NFile::NDirectory::MyRemoveDirectory(_diskFilePath);
- return S_OK;
+ RemoveDir(_diskFilePath);
+ #ifdef SUPPORT_LINKS
+ if (linkPath.IsEmpty())
+ #endif
+ return S_OK;
}
-
- if (!_isSplit)
+ else if (!_isSplit)
{
- NFile::NFind::CFileInfo fileInfo;
+
+ // ----- Is file (not split) -----
+ NFind::CFileInfo fileInfo;
if (fileInfo.Find(fullProcessedPath))
{
- switch(_overwriteMode)
+ switch (_overwriteMode)
{
- case NExtract::NOverwriteMode::kSkipExisting:
+ case NExtract::NOverwriteMode::kSkip:
return S_OK;
- case NExtract::NOverwriteMode::kAskBefore:
+ case NExtract::NOverwriteMode::kAsk:
{
- Int32 overwiteResult;
+ int slashPos = fullProcessedPath.ReverseFind_PathSepar();
+ FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name;
+
+ Int32 overwriteResult;
RINOK(_extractCallback2->AskOverwrite(
- fs2us(fullProcessedPath), &fileInfo.MTime, &fileInfo.Size, fullPath,
+ fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path,
_fi.MTimeDefined ? &_fi.MTime : NULL,
_curSizeDefined ? &_curSize : NULL,
- &overwiteResult))
+ &overwriteResult))
- switch(overwiteResult)
+ switch (overwriteResult)
{
- case NOverwriteAnswer::kCancel:
- return E_ABORT;
- case NOverwriteAnswer::kNo:
- return S_OK;
- case NOverwriteAnswer::kNoToAll:
- _overwriteMode = NExtract::NOverwriteMode::kSkipExisting;
- return S_OK;
- case NOverwriteAnswer::kYesToAll:
- _overwriteMode = NExtract::NOverwriteMode::kWithoutPrompt;
- break;
- case NOverwriteAnswer::kYes:
- break;
- case NOverwriteAnswer::kAutoRename:
- _overwriteMode = NExtract::NOverwriteMode::kAutoRename;
- break;
+ 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::kAutoRename)
+ if (_overwriteMode == NExtract::NOverwriteMode::kRename)
{
if (!AutoRenamePath(fullProcessedPath))
{
RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));
return E_FAIL;
}
+ isRenamed = true;
}
- else if (_overwriteMode == NExtract::NOverwriteMode::kAutoRenameExisting)
+ else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting)
{
FString existPath = fullProcessedPath;
if (!AutoRenamePath(existPath))
@@ -335,65 +1126,290 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));
return E_FAIL;
}
- if (!NFile::NDirectory::MyMoveFile(fullProcessedPath, existPath))
+ // MyMoveFile can raname folders. So it's OK to use it for folders too
+ if (!MyMoveFile(fullProcessedPath, existPath))
{
- RINOK(SendMessageError(kCantRenameFile, fullProcessedPath));
+ RINOK(SendMessageError2(kCantRenameFile, existPath, fullProcessedPath));
return E_FAIL;
}
}
else
- if (!NFile::NDirectory::DeleteFileAlways(fullProcessedPath))
+ {
+ if (fileInfo.IsDir())
{
- RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath));
- return S_OK;
- // return E_FAIL;
+ // 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)
{
- _outFileStreamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
- if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ #ifdef SUPPORT_LINKS
+
+ if (!linkPath.IsEmpty())
{
- // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ #ifndef UNDER_CE
+
+ UString relatPath;
+ if (isRelative)
+ relatPath = GetDirPrefixOf(_item.Path);
+ relatPath += linkPath;
+
+ if (!IsSafePath(relatPath))
{
- RINOK(SendMessageError("can not open output file ", fullProcessedPath));
- return S_OK;
+ 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("Can not create hard link", 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;
+ if (!attr.Parse(data, data.Size()))
+ {
+ 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("Can not create symbolic link", fullProcessedPath));
+ }
+ }
+ }
+ }
}
+
+ #endif
}
- if (_isSplit)
+
+ if (linkPath.IsEmpty() /* || !_CopyFile_Path.IsEmpty() */)
+ #endif // SUPPORT_LINKS
{
- RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
+ 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("Can not create hard link", fullProcessedPath, hl));
+ return S_OK;
+ }
+ needWriteFile = false;
+ }
+ }
+ }
+ }
+ }
+ #endif
+
+ if (needWriteFile)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ RINOK(SendMessageError_with_LastError("Can not open output file", fullProcessedPath));
+ return S_OK;
+ }
+ }
+
+
+ #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 = outStreamLoc;
+ }
}
- _outFileStream = outStreamLoc;
- *outStream = outStreamLoc.Detach();
}
- _diskFilePath = fullProcessedPath;
+
+ outStreamLoc = _outFileStream;
}
- else
+}
+
+ #ifndef _SFX
+
+ if (_hashStream)
{
- *outStream = NULL;
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
+ askExtractMode == NArchive::NExtract::NAskMode::kTest)
+ {
+ _hashStreamSpec->SetStream(outStreamLoc);
+ outStreamLoc = _hashStream;
+ _hashStreamSpec->Init(true);
+ _hashStreamWasUsed = true;
+ }
}
- if (_crcMode)
+
+ #endif
+
+
+ if (outStreamLoc)
{
- _crcStreamSpec = new COutStreamWithCRC;
- _crcStream = _crcStreamSpec;
- CMyComPtr<ISequentialOutStream> crcStream = _crcStreamSpec;
- _crcStreamSpec->SetStream(*outStream);
- if (*outStream)
- (*outStream)->Release();
- *outStream = crcStream.Detach();
- _crcStreamSpec->Init(true);
+ /*
+ #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:
@@ -403,32 +1419,42 @@ STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
_extractMode = true;
break;
};
- return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir,
+
+ return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir),
askExtractMode, _isSplit ? &_position: 0);
+
COM_TRY_END
}
-STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
+
+STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
{
COM_TRY_BEGIN
- switch(operationResult)
- {
- case NArchive::NExtract::NOperationResult::kOK:
- case NArchive::NExtract::NOperationResult::kUnSupportedMethod:
- case NArchive::NExtract::NOperationResult::kCRCError:
- case NArchive::NExtract::NOperationResult::kDataError:
- break;
- default:
- _outFileStream.Release();
- return E_FAIL;
- }
- if (_crcStream)
+
+ #ifndef _SFX
+ if (ExtractToStreamCallback)
+ return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted));
+ #endif
+
+ #ifndef _SFX
+
+ if (_hashStreamWasUsed)
{
- CrcSum += _crcStreamSpec->GetCRC();
- _curSize = _crcStreamSpec->GetSize();
+ _hashStreamSpec->_hash->Final(_item.IsDir,
+ #ifdef SUPPORT_ALT_STREAMS
+ _item.IsAltStream
+ #else
+ false
+ #endif
+ , _item.Path);
+ _curSize = _hashStreamSpec->GetSize();
_curSizeDefined = true;
- _crcStream.Release();
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
}
+
+ #endif
+
if (_outFileStream)
{
_outFileStreamSpec->SetTime(
@@ -440,36 +1466,92 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
RINOK(_outFileStreamSpec->Close());
_outFileStream.Release();
}
+
+ #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)
- UnpackSize += _curSize;
- if (_fi.IsDir)
+ {
+ #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 (_extractMode && _fi.AttribDefined)
- NFile::NDirectory::MySetFileAttributes(_diskFilePath, _fi.Attrib);
- RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted));
+ if (!_stdOutMode && _extractMode && _fi.AttribDefined)
+ SetFileAttrib(_diskFilePath, _fi.Attrib);
+
+ RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)));
+
return S_OK;
+
COM_TRY_END
}
-/*
-STDMETHODIMP CArchiveExtractCallback::GetInStream(
- const wchar_t *name, ISequentialInStream **inStream)
+STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
{
- COM_TRY_BEGIN
- CInFileStream *inFile = new CInFileStream;
- CMyComPtr<ISequentialInStream> inStreamTemp = inFile;
- if (!inFile->Open(_srcDirectoryPrefix + name))
- return ::GetLastError();
- *inStream = inStreamTemp.Detach();
+ if (_folderArchiveExtractCallback2)
+ {
+ bool isEncrypted = false;
+ wchar_t temp[16];
+ UString s2;
+ const wchar_t *s = NULL;
+
+ if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1)
+ {
+ CReadArcItem item;
+ RINOK(_arc->GetItem(index, item));
+ s2 = item.Path;
+ s = s2;
+ RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted));
+ }
+ else
+ {
+ temp[0] = '#';
+ ConvertUInt32ToString(index, temp + 1);
+ s = temp;
+ // if (indexType == NArchive::NEventIndexType::kBlockIndex) {}
+ }
+
+ return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s);
+ }
+
return S_OK;
- COM_TRY_END
}
-*/
+
STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
{
@@ -482,3 +1564,73 @@ STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
return _cryptoGetTextPassword->CryptoGetTextPassword(password);
COM_TRY_END
}
+
+
+struct CExtrRefSortPair
+{
+ unsigned Len;
+ unsigned Index;
+
+ int Compare(const CExtrRefSortPair &a) const;
+};
+
+#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+
+int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const
+{
+ RINOZ(-MyCompare(Len, a.Len));
+ return MyCompare(Index, a.Index);
+}
+
+static unsigned GetNumSlashes(const FChar *s)
+{
+ for (unsigned numSlashes = 0;;)
+ {
+ FChar c = *s++;
+ if (c == 0)
+ return numSlashes;
+ if (IS_PATH_SEPAR(c))
+ numSlashes++;
+ }
+}
+
+HRESULT CArchiveExtractCallback::SetDirsTimes()
+{
+ CRecordVector<CExtrRefSortPair> pairs;
+ pairs.ClearAndSetSize(_extractedFolderPaths.Size());
+ unsigned i;
+
+ for (i = 0; i < _extractedFolderPaths.Size(); i++)
+ {
+ CExtrRefSortPair &pair = pairs[i];
+ pair.Index = i;
+ pair.Len = GetNumSlashes(_extractedFolderPaths[i]);
+ }
+
+ pairs.Sort2();
+
+ for (i = 0; i < pairs.Size(); i++)
+ {
+ int pairIndex = pairs[i].Index;
+ int index = _extractedFolderIndices[pairIndex];
+
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+
+ RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined));
+ RINOK(GetTime(index, kpidATime, ATime, ATimeDefined));
+ RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined));
+
+ // printf("\n%S", _extractedFolderPaths[pairIndex]);
+ SetDirTime(_extractedFolderPaths[pairIndex],
+ (WriteCTime && CTimeDefined) ? &CTime : NULL,
+ (WriteATime && ATimeDefined) ? &ATime : NULL,
+ (WriteMTime && MTimeDefined) ? &MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
+ }
+ return S_OK;
+}