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.cpp2293
1 files changed, 1625 insertions, 668 deletions
diff --git a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index bc116c93d66..4b0cbedad31 100644
--- a/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/3rdparty/lzma/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -5,11 +5,17 @@
#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/UTFConvert.h"
#include "../../../Common/Wildcard.h"
#include "../../../Windows/ErrorMsg.h"
@@ -19,13 +25,13 @@
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/PropVariantConv.h"
-#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
-#define _USE_SECURITY_CODE
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+#define Z7_USE_SECURITY_CODE
#include "../../../Windows/SecurityUtils.h"
#endif
#include "../../Common/FilePathAutoRename.h"
-// #include "../../Common/StreamUtils.h"
+#include "../../Common/StreamUtils.h"
#include "../Common/ExtractingFilePath.h"
#include "../Common/PropIDUtils.h"
@@ -36,15 +42,21 @@ 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";
-
+static const char * const kCantAutoRename = "Cannot create file with auto name";
+static const char * const kCantRenameFile = "Cannot rename existing file";
+static const char * const kCantDeleteOutputFile = "Cannot delete output file";
+static const char * const kCantDeleteOutputDir = "Cannot delete output folder";
+static const char * const kCantOpenOutFile = "Cannot open output file";
+static const char * const kCantOpenInFile = "Cannot open input file";
+static const char * const kCantSetFileLen = "Cannot set length for output file";
+#ifdef SUPPORT_LINKS
+static const char * const kCantCreateHardLink = "Cannot create hard link";
+static const char * const kCantCreateSymLink = "Cannot create symbolic link";
+#endif
-#ifndef _SFX
+#ifndef Z7_SFX
-STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)
+Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
{
HRESULT result = S_OK;
if (_stream)
@@ -57,9 +69,11 @@ STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *pr
return result;
}
-#endif
+#endif // Z7_SFX
-#ifdef _USE_SECURITY_CODE
+
+#ifdef Z7_USE_SECURITY_CODE
+bool InitLocalPrivileges();
bool InitLocalPrivileges()
{
NSecurity::CAccessToken token;
@@ -78,8 +92,86 @@ bool InitLocalPrivileges()
return false;
return (GetLastError() == ERROR_SUCCESS);
}
+#endif // Z7_USE_SECURITY_CODE
+
+
+
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+
+static const char * const kOfficeExtensions =
+ " doc dot wbk"
+ " docx docm dotx dotm docb wll wwl"
+ " xls xlt xlm"
+ " xlsx xlsm xltx xltm xlsb xla xlam"
+ " ppt pot pps ppa ppam"
+ " pptx pptm potx potm ppam ppsx ppsm sldx sldm"
+ " ";
+
+static bool FindExt2(const char *p, const UString &name)
+{
+ const int pathPos = name.ReverseFind_PathSepar();
+ const int dotPos = name.ReverseFind_Dot();
+ if (dotPos < 0
+ || dotPos < pathPos
+ || dotPos == (int)name.Len() - 1)
+ return false;
+
+ AString s;
+ for (unsigned pos = (unsigned)(dotPos + 1);; pos++)
+ {
+ const wchar_t c = name[pos];
+ if (c <= 0)
+ break;
+ if (c >= 0x80)
+ return false;
+ s += (char)MyCharLower_Ascii((char)c);
+ }
+ for (unsigned i = 0; p[i] != 0;)
+ {
+ unsigned j;
+ for (j = i; p[j] != ' '; j++);
+ if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0)
+ return true;
+ i = j + 1;
+ }
+ return false;
+}
+
+
+static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
+
+void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf)
+{
+ FString fileName (fileName2);
+ fileName += k_ZoneId_StreamName;
+
+ buf.Free();
+ NIO::CInFile file;
+ if (!file.Open(fileName))
+ return;
+ UInt64 fileSize;
+ if (!file.GetLength(fileSize))
+ return;
+ if (fileSize == 0 || fileSize >= ((UInt32)1 << 16))
+ return;
+ buf.Alloc((size_t)fileSize);
+ size_t processed;
+ if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize)
+ return;
+ buf.Free();
+}
+
+static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
+{
+ NIO::COutFile file;
+ if (!file.Create(fileName, true))
+ return false;
+ return file.WriteFull(buf, buf.Size());
+}
+
#endif
+
#ifdef SUPPORT_LINKS
int CHardLinkNode::Compare(const CHardLinkNode &a) const
@@ -96,13 +188,13 @@ static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHard
defined = false;
{
NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidINode, &prop));
+ RINOK(archive->GetProperty(index, kpidINode, &prop))
if (!ConvertPropVariantToUInt64(prop, h.INode))
return S_OK;
}
{
NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidStreamId, &prop));
+ RINOK(archive->GetProperty(index, kpidStreamId, &prop))
ConvertPropVariantToUInt64(prop, h.StreamId);
}
defined = true;
@@ -126,22 +218,27 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
numItems = realIndices->Size();
else
{
- RINOK(archive->GetNumberOfItems(&numItems));
+ RINOK(archive->GetNumberOfItems(&numItems))
}
for (UInt32 i = 0; i < numItems; i++)
{
CHardLinkNode h;
bool defined;
- UInt32 realIndex = realIndices ? (*realIndices)[i] : i;
+ const UInt32 realIndex = realIndices ? (*realIndices)[i] : i;
- RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined));
+ RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined))
if (defined)
{
bool isAltStream = false;
- RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream));
+ RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream))
if (!isAltStream)
- hardIDs.Add(h);
+ {
+ bool isDir = false;
+ RINOK(Archive_IsItem_Dir(archive, realIndex, isDir))
+ if (!isDir)
+ hardIDs.Add(h);
+ }
}
}
}
@@ -149,7 +246,7 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
hardIDs.Sort2();
{
- // wee keep only items that have 2 or more items
+ // we keep only items that have 2 or more items
unsigned k = 0;
unsigned numSame = 1;
for (unsigned i = 1; i < hardIDs.Size(); i++)
@@ -170,22 +267,32 @@ HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *r
return S_OK;
}
-#endif
+#endif // SUPPORT_LINKS
+
CArchiveExtractCallback::CArchiveExtractCallback():
- WriteCTime(true),
- WriteATime(true),
- WriteMTime(true),
+ _arc(NULL),
+ Write_CTime(true),
+ Write_ATime(true),
+ Write_MTime(true),
_multiArchives(false)
{
LocalProgressSpec = new CLocalProgress();
_localProgress = LocalProgressSpec;
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
_saclEnabled = InitLocalPrivileges();
#endif
}
+
+void CArchiveExtractCallback::InitBeforeNewArchive()
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ ZoneBuf.Free();
+ #endif
+}
+
void CArchiveExtractCallback::Init(
const CExtractNtOptions &ntOptions,
const NWildcard::CCensorNode *wildcardCensor,
@@ -196,8 +303,9 @@ void CArchiveExtractCallback::Init(
const UStringVector &removePathParts, bool removePartsForAltStreams,
UInt64 packSize)
{
- _extractedFolderPaths.Clear();
- _extractedFolderIndices.Clear();
+ ClearExtractedDirsInfo();
+ _outFileStream.Release();
+ _bufPtrSeqOutStream.Release();
#ifdef SUPPORT_LINKS
_hardLinks.Clear();
@@ -221,13 +329,21 @@ void CArchiveExtractCallback::Init(
_progressTotal_Defined = true;
_extractCallback2 = extractCallback2;
+
+ /*
_compressProgress.Release();
_extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
- _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage);
+
+ _callbackMessage.Release();
+ _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage);
+ */
+
+ _folderArchiveExtractCallback2.Release();
_extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
- #ifndef _SFX
+ #ifndef Z7_SFX
+ ExtractToStreamCallback.Release();
_extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);
if (ExtractToStreamCallback)
{
@@ -246,7 +362,7 @@ void CArchiveExtractCallback::Init(
_removePathParts = removePathParts;
_removePartsForAltStreams = removePartsForAltStreams;
- #ifndef _SFX
+ #ifndef Z7_SFX
_baseParentFolder = (UInt32)(Int32)-1;
_use_baseParentFolder_mode = false;
#endif
@@ -264,7 +380,8 @@ void CArchiveExtractCallback::Init(
}
}
-STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size))
{
COM_TRY_BEGIN
_progressTotal = size;
@@ -275,6 +392,7 @@ STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
COM_TRY_END
}
+
static void NormalizeVals(UInt64 &v1, UInt64 &v2)
{
const UInt64 kMax = (UInt64)1 << 31;
@@ -285,6 +403,7 @@ static void NormalizeVals(UInt64 &v1, UInt64 &v2)
}
}
+
static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
{
NormalizeVals(packTotal, unpTotal);
@@ -294,7 +413,8 @@ static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
return unpCur * packTotal / unpTotal;
}
-STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
{
COM_TRY_BEGIN
@@ -314,15 +434,19 @@ STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
COM_TRY_END
}
-STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+
+Z7_COM7F_IMF(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)
{
+ // we use (_item.IsDir) in this function
+
bool isAbsPath = false;
if (!dirPathParts.IsEmpty())
@@ -350,45 +474,72 @@ void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPat
fullPath.Add_PathSepar();
const UString &s = dirPathParts[i];
fullPath += us2fs(s);
+
+ const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir);
+
+ if (fullPath.IsEmpty())
+ {
+ if (isFinalDir)
+ _itemFailure = true;
+ continue;
+ }
+
#if defined(_WIN32) && !defined(UNDER_CE)
if (_pathMode == NExtract::NPathMode::kAbsPaths)
if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))
+ {
+ if (isFinalDir)
+ {
+ // we don't want to call SetAttrib() for root drive path
+ _itemFailure = true;
+ }
continue;
+ }
#endif
+
+ // bool res =
CreateDir(fullPath);
+ // if (!res)
+ if (isFinalDir)
+ {
+ if (!NFile::NFind::DoesDirExist(fullPath))
+ {
+ _itemFailure = true;
+ SendMessageError("Cannot create folder", fullPath);
+ // SendMessageError_with_LastError()
+ }
+ }
}
}
-HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+
+HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft)
{
- filetimeIsDefined = false;
+ ft.Clear();
NCOM::CPropVariant prop;
- RINOK(_arc->Archive->GetProperty(index, propID, &prop));
+ RINOK(_arc->Archive->GetProperty(index, propID, &prop))
if (prop.vt == VT_FILETIME)
- {
- filetime = prop.filetime;
- filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
- }
+ ft.Set_From_Prop(prop);
else if (prop.vt != VT_EMPTY)
return E_FAIL;
return S_OK;
}
+
HRESULT CArchiveExtractCallback::GetUnpackSize()
{
- return _arc->GetItemSize(_index, _curSize, _curSizeDefined);
+ return _arc->GetItem_Size(_index, _curSize, _curSize_Defined);
}
static void AddPathToMessage(UString &s, const FString &path)
{
- s.AddAscii(" : ");
+ s += " : ";
s += fs2us(path);
}
HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)
{
- UString s;
- s.AddAscii(message);
+ UString s (message);
AddPathToMessage(s, path);
return _extractCallback2->MessageError(s);
}
@@ -396,29 +547,33 @@ HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FSt
HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)
{
DWORD errorCode = GetLastError();
- UString s;
- s.AddAscii(message);
- if (errorCode != 0)
+ if (errorCode == 0)
+ errorCode = (DWORD)E_FAIL;
+ UString s (message);
{
- s.AddAscii(" : ");
+ s += " : ";
s += NError::MyFormatMessage(errorCode);
}
AddPathToMessage(s, path);
return _extractCallback2->MessageError(s);
}
-HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2)
+HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2)
{
- UString s;
- s.AddAscii(message);
+ UString s (message);
+ if (errorCode != 0)
+ {
+ s += " : ";
+ s += NError::MyFormatMessage(errorCode);
+ }
AddPathToMessage(s, path1);
AddPathToMessage(s, path2);
return _extractCallback2->MessageError(s);
}
-#ifndef _SFX
+#ifndef Z7_SFX
-STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value)
+Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
{
/*
if (propID == kpidName)
@@ -433,35 +588,45 @@ STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value)
return Arc->Archive->GetProperty(IndexInArc, propID, value);
}
-#endif
+#endif // Z7_SFX
#ifdef SUPPORT_LINKS
static UString GetDirPrefixOf(const UString &src)
{
- UString s = src;
+ UString s (src);
if (!s.IsEmpty())
{
if (IsPathSepar(s.Back()))
s.DeleteBack();
int pos = s.ReverseFind_PathSepar();
- s.DeleteFrom(pos + 1);
+ s.DeleteFrom((unsigned)(pos + 1));
}
return s;
}
-#endif
+#endif // SUPPORT_LINKS
+struct CLinkLevelsInfo
+{
+ bool IsAbsolute;
+ int LowLevel;
+ int FinalLevel;
-bool IsSafePath(const UString &path)
+ void Parse(const UString &path);
+};
+
+void CLinkLevelsInfo::Parse(const UString &path)
{
- if (NName::IsAbsolutePath(path))
- return false;
+ IsAbsolute = NName::IsAbsolutePath(path);
+
+ LowLevel = 0;
+ FinalLevel = 0;
UStringVector parts;
SplitPathToParts(path, parts);
- unsigned level = 0;
+ int level = 0;
FOR_VECTOR (i, parts)
{
@@ -469,29 +634,42 @@ bool IsSafePath(const UString &path)
if (s.IsEmpty())
{
if (i == 0)
- return false;
+ IsAbsolute = true;
continue;
}
if (s == L".")
continue;
if (s == L"..")
{
- if (level == 0)
- return false;
level--;
+ if (LowLevel > level)
+ LowLevel = level;
}
else
level++;
}
- return level > 0;
+ FinalLevel = level;
+}
+
+
+bool IsSafePath(const UString &path);
+bool IsSafePath(const UString &path)
+{
+ CLinkLevelsInfo levelsInfo;
+ levelsInfo.Parse(path);
+ return !levelsInfo.IsAbsolute
+ && levelsInfo.LowLevel >= 0
+ && levelsInfo.FinalLevel > 0;
}
+bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
{
bool found = false;
-
+
+ // CheckPathVect() doesn't check path to Parent nodes
if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include))
{
if (!include)
@@ -514,7 +692,7 @@ bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcIte
if (pathParts2.IsEmpty())
pathParts2.AddNew();
UString &back = pathParts2.Back();
- back += L':';
+ back += ':';
back += item.AltStreamName;
bool include2;
@@ -526,11 +704,12 @@ bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcIte
return true;
}
- #endif
+ #endif // SUPPORT_ALT_STREAMS
return found;
}
+
bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item)
{
bool include;
@@ -539,9 +718,10 @@ bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem
return false;
}
+
static FString MakePath_from_2_Parts(const FString &prefix, const FString &path)
{
- FString s = prefix;
+ FString s (prefix);
#if defined(_WIN32) && !defined(UNDER_CE)
if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back()))
{
@@ -554,9 +734,10 @@ static FString MakePath_from_2_Parts(const FString &prefix, const FString &path)
}
-/*
+
#ifdef SUPPORT_LINKS
+/*
struct CTempMidBuffer
{
void *Buf;
@@ -575,15 +756,15 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
NIO::CInFile inFile;
NIO::COutFile outFile;
- if (!inFile.Open(_CopyFile_Path))
- return SendMessageError_with_LastError("Open error", _CopyFile_Path);
+ 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);
+ return SendMessageError_with_LastError("Read error", _copyFile_Path);
if (num == 0)
return S_OK;
@@ -592,88 +773,24 @@ HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
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;
- _index = index;
-
- _diskFilePath.Empty();
-
- // _fi.Clear();
-
- #ifdef SUPPORT_LINKS
- // _CopyFile_Path.Empty();
- linkPath.Empty();
- #endif
+HRESULT CArchiveExtractCallback::ReadLink()
+{
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));
+ const UInt32 index = _index;
+ _link.Clear();
{
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));
+ 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);
+ _link.isHardLink = true;
+ // _link.isCopyLink = false;
+ _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
+ _link.linkPath.SetFromBstr(prop.bstrVal);
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
@@ -685,10 +802,10 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
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);
+ _link.isHardLink = false;
+ _link.isCopyLink = true;
+ _link.isRelative = false; // RAR5: copy links are from root folder of archive
+ _link.linkPath.SetFromBstr(prop.bstrVal);
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
@@ -697,22 +814,22 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
{
NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidSymLink, &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);
+ _link.isHardLink = false;
+ // _link.isCopyLink = false;
+ _link.isRelative = true; // RAR5, TAR: symbolic links can be relative
+ _link.linkPath.SetFromBstr(prop.bstrVal);
}
else if (prop.vt != VT_EMPTY)
return E_FAIL;
}
+ NtReparse_Data = NULL;
+ NtReparse_Size = 0;
- bool isOkReparse = false;
-
- if (linkPath.IsEmpty() && _arc->GetRawProps)
+ if (_link.linkPath.IsEmpty() && _arc->GetRawProps)
{
const void *data;
UInt32 dataSize;
@@ -720,55 +837,79 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
_arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);
+ // if (dataSize == 1234567) // for debug: unpacking without reparse
if (dataSize != 0)
{
if (propType != NPropDataType::kRaw)
return E_FAIL;
- UString s;
+
+ // 21.06: we need kpidNtReparse in linux for wim archives created in Windows
+ // #ifdef _WIN32
+
+ NtReparse_Data = data;
+ NtReparse_Size = dataSize;
+
CReparseAttr reparse;
- isOkReparse = reparse.Parse((const Byte *)data, dataSize);
+ bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
if (isOkReparse)
{
- isHardLink = false;
- // isCopyLink = false;
- linkPath = reparse.GetPath();
- isJunction = reparse.IsMountPoint();
- isRelative = reparse.IsRelative();
+ _link.isHardLink = false;
+ // _link.isCopyLink = false;
+ _link.linkPath = reparse.GetPath();
+ _link.isJunction = reparse.IsMountPoint();
+
+ if (reparse.IsSymLink_WSL())
+ {
+ _link.isWSL = true;
+ _link.isRelative = reparse.IsRelative_WSL();
+ }
+ else
+ _link.isRelative = reparse.IsRelative_Win();
+
+ // const AString s = GetAnsiString(_link.linkPath);
+ // printf("\n_link.linkPath: %s\n", s.Ptr());
+
#ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
#endif
}
+ // #endif
}
}
- if (!linkPath.IsEmpty())
+ if (_link.linkPath.IsEmpty())
+ return S_OK;
+
{
#ifdef _WIN32
- linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);
#endif
// rar5 uses "\??\" prefix for absolute links
- if (linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
+ if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
{
- isRelative = false;
- linkPath.DeleteFrontal(4);
+ _link.isRelative = false;
+ _link.linkPath.DeleteFrontal(4);
}
for (;;)
// while (NName::IsAbsolutePath(linkPath))
{
- unsigned n = NName::GetRootPrefixSize(linkPath);
+ unsigned n = NName::GetRootPrefixSize(_link.linkPath);
if (n == 0)
break;
- isRelative = false;
- linkPath.DeleteFrontal(n);
+ _link.isRelative = false;
+ _link.linkPath.DeleteFrontal(n);
}
}
- if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0)
+ if (_link.linkPath.IsEmpty())
+ return S_OK;
+
+ if (!_link.isRelative && _removePathParts.Size() != 0)
{
UStringVector pathParts;
- SplitPathToParts(linkPath, pathParts);
+ SplitPathToParts(_link.linkPath, pathParts);
bool badPrefix = false;
FOR_VECTOR (i, _removePathParts)
{
@@ -780,23 +921,726 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
}
if (!badPrefix)
pathParts.DeleteFrontal(_removePathParts.Size());
- linkPath = MakePathFromParts(pathParts);
+ _link.linkPath = MakePathFromParts(pathParts);
+ }
+
+ /*
+ if (!_link.linkPath.IsEmpty())
+ {
+ printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
+ }
+ */
+
+ return S_OK;
+}
+
+#endif // SUPPORT_LINKS
+
+
+#ifndef _WIN32
+
+static HRESULT GetOwner(IInArchive *archive,
+ UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res)
+{
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, pidId, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ res.Id_Defined = true;
+ res.Id = prop.ulVal; // for debug
+ // res.Id++; // for debug
+ // if (pidId == kpidGroupId) res.Id += 7; // for debug
+ // res.Id = 0; // for debug
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, pidName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ ConvertUnicodeToUTF8(s, res.Name);
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ res.Id_Defined = true;
+ res.Id = prop.ulVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
}
+ return S_OK;
+}
+#endif
+
+
+HRESULT CArchiveExtractCallback::Read_fi_Props()
+{
+ IInArchive *archive = _arc->Archive;
+ const UInt32 index = _index;
+
+ _fi.Attrib_Defined = false;
+
+ #ifndef _WIN32
+ _fi.Owner.Clear();
+ _fi.Group.Clear();
+ #endif
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPosixAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ _fi.SetFromPosixAttrib(prop.ulVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ _fi.Attrib = prop.ulVal;
+ _fi.Attrib_Defined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ RINOK(GetTime(index, kpidCTime, _fi.CTime))
+ RINOK(GetTime(index, kpidATime, _fi.ATime))
+ RINOK(GetTime(index, kpidMTime, _fi.MTime))
+
+ #ifndef _WIN32
+ if (_ntOptions.ExtractOwner)
+ {
+ // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath);
+ GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner);
+ GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group);
+ }
+ #endif
+
+ return S_OK;
+}
+
+
+
+void CArchiveExtractCallback::CorrectPathParts()
+{
+ UStringVector &pathParts = _item.PathParts;
+
+ #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;
+ }
+ #ifdef _WIN32
+ else if (_pathMode == NExtract::NPathMode::kAbsPaths &&
+ NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())
+ pathParts.AddNew();
+ #endif
+
+ UString &name = pathParts.Back();
+ if (needColon)
+ name += (char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':');
+ name += s;
+ }
+
+ #endif // SUPPORT_ALT_STREAMS
+}
+
+
+void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt)
+{
+ pt.CTime_Defined = false;
+ pt.ATime_Defined = false;
+ pt.MTime_Defined = false;
+
+ if (Write_MTime)
+ {
+ if (_fi.MTime.Def)
+ {
+ _fi.MTime.Write_To_FiTime(pt.MTime);
+ pt.MTime_Defined = true;
+ }
+ else if (_arc->MTime.Def)
+ {
+ _arc->MTime.Write_To_FiTime(pt.MTime);
+ pt.MTime_Defined = true;
+ }
+ }
+
+ if (Write_CTime && _fi.CTime.Def)
+ {
+ _fi.CTime.Write_To_FiTime(pt.CTime);
+ pt.CTime_Defined = true;
+ }
+
+ if (Write_ATime && _fi.ATime.Def)
+ {
+ _fi.ATime.Write_To_FiTime(pt.ATime);
+ pt.ATime_Defined = true;
+ }
+}
+
+
+void CArchiveExtractCallback::CreateFolders()
+{
+ // 21.04 : we don't change original (_item.PathParts) here
+ UStringVector pathParts = _item.PathParts;
+
+ if (!pathParts.IsEmpty())
+ {
+ /* v23: if we extract symlink, and we know that it links to dir:
+ Linux: we don't create dir item (symlink_from_path) here.
+ Windows: SetReparseData() will create dir item, if it doesn't exist,
+ but if we create dir item here, it's not problem. */
+ if (!_item.IsDir
+ #ifdef SUPPORT_LINKS
+ #ifndef WIN32
+ || !_link.linkPath.IsEmpty()
+ #endif
+ #endif
+ )
+ pathParts.DeleteBack();
+ }
+
+ if (pathParts.IsEmpty())
+ return;
+
+ FString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+
+ if (!_item.IsDir)
+ return;
+
+ if (_itemFailure)
+ return;
+
+ CDirPathTime pt;
+ GetFiTimesCAM(pt);
+
+ if (pt.IsSomeTimeDefined())
+ {
+ pt.Path = fullPathNew;
+ pt.SetDirTime();
+ _extractedFolders.Add(pt);
+ }
+}
+
+
+
+/*
+ CheckExistFile(fullProcessedPath)
+ it can change: fullProcessedPath, _isRenamed, _overwriteMode
+ (needExit = true) means that we must exit GetStream() even for S_OK result.
+*/
+
+HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool &needExit)
+{
+ needExit = true; // it was set already before
+
+ NFind::CFileInfo fileInfo;
+
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ if (_overwriteMode == NExtract::NOverwriteMode::kSkip)
+ return S_OK;
+
+ if (_overwriteMode == NExtract::NOverwriteMode::kAsk)
+ {
+ const int slashPos = fullProcessedPath.ReverseFind_PathSepar();
+ const FString realFullProcessedPath = fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name;
+
+ /* (fileInfo) can be symbolic link.
+ we can show final file properties here. */
+
+ FILETIME ft1;
+ FiTime_To_FILETIME(fileInfo.MTime, ft1);
+
+ Int32 overwriteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path,
+ _fi.MTime.Def ? &_fi.MTime.FT : NULL,
+ _curSize_Defined ? &_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;
+ }
+ } // NExtract::NOverwriteMode::kAsk
+
+ 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 rename folders. So it's OK to use it for folders too
+ if (!MyMoveFile(fullProcessedPath, existPath))
+ {
+ HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
+ return E_FAIL;
+ }
+ }
+ else // not Rename*
+ {
+ 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 // fileInfo is not Dir
+ {
+ if (NFind::DoesFileExist_Raw(fullProcessedPath))
+ if (!DeleteFileAlways(fullProcessedPath))
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) // check it in linux
+ {
+ RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath))
+ return S_OK;
+ // return E_FAIL;
+ }
+ } // fileInfo is not Dir
+ } // not Rename*
+ }
+ else // not Find(fullProcessedPath)
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // we need to clear READ-ONLY of parent before creating alt stream
+ int colonPos = NName::FindAltStreamColon(fullProcessedPath);
+ if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)
+ {
+ FString parentFsPath (fullProcessedPath);
+ parentFsPath.DeleteFrom((unsigned)colonPos);
+ NFind::CFileInfo parentFi;
+ if (parentFi.Find(parentFsPath))
+ {
+ if (parentFi.IsReadOnly())
+ SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY);
+ }
+ }
+ #endif // defined(_WIN32) && !defined(UNDER_CE)
+ }
- RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted));
+ needExit = false;
+ return S_OK;
+}
+
+
+
+
+
+
+HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit)
+{
+ needExit = true;
+
+ RINOK(Read_fi_Props())
+
+ #ifdef SUPPORT_LINKS
+ IInArchive *archive = _arc->Archive;
+ #endif
+
+ const UInt32 index = _index;
- RINOK(GetUnpackSize());
+ bool isAnti = false;
+ RINOK(_arc->IsItem_Anti(index, isAnti))
+
+ CorrectPathParts();
+ UString processedPath (MakePathFromParts(_item.PathParts));
+
+ if (!isAnti)
+ {
+ // 21.04: CreateFolders doesn't change (_item.PathParts)
+ CreateFolders();
+ }
+
+ 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)
+ {
+ const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));
+ if (renIndex != -1)
+ {
+ const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex];
+ fullProcessedPath = pair.Path;
+ fullProcessedPath += ':';
+ UString s (_item.AltStreamName);
+ Correct_AltStream_Name(s);
+ fullProcessedPath += us2fs(s);
+ }
+ }
+ #endif // SUPPORT_ALT_STREAMS
+
+ if (_item.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ RemoveDir(_diskFilePath);
+ #ifdef SUPPORT_LINKS
+ if (_link.linkPath.IsEmpty())
+ #endif
+ {
+ if (!isAnti)
+ SetAttrib();
+ return S_OK;
+ }
+ }
+ else if (!_isSplit)
+ {
+ RINOK(CheckExistFile(fullProcessedPath, needExit))
+ if (needExit)
+ return S_OK;
+ needExit = true;
+ }
- if (!_ntOptions.AltStreams.Val && _item.IsAltStream)
+ _diskFilePath = fullProcessedPath;
+
+
+ if (isAnti)
+ {
+ needExit = false;
return S_OK;
+ }
+
+ // not anti
+
+ #ifdef SUPPORT_LINKS
+
+ if (!_link.linkPath.IsEmpty())
+ {
+ #ifndef UNDER_CE
+ {
+ bool linkWasSet = false;
+ RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet))
+ if (linkWasSet)
+ {
+ _isSymLinkCreated = _link.IsSymLink();
+ SetAttrib();
+ // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
+ }
+ }
+ #endif // UNDER_CE
+
+ // if (_copyFile_Path.IsEmpty())
+ {
+ needExit = false;
+ return S_OK;
+ }
+ }
+
+ if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream && !_item.IsDir)
+ {
+ CHardLinkNode h;
+ bool defined;
+ RINOK(Archive_Get_HardLinkNode(archive, index, h, defined))
+ if (defined)
+ {
+ const int linkIndex = _hardLinks.IDs.FindInSorted2(h);
+ if (linkIndex != -1)
+ {
+ FString &hl = _hardLinks.Links[(unsigned)linkIndex];
+ if (hl.IsEmpty())
+ hl = fullProcessedPath;
+ else
+ {
+ if (!MyCreateHardLink(fullProcessedPath, hl))
+ {
+ HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
+ return S_OK;
+ }
+
+ // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
+ // _needSetAttrib = true; // do we need to set attribute ?
+ SetAttrib();
+ needExit = false;
+ return S_OK;
+ }
+ }
+ }
+ }
+
+ #endif // SUPPORT_LINKS
+
+
+ // ---------- CREATE WRITE FILE -----
+
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<IOutStream> outFileStream_Loc(_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;
+ }
+ }
+
+ _needSetAttrib = true;
+ bool is_SymLink_in_Data = false;
+
+ if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12))
+ {
+ if (_fi.IsLinuxSymLink())
+ {
+ is_SymLink_in_Data = true;
+ _is_SymLink_in_Data_Linux = true;
+ }
+ else if (_fi.IsReparse())
+ {
+ is_SymLink_in_Data = true;
+ _is_SymLink_in_Data_Linux = false;
+ }
+ }
+
+ if (is_SymLink_in_Data)
+ {
+ _outMemBuf.Alloc((size_t)_curSize);
+ _bufPtrSeqOutStream_Spec = new CBufPtrSeqOutStream;
+ _bufPtrSeqOutStream = _bufPtrSeqOutStream_Spec;
+ _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
+ outStreamLoc = _bufPtrSeqOutStream;
+ }
+ else // not reprase
+ {
+ if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
+ {
+ // UInt64 ticks = GetCpuTicks();
+ _fileLength_that_WasSet = _curSize;
+ bool res = _outFileStreamSpec->File.SetLength(_curSize);
+ _fileLength_WasSet = res;
+
+ // ticks = GetCpuTicks() - ticks;
+ // printf("\nticks = %10d\n", (unsigned)ticks);
+ if (!res)
+ {
+ RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath))
+ }
+
+ /*
+ _outFileStreamSpec->File.Close();
+ ticks = GetCpuTicks() - ticks;
+ printf("\nticks = %10d\n", (unsigned)ticks);
+ return S_FALSE;
+ */
+
+ /*
+ File.SetLength() on FAT (xp64): is fast, but then File.Close() can be slow,
+ if we don't write any data.
+ File.SetLength() for remote share file (exFAT) can be slow in some cases,
+ and the Windows can return "network error" after 1 minute,
+ while remote file still can grow.
+ We need some way to detect such bad cases and disable PreAllocateOutFile mode.
+ */
+
+ res = _outFileStreamSpec->SeekToBegin_bool();
+ if (!res)
+ {
+ RINOK(SendMessageError_with_LastError("Cannot seek to begin of file", fullProcessedPath))
+ }
+ } // PreAllocateOutFile
+
+ #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 // SUPPORT_ALT_STREAMS
+
+ if (_isSplit)
+ {
+ RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
+ }
+ outStreamLoc = outFileStream_Loc;
+ } // if not reprase
+
+ _outFileStream = outFileStream_Loc;
+
+ needExit = false;
+ return S_OK;
+}
+
+
+
+HRESULT CArchiveExtractCallback::GetItem(UInt32 index)
+{
+ #ifndef Z7_SFX
+ _item._use_baseParentFolder_mode = _use_baseParentFolder_mode;
+ if (_use_baseParentFolder_mode)
+ {
+ _item._baseParentFolder = (int)_baseParentFolder;
+ if (_pathMode == NExtract::NPathMode::kFullPaths ||
+ _pathMode == NExtract::NPathMode::kAbsPaths)
+ _item._baseParentFolder = -1;
+ }
+ #endif // Z7_SFX
+
+ #ifdef SUPPORT_ALT_STREAMS
+ _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon;
#endif
+ return _arc->GetItem(index, _item);
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode))
+{
+ COM_TRY_BEGIN
+
+ *outStream = NULL;
+
+ #ifndef Z7_SFX
+ if (_hashStream)
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ #endif
+ _outFileStream.Release();
+ _bufPtrSeqOutStream.Release();
+
+ _encrypted = false;
+ _position = 0;
+ _isSplit = false;
+
+ _curSize = 0;
+ _curSize_Defined = false;
+ _fileLength_WasSet = false;
+ _fileLength_that_WasSet = 0;
+ _index = index;
+
+ _diskFilePath.Empty();
+
+ _isRenamed = false;
+
+ // _fi.Clear();
+
+ // _is_SymLink_in_Data = false;
+ _is_SymLink_in_Data_Linux = false;
+
+ _needSetAttrib = false;
+ _isSymLinkCreated = false;
+ _itemFailure = false;
+
+ #ifdef SUPPORT_LINKS
+ // _copyFile_Path.Empty();
+ _link.Clear();
+ #endif
+
+ _extractMode = false;
+
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ {
+ // askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ }
+ else
+ _extractMode = true;
+ break;
+ }
+
+
+ IInArchive *archive = _arc->Archive;
+
+ RINOK(GetItem(index))
+
+ {
+ 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
+ RINOK(ReadLink())
+ #endif // SUPPORT_LINKS
+
+
+ RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
+
+ RINOK(GetUnpackSize())
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_ntOptions.AltStreams.Val && _item.IsAltStream)
+ return S_OK;
+ #endif // SUPPORT_ALT_STREAMS
+
+ // we can change (_item.PathParts) in this function
UStringVector &pathParts = _item.PathParts;
if (_wildcardCensor)
@@ -805,7 +1649,7 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
return S_OK;
}
- #ifndef _SFX
+ #ifndef Z7_SFX
if (_use_baseParentFolder_mode)
{
if (!pathParts.IsEmpty())
@@ -824,7 +1668,7 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
}
}
else
- #endif
+ #endif // Z7_SFX
{
if (pathParts.IsEmpty())
{
@@ -907,17 +1751,16 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
numRemovePathParts = pathParts.Size() - 1;
break;
}
- /*
- case NExtract::NPathMode::kFullPaths:
case NExtract::NPathMode::kAbsPaths:
+ // default:
break;
- */
}
pathParts.DeleteFrontal(numRemovePathParts);
}
- #ifndef _SFX
+
+ #ifndef Z7_SFX
if (ExtractToStreamCallback)
{
@@ -928,13 +1771,13 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
}
GetProp_Spec->Arc = _arc;
GetProp_Spec->IndexInArc = index;
- UString name = MakePathFromParts(pathParts);
+ UString name (MakePathFromParts(pathParts));
#ifdef SUPPORT_ALT_STREAMS
if (_item.IsAltStream)
{
if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt))
- name += L':';
+ name += ':';
name += _item.AltStreamName;
}
#endif
@@ -942,500 +1785,531 @@ STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStre
return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);
}
- #endif
+ #endif // Z7_SFX
+
CMyComPtr<ISequentialOutStream> outStreamLoc;
-if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
-{
- if (_stdOutMode)
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
{
- outStreamLoc = new CStdOutFileStream;
+ if (_stdOutMode)
+ outStreamLoc = new CStdOutFileStream;
+ else
+ {
+ bool needExit = true;
+ RINOK(GetExtractStream(outStreamLoc, needExit))
+ if (needExit)
+ return S_OK;
+ }
}
- else
+
+ #ifndef Z7_SFX
+ if (_hashStream)
{
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
+ askExtractMode == NArchive::NExtract::NAskMode::kTest)
{
- 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;
+ _hashStreamSpec->SetStream(outStreamLoc);
+ outStreamLoc = _hashStream;
+ _hashStreamSpec->Init(true);
+ _hashStreamWasUsed = true;
}
+ }
+ #endif // Z7_SFX
- RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));
- RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));
- RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));
+ if (outStreamLoc)
+ {
+ /*
+ #ifdef SUPPORT_LINKS
+ if (!_copyFile_Path.IsEmpty())
+ {
+ RINOK(PrepareOperation(askExtractMode));
+ RINOK(MyCopyFile(outStreamLoc));
+ return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);
+ }
+ if (_link.isCopyLink && _testMode)
+ return S_OK;
+ #endif
+ */
+ *outStream = outStreamLoc.Detach();
+ }
+
+ return S_OK;
- bool isAnti = false;
- RINOK(_arc->IsItemAnti(index, isAnti));
+ COM_TRY_END
+}
- #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 (_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 += (wchar_t)(_ntOptions.ReplaceColonForAltStream ? L'_' : L':');
- 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)
- {
- _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 = us2fs(processedPath);
- if (_pathMode != NExtract::NPathMode::kAbsPaths
- || !NName::IsAbsolutePath(processedPath))
+
+
+
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
+{
+ COM_TRY_BEGIN
+
+ #ifndef Z7_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: NULL);
+
+ COM_TRY_END
+}
+
+
+
+
+
+HRESULT CArchiveExtractCallback::CloseFile()
+{
+ if (!_outFileStream)
+ return S_OK;
+
+ HRESULT hres = S_OK;
+
+ const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;
+ if (_fileLength_WasSet && _fileLength_that_WasSet > processedSize)
+ {
+ const bool res = _outFileStreamSpec->File.SetLength(processedSize);
+ _fileLength_WasSet = res;
+ if (!res)
{
- fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath);
+ const HRESULT hres2 = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));
+ if (hres == S_OK)
+ hres = hres2;
}
+ }
- #ifdef SUPPORT_ALT_STREAMS
-
- if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)
+ _curSize = processedSize;
+ _curSize_Defined = true;
+
+ #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+ if (ZoneBuf.Size() != 0
+ && !_item.IsAltStream)
+ {
+ // if (NFind::DoesFileExist_Raw(tempFilePath))
+ if (ZoneMode != NExtract::NZoneIdMode::kOffice ||
+ FindExt2(kOfficeExtensions, fs2us(_diskFilePath)))
{
- int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));
- if (renIndex >= 0)
+ // we must write zone file before setting of timestamps
+ const FString path = _diskFilePath + k_ZoneId_StreamName;
+ if (!WriteZoneFile(path, ZoneBuf))
{
- const CIndexToPathPair &pair = _renamedFiles[renIndex];
- fullProcessedPath = pair.Path;
- fullProcessedPath += (FChar)':';
- UString s = _item.AltStreamName;
- Correct_AltStream_Name(s);
- fullProcessedPath += us2fs(s);
+ // we can't write it in FAT
+ // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path);
}
}
-
- #endif
+ }
+ #endif
- bool isRenamed = false;
+ CFiTimesCAM t;
+ GetFiTimesCAM(t);
- if (_item.IsDir)
+ // #ifdef _WIN32
+ if (t.IsSomeTimeDefined())
+ _outFileStreamSpec->SetTime(
+ t.CTime_Defined ? &t.CTime : NULL,
+ t.ATime_Defined ? &t.ATime : NULL,
+ t.MTime_Defined ? &t.MTime : NULL);
+ // #endif
+
+ RINOK(_outFileStreamSpec->Close())
+ _outFileStream.Release();
+ return hres;
+}
+
+
+#ifdef SUPPORT_LINKS
+
+
+HRESULT CArchiveExtractCallback::SetFromLinkPath(
+ const FString &fullProcessedPath,
+ const CLinkInfo &linkInfo,
+ bool &linkWasSet)
+{
+ linkWasSet = false;
+ if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink)
+ return S_OK;
+
+ UString relatPath;
+
+ /* if (linkInfo.isRelative)
+ linkInfo.linkPath is final link path that must be stored to file link field
+ else
+ linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath.
+ */
+
+ if (linkInfo.isRelative)
+ relatPath = GetDirPrefixOf(_item.Path);
+ relatPath += linkInfo.linkPath;
+
+ if (!IsSafePath(relatPath))
+ {
+ return SendMessageError2(
+ 0, // errorCode
+ "Dangerous link path was ignored",
+ us2fs(_item.Path),
+ us2fs(linkInfo.linkPath)); // us2fs(relatPath)
+ }
+
+ FString existPath;
+ if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative)
+ {
+ if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))
{
- _diskFilePath = fullProcessedPath;
- if (isAnti)
- RemoveDir(_diskFilePath);
- #ifdef SUPPORT_LINKS
- if (linkPath.IsEmpty())
- #endif
- return S_OK;
+ RINOK(SendMessageError("Incorrect path", us2fs(relatPath)))
}
- else if (!_isSplit)
- {
+ }
+ else
+ {
+ existPath = us2fs(linkInfo.linkPath);
+ // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr());
+ }
- // ----- Is file (not split) -----
- NFind::CFileInfo fileInfo;
- if (fileInfo.Find(fullProcessedPath))
+ if (existPath.IsEmpty())
+ return SendMessageError("Empty link", fullProcessedPath);
+
+ if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */)
+ {
+ // if (linkInfo.isHardLink)
{
- switch (_overwriteMode)
+ if (!MyCreateHardLink(fullProcessedPath, existPath))
{
- 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;
- }
- }
+ const HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
}
- if (_overwriteMode == NExtract::NOverwriteMode::kRename)
+ linkWasSet = true;
+ return S_OK;
+ }
+ /*
+ // IsCopyLink
+ {
+ NFind::CFileInfo fi;
+ if (!fi.Find(existPath))
{
- 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;
- }
+ RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath));
}
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;
- }
- }
+ if (_curSize_Defined && _curSize == fi.Size)
+ _copyFile_Path = existPath;
else
{
- bool needDelete = true;
- if (needDelete)
- {
- if (!DeleteFileAlways(fullProcessedPath))
- {
- RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath));
- return S_OK;
- // return E_FAIL;
- }
- }
+ RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));
}
+ // RINOK(MyCopyFile(existPath, fullProcessedPath));
}
}
- 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)
+ */
+ }
+
+ // is Symbolic link
+
+ /*
+ if (_item.IsDir && !isRelative)
+ {
+ // Windows before Vista doesn't support symbolic links.
+ // we could convert such symbolic links to Junction Points
+ // isJunction = true;
+ // convertToAbs = true;
+ }
+ */
+
+ if (!_ntOptions.SymLinks_AllowDangerous.Val)
+ {
+ #ifdef _WIN32
+ if (_item.IsDir)
+ #endif
+ if (linkInfo.isRelative)
{
- FString parentFsPath = fullProcessedPath;
- parentFsPath.DeleteFrom(colonPos);
- NFind::CFileInfo parentFi;
- if (parentFi.Find(parentFsPath))
+ CLinkLevelsInfo levelsInfo;
+ levelsInfo.Parse(linkInfo.linkPath);
+ if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute)
{
- if (parentFi.IsReadOnly())
- SetFileAttrib(parentFsPath, parentFi.Attrib & ~FILE_ATTRIBUTE_READONLY);
+ return SendMessageError2(
+ 0, // errorCode
+ "Dangerous symbolic link path was ignored",
+ us2fs(_item.Path),
+ us2fs(linkInfo.linkPath));
}
}
- #endif
- }
- // ----- END of code for Is file (not split) -----
+ }
- }
- _diskFilePath = fullProcessedPath;
-
+
+ #ifdef _WIN32
+
+ CByteBuffer data;
+ // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr());
+ if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL))
+ return SendMessageError("Cannot fill link data", us2fs(_item.Path));
- if (!isAnti)
- {
- #ifdef SUPPORT_LINKS
+ /*
+ if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
+ {
+ SendMessageError("reconstructed Reparse is different", fs2us(existPath));
+ }
+ */
+
+ CReparseAttr attr;
+ if (!attr.Parse(data, data.Size()))
+ {
+ RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)))
+ return S_OK;
+ }
+ if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))
+ {
+ RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
+ return S_OK;
+ }
+ linkWasSet = true;
- if (!linkPath.IsEmpty())
- {
- #ifndef UNDER_CE
+ return S_OK;
+
+
+ #else // ! _WIN32
- 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("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 (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("Can not create hard link", 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("Can not open output file", fullProcessedPath));
- return S_OK;
- }
- }
+ if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath))
+ {
+ RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
+ return S_OK;
+ }
+ linkWasSet = true;
+ 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
+ #endif // ! _WIN32
+}
- if (_isSplit)
- {
- RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
- }
-
- _outFileStream = outStreamLoc2;
- }
- }
- }
+
+bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
+{
+ Clear();
+ // this->isLinux = isLinuxData;
+
+ if (isLinuxData)
+ {
+ isJunction = false;
+ isHardLink = false;
+ AString utf;
+ if (dataSize >= (1 << 12))
+ return false;
+ utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
+ UString u;
+ if (!ConvertUTF8ToUnicode(utf, u))
+ return false;
+ linkPath = u;
- outStreamLoc = _outFileStream;
+ // in linux symbolic data: we expect that linux separator '/' is used
+ // if windows link was created, then we also must use linux separator
+ if (u.IsEmpty())
+ return false;
+ const wchar_t c = u[0];
+ isRelative = !IS_PATH_SEPAR(c);
+ return true;
}
+
+ CReparseAttr reparse;
+ if (!reparse.Parse(data, dataSize))
+ return false;
+ isHardLink = false;
+ // isCopyLink = false;
+ linkPath = reparse.GetPath();
+ isJunction = reparse.IsMountPoint();
+
+ if (reparse.IsSymLink_WSL())
+ {
+ isWSL = true;
+ isRelative = reparse.IsRelative_WSL();
+ }
+ else
+ isRelative = reparse.IsRelative_Win();
+
+ // FIXME !!!
+ #ifndef _WIN32
+ linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ return true;
}
+
+#endif // SUPPORT_LINKS
- #ifndef _SFX
- if (_hashStream)
+HRESULT CArchiveExtractCallback::CloseReparseAndFile()
+{
+ HRESULT res = S_OK;
+
+ #ifdef SUPPORT_LINKS
+
+ size_t reparseSize = 0;
+ bool repraseMode = false;
+ bool needSetReparse = false;
+ CLinkInfo linkInfo;
+
+ if (_bufPtrSeqOutStream)
{
- if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
- askExtractMode == NArchive::NExtract::NAskMode::kTest)
+ repraseMode = true;
+ reparseSize = _bufPtrSeqOutStream_Spec->GetPos();
+ if (_curSize_Defined && reparseSize == _outMemBuf.Size())
{
- _hashStreamSpec->SetStream(outStreamLoc);
- outStreamLoc = _hashStream;
- _hashStreamSpec->Init(true);
- _hashStreamWasUsed = true;
+ /*
+ CReparseAttr reparse;
+ DWORD errorCode = 0;
+ needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
+ if (needSetReparse)
+ {
+ UString linkPath = reparse.GetPath();
+ #ifndef _WIN32
+ linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ #endif
+ }
+ */
+ needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux);
+ if (!needSetReparse)
+ res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
+ }
+ else
+ {
+ res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path));
}
+ if (!needSetReparse && _outFileStream)
+ {
+ const HRESULT res2 = WriteStream(_outFileStream, _outMemBuf, reparseSize);
+ if (res == S_OK)
+ res = res2;
+ }
+ _bufPtrSeqOutStream.Release();
}
- #endif
+ #endif // SUPPORT_LINKS
-
- if (outStreamLoc)
+
+ const HRESULT res2 = CloseFile();
+
+ if (res == S_OK)
+ res = res2;
+
+ RINOK(res)
+
+ #ifdef SUPPORT_LINKS
+ if (repraseMode)
{
- /*
- #ifdef SUPPORT_LINKS
+ _curSize = reparseSize;
+ _curSize_Defined = true;
- if (!_CopyFile_Path.IsEmpty())
+ #ifdef SUPPORT_LINKS
+ if (needSetReparse)
{
- RINOK(PrepareOperation(askExtractMode));
- RINOK(MyCopyFile(outStreamLoc));
- return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);
+ // in Linux : we must delete empty file before symbolic link creation
+ // in Windows : we can create symbolic link even without file deleting
+ if (!DeleteFileAlways(_diskFilePath))
+ {
+ RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
+ }
+ {
+ /*
+ // for DEBUG ONLY: we can extract sym links as WSL links
+ // to eliminate (non-admin) errors for sym links.
+ #ifdef _WIN32
+ if (!linkInfo.isHardLink && !linkInfo.isJunction)
+ linkInfo.isWSL = true;
+ #endif
+ */
+ bool linkWasSet = false;
+ RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet))
+ if (linkWasSet)
+ _isSymLinkCreated = linkInfo.IsSymLink();
+ else
+ _needSetAttrib = false;
+ }
+ /*
+ if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
+ {
+ res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
+ }
+ */
}
-
- if (isCopyLink && _testMode)
- return S_OK;
-
#endif
- */
-
- *outStream = outStreamLoc.Detach();
}
-
- return S_OK;
-
- COM_TRY_END
+ #endif
+ return res;
}
-STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
+void CArchiveExtractCallback::SetAttrib()
{
- COM_TRY_BEGIN
+ #ifndef _WIN32
+ // Linux now doesn't support permissions for symlinks
+ if (_isSymLinkCreated)
+ return;
+ #endif
+
+ if (_itemFailure
+ || _diskFilePath.IsEmpty()
+ || _stdOutMode
+ || !_extractMode)
+ return;
+
+ #ifndef _WIN32
+ if (_fi.Owner.Id_Defined &&
+ _fi.Group.Id_Defined)
+ {
+ if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0)
+ {
+ SendMessageError_with_LastError("Cannot set owner", _diskFilePath);
+ }
+ }
+ #endif
- #ifndef _SFX
- if (ExtractToStreamCallback)
- return ExtractToStreamCallback->PrepareOperation7(askExtractMode);
- #endif
-
- _extractMode = false;
-
- switch (askExtractMode)
+ if (_fi.Attrib_Defined)
{
- 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
+ // const AString s = GetAnsiString(_diskFilePath);
+ // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib);
+ bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib);
+ if (!res)
+ {
+ // do we need error message here in Windows and in posix?
+ SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath);
+ }
+ }
}
-STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
+Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
{
COM_TRY_BEGIN
- #ifndef _SFX
+ // printf("\nCArchiveExtractCallback::SetOperationResult: %d %s\n", opRes, GetAnsiString(_diskFilePath));
+
+ #ifndef Z7_SFX
if (ExtractToStreamCallback)
- return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted));
+ {
+ GetUnpackSize();
+ return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize);
+ }
#endif
- #ifndef _SFX
+ #ifndef Z7_SFX
if (_hashStreamWasUsed)
{
@@ -1447,26 +2321,16 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
#endif
, _item.Path);
_curSize = _hashStreamSpec->GetSize();
- _curSizeDefined = true;
+ _curSize_Defined = true;
_hashStreamSpec->ReleaseStream();
_hashStreamWasUsed = false;
}
- #endif
+ #endif // Z7_SFX
- if (_outFileStream)
- {
- _outFileStreamSpec->SetTime(
- (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
- (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
- (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
- _curSize = _outFileStreamSpec->ProcessedSize;
- _curSizeDefined = true;
- RINOK(_outFileStreamSpec->Close());
- _outFileStream.Release();
- }
+ RINOK(CloseReparseAndFile())
- #ifdef _USE_SECURITY_CODE
+ #ifdef Z7_USE_SECURITY_CODE
if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
{
const void *data;
@@ -1482,16 +2346,16 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
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);
+ ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
}
}
}
- #endif
+ #endif // Z7_USE_SECURITY_CODE
- if (!_curSizeDefined)
+ if (!_curSize_Defined)
GetUnpackSize();
- if (_curSizeDefined)
+ if (_curSize_Defined)
{
#ifdef SUPPORT_ALT_STREAMS
if (_item.IsAltStream)
@@ -1510,38 +2374,36 @@ STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
else
NumFiles++;
- if (!_stdOutMode && _extractMode && _fi.AttribDefined)
- SetFileAttrib(_diskFilePath, _fi.Attrib);
+ if (_needSetAttrib)
+ SetAttrib();
- RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)));
+ RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)))
return S_OK;
COM_TRY_END
}
-STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
{
if (_folderArchiveExtractCallback2)
{
bool isEncrypted = false;
- wchar_t temp[16];
- UString s2;
- const wchar_t *s = NULL;
+ UString s;
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));
+ RINOK(_arc->GetItem(index, item))
+ s = item.Path;
+ RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted))
}
else
{
- temp[0] = '#';
- ConvertUInt32ToString(index, temp + 1);
- s = temp;
+ s = '#';
+ s.Add_UInt32(index);
// if (indexType == NArchive::NEventIndexType::kBlockIndex) {}
}
@@ -1552,84 +2414,179 @@ STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt
}
-STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
+Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
{
COM_TRY_BEGIN
if (!_cryptoGetTextPassword)
{
RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
- &_cryptoGetTextPassword));
+ &_cryptoGetTextPassword))
}
return _cryptoGetTextPassword->CryptoGetTextPassword(password);
COM_TRY_END
}
-struct CExtrRefSortPair
+// ---------- HASH functions ----------
+
+FString CArchiveExtractCallback::Hash_GetFullFilePath()
{
- unsigned Len;
- unsigned Index;
+ // this function changes _item.PathParts.
+ CorrectPathParts();
+ const UStringVector &pathParts = _item.PathParts;
+ const UString processedPath (MakePathFromParts(pathParts));
+ FString fullProcessedPath (us2fs(processedPath));
+ if (_pathMode != NExtract::NPathMode::kAbsPaths
+ || !NName::IsAbsolutePath(processedPath))
+ {
+ fullProcessedPath = MakePath_from_2_Parts(
+ DirPathPrefix_for_HashFiles,
+ // _dirPathPrefix,
+ fullProcessedPath);
+ }
+ return fullProcessedPath;
+}
- int Compare(const CExtrRefSortPair &a) const;
-};
-#define RINOZ(x) { int __tt = (x); if (__tt != 0) return __tt; }
+Z7_COM7F_IMF(CArchiveExtractCallback::GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (propID == kpidSize)
+ {
+ RINOK(GetItem(index))
+ const FString fullProcessedPath = Hash_GetFullFilePath();
+ NFile::NFind::CFileInfo fi;
+ if (fi.Find_FollowLink(fullProcessedPath))
+ if (!fi.IsDir())
+ prop = (UInt64)fi.Size;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode))
+{
+ COM_TRY_BEGIN
+ *inStream = NULL;
+ // if (index != _index) return E_FAIL;
+ if (mode != NUpdateNotifyOp::kHashRead)
+ return E_FAIL;
+
+ RINOK(GetItem(index))
+ const FString fullProcessedPath = Hash_GetFullFilePath();
+
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamRef = inStreamSpec;
+ inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime);
+ if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite))
+ {
+ RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath))
+ return S_OK;
+ }
+ *inStream = inStreamRef.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
-int CExtrRefSortPair::Compare(const CExtrRefSortPair &a) const
+Z7_COM7F_IMF(CArchiveExtractCallback::ReportOperation(
+ UInt32 /* indexType */, UInt32 /* index */, UInt32 /* op */))
{
- RINOZ(-MyCompare(Len, a.Len));
- return MyCompare(Index, a.Index);
+ // COM_TRY_BEGIN
+ return S_OK;
+ // COM_TRY_END
}
-static unsigned GetNumSlashes(const FChar *s)
+
+// ------------ After Extracting functions ------------
+
+void CDirPathSortPair::SetNumSlashes(const FChar *s)
{
for (unsigned numSlashes = 0;;)
{
FChar c = *s++;
if (c == 0)
- return numSlashes;
+ {
+ Len = numSlashes;
+ return;
+ }
if (IS_PATH_SEPAR(c))
numSlashes++;
}
}
+
+bool CDirPathTime::SetDirTime() const
+{
+ return NDir::SetDirTime(Path,
+ CTime_Defined ? &CTime : NULL,
+ ATime_Defined ? &ATime : NULL,
+ MTime_Defined ? &MTime : NULL);
+}
+
+
HRESULT CArchiveExtractCallback::SetDirsTimes()
{
- CRecordVector<CExtrRefSortPair> pairs;
- pairs.ClearAndSetSize(_extractedFolderPaths.Size());
+ if (!_arc)
+ return S_OK;
+
+ CRecordVector<CDirPathSortPair> pairs;
+ pairs.ClearAndSetSize(_extractedFolders.Size());
unsigned i;
- for (i = 0; i < _extractedFolderPaths.Size(); i++)
+ for (i = 0; i < _extractedFolders.Size(); i++)
{
- CExtrRefSortPair &pair = pairs[i];
+ CDirPathSortPair &pair = pairs[i];
pair.Index = i;
- pair.Len = GetNumSlashes(_extractedFolderPaths[i]);
+ pair.SetNumSlashes(_extractedFolders[i].Path);
}
pairs.Sort2();
+ HRESULT res = S_OK;
+
for (i = 0; i < pairs.Size(); i++)
{
- int pairIndex = pairs[i].Index;
- int index = _extractedFolderIndices[pairIndex];
+ const CDirPathTime &dpt = _extractedFolders[pairs[i].Index];
+ if (!dpt.SetDirTime())
+ {
+ // result = E_FAIL;
+ // do we need error message here in Windows and in posix?
+ // SendMessageError_with_LastError("Cannot set directory time", dpt.Path);
+ }
+ }
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
-
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
+ /*
+ #ifndef _WIN32
+ for (i = 0; i < _delayedSymLinks.Size(); i++)
+ {
+ const CDelayedSymLink &link = _delayedSymLinks[i];
+ if (!link.Create())
+ {
+ if (res == S_OK)
+ res = GetLastError_noZero_HRESULT();
+ // res = E_FAIL;
+ // do we need error message here in Windows and in posix?
+ SendMessageError_with_LastError("Cannot create Symbolic Link", link._source);
+ }
+ }
+ #endif // _WIN32
+ */
- RINOK(GetTime(index, kpidCTime, CTime, CTimeDefined));
- RINOK(GetTime(index, kpidATime, ATime, ATimeDefined));
- RINOK(GetTime(index, kpidMTime, MTime, MTimeDefined));
+ ClearExtractedDirsInfo();
+ return res;
+}
- // 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;
+
+HRESULT CArchiveExtractCallback::CloseArc()
+{
+ HRESULT res = CloseReparseAndFile();
+ const HRESULT res2 = SetDirsTimes();
+ if (res == S_OK)
+ res = res2;
+ _arc = NULL;
+ return res;
}