diff options
Diffstat (limited to 'src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp')
-rw-r--r-- | src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp | 1191 |
1 files changed, 0 insertions, 1191 deletions
diff --git a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp deleted file mode 100644 index 250f66797..000000000 --- a/src/libs/7zip/win/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp +++ /dev/null @@ -1,1191 +0,0 @@ -// ArchiveExtractCallback.cpp - -#include "StdAfx.h" - -#undef sprintf -#undef printf - -#include "../../../Common/ComTry.h" -#include "../../../Common/StringConvert.h" -#include "../../../Common/Wildcard.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/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); -} - -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; - RINOK(Archive_Get_HardLinkNode(archive, realIndices ? (*realIndices)[i] : i, h, defined)); - if (defined) - hardIDs.Add(h); - } - } - - hardIDs.Sort2(); - - { - // wee keep only items that have 2 or more items - unsigned k = 0; - unsigned numSame = 1; - for (unsigned i = 1; i < hardIDs.Size(); i++) - { - if (hardIDs[i].Compare(hardIDs[i - 1]) != 0) - numSame = 1; - else if (++numSame == 2) - { - if (i - 1 != k) - hardIDs[k] = hardIDs[i - 1]; - k++; - } - } - hardIDs.DeleteFrom(k); - } - - _hardLinks.PrepareLinks(); - return S_OK; -} - -#endif - -CArchiveExtractCallback::CArchiveExtractCallback(): - WriteCTime(true), - WriteATime(true), - WriteMTime(true), - _multiArchives(false) -{ - LocalProgressSpec = new CLocalProgress(); - _localProgress = LocalProgressSpec; - - #ifdef _USE_SECURITY_CODE - _saclEnabled = InitLocalPrivileges(); - #endif -} - -void CArchiveExtractCallback::Init( - const CExtractNtOptions &ntOptions, - const NWildcard::CCensorNode *wildcardCensor, - const CArc *arc, - IFolderArchiveExtractCallback *extractCallback2, - bool stdOutMode, bool testMode, - const FString &directoryPath, - const UStringVector &removePathParts, - UInt64 packSize) -{ - _extractedFolderPaths.Clear(); - _extractedFolderIndices.Clear(); - - #ifdef SUPPORT_LINKS - _hardLinks.Clear(); - #endif - - _ntOptions = ntOptions; - _wildcardCensor = wildcardCensor; - - _stdOutMode = stdOutMode; - _testMode = testMode; - _unpTotal = 1; - _packTotal = packSize; - - _extractCallback2 = extractCallback2; - _compressProgress.Release(); - _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress); - - #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; - _baseParentFolder = (UInt32)(Int32)-1; - _use_baseParentFolder_mode = false; - - _arc = arc; - _directoryPath = directoryPath; - NName::NormalizeDirPathPrefix(_directoryPath); - NDir::MyGetFullPathName(directoryPath, _directoryPathFull); -} - -STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size) -{ - COM_TRY_BEGIN - _unpTotal = size; - if (!_multiArchives && _extractCallback2) - return _extractCallback2->SetTotal(size); - return S_OK; - COM_TRY_END -} - -static void NormalizeVals(UInt64 &v1, UInt64 &v2) -{ - const UInt64 kMax = (UInt64)1 << 31; - while (v1 > kMax) - { - v1 >>= 1; - v2 >>= 1; - } -} - -static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal) -{ - NormalizeVals(packTotal, unpTotal); - NormalizeVals(unpCur, unpTotal); - if (unpTotal == 0) - unpTotal = 1; - return unpCur * packTotal / unpTotal; -} - -STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue) -{ - COM_TRY_BEGIN - if (!_extractCallback2) - return S_OK; - - if (_multiArchives) - { - if (completeValue != NULL) - { - UInt64 packCur = LocalProgressSpec->InSize + MyMultDiv64(*completeValue, _unpTotal, _packTotal); - return _extractCallback2->SetCompleted(&packCur); - } - } - return _extractCallback2->SetCompleted(completeValue); - COM_TRY_END -} - -STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) -{ - COM_TRY_BEGIN - return _localProgress->SetRatioInfo(inSize, outSize); - COM_TRY_END -} - -#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') - -static inline bool IsDriveName(const UString &s) -{ - return s.Len() == 2 && s[1] == ':' && IS_LETTER_CHAR(s[0]); -} - -void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath) -{ - bool isAbsPath = false; - - if (!dirPathParts.IsEmpty()) - { - const UString &s = dirPathParts[0]; - if (s.IsEmpty()) - isAbsPath = true; - #ifdef _WIN32 - else - { - if (dirPathParts.Size() > 1 && IsDriveName(s)) - isAbsPath = true; - } - #endif - } - - if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath) - fullPath.Empty(); - else - fullPath = _directoryPath; - - FOR_VECTOR (i, dirPathParts) - { - if (i > 0) - fullPath += FCHAR_PATH_SEPARATOR; - const UString &s = dirPathParts[i]; - fullPath += us2fs(s); - #ifdef _WIN32 - if (_pathMode == NExtract::NPathMode::kAbsPaths) - if (i == 0 && IsDriveName(s)) - continue; - #endif - CreateDir(fullPath); - } -} - -HRESULT CArchiveExtractCallback::GetTime(int index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined) -{ - filetimeIsDefined = false; - NCOM::CPropVariant prop; - RINOK(_arc->Archive->GetProperty(index, propID, &prop)); - if (prop.vt == VT_FILETIME) - { - filetime = prop.filetime; - filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0); - } - else if (prop.vt != VT_EMPTY) - return E_FAIL; - return S_OK; -} - -HRESULT CArchiveExtractCallback::GetUnpackSize() -{ - return _arc->GetItemSize(_index, _curSize, _curSizeDefined); -} - -HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path) -{ - return _extractCallback2->MessageError( - UString(L"ERROR: ") + - GetUnicodeString(message) + L": " + fs2us(path)); -} - -HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2) -{ - return _extractCallback2->MessageError( - UString(L"ERROR: ") + - GetUnicodeString(message) + UString(L": ") + fs2us(path1) + UString(L" : ") + fs2us(path2)); -} - -#ifndef _SFX - -STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value) -{ - if (propID == kpidName) - { - COM_TRY_BEGIN - NCOM::CPropVariant prop = Name.Ptr(); - 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 (s.Back() == WCHAR_PATH_SEPARATOR) - s.DeleteBack(); - int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR); - s.DeleteFrom(pos + 1); - } - return s; -} - -static bool IsSafePath(const UString &path) -{ - UStringVector parts; - SplitPathToParts(path, parts); - int level = 0; - FOR_VECTOR(i, parts) - { - const UString &s = parts[i]; - if (s.IsEmpty()) - continue; - if (s == L".") - continue; - if (s == L"..") - { - if (level <= 0) - return false; - level--; - } - else - level++; - } - return level > 0; -} - -#endif - - -STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) -{ - COM_TRY_BEGIN - - *outStream = 0; - - #ifndef _SFX - if (_hashStream) - _hashStreamSpec->ReleaseStream(); - _hashStreamWasUsed = false; - #endif - - _outFileStream.Release(); - - _encrypted = false; - _isSplit = false; - _isAltStream = false; - _curSize = 0; - _curSizeDefined = false; - _index = index; - - UString fullPath; - - IInArchive *archive = _arc->Archive; - RINOK(_arc->GetItemPath(index, fullPath)); - RINOK(Archive_IsItem_Folder(archive, index, _fi.IsDir)); - - _filePath = fullPath; - - { - 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 isHardLink = false; - bool isJunction = false; - bool isRelative = false; - - UString linkPath; - // RINOK(Archive_GetItemBoolProp(archive, index, kpidIsHardLink, isHardLink)); - // if (isHardLink) - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidHardLink, &prop)); - if (prop.vt == VT_BSTR) - { - isHardLink = true; - linkPath = prop.bstrVal; - isRelative = false; // TAR: hard links are from root folder of archive - } - else if (prop.vt == VT_EMPTY) - { - // linkPath.Empty(); - } - else - return E_FAIL; - } - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidSymLink, &prop)); - if (prop.vt == VT_BSTR) - { - isHardLink = false; - linkPath = prop.bstrVal; - isRelative = true; // TAR: symbolic links are relative - } - else if (prop.vt == VT_EMPTY) - { - // linkPath.Empty(); - } - else - return E_FAIL; - } - - bool isOkReparse = false; - - if (linkPath.IsEmpty() && _arc->GetRawProps) - { - const void *data; - UInt32 dataSize; - UInt32 propType; - _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType); - if (dataSize != 0) - { - if (propType != NPropDataType::kRaw) - return E_FAIL; - UString s; - CReparseAttr reparse; - isOkReparse = reparse.Parse((const Byte *)data, dataSize); - if (isOkReparse) - { - isHardLink = false; - linkPath = reparse.GetPath(); - isJunction = reparse.IsMountPoint(); - isRelative = reparse.IsRelative(); - #ifndef _WIN32 - linkPath.Replace(WCHAR_PATH_SEPARATOR, '/', ); - #endif - } - } - } - - if (!linkPath.IsEmpty()) - { - #ifdef _WIN32 - linkPath.Replace('/', WCHAR_PATH_SEPARATOR); - #endif - - 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 = MakePathNameFromParts(pathParts); - } - - #endif - - RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted)); - - RINOK(GetUnpackSize()); - - RINOK(Archive_IsItem_AltStream(archive, index, _isAltStream)); - - if (!_ntOptions.AltStreams.Val && _isAltStream) - return S_OK; - - if (_wildcardCensor) - { - if (!_wildcardCensor->CheckPath(_isAltStream, fullPath, !_fi.IsDir)) - return S_OK; - } - - - UStringVector pathParts; - - if (_use_baseParentFolder_mode) - { - int baseParent = _baseParentFolder; - if (_pathMode == NExtract::NPathMode::kFullPaths || - _pathMode == NExtract::NPathMode::kAbsPaths) - baseParent = -1; - RINOK(_arc->GetItemPathToParent(index, baseParent, pathParts)); - if (_pathMode == NExtract::NPathMode::kNoPaths && !pathParts.IsEmpty()) - pathParts.DeleteFrontal(pathParts.Size() - 1); - } - else - { - SplitPathToParts(fullPath, pathParts); - - if (pathParts.IsEmpty()) - return E_FAIL; - unsigned numRemovePathParts = 0; - - switch (_pathMode) - { - case NExtract::NPathMode::kCurPaths: - { - bool badPrefix = false; - if (pathParts.Size() <= _removePathParts.Size()) - badPrefix = true; - else - { - FOR_VECTOR (i, _removePathParts) - { - if (!_removePathParts[i].IsEqualToNoCase(pathParts[i])) - { - badPrefix = true; - break; - } - } - } - if (badPrefix) - { - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) - return E_FAIL; - } - else - numRemovePathParts = _removePathParts.Size(); - break; - } - case NExtract::NPathMode::kNoPaths: - { - 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; - GetProp_Spec->Name = MakePathNameFromParts(pathParts); - - return ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, _fi.IsDir, outStream, askExtractMode, GetProp); - } - - #endif - - CMyComPtr<ISequentialOutStream> outStreamLoc; - -if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode) -{ - if (_stdOutMode) - { - outStreamLoc = new CStdOutFileStream; - } - else - { - { - NCOM::CPropVariant prop; - RINOK(archive->GetProperty(index, kpidAttrib, &prop)); - if (prop.vt == VT_UI4) - { - _fi.Attrib = prop.ulVal; - _fi.AttribDefined = true; - } - else if (prop.vt == VT_EMPTY) - _fi.AttribDefined = false; - else - return E_FAIL; - } - - RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined)); - RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined)); - RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined)); - - bool isAnti = false; - RINOK(_arc->IsItemAnti(index, isAnti)); - - bool replace = _isAltStream ? - _ntOptions.ReplaceColonForAltStream : - !_ntOptions.WriteToAltStreamIfColon; - - if (_pathMode != NExtract::NPathMode::kAbsPaths) - MakeCorrectPath(_directoryPath.IsEmpty(), pathParts, replace); - Correct_IfEmptyLastPart(pathParts); - UString processedPath = MakePathNameFromParts(pathParts); - - if (!isAnti) - { - if (!_fi.IsDir) - { - if (!pathParts.IsEmpty()) - pathParts.DeleteBack(); - } - - if (!pathParts.IsEmpty()) - { - FString fullPathNew; - CreateComplexDirectory(pathParts, fullPathNew); - if (_fi.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)) - fullProcessedPath = _directoryPath + fullProcessedPath; - - if (_fi.IsDir) - { - _diskFilePath = fullProcessedPath; - if (isAnti) - RemoveDir(_diskFilePath); - #ifdef SUPPORT_LINKS - if (linkPath.IsEmpty()) - #endif - return S_OK; - } - else if (!_isSplit) - { - NFind::CFileInfo fileInfo; - if (fileInfo.Find(fullProcessedPath)) - { - switch (_overwriteMode) - { - case NExtract::NOverwriteMode::kSkip: - return S_OK; - case NExtract::NOverwriteMode::kAsk: - { - int slashPos = fullProcessedPath.ReverseFind(FTEXT('/')); - #ifdef _WIN32 - int slash1Pos = fullProcessedPath.ReverseFind(FTEXT('\\')); - slashPos = MyMax(slashPos, slash1Pos); - #endif - FString realFullProcessedPath = fullProcessedPath.Left(slashPos + 1) + fileInfo.Name; - - Int32 overwiteResult; - RINOK(_extractCallback2->AskOverwrite( - fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, fullPath, - _fi.MTimeDefined ? &_fi.MTime : NULL, - _curSizeDefined ? &_curSize : NULL, - &overwiteResult)) - - switch (overwiteResult) - { - case NOverwriteAnswer::kCancel: return E_ABORT; - case NOverwriteAnswer::kNo: return S_OK; - case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK; - case NOverwriteAnswer::kYes: break; - case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break; - case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break; - default: - return E_FAIL; - } - } - } - if (_overwriteMode == NExtract::NOverwriteMode::kRename) - { - if (!AutoRenamePath(fullProcessedPath)) - { - RINOK(SendMessageError(kCantAutoRename, fullProcessedPath)); - return E_FAIL; - } - } - 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 folders too - if (!MyMoveFile(fullProcessedPath, existPath)) - { - RINOK(SendMessageError(kCantRenameFile, fullProcessedPath)); - return E_FAIL; - } - } - else - { - if (fileInfo.IsDir()) - { - // do we need to delete all files in folder? - if (!RemoveDir(fullProcessedPath)) - { - RINOK(SendMessageError(kCantDeleteOutputDir, fullProcessedPath)); - return S_OK; - } - } - else if (!DeleteFileAlways(fullProcessedPath)) - { - RINOK(SendMessageError(kCantDeleteOutputFile, fullProcessedPath)); - return S_OK; - // return E_FAIL; - } - } - } - } - _diskFilePath = fullProcessedPath; - - - if (!isAnti) - { - #ifdef SUPPORT_LINKS - - if (!linkPath.IsEmpty()) - { - #ifndef UNDER_CE - - UString relatPath; - if (isRelative) - relatPath = GetDirPrefixOf(_filePath); - relatPath += linkPath; - - if (!IsSafePath(relatPath)) - { - RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath))); - } - else - { - FString existPath; - if (isHardLink || !isRelative) - { - if (!NName::GetFullPath(_directoryPathFull, us2fs(relatPath), existPath)) - { - RINOK(SendMessageError("Incorrect path", us2fs(relatPath))); - } - } - else - { - existPath = us2fs(linkPath); - } - - if (!existPath.IsEmpty()) - { - if (isHardLink) - { - if (!MyCreateHardLink(fullProcessedPath, existPath)) - { - RINOK(SendMessageError2("Can not create hard link", fullProcessedPath, existPath)); - // return S_OK; - } - } - else if (_ntOptions.SymLinks.Val) - { - // bool isSymLink = true; // = false for junction - if (_fi.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())) - { - return E_FAIL; // "Internal conversion error"; - } - - if (!NFile::NIO::SetReparseData(fullProcessedPath, _fi.IsDir, data, (DWORD)data.Size())) - { - RINOK(SendMessageError("Can not set reparse data", fullProcessedPath)); - } - } - } - } - } - - #endif - } - else - #endif // SUPPORT_LINKS - { - bool needWriteFile = true; - - #ifdef SUPPORT_LINKS - if (!_hardLinks.IDs.IsEmpty()) - { - 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("Can not open output file ", fullProcessedPath)); - return S_OK; - } - } - if (_isSplit) - { - RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL)); - } - _outFileStream = outStreamLoc; - } - } - } - - outStreamLoc = _outFileStream; - } -} - - #ifndef _SFX - - if (_hashStream) - { - if (askExtractMode == NArchive::NExtract::NAskMode::kExtract || - askExtractMode == NArchive::NExtract::NAskMode::kTest) - { - _hashStreamSpec->SetStream(outStreamLoc); - outStreamLoc = _hashStream; - _hashStreamSpec->Init(true); - _hashStreamWasUsed = true; - } - } - - #endif - - if (outStreamLoc) - *outStream = outStreamLoc.Detach(); - return S_OK; - COM_TRY_END -} - -STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode) -{ - COM_TRY_BEGIN - - #ifndef _SFX - if (ExtractToStreamCallback) - return ExtractToStreamCallback->PrepareOperation7(askExtractMode); - #endif - - _extractMode = false; - switch (askExtractMode) - { - case NArchive::NExtract::NAskMode::kExtract: - if (_testMode) - askExtractMode = NArchive::NExtract::NAskMode::kTest; - else - _extractMode = true; - break; - }; - return _extractCallback2->PrepareOperation(_filePath, _fi.IsDir, - askExtractMode, _isSplit ? &_position: 0); - COM_TRY_END -} - -STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult) -{ - COM_TRY_BEGIN - - #ifndef _SFX - if (ExtractToStreamCallback) - return ExtractToStreamCallback->SetOperationResult7(operationResult, _encrypted); - #endif - - #ifndef _SFX - - if (_hashStreamWasUsed) - { - _hashStreamSpec->_hash->Final(_fi.IsDir, _isAltStream, _filePath); - _curSize = _hashStreamSpec->GetSize(); - _curSizeDefined = true; - _hashStreamSpec->ReleaseStream(); - _hashStreamWasUsed = false; - } - - #endif - - 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(); - } - - #ifdef _USE_SECURITY_CODE - if (_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) - { - if (_isAltStream) - AltStreams_UnpackSize += _curSize; - else - UnpackSize += _curSize; - } - - if (_fi.IsDir) - NumFolders++; - else if (_isAltStream) - NumAltStreams++; - else - NumFiles++; - - if (_extractMode && _fi.AttribDefined) - SetFileAttrib(_diskFilePath, _fi.Attrib); - RINOK(_extractCallback2->SetOperationResult(operationResult, _encrypted)); - return S_OK; - COM_TRY_END -} - -/* -STDMETHODIMP CArchiveExtractCallback::GetInStream( - const wchar_t *name, ISequentialInStream **inStream) -{ - COM_TRY_BEGIN - CInFileStream *inFile = new CInFileStream; - CMyComPtr<ISequentialInStream> inStreamTemp = inFile; - if (!inFile->Open(_srcDirectoryPrefix + name)) - return ::GetLastError(); - *inStream = inStreamTemp.Detach(); - return S_OK; - COM_TRY_END -} -*/ - -STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password) -{ - COM_TRY_BEGIN - if (!_cryptoGetTextPassword) - { - RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword, - &_cryptoGetTextPassword)); - } - return _cryptoGetTextPassword->CryptoGetTextPassword(password); - COM_TRY_END -} - - -struct CExtrRefSortPair -{ - int Len; - int 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 int GetNumSlashes(const FChar *s) -{ - for (int numSlashes = 0;;) - { - FChar c = *s++; - if (c == 0) - return numSlashes; - if ( - #ifdef _WIN32 - c == FTEXT('\\') || - #endif - c == FTEXT('/')) - 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; -} |