other-licenses/7zstub/src/7zip/UI/Common/OpenArchive.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 // OpenArchive.cpp
     3 #include "StdAfx.h"
     5 #include "OpenArchive.h"
     7 #include "Common/Wildcard.h"
     9 #include "Windows/FileName.h"
    10 #include "Windows/FileDir.h"
    11 #include "Windows/Defs.h"
    12 #include "Windows/PropVariant.h"
    14 #include "../../Common/FileStreams.h"
    15 #include "../../Common/StreamUtils.h"
    17 #include "Common/StringConvert.h"
    19 #ifdef FORMAT_7Z
    20 #include "../../Archive/7z/7zHandler.h"
    21 #endif
    23 #ifdef FORMAT_BZIP2
    24 #include "../../Archive/BZip2/BZip2Handler.h"
    25 #endif
    27 #ifdef FORMAT_GZIP
    28 #include "../../Archive/GZip/GZipHandler.h"
    29 #endif
    31 #ifdef FORMAT_SPLIT
    32 #include "../../Archive/Split/SplitHandler.h"
    33 #endif
    35 #ifdef FORMAT_TAR
    36 #include "../../Archive/Tar/TarHandler.h"
    37 #endif
    39 #ifdef FORMAT_ZIP
    40 #include "../../Archive/Zip/ZipHandler.h"
    41 #endif
    43 #ifdef FORMAT_Z
    44 #include "../../Archive/Z/ZHandler.h"
    45 #endif
    47 #ifndef EXCLUDE_COM
    48 #include "HandlerLoader.h"
    49 #endif
    51 #include "DefaultName.h"
    53 using namespace NWindows;
    55 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result)
    56 {
    57   NCOM::CPropVariant prop;
    58   RINOK(archive->GetProperty(index, kpidPath, &prop));
    59   if(prop.vt == VT_BSTR)
    60     result = prop.bstrVal;
    61   else if (prop.vt == VT_EMPTY)
    62     result.Empty();
    63   else
    64     return E_FAIL;
    65   return S_OK;
    66 }
    68 HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result)
    69 {
    70   RINOK(GetArchiveItemPath(archive, index, result));
    71   if (result.IsEmpty())
    72     result = defaultName;
    73   return S_OK;
    74 }
    76 HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, 
    77     const FILETIME &defaultFileTime, FILETIME &fileTime)
    78 {
    79   NCOM::CPropVariant prop;
    80   RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop));
    81   if (prop.vt == VT_FILETIME)
    82     fileTime = prop.filetime;
    83   else if (prop.vt == VT_EMPTY)
    84     fileTime = defaultFileTime;
    85   else
    86     return E_FAIL;
    87   return S_OK;
    88 }
    90 static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
    91 {
    92   NCOM::CPropVariant prop;
    93   RINOK(archive->GetProperty(index, propID, &prop));
    94   if(prop.vt == VT_BOOL)
    95     result = VARIANT_BOOLToBool(prop.boolVal);
    96   else if (prop.vt == VT_EMPTY)
    97     result = false;
    98   else
    99     return E_FAIL;
   100   return S_OK;
   101 }
   103 HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
   104 {
   105   return IsArchiveItemProp(archive, index, kpidIsFolder, result);
   106 }
   108 HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result)
   109 {
   110   return IsArchiveItemProp(archive, index, kpidIsAnti, result);
   111 }
   113 // Static-SFX (for Linux) can be big
   114 const UInt64 kMaxCheckStartPosition = 
   115 #ifdef _WIN32
   116 1 << 20;
   117 #else
   118 1 << 22;
   119 #endif
   122 HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName)
   123 {
   124   CInFileStream *inStreamSpec = new CInFileStream;
   125   CMyComPtr<IInStream> inStream(inStreamSpec);
   126   inStreamSpec->Open(fileName);
   127   return archive->Open(inStream, &kMaxCheckStartPosition, NULL);
   128 }
   130 #ifndef _SFX
   131 static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
   132 {
   133   for (size_t i = 0; i < size; i++)
   134     if (p1[i] != p2[i])
   135       return false;
   136   return true;
   137 }
   138 #endif
   140 HRESULT OpenArchive(
   141     IInStream *inStream,
   142     const UString &fileName, 
   143     #ifndef EXCLUDE_COM
   144     HMODULE *module,
   145     #endif
   146     IInArchive **archiveResult, 
   147     CArchiverInfo &archiverInfoResult,
   148     UString &defaultItemName,
   149     IArchiveOpenCallback *openArchiveCallback)
   150 {
   151   *archiveResult = NULL;
   152   CObjectVector<CArchiverInfo> archiverInfoList;
   153   ReadArchiverInfoList(archiverInfoList);
   154   UString extension;
   155   {
   156     int dotPos = fileName.ReverseFind(L'.');
   157     if (dotPos >= 0)
   158       extension = fileName.Mid(dotPos + 1);
   159   }
   160   CIntVector orderIndices;
   161   int i;
   162   bool finded = false;
   163   for(i = 0; i < archiverInfoList.Size(); i++)
   164   {
   165     if (archiverInfoList[i].FindExtension(extension) >= 0)
   166     {
   167       orderIndices.Insert(0, i);
   168       finded = true;
   169     }
   170     else
   171       orderIndices.Add(i);
   172   }
   174   #ifndef _SFX
   175   if (!finded)
   176   {
   177     CByteBuffer byteBuffer;
   178     const UInt32 kBufferSize = (200 << 10);
   179     byteBuffer.SetCapacity(kBufferSize);
   180     Byte *buffer = byteBuffer;
   181     RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
   182     UInt32 processedSize;
   183     RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize));
   184     int numFinded = 0;
   185     for (int pos = (int)processedSize; pos >= 0 ; pos--)
   186     {
   187       for(int i = numFinded; i < orderIndices.Size(); i++)
   188       {
   189         int index = orderIndices[i];
   190         const CArchiverInfo &ai = archiverInfoList[index];
   191         const CByteBuffer &sig = ai.StartSignature;
   192         if (sig.GetCapacity() == 0)
   193           continue;
   194         if (pos + sig.GetCapacity() > processedSize)
   195           continue;
   196         if (TestSignature(buffer + pos, sig, sig.GetCapacity()))
   197         {
   198           orderIndices.Delete(i);
   199           orderIndices.Insert(0, index);
   200           numFinded++;
   201         }
   202       }
   203     }
   204   }
   205   #endif
   207   HRESULT badResult = S_OK;
   208   for(i = 0; i < orderIndices.Size(); i++)
   209   {
   210     inStream->Seek(0, STREAM_SEEK_SET, NULL);
   211     const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]];
   212     #ifndef EXCLUDE_COM
   213     CHandlerLoader loader;
   214     #endif
   215     CMyComPtr<IInArchive> archive;
   217     #ifdef FORMAT_7Z
   218     if (archiverInfo.Name.CompareNoCase(L"7z") == 0)
   219       archive = new NArchive::N7z::CHandler;
   220     #endif
   222     #ifdef FORMAT_BZIP2
   223     if (archiverInfo.Name.CompareNoCase(L"BZip2") == 0)
   224       archive = new NArchive::NBZip2::CHandler;
   225     #endif
   227     #ifdef FORMAT_GZIP
   228     if (archiverInfo.Name.CompareNoCase(L"GZip") == 0)
   229       archive = new NArchive::NGZip::CHandler;
   230     #endif
   232     #ifdef FORMAT_SPLIT
   233     if (archiverInfo.Name.CompareNoCase(L"Split") == 0)
   234       archive = new NArchive::NSplit::CHandler;
   235     #endif
   237     #ifdef FORMAT_TAR
   238     if (archiverInfo.Name.CompareNoCase(L"Tar") == 0)
   239       archive = new NArchive::NTar::CHandler;
   240     #endif
   242     #ifdef FORMAT_ZIP
   243     if (archiverInfo.Name.CompareNoCase(L"Zip") == 0)
   244       archive = new NArchive::NZip::CHandler;
   245     #endif
   247     #ifdef FORMAT_Z
   248     if (archiverInfo.Name.CompareNoCase(L"Z") == 0)
   249       archive = new NArchive::NZ::CHandler;
   250     #endif
   253     #ifndef EXCLUDE_COM
   254     if (!archive)
   255     {
   256       HRESULT result = loader.CreateHandler(archiverInfo.FilePath, 
   257           archiverInfo.ClassID, (void **)&archive, false);
   258       if (result != S_OK)
   259         continue;
   260     }
   261     #endif
   263     if (!archive)
   264       return E_FAIL;
   266     HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback);
   267     if(result == S_FALSE)
   268       continue;
   269     if(result != S_OK)
   270     {
   271       badResult = result;
   272       if(result == E_ABORT)
   273         break;
   274       continue;
   275     }
   276     *archiveResult = archive.Detach();
   277     #ifndef EXCLUDE_COM
   278     *module = loader.Detach();
   279     #endif
   280     archiverInfoResult = archiverInfo;
   281     int subExtIndex = archiverInfo.FindExtension(extension);
   282     if (subExtIndex < 0)
   283       subExtIndex = 0;
   284     defaultItemName = GetDefaultName2(fileName, 
   285         archiverInfo.Extensions[subExtIndex].Ext, 
   286         archiverInfo.Extensions[subExtIndex].AddExt);
   288     return S_OK;
   289   }
   290   if (badResult != S_OK)
   291     return badResult;
   292   return S_FALSE;
   293 }
   295 HRESULT OpenArchive(const UString &filePath, 
   296     #ifndef EXCLUDE_COM
   297     HMODULE *module,
   298     #endif
   299     IInArchive **archiveResult, 
   300     CArchiverInfo &archiverInfo,
   301     UString &defaultItemName,
   302     IArchiveOpenCallback *openArchiveCallback)
   303 {
   304   CInFileStream *inStreamSpec = new CInFileStream;
   305   CMyComPtr<IInStream> inStream(inStreamSpec);
   306   if (!inStreamSpec->Open(filePath))
   307     return GetLastError();
   308   return OpenArchive(inStream, ExtractFileNameFromPath(filePath),
   309     #ifndef EXCLUDE_COM
   310     module,
   311     #endif
   312     archiveResult, archiverInfo,
   313     defaultItemName, openArchiveCallback);
   314 }
   316 static void MakeDefaultName(UString &name)
   317 {
   318   int dotPos = name.ReverseFind(L'.');
   319   if (dotPos < 0)
   320     return;
   321   UString ext = name.Mid(dotPos + 1);
   322   if (ext.IsEmpty())
   323     return;
   324   for (int pos = 0; pos < ext.Length(); pos++)
   325     if (ext[pos] < L'0' || ext[pos] > L'9')
   326       return;
   327   name = name.Left(dotPos);
   328 }
   330 HRESULT OpenArchive(const UString &fileName, 
   331     #ifndef EXCLUDE_COM
   332     HMODULE *module0,
   333     HMODULE *module1,
   334     #endif
   335     IInArchive **archive0, 
   336     IInArchive **archive1, 
   337     CArchiverInfo &archiverInfo0,
   338     CArchiverInfo &archiverInfo1,
   339     UString &defaultItemName0,
   340     UString &defaultItemName1,
   341     IArchiveOpenCallback *openArchiveCallback)
   342 {
   343   HRESULT result = OpenArchive(fileName, 
   344     #ifndef EXCLUDE_COM
   345     module0,
   346     #endif
   347     archive0, archiverInfo0, defaultItemName0, openArchiveCallback);
   348   RINOK(result);
   349   CMyComPtr<IInArchiveGetStream> getStream;
   350   result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream);
   351   if (result != S_OK || getStream == 0)
   352     return S_OK;
   354   CMyComPtr<ISequentialInStream> subSeqStream;
   355   result = getStream->GetStream(0, &subSeqStream);
   356   if (result != S_OK)
   357     return S_OK;
   359   CMyComPtr<IInStream> subStream;
   360   if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK)
   361     return S_OK;
   362   if (!subStream)
   363     return S_OK;
   365   UInt32 numItems;
   366   RINOK((*archive0)->GetNumberOfItems(&numItems));
   367   if (numItems < 1)
   368     return S_OK;
   370   UString subPath;
   371   RINOK(GetArchiveItemPath(*archive0, 0, subPath))
   372   if (subPath.IsEmpty())
   373   {
   374     MakeDefaultName(defaultItemName0);
   375     subPath = defaultItemName0;
   376     if (archiverInfo0.Name.CompareNoCase(L"7z") == 0)
   377     {
   378       if (subPath.Right(3).CompareNoCase(L".7z") != 0)
   379         subPath += L".7z";
   380     }
   381   }
   382   else
   383     subPath = ExtractFileNameFromPath(subPath);
   385   CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
   386   openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
   387   if (setSubArchiveName)
   388     setSubArchiveName->SetSubArchiveName(subPath);
   390   result = OpenArchive(subStream, subPath, 
   391     #ifndef EXCLUDE_COM
   392     module1,
   393     #endif
   394     archive1, archiverInfo1, defaultItemName1, openArchiveCallback);
   395   return S_OK;
   396 }
   398 HRESULT MyOpenArchive(const UString &archiveName, 
   399     #ifndef EXCLUDE_COM
   400     HMODULE *module,
   401     #endif
   402     IInArchive **archive,
   403     UString &defaultItemName,
   404     IOpenCallbackUI *openCallbackUI)
   405 {
   406   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
   407   CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
   408   openCallbackSpec->Callback = openCallbackUI;
   410   UString fullName;
   411   int fileNamePartStartIndex;
   412   NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
   413   openCallbackSpec->Init(
   414       fullName.Left(fileNamePartStartIndex), 
   415       fullName.Mid(fileNamePartStartIndex));
   417   CArchiverInfo archiverInfo;
   418   return OpenArchive(archiveName, 
   419       #ifndef EXCLUDE_COM
   420       module,
   421       #endif
   422       archive, 
   423       archiverInfo, 
   424       defaultItemName,
   425       openCallback);
   426 }
   428 HRESULT MyOpenArchive(const UString &archiveName, 
   429     #ifndef EXCLUDE_COM
   430     HMODULE *module0,
   431     HMODULE *module1,
   432     #endif
   433     IInArchive **archive0,
   434     IInArchive **archive1,
   435     UString &defaultItemName0,
   436     UString &defaultItemName1,
   437     UStringVector &volumePaths,
   438     IOpenCallbackUI *openCallbackUI)
   439 {
   440   COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
   441   CMyComPtr<IArchiveOpenCallback> openCallback = openCallbackSpec;
   442   openCallbackSpec->Callback = openCallbackUI;
   444   UString fullName;
   445   int fileNamePartStartIndex;
   446   NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex);
   447   UString prefix = fullName.Left(fileNamePartStartIndex);
   448   UString name = fullName.Mid(fileNamePartStartIndex);
   449   openCallbackSpec->Init(prefix, name);
   451   CArchiverInfo archiverInfo0, archiverInfo1;
   452   HRESULT result = OpenArchive(archiveName, 
   453       #ifndef EXCLUDE_COM
   454       module0,
   455       module1,
   456       #endif
   457       archive0, 
   458       archive1, 
   459       archiverInfo0, 
   460       archiverInfo1, 
   461       defaultItemName0,
   462       defaultItemName1,
   463       openCallback);
   464   RINOK(result);
   465   volumePaths.Add(prefix + name);
   466   for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++)
   467     volumePaths.Add(prefix + openCallbackSpec->FileNames[i]);
   468   return S_OK;
   469 }
   471 HRESULT CArchiveLink::Close()
   472 {
   473   if (Archive1 != 0)
   474     RINOK(Archive1->Close());
   475   if (Archive0 != 0)
   476     RINOK(Archive0->Close());
   477   return S_OK;
   478 }
   480 void CArchiveLink::Release()
   481 {
   482   if (Archive1 != 0)
   483     Archive1.Release();
   484   if (Archive0 != 0)
   485     Archive0.Release();
   486   #ifndef EXCLUDE_COM
   487   Library1.Free();
   488   Library0.Free();
   489   #endif
   490 }
   492 HRESULT OpenArchive(const UString &archiveName, 
   493     CArchiveLink &archiveLink,
   494     IArchiveOpenCallback *openCallback)
   495 {
   496   return OpenArchive(archiveName, 
   497     #ifndef EXCLUDE_COM
   498     &archiveLink.Library0, &archiveLink.Library1,
   499     #endif
   500     &archiveLink.Archive0, &archiveLink.Archive1, 
   501     archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1, 
   502     archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
   503     openCallback);
   504 }
   506 HRESULT MyOpenArchive(const UString &archiveName, 
   507     CArchiveLink &archiveLink,
   508     IOpenCallbackUI *openCallbackUI)
   509 {
   510   return MyOpenArchive(archiveName, 
   511     #ifndef EXCLUDE_COM
   512     &archiveLink.Library0, &archiveLink.Library1,
   513     #endif
   514     &archiveLink.Archive0, &archiveLink.Archive1, 
   515     archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, 
   516     archiveLink.VolumePaths,
   517     openCallbackUI);
   518 }
   520 HRESULT ReOpenArchive(CArchiveLink &archiveLink, 
   521     const UString &fileName)
   522 {
   523   if (archiveLink.GetNumLevels() > 1)
   524     return E_NOTIMPL;
   525   if (archiveLink.GetNumLevels() == 0)
   526     return MyOpenArchive(fileName, archiveLink, 0);
   527   return ReOpenArchive(archiveLink.GetArchive(), fileName);
   528 }

mercurial