other-licenses/7zstub/src/7zip/Archive/7z/7zExtract.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 // 7zExtract.cpp
     3 #include "StdAfx.h"
     5 #include "7zHandler.h"
     6 #include "7zFolderOutStream.h"
     7 #include "7zMethods.h"
     8 #include "7zDecode.h"
     9 // #include "7z1Decode.h"
    11 #include "../../../Common/ComTry.h"
    12 #include "../../Common/StreamObjects.h"
    13 #include "../../Common/ProgressUtils.h"
    14 #include "../../Common/LimitedStreams.h"
    16 namespace NArchive {
    17 namespace N7z {
    19 struct CExtractFolderInfo
    20 {
    21   #ifdef _7Z_VOL
    22   int VolumeIndex;
    23   #endif
    24   CNum FileIndex;
    25   CNum FolderIndex;
    26   CBoolVector ExtractStatuses;
    27   UInt64 UnPackSize;
    28   CExtractFolderInfo(
    29     #ifdef _7Z_VOL
    30     int volumeIndex, 
    31     #endif
    32     CNum fileIndex, CNum folderIndex): 
    33     #ifdef _7Z_VOL
    34     VolumeIndex(volumeIndex),
    35     #endif
    36     FileIndex(fileIndex),
    37     FolderIndex(folderIndex), 
    38     UnPackSize(0) 
    39   {
    40     if (fileIndex != kNumNoIndex)
    41     {
    42       ExtractStatuses.Reserve(1);
    43       ExtractStatuses.Add(true);
    44     }
    45   };
    46 };
    48 STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems,
    49     Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
    50 {
    51   COM_TRY_BEGIN
    52   bool testMode = (testModeSpec != 0);
    53   CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
    54   UInt64 importantTotalUnPacked = 0;
    56   bool allFilesMode = (numItems == UInt32(-1));
    57   if (allFilesMode)
    58     numItems = 
    59     #ifdef _7Z_VOL
    60     _refs.Size();
    61     #else
    62     _database.Files.Size();
    63     #endif
    65   if(numItems == 0)
    66     return S_OK;
    68   /*
    69   if(_volumes.Size() != 1)
    70     return E_FAIL;
    71   const CVolume &volume = _volumes.Front();
    72   const CArchiveDatabaseEx &_database = volume.Database;
    73   IInStream *_inStream = volume.Stream;
    74   */
    76   CObjectVector<CExtractFolderInfo> extractFolderInfoVector;
    77   for(UInt32 ii = 0; ii < numItems; ii++)
    78   {
    79     // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex];
    80     UInt32 ref2Index = allFilesMode ? ii : indices[ii];
    81     // const CRef2 &ref2 = _refs[ref2Index];
    83     // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++)
    84     {
    85       #ifdef _7Z_VOL
    86       // const CRef &ref = ref2.Refs[ri];
    87       const CRef &ref = _refs[ref2Index];
    89       int volumeIndex = ref.VolumeIndex;
    90       const CVolume &volume = _volumes[volumeIndex];
    91       const CArchiveDatabaseEx &database = volume.Database;
    92       UInt32 fileIndex = ref.ItemIndex;
    93       #else
    94       const CArchiveDatabaseEx &database = _database;
    95       UInt32 fileIndex = ref2Index;
    96       #endif
    98       CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex];
    99       if (folderIndex == kNumNoIndex)
   100       {
   101         extractFolderInfoVector.Add(CExtractFolderInfo(
   102             #ifdef _7Z_VOL
   103             volumeIndex, 
   104             #endif
   105             fileIndex, kNumNoIndex));
   106         continue;
   107       }
   108       if (extractFolderInfoVector.IsEmpty() || 
   109         folderIndex != extractFolderInfoVector.Back().FolderIndex 
   110         #ifdef _7Z_VOL
   111         || volumeIndex != extractFolderInfoVector.Back().VolumeIndex
   112         #endif
   113         )
   114       {
   115         extractFolderInfoVector.Add(CExtractFolderInfo(
   116             #ifdef _7Z_VOL
   117             volumeIndex, 
   118             #endif
   119             kNumNoIndex, folderIndex));
   120         const CFolder &folderInfo = database.Folders[folderIndex];
   121         UInt64 unPackSize = folderInfo.GetUnPackSize();
   122         importantTotalUnPacked += unPackSize;
   123         extractFolderInfoVector.Back().UnPackSize = unPackSize;
   124       }
   126       CExtractFolderInfo &efi = extractFolderInfoVector.Back();
   128       // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex];
   129       CNum startIndex = database.FolderStartFileIndex[folderIndex];
   130       for (CNum index = efi.ExtractStatuses.Size();
   131           index <= fileIndex - startIndex; index++)
   132       {
   133         // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize;
   134         // Count partial_folder_size
   135         // efi.UnPackSize += unPackSize;
   136         // importantTotalUnPacked += unPackSize;
   137         efi.ExtractStatuses.Add(index == fileIndex - startIndex);
   138       }
   139     }
   140   }
   142   extractCallback->SetTotal(importantTotalUnPacked);
   144   CDecoder decoder(
   145     #ifdef _ST_MODE
   146     false
   147     #else
   148     true
   149     #endif
   150     );
   151   // CDecoder1 decoder;
   153   UInt64 currentImportantTotalUnPacked = 0;
   154   UInt64 totalFolderUnPacked;
   156   for(int i = 0; i < extractFolderInfoVector.Size(); i++, 
   157       currentImportantTotalUnPacked += totalFolderUnPacked)
   158   {
   159     const CExtractFolderInfo &efi = extractFolderInfoVector[i];
   160     totalFolderUnPacked = efi.UnPackSize;
   162     RINOK(extractCallback->SetCompleted(&currentImportantTotalUnPacked));
   164     CFolderOutStream *folderOutStream = new CFolderOutStream;
   165     CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
   167     #ifdef _7Z_VOL
   168     const CVolume &volume = _volumes[efi.VolumeIndex];
   169     const CArchiveDatabaseEx &database = volume.Database;
   170     #else
   171     const CArchiveDatabaseEx &database = _database;
   172     #endif
   174     CNum startIndex;
   175     if (efi.FileIndex != kNumNoIndex)
   176       startIndex = efi.FileIndex;
   177     else
   178       startIndex = database.FolderStartFileIndex[efi.FolderIndex];
   181     HRESULT result = folderOutStream->Init(&database, 
   182         #ifdef _7Z_VOL
   183         volume.StartRef2Index, 
   184         #else
   185         0,
   186         #endif
   187         startIndex, 
   188         &efi.ExtractStatuses, extractCallback, testMode);
   190     RINOK(result);
   192     if (efi.FileIndex != kNumNoIndex)
   193       continue;
   195     CNum folderIndex = efi.FolderIndex;
   196     const CFolder &folderInfo = database.Folders[folderIndex];
   198     CLocalProgress *localProgressSpec = new CLocalProgress;
   199     CMyComPtr<ICompressProgressInfo> progress = localProgressSpec;
   200     localProgressSpec->Init(extractCallback, false);
   202     CLocalCompressProgressInfo *localCompressProgressSpec = 
   203         new CLocalCompressProgressInfo;
   204     CMyComPtr<ICompressProgressInfo> compressProgress = localCompressProgressSpec;
   205     localCompressProgressSpec->Init(progress, NULL, &currentImportantTotalUnPacked);
   207     CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex];
   208     UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0);
   210     #ifndef _NO_CRYPTO
   211     CMyComPtr<ICryptoGetTextPassword> getTextPassword;
   212     if (extractCallback)
   213       extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
   214     #endif
   216     try
   217     {
   218       HRESULT result = decoder.Decode(
   219           #ifdef _7Z_VOL
   220           volume.Stream,
   221           #else
   222           _inStream,
   223           #endif
   224           folderStartPackPos, 
   225           &database.PackSizes[packStreamIndex],
   226           folderInfo,
   227           outStream,
   228           compressProgress
   229           #ifndef _NO_CRYPTO
   230           , getTextPassword
   231           #endif
   232           #ifdef COMPRESS_MT
   233           , true, _numThreads
   234           #endif
   235           );
   237       if (result == S_FALSE)
   238       {
   239         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
   240         continue;
   241       }
   242       if (result == E_NOTIMPL)
   243       {
   244         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod));
   245         continue;
   246       }
   247       if (result != S_OK)
   248         return result;
   249       if (folderOutStream->WasWritingFinished() != S_OK)
   250       {
   251         RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
   252         continue;
   253       }
   254     }
   255     catch(...)
   256     {
   257       RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError));
   258       continue;
   259     }
   260   }
   261   return S_OK;
   262   COM_TRY_END
   263 }
   265 }}

mercurial