LCOV - code coverage report
Current view: top level - modules/libjar - nsZipArchive.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 224 581 38.6 %
Date: 2017-07-14 16:53:18 Functions: 30 58 51.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /*
       7             :  * This module implements a simple archive extractor for the PKZIP format.
       8             :  *
       9             :  * The underlying nsZipArchive is NOT thread-safe. Do not pass references
      10             :  * or pointers to it across thread boundaries.
      11             :  */
      12             : 
      13             : #define READTYPE  int32_t
      14             : #include "zlib.h"
      15             : #ifdef MOZ_JAR_BROTLI
      16             : #include "decode.h" // brotli
      17             : #endif
      18             : #include "nsISupportsUtils.h"
      19             : #include "prio.h"
      20             : #include "plstr.h"
      21             : #include "mozilla/Logging.h"
      22             : #include "mozilla/UniquePtrExtensions.h"
      23             : #include "stdlib.h"
      24             : #include "nsWildCard.h"
      25             : #include "nsZipArchive.h"
      26             : #include "nsString.h"
      27             : #include "prenv.h"
      28             : #if defined(XP_WIN)
      29             : #include <windows.h>
      30             : #endif
      31             : 
      32             : // For placement new used for arena allocations of zip file list
      33             : #include <new>
      34             : #define ZIP_ARENABLOCKSIZE (1*1024)
      35             : 
      36             : #ifdef XP_UNIX
      37             :     #include <sys/mman.h>
      38             :     #include <sys/types.h>
      39             :     #include <sys/stat.h>
      40             :     #include <limits.h>
      41             :     #include <unistd.h>
      42             : #elif defined(XP_WIN)
      43             :     #include <io.h>
      44             : #endif
      45             : 
      46             : #ifdef __SYMBIAN32__
      47             :     #include <sys/syslimits.h>
      48             : #endif /*__SYMBIAN32__*/
      49             : 
      50             : 
      51             : #ifndef XP_UNIX /* we need some constants defined in limits.h and unistd.h */
      52             : #  ifndef S_IFMT
      53             : #    define S_IFMT 0170000
      54             : #  endif
      55             : #  ifndef S_IFLNK
      56             : #    define S_IFLNK  0120000
      57             : #  endif
      58             : #  ifndef PATH_MAX
      59             : #    define PATH_MAX 1024
      60             : #  endif
      61             : #endif  /* XP_UNIX */
      62             : 
      63             : #ifdef XP_WIN
      64             : #include "private/pprio.h"  // To get PR_ImportFile
      65             : #endif
      66             : 
      67             : using namespace mozilla;
      68             : 
      69             : static const uint32_t kMaxNameLength = PATH_MAX; /* Maximum name length */
      70             : // For synthetic zip entries. Date/time corresponds to 1980-01-01 00:00.
      71             : static const uint16_t kSyntheticTime = 0;
      72             : static const uint16_t kSyntheticDate = (1 + (1 << 5) + (0 << 9));
      73             : 
      74             : static uint16_t xtoint(const uint8_t *ii);
      75             : static uint32_t xtolong(const uint8_t *ll);
      76             : static uint32_t HashName(const char* aName, uint16_t nameLen);
      77             : #ifdef XP_UNIX
      78             : static nsresult ResolveSymlink(const char *path);
      79             : #endif
      80             : 
      81             : class ZipArchiveLogger {
      82             : public:
      83         100 :   void Write(const nsACString &zip, const char *entry) const {
      84         100 :     if (!fd) {
      85         100 :       char *env = PR_GetEnv("MOZ_JAR_LOG_FILE");
      86         100 :       if (!env)
      87         200 :         return;
      88             : 
      89           0 :       nsCOMPtr<nsIFile> logFile;
      90           0 :       nsresult rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(env), false, getter_AddRefs(logFile));
      91           0 :       if (NS_FAILED(rv))
      92           0 :         return;
      93             : 
      94             :       // Create the log file and its parent directory (in case it doesn't exist)
      95           0 :       rv = logFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
      96           0 :       if (NS_FAILED(rv))
      97           0 :         return;
      98             : 
      99             :       PRFileDesc* file;
     100             : #ifdef XP_WIN
     101             :       // PR_APPEND is racy on Windows, so open a handle ourselves with flags that
     102             :       // will work, and use PR_ImportFile to make it a PRFileDesc.
     103             :       // This can go away when bug 840435 is fixed.
     104             :       nsAutoString path;
     105             :       logFile->GetPath(path);
     106             :       if (path.IsEmpty())
     107             :         return;
     108             :       HANDLE handle = CreateFileW(path.get(), FILE_APPEND_DATA, FILE_SHARE_WRITE,
     109             :                                   nullptr, OPEN_ALWAYS, 0, nullptr);
     110             :       if (handle == INVALID_HANDLE_VALUE)
     111             :         return;
     112             :       file = PR_ImportFile((PROsfd)handle);
     113             :       if (!file)
     114             :         return;
     115             : #else
     116           0 :       rv = logFile->OpenNSPRFileDesc(PR_WRONLY|PR_CREATE_FILE|PR_APPEND, 0644, &file);
     117           0 :       if (NS_FAILED(rv))
     118           0 :         return;
     119             : #endif
     120           0 :       fd = file;
     121             :     }
     122           0 :     nsCString buf(zip);
     123           0 :     buf.Append(' ');
     124           0 :     buf.Append(entry);
     125           0 :     buf.Append('\n');
     126           0 :     PR_Write(fd, buf.get(), buf.Length());
     127             :   }
     128             : 
     129           1 :   void AddRef() {
     130           1 :     MOZ_ASSERT(refCnt >= 0);
     131           1 :     ++refCnt;
     132           1 :   }
     133             : 
     134           0 :   void Release() {
     135           0 :     MOZ_ASSERT(refCnt > 0);
     136           0 :     if ((0 == --refCnt) && fd) {
     137           0 :       PR_Close(fd);
     138           0 :       fd = nullptr;
     139             :     }
     140           0 :   }
     141             : private:
     142             :   int refCnt;
     143             :   mutable PRFileDesc *fd;
     144             : };
     145             : 
     146             : static ZipArchiveLogger zipLog;
     147             : 
     148             : //***********************************************************
     149             : // For every inflation the following allocations are done:
     150             : // malloc(1 * 9520)
     151             : // malloc(32768 * 1)
     152             : //***********************************************************
     153             : 
     154         100 : nsresult gZlibInit(z_stream *zs)
     155             : {
     156         100 :   memset(zs, 0, sizeof(z_stream));
     157         100 :   int zerr = inflateInit2(zs, -MAX_WBITS);
     158         100 :   if (zerr != Z_OK) return NS_ERROR_OUT_OF_MEMORY;
     159             : 
     160         100 :   return NS_OK;
     161             : }
     162             : 
     163           1 : nsZipHandle::nsZipHandle()
     164             :   : mFileData(nullptr)
     165             :   , mLen(0)
     166             :   , mMap(nullptr)
     167             :   , mRefCnt(0)
     168             :   , mFileStart(nullptr)
     169           1 :   , mTotalLen(0)
     170             : {
     171           1 : }
     172             : 
     173         167 : NS_IMPL_ADDREF(nsZipHandle)
     174         166 : NS_IMPL_RELEASE(nsZipHandle)
     175             : 
     176           1 : nsresult nsZipHandle::Init(nsIFile *file, nsZipHandle **ret,
     177             :                            PRFileDesc **aFd)
     178             : {
     179           2 :   mozilla::AutoFDClose fd;
     180           1 :   int32_t flags = PR_RDONLY;
     181             : #if defined(XP_WIN)
     182             :   flags |= nsIFile::OS_READAHEAD;
     183             : #endif
     184           1 :   nsresult rv = file->OpenNSPRFileDesc(flags, 0000, &fd.rwget());
     185           1 :   if (NS_FAILED(rv))
     186           0 :     return rv;
     187             : 
     188           1 :   int64_t size = PR_Available64(fd);
     189           1 :   if (size >= INT32_MAX)
     190           0 :     return NS_ERROR_FILE_TOO_BIG;
     191             : 
     192           1 :   PRFileMap *map = PR_CreateFileMap(fd, size, PR_PROT_READONLY);
     193           1 :   if (!map)
     194           0 :     return NS_ERROR_FAILURE;
     195             : 
     196           1 :   uint8_t *buf = (uint8_t*) PR_MemMap(map, 0, (uint32_t) size);
     197             :   // Bug 525755: PR_MemMap fails when fd points at something other than a normal file.
     198           1 :   if (!buf) {
     199           0 :     PR_CloseFileMap(map);
     200           0 :     return NS_ERROR_FAILURE;
     201             :   }
     202             : 
     203           2 :   RefPtr<nsZipHandle> handle = new nsZipHandle();
     204           1 :   if (!handle) {
     205           0 :     PR_MemUnmap(buf, (uint32_t) size);
     206           0 :     PR_CloseFileMap(map);
     207           0 :     return NS_ERROR_OUT_OF_MEMORY;
     208             :   }
     209             : 
     210             : #if defined(XP_WIN)
     211             :   if (aFd) {
     212             :     *aFd = fd.forget();
     213             :   }
     214             : #else
     215           1 :   handle->mNSPRFileDesc = fd.forget();
     216             : #endif
     217           1 :   handle->mMap = map;
     218           1 :   handle->mFile.Init(file);
     219           1 :   handle->mTotalLen = (uint32_t) size;
     220           1 :   handle->mFileStart = buf;
     221           1 :   rv = handle->findDataStart();
     222           1 :   if (NS_FAILED(rv)) {
     223           0 :     PR_MemUnmap(buf, (uint32_t) size);
     224           0 :     PR_CloseFileMap(map);
     225           0 :     return rv;
     226             :   }
     227           1 :   handle.forget(ret);
     228           1 :   return NS_OK;
     229             : }
     230             : 
     231           0 : nsresult nsZipHandle::Init(nsZipArchive *zip, const char *entry,
     232             :                            nsZipHandle **ret)
     233             : {
     234           0 :   RefPtr<nsZipHandle> handle = new nsZipHandle();
     235           0 :   if (!handle)
     236           0 :     return NS_ERROR_OUT_OF_MEMORY;
     237             : 
     238           0 :   handle->mBuf = new nsZipItemPtr<uint8_t>(zip, entry);
     239           0 :   if (!handle->mBuf)
     240           0 :     return NS_ERROR_OUT_OF_MEMORY;
     241             : 
     242           0 :   if (!handle->mBuf->Buffer())
     243           0 :     return NS_ERROR_UNEXPECTED;
     244             : 
     245           0 :   handle->mMap = nullptr;
     246           0 :   handle->mFile.Init(zip, entry);
     247           0 :   handle->mTotalLen = handle->mBuf->Length();
     248           0 :   handle->mFileStart = handle->mBuf->Buffer();
     249           0 :   nsresult rv = handle->findDataStart();
     250           0 :   if (NS_FAILED(rv)) {
     251           0 :     return rv;
     252             :   }
     253           0 :   handle.forget(ret);
     254           0 :   return NS_OK;
     255             : }
     256             : 
     257           0 : nsresult nsZipHandle::Init(const uint8_t* aData, uint32_t aLen,
     258             :                            nsZipHandle **aRet)
     259             : {
     260           0 :   RefPtr<nsZipHandle> handle = new nsZipHandle();
     261             : 
     262           0 :   handle->mFileStart = aData;
     263           0 :   handle->mTotalLen = aLen;
     264           0 :   nsresult rv = handle->findDataStart();
     265           0 :   if (NS_FAILED(rv)) {
     266           0 :     return rv;
     267             :   }
     268           0 :   handle.forget(aRet);
     269           0 :   return NS_OK;
     270             : }
     271             : 
     272             : // This function finds the start of the ZIP data. If the file is a regular ZIP,
     273             : // this is just the start of the file. If the file is a CRX file, the start of
     274             : // the data is after the CRX header.
     275             : // CRX header reference: (CRX version 2)
     276             : //    Header requires little-endian byte ordering with 4-byte alignment.
     277             : //    32 bits       : magicNumber   - Defined as a |char m[] = "Cr24"|.
     278             : //                                    Equivilant to |uint32_t m = 0x34327243|.
     279             : //    32 bits       : version       - Unsigned integer representing the CRX file
     280             : //                                    format version. Currently equal to 2.
     281             : //    32 bits       : pubKeyLength  - Unsigned integer representing the length
     282             : //                                    of the public key in bytes.
     283             : //    32 bits       : sigLength     - Unsigned integer representing the length
     284             : //                                    of the signature in bytes.
     285             : //    pubKeyLength  : publicKey     - Contents of the author's public key.
     286             : //    sigLength     : signature     - Signature of the ZIP content.
     287             : //                                    Signature is created using the RSA
     288             : //                                    algorithm with the SHA-1 hash function.
     289           1 : nsresult nsZipHandle::findDataStart()
     290             : {
     291             :   // In the CRX header, integers are 32 bits. Our pointer to the file is of
     292             :   // type |uint8_t|, which is guaranteed to be 8 bits.
     293           1 :   const uint32_t CRXIntSize = 4;
     294             : 
     295             : MOZ_WIN_MEM_TRY_BEGIN
     296           1 :   if (mTotalLen > CRXIntSize * 4 && xtolong(mFileStart) == kCRXMagic) {
     297           0 :     const uint8_t* headerData = mFileStart;
     298           0 :     headerData += CRXIntSize * 2; // Skip magic number and version number
     299           0 :     uint32_t pubKeyLength = xtolong(headerData);
     300           0 :     headerData += CRXIntSize;
     301           0 :     uint32_t sigLength = xtolong(headerData);
     302           0 :     uint32_t headerSize = CRXIntSize * 4 + pubKeyLength + sigLength;
     303           0 :     if (mTotalLen > headerSize) {
     304           0 :       mLen = mTotalLen - headerSize;
     305           0 :       mFileData = mFileStart + headerSize;
     306           0 :       return NS_OK;
     307             :     }
     308             :   }
     309           1 :   mLen = mTotalLen;
     310           1 :   mFileData = mFileStart;
     311             : MOZ_WIN_MEM_TRY_CATCH(return NS_ERROR_FAILURE)
     312           1 :   return NS_OK;
     313             : }
     314             : 
     315           0 : int64_t nsZipHandle::SizeOfMapping()
     316             : {
     317           0 :   return mTotalLen;
     318             : }
     319             : 
     320           0 : nsresult nsZipHandle::GetNSPRFileDesc(PRFileDesc** aNSPRFileDesc)
     321             : {
     322           0 :   if (!aNSPRFileDesc) {
     323           0 :     return NS_ERROR_ILLEGAL_VALUE;
     324             :   }
     325             : 
     326           0 :   *aNSPRFileDesc = mNSPRFileDesc;
     327           0 :   if (!mNSPRFileDesc) {
     328           0 :     return NS_ERROR_NOT_AVAILABLE;
     329             :   }
     330             : 
     331           0 :   return NS_OK;
     332             : }
     333             : 
     334           0 : nsZipHandle::~nsZipHandle()
     335             : {
     336           0 :   if (mMap) {
     337           0 :     PR_MemUnmap((void *)mFileStart, mTotalLen);
     338           0 :     PR_CloseFileMap(mMap);
     339             :   }
     340           0 :   mFileStart = nullptr;
     341           0 :   mFileData = nullptr;
     342           0 :   mMap = nullptr;
     343           0 :   mBuf = nullptr;
     344           0 : }
     345             : 
     346             : //***********************************************************
     347             : //      nsZipArchive  --  public methods
     348             : //***********************************************************
     349             : 
     350             : //---------------------------------------------
     351             : //  nsZipArchive::OpenArchive
     352             : //---------------------------------------------
     353           1 : nsresult nsZipArchive::OpenArchive(nsZipHandle *aZipHandle, PRFileDesc *aFd)
     354             : {
     355           1 :   mFd = aZipHandle;
     356             : 
     357             :   //-- get table of contents for archive
     358           1 :   nsresult rv = BuildFileList(aFd);
     359           1 :   if (NS_SUCCEEDED(rv)) {
     360           1 :     if (aZipHandle->mFile)
     361           1 :       aZipHandle->mFile.GetURIString(mURI);
     362             :   }
     363           1 :   return rv;
     364             : }
     365             : 
     366           1 : nsresult nsZipArchive::OpenArchive(nsIFile *aFile)
     367             : {
     368           2 :   RefPtr<nsZipHandle> handle;
     369             : #if defined(XP_WIN)
     370             :   mozilla::AutoFDClose fd;
     371             :   nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle),
     372             :                                   &fd.rwget());
     373             : #else
     374           1 :   nsresult rv = nsZipHandle::Init(aFile, getter_AddRefs(handle));
     375             : #endif
     376           1 :   if (NS_FAILED(rv))
     377           0 :     return rv;
     378             : 
     379             : #if defined(XP_WIN)
     380             :   return OpenArchive(handle, fd.get());
     381             : #else
     382           1 :   return OpenArchive(handle);
     383             : #endif
     384             : }
     385             : 
     386             : //---------------------------------------------
     387             : //  nsZipArchive::Test
     388             : //---------------------------------------------
     389           0 : nsresult nsZipArchive::Test(const char *aEntryName)
     390             : {
     391             :   nsZipItem* currItem;
     392             : 
     393           0 :   if (aEntryName) // only test specified item
     394             :   {
     395           0 :     currItem = GetItem(aEntryName);
     396           0 :     if (!currItem)
     397           0 :       return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
     398             :     //-- don't test (synthetic) directory items
     399           0 :     if (currItem->IsDirectory())
     400           0 :       return NS_OK;
     401           0 :     return ExtractFile(currItem, 0, 0);
     402             :   }
     403             : 
     404             :   // test all items in archive
     405           0 :   for (auto* item : mFiles) {
     406           0 :     for (currItem = item; currItem; currItem = currItem->next) {
     407             :       //-- don't test (synthetic) directory items
     408           0 :       if (currItem->IsDirectory())
     409           0 :         continue;
     410           0 :       nsresult rv = ExtractFile(currItem, 0, 0);
     411           0 :       if (rv != NS_OK)
     412           0 :         return rv;
     413             :     }
     414             :   }
     415             : 
     416           0 :   return NS_OK;
     417             : }
     418             : 
     419             : //---------------------------------------------
     420             : //  nsZipArchive::CloseArchive
     421             : //---------------------------------------------
     422           0 : nsresult nsZipArchive::CloseArchive()
     423             : {
     424           0 :   if (mFd) {
     425           0 :     mArena.Clear();
     426           0 :     mFd = nullptr;
     427             :   }
     428             : 
     429             :   // CAUTION:
     430             :   // We don't need to delete each of the nsZipItem as the memory for
     431             :   // the zip item and the filename it holds are both allocated from the Arena.
     432             :   // Hence, destroying the Arena is like destroying all the memory
     433             :   // for all the nsZipItem in one shot. But if the ~nsZipItem is doing
     434             :   // anything more than cleaning up memory, we should start calling it.
     435             :   // Let us also cleanup the mFiles table for re-use on the next 'open' call
     436           0 :   memset(mFiles, 0, sizeof(mFiles));
     437           0 :   mBuiltSynthetics = false;
     438           0 :   return NS_OK;
     439             : }
     440             : 
     441             : //---------------------------------------------
     442             : // nsZipArchive::GetItem
     443             : //---------------------------------------------
     444         230 : nsZipItem*  nsZipArchive::GetItem(const char * aEntryName)
     445             : {
     446         230 :   if (aEntryName) {
     447         230 :     uint32_t len = strlen(aEntryName);
     448             :     //-- If the request is for a directory, make sure that synthetic entries
     449             :     //-- are created for the directories without their own entry.
     450         230 :     if (!mBuiltSynthetics) {
     451         230 :         if ((len > 0) && (aEntryName[len-1] == '/')) {
     452           0 :             if (BuildSynthetics() != NS_OK)
     453           0 :                 return 0;
     454             :         }
     455             :     }
     456             : MOZ_WIN_MEM_TRY_BEGIN
     457         230 :     nsZipItem* item = mFiles[ HashName(aEntryName, len) ];
     458         590 :     while (item) {
     459         380 :       if ((len == item->nameLength) &&
     460         100 :           (!memcmp(aEntryName, item->Name(), len))) {
     461             : 
     462             :         // Successful GetItem() is a good indicator that the file is about to be read
     463         100 :         zipLog.Write(mURI, aEntryName);
     464         100 :         return item; //-- found it
     465             :       }
     466         180 :       item = item->next;
     467             :     }
     468             : MOZ_WIN_MEM_TRY_CATCH(return nullptr)
     469             :   }
     470         130 :   return nullptr;
     471             : }
     472             : 
     473             : //---------------------------------------------
     474             : // nsZipArchive::ExtractFile
     475             : // This extracts the item to the filehandle provided.
     476             : // If 'aFd' is null, it only tests the extraction.
     477             : // On extraction error(s) it removes the file.
     478             : // When needed, it also resolves the symlink.
     479             : //---------------------------------------------
     480           0 : nsresult nsZipArchive::ExtractFile(nsZipItem *item, const char *outname,
     481             :                                    PRFileDesc* aFd)
     482             : {
     483           0 :   if (!item)
     484           0 :     return NS_ERROR_ILLEGAL_VALUE;
     485           0 :   if (!mFd)
     486           0 :     return NS_ERROR_FAILURE;
     487             : 
     488             :   // Directory extraction is handled in nsJAR::Extract,
     489             :   // so the item to be extracted should never be a directory
     490           0 :   MOZ_ASSERT(!item->IsDirectory());
     491             : 
     492             :   Bytef outbuf[ZIP_BUFLEN];
     493             : 
     494           0 :   nsZipCursor cursor(item, this, outbuf, ZIP_BUFLEN, true);
     495             : 
     496           0 :   nsresult rv = NS_OK;
     497             : 
     498             :   while (true) {
     499           0 :     uint32_t count = 0;
     500           0 :     uint8_t* buf = cursor.Read(&count);
     501           0 :     if (!buf) {
     502           0 :       nsZipArchive::sFileCorruptedReason = "nsZipArchive: Read() failed to return a buffer";
     503           0 :       rv = NS_ERROR_FILE_CORRUPTED;
     504           0 :       break;
     505             :     }
     506           0 :     if (count == 0) {
     507           0 :       break;
     508             :     }
     509             : 
     510           0 :     if (aFd && PR_Write(aFd, buf, count) < (READTYPE)count) {
     511           0 :       rv = NS_ERROR_FILE_DISK_FULL;
     512           0 :       break;
     513             :     }
     514           0 :   }
     515             : 
     516             :   //-- delete the file on errors, or resolve symlink if needed
     517           0 :   if (aFd) {
     518           0 :     PR_Close(aFd);
     519           0 :     if (rv != NS_OK)
     520           0 :       PR_Delete(outname);
     521             : #ifdef XP_UNIX
     522           0 :     else if (item->IsSymlink())
     523           0 :       rv = ResolveSymlink(outname);
     524             : #endif
     525             :   }
     526             : 
     527           0 :   return rv;
     528             : }
     529             : 
     530             : //---------------------------------------------
     531             : // nsZipArchive::FindInit
     532             : //---------------------------------------------
     533             : nsresult
     534           0 : nsZipArchive::FindInit(const char * aPattern, nsZipFind **aFind)
     535             : {
     536           0 :   if (!aFind)
     537           0 :     return NS_ERROR_ILLEGAL_VALUE;
     538             : 
     539             :   // null out param in case an error happens
     540           0 :   *aFind = nullptr;
     541             : 
     542           0 :   bool    regExp = false;
     543           0 :   char*   pattern = 0;
     544             : 
     545             :   // Create synthetic directory entries on demand
     546           0 :   nsresult rv = BuildSynthetics();
     547           0 :   if (rv != NS_OK)
     548           0 :     return rv;
     549             : 
     550             :   // validate the pattern
     551           0 :   if (aPattern)
     552             :   {
     553           0 :     switch (NS_WildCardValid((char*)aPattern))
     554             :     {
     555             :       case INVALID_SXP:
     556           0 :         return NS_ERROR_ILLEGAL_VALUE;
     557             : 
     558             :       case NON_SXP:
     559           0 :         regExp = false;
     560           0 :         break;
     561             : 
     562             :       case VALID_SXP:
     563           0 :         regExp = true;
     564           0 :         break;
     565             : 
     566             :       default:
     567             :         // undocumented return value from RegExpValid!
     568           0 :         MOZ_ASSERT(false);
     569             :         return NS_ERROR_ILLEGAL_VALUE;
     570             :     }
     571             : 
     572           0 :     pattern = PL_strdup(aPattern);
     573           0 :     if (!pattern)
     574           0 :       return NS_ERROR_OUT_OF_MEMORY;
     575             :   }
     576             : 
     577           0 :   *aFind = new nsZipFind(this, pattern, regExp);
     578           0 :   if (!*aFind) {
     579           0 :     PL_strfree(pattern);
     580           0 :     return NS_ERROR_OUT_OF_MEMORY;
     581             :   }
     582             : 
     583           0 :   return NS_OK;
     584             : }
     585             : 
     586             : 
     587             : 
     588             : //---------------------------------------------
     589             : // nsZipFind::FindNext
     590             : //---------------------------------------------
     591           0 : nsresult nsZipFind::FindNext(const char ** aResult, uint16_t *aNameLen)
     592             : {
     593           0 :   if (!mArchive || !aResult || !aNameLen)
     594           0 :     return NS_ERROR_ILLEGAL_VALUE;
     595             : 
     596           0 :   *aResult = 0;
     597           0 :   *aNameLen = 0;
     598             : MOZ_WIN_MEM_TRY_BEGIN
     599             :   // we start from last match, look for next
     600           0 :   while (mSlot < ZIP_TABSIZE)
     601             :   {
     602             :     // move to next in current chain, or move to new slot
     603           0 :     mItem = mItem ? mItem->next : mArchive->mFiles[mSlot];
     604             : 
     605           0 :     bool found = false;
     606           0 :     if (!mItem)
     607           0 :       ++mSlot;                          // no more in this chain, move to next slot
     608           0 :     else if (!mPattern)
     609           0 :       found = true;            // always match
     610           0 :     else if (mRegExp)
     611             :     {
     612             :       char buf[kMaxNameLength+1];
     613           0 :       memcpy(buf, mItem->Name(), mItem->nameLength);
     614           0 :       buf[mItem->nameLength]='\0';
     615           0 :       found = (NS_WildCardMatch(buf, mPattern, false) == MATCH);
     616             :     }
     617             :     else
     618           0 :       found = ((mItem->nameLength == strlen(mPattern)) &&
     619           0 :                (memcmp(mItem->Name(), mPattern, mItem->nameLength) == 0));
     620           0 :     if (found) {
     621             :       // Need also to return the name length, as it is NOT zero-terminatdd...
     622           0 :       *aResult = mItem->Name();
     623           0 :       *aNameLen = mItem->nameLength;
     624           0 :       return NS_OK;
     625             :     }
     626             :   }
     627             : MOZ_WIN_MEM_TRY_CATCH(return NS_ERROR_FAILURE)
     628           0 :   return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
     629             : }
     630             : 
     631             : #ifdef XP_UNIX
     632             : //---------------------------------------------
     633             : // ResolveSymlink
     634             : //---------------------------------------------
     635           0 : static nsresult ResolveSymlink(const char *path)
     636             : {
     637           0 :   PRFileDesc * fIn = PR_Open(path, PR_RDONLY, 0000);
     638           0 :   if (!fIn)
     639           0 :     return NS_ERROR_FILE_DISK_FULL;
     640             : 
     641             :   char buf[PATH_MAX+1];
     642           0 :   int32_t length = PR_Read(fIn, (void*)buf, PATH_MAX);
     643           0 :   PR_Close(fIn);
     644             : 
     645           0 :   if (length <= 0) {
     646           0 :     return NS_ERROR_FILE_DISK_FULL;
     647             :   }
     648             : 
     649           0 :   buf[length] = '\0';
     650             : 
     651           0 :   if (PR_Delete(path) != 0 || symlink(buf, path) != 0) {
     652           0 :      return NS_ERROR_FILE_DISK_FULL;
     653             :   }
     654           0 :   return NS_OK;
     655             : }
     656             : #endif
     657             : 
     658             : //***********************************************************
     659             : //      nsZipArchive  --  private implementation
     660             : //***********************************************************
     661             : 
     662             : //---------------------------------------------
     663             : //  nsZipArchive::CreateZipItem
     664             : //---------------------------------------------
     665         287 : nsZipItem* nsZipArchive::CreateZipItem()
     666             : {
     667             :   // Arena allocate the nsZipItem
     668         287 :   return (nsZipItem*)mArena.Allocate(sizeof(nsZipItem));
     669             : }
     670             : 
     671             : //---------------------------------------------
     672             : //  nsZipArchive::BuildFileList
     673             : //---------------------------------------------
     674           1 : nsresult nsZipArchive::BuildFileList(PRFileDesc *aFd)
     675             : {
     676             :   // Get archive size using end pos
     677             :   const uint8_t* buf;
     678           1 :   const uint8_t* startp = mFd->mFileData;
     679           1 :   const uint8_t* endp = startp + mFd->mLen;
     680             : MOZ_WIN_MEM_TRY_BEGIN
     681           1 :   uint32_t centralOffset = 4;
     682           1 :   if (mFd->mLen > ZIPCENTRAL_SIZE && xtolong(startp + centralOffset) == CENTRALSIG) {
     683             :     // Success means optimized jar layout from bug 559961 is in effect
     684           0 :     uint32_t readaheadLength = xtolong(startp);
     685           0 :     if (readaheadLength) {
     686             : #if defined(XP_SOLARIS)
     687             :       posix_madvise(const_cast<uint8_t*>(startp), readaheadLength, POSIX_MADV_WILLNEED);
     688             : #elif defined(XP_UNIX)
     689           0 :       madvise(const_cast<uint8_t*>(startp), readaheadLength, MADV_WILLNEED);
     690             : #elif defined(XP_WIN)
     691             :       if (aFd) {
     692             :         HANDLE hFile = (HANDLE) PR_FileDesc2NativeHandle(aFd);
     693             :         mozilla::ReadAhead(hFile, 0, readaheadLength);
     694             :       }
     695             : #endif
     696             :     }
     697             :   } else {
     698           9 :     for (buf = endp - ZIPEND_SIZE; buf > startp; buf--)
     699             :       {
     700           9 :         if (xtolong(buf) == ENDSIG) {
     701           1 :           centralOffset = xtolong(((ZipEnd *)buf)->offset_central_dir);
     702           1 :           break;
     703             :         }
     704             :       }
     705             :   }
     706             : 
     707           1 :   if (!centralOffset) {
     708           0 :     nsZipArchive::sFileCorruptedReason = "nsZipArchive: no central offset";
     709           0 :     return NS_ERROR_FILE_CORRUPTED;
     710             :   }
     711             : 
     712           1 :   buf = startp + centralOffset;
     713             : 
     714             :   // avoid overflow of startp + centralOffset.
     715           1 :   if (buf < startp) {
     716           0 :     nsZipArchive::sFileCorruptedReason = "nsZipArchive: overflow looking for central directory";
     717           0 :     return NS_ERROR_FILE_CORRUPTED;
     718             :   }
     719             : 
     720             :   //-- Read the central directory headers
     721           1 :   uint32_t sig = 0;
     722        1151 :   while ((buf + int32_t(sizeof(uint32_t)) > buf) &&
     723         576 :          (buf + int32_t(sizeof(uint32_t)) <= endp) &&
     724             :          ((sig = xtolong(buf)) == CENTRALSIG)) {
     725             :     // Make sure there is enough data available.
     726         287 :     if ((buf > endp) || (endp - buf < ZIPCENTRAL_SIZE)) {
     727           0 :       nsZipArchive::sFileCorruptedReason = "nsZipArchive: central directory too small";
     728           0 :       return NS_ERROR_FILE_CORRUPTED;
     729             :     }
     730             : 
     731             :     // Read the fixed-size data.
     732         287 :     ZipCentral* central = (ZipCentral*)buf;
     733             : 
     734         287 :     uint16_t namelen = xtoint(central->filename_len);
     735         287 :     uint16_t extralen = xtoint(central->extrafield_len);
     736         287 :     uint16_t commentlen = xtoint(central->commentfield_len);
     737         287 :     uint32_t diff = ZIPCENTRAL_SIZE + namelen + extralen + commentlen;
     738             : 
     739             :     // Sanity check variable sizes and refuse to deal with
     740             :     // anything too big: it's likely a corrupt archive.
     741         287 :     if (namelen < 1 ||
     742             :         namelen > kMaxNameLength) {
     743           0 :       nsZipArchive::sFileCorruptedReason = "nsZipArchive: namelen out of range";
     744           0 :       return NS_ERROR_FILE_CORRUPTED;
     745             :     }
     746         574 :     if (buf >= buf + diff || // No overflow
     747         287 :         buf >= endp - diff) {
     748           0 :       nsZipArchive::sFileCorruptedReason = "nsZipArchive: overflow looking for next item";
     749           0 :       return NS_ERROR_FILE_CORRUPTED;
     750             :     }
     751             : 
     752             :     // Point to the next item at the top of loop
     753         287 :     buf += diff;
     754             : 
     755         287 :     nsZipItem* item = CreateZipItem();
     756         287 :     if (!item)
     757           0 :       return NS_ERROR_OUT_OF_MEMORY;
     758             : 
     759         287 :     item->central = central;
     760         287 :     item->nameLength = namelen;
     761         287 :     item->isSynthetic = false;
     762             : 
     763             :     // Add item to file table
     764         287 :     uint32_t hash = HashName(item->Name(), namelen);
     765         287 :     item->next = mFiles[hash];
     766         287 :     mFiles[hash] = item;
     767             : 
     768         287 :     sig = 0;
     769             :   } /* while reading central directory records */
     770             : 
     771           1 :   if (sig != ENDSIG) {
     772           0 :     nsZipArchive::sFileCorruptedReason = "nsZipArchive: unexpected sig";
     773           0 :     return NS_ERROR_FILE_CORRUPTED;
     774             :   }
     775             : 
     776             :   // Make the comment available for consumers.
     777           1 :   if ((endp >= buf) && (endp - buf >= ZIPEND_SIZE)) {
     778           1 :     ZipEnd *zipend = (ZipEnd *)buf;
     779             : 
     780           1 :     buf += ZIPEND_SIZE;
     781           1 :     uint16_t commentlen = xtoint(zipend->commentfield_len);
     782           1 :     if (endp - buf >= commentlen) {
     783           1 :       mCommentPtr = (const char *)buf;
     784           1 :       mCommentLen = commentlen;
     785             :     }
     786             :   }
     787             : 
     788             : MOZ_WIN_MEM_TRY_CATCH(return NS_ERROR_FAILURE)
     789           1 :   return NS_OK;
     790             : }
     791             : 
     792             : //---------------------------------------------
     793             : //  nsZipArchive::BuildSynthetics
     794             : //---------------------------------------------
     795           0 : nsresult nsZipArchive::BuildSynthetics()
     796             : {
     797           0 :   if (mBuiltSynthetics)
     798           0 :     return NS_OK;
     799           0 :   mBuiltSynthetics = true;
     800             : 
     801             : MOZ_WIN_MEM_TRY_BEGIN
     802             :   // Create synthetic entries for any missing directories.
     803             :   // Do this when all ziptable has scanned to prevent double entries.
     804           0 :   for (auto* item : mFiles)
     805             :   {
     806           0 :     for (; item != nullptr; item = item->next)
     807             :     {
     808           0 :       if (item->isSynthetic)
     809           0 :         continue;
     810             : 
     811             :       //-- add entries for directories in the current item's path
     812             :       //-- go from end to beginning, because then we can stop trying
     813             :       //-- to create diritems if we find that the diritem we want to
     814             :       //-- create already exists
     815             :       //-- start just before the last char so as to not add the item
     816             :       //-- twice if it's a directory
     817           0 :       uint16_t namelen = item->nameLength;
     818           0 :       MOZ_ASSERT(namelen > 0, "Attempt to build synthetic for zero-length entry name!");
     819           0 :       const char *name = item->Name();
     820           0 :       for (uint16_t dirlen = namelen - 1; dirlen > 0; dirlen--)
     821             :       {
     822           0 :         if (name[dirlen-1] != '/')
     823           0 :           continue;
     824             : 
     825             :         // The character before this is '/', so if this is also '/' then we
     826             :         // have an empty path component. Skip it.
     827           0 :         if (name[dirlen] == '/')
     828           0 :           continue;
     829             : 
     830             :         // Is the directory already in the file table?
     831           0 :         uint32_t hash = HashName(item->Name(), dirlen);
     832           0 :         bool found = false;
     833           0 :         for (nsZipItem* zi = mFiles[hash]; zi != nullptr; zi = zi->next)
     834             :         {
     835           0 :           if ((dirlen == zi->nameLength) &&
     836           0 :               (0 == memcmp(item->Name(), zi->Name(), dirlen)))
     837             :           {
     838             :             // we've already added this dir and all its parents
     839           0 :             found = true;
     840           0 :             break;
     841             :           }
     842             :         }
     843             :         // if the directory was found, break out of the directory
     844             :         // creation loop now that we know all implicit directories
     845             :         // are there -- otherwise, start creating the zip item
     846           0 :         if (found)
     847           0 :           break;
     848             : 
     849           0 :         nsZipItem* diritem = CreateZipItem();
     850           0 :         if (!diritem)
     851           0 :           return NS_ERROR_OUT_OF_MEMORY;
     852             : 
     853             :         // Point to the central record of the original item for the name part.
     854           0 :         diritem->central =  item->central;
     855           0 :         diritem->nameLength = dirlen;
     856           0 :         diritem->isSynthetic = true;
     857             : 
     858             :         // add diritem to the file table
     859           0 :         diritem->next = mFiles[hash];
     860           0 :         mFiles[hash] = diritem;
     861             :       } /* end processing of dirs in item's name */
     862             :     }
     863             :   }
     864             : MOZ_WIN_MEM_TRY_CATCH(return NS_ERROR_FAILURE)
     865           0 :   return NS_OK;
     866             : }
     867             : 
     868         165 : nsZipHandle* nsZipArchive::GetFD()
     869             : {
     870         165 :   if (!mFd)
     871           0 :     return nullptr;
     872         165 :   return mFd.get();
     873             : }
     874             : 
     875             : //---------------------------------------------
     876             : // nsZipArchive::GetDataOffset
     877             : //---------------------------------------------
     878         100 : uint32_t nsZipArchive::GetDataOffset(nsZipItem* aItem)
     879             : {
     880         100 :   MOZ_ASSERT(aItem);
     881             : MOZ_WIN_MEM_TRY_BEGIN
     882             :   //-- read local header to get variable length values and calculate
     883             :   //-- the real data offset
     884         100 :   uint32_t len = mFd->mLen;
     885         100 :   const uint8_t* data = mFd->mFileData;
     886         100 :   uint32_t offset = aItem->LocalOffset();
     887         100 :   if (len < ZIPLOCAL_SIZE || offset > len - ZIPLOCAL_SIZE)
     888           0 :     return 0;
     889             : 
     890             :   // -- check signature before using the structure, in case the zip file is corrupt
     891         100 :   ZipLocal* Local = (ZipLocal*)(data + offset);
     892         100 :   if ((xtolong(Local->signature) != LOCALSIG))
     893           0 :     return 0;
     894             : 
     895             :   //-- NOTE: extralen is different in central header and local header
     896             :   //--       for archives created using the Unix "zip" utility. To set
     897             :   //--       the offset accurately we need the _local_ extralen.
     898         200 :   offset += ZIPLOCAL_SIZE +
     899         200 :             xtoint(Local->filename_len) +
     900         200 :             xtoint(Local->extrafield_len);
     901             : 
     902         100 :   return offset;
     903             : MOZ_WIN_MEM_TRY_CATCH(return 0)
     904             : }
     905             : 
     906             : //---------------------------------------------
     907             : // nsZipArchive::GetData
     908             : //---------------------------------------------
     909         100 : const uint8_t* nsZipArchive::GetData(nsZipItem* aItem)
     910             : {
     911         100 :   MOZ_ASSERT(aItem);
     912             : MOZ_WIN_MEM_TRY_BEGIN
     913         100 :   uint32_t offset = GetDataOffset(aItem);
     914             : 
     915             :   // -- check if there is enough source data in the file
     916         200 :   if (!offset ||
     917         200 :       mFd->mLen < aItem->Size() ||
     918         300 :       offset > mFd->mLen - aItem->Size() ||
     919         100 :       (aItem->Compression() == STORED && aItem->Size() != aItem->RealSize())) {
     920           0 :     return nullptr;
     921             :   }
     922             : 
     923         100 :   return mFd->mFileData + offset;
     924             : MOZ_WIN_MEM_TRY_CATCH(return nullptr)
     925             : }
     926             : 
     927             : // nsZipArchive::GetComment
     928           0 : bool nsZipArchive::GetComment(nsACString &aComment)
     929             : {
     930             : MOZ_WIN_MEM_TRY_BEGIN
     931           0 :   aComment.Assign(mCommentPtr, mCommentLen);
     932             : MOZ_WIN_MEM_TRY_CATCH(return false)
     933           0 :   return true;
     934             : }
     935             : 
     936             : //---------------------------------------------
     937             : // nsZipArchive::SizeOfMapping
     938             : //---------------------------------------------
     939           0 : int64_t nsZipArchive::SizeOfMapping()
     940             : {
     941           0 :     return mFd ? mFd->SizeOfMapping() : 0;
     942             : }
     943             : 
     944             : //------------------------------------------
     945             : // nsZipArchive constructor and destructor
     946             : //------------------------------------------
     947             : 
     948           1 : nsZipArchive::nsZipArchive()
     949             :   : mRefCnt(0)
     950             :   , mCommentPtr(nullptr)
     951             :   , mCommentLen(0)
     952           1 :   , mBuiltSynthetics(false)
     953             : {
     954           1 :   zipLog.AddRef();
     955             : 
     956             :   // initialize the table to nullptr
     957           1 :   memset(mFiles, 0, sizeof(mFiles));
     958           1 : }
     959             : 
     960           1 : NS_IMPL_ADDREF(nsZipArchive)
     961           0 : NS_IMPL_RELEASE(nsZipArchive)
     962             : 
     963           0 : nsZipArchive::~nsZipArchive()
     964             : {
     965           0 :   CloseArchive();
     966             : 
     967           0 :   zipLog.Release();
     968           0 : }
     969             : 
     970             : 
     971             : //------------------------------------------
     972             : // nsZipFind constructor and destructor
     973             : //------------------------------------------
     974             : 
     975           0 : nsZipFind::nsZipFind(nsZipArchive* aZip, char* aPattern, bool aRegExp)
     976             :   : mArchive(aZip)
     977             :   , mPattern(aPattern)
     978             :   , mItem(nullptr)
     979             :   , mSlot(0)
     980           0 :   , mRegExp(aRegExp)
     981             : {
     982           0 :   MOZ_COUNT_CTOR(nsZipFind);
     983           0 : }
     984             : 
     985           0 : nsZipFind::~nsZipFind()
     986             : {
     987           0 :   PL_strfree(mPattern);
     988             : 
     989           0 :   MOZ_COUNT_DTOR(nsZipFind);
     990           0 : }
     991             : 
     992             : //------------------------------------------
     993             : // helper functions
     994             : //------------------------------------------
     995             : 
     996             : /*
     997             :  * HashName
     998             :  *
     999             :  * returns a hash key for the entry name
    1000             :  */
    1001         517 : static uint32_t HashName(const char* aName, uint16_t len)
    1002             : {
    1003         517 :   MOZ_ASSERT(aName != 0);
    1004             : 
    1005         517 :   const uint8_t* p = (const uint8_t*)aName;
    1006         517 :   const uint8_t* endp = p + len;
    1007         517 :   uint32_t val = 0;
    1008       64281 :   while (p != endp) {
    1009       31882 :     val = val*37 + *p++;
    1010             :   }
    1011             : 
    1012         517 :   return (val % ZIP_TABSIZE);
    1013             : }
    1014             : 
    1015             : /*
    1016             :  *  x t o i n t
    1017             :  *
    1018             :  *  Converts a two byte ugly endianed integer
    1019             :  *  to our platform's integer.
    1020             :  */
    1021        1862 : static uint16_t xtoint (const uint8_t *ii)
    1022             : {
    1023        1862 :   return (uint16_t) ((ii [0]) | (ii [1] << 8));
    1024             : }
    1025             : 
    1026             : /*
    1027             :  *  x t o l o n g
    1028             :  *
    1029             :  *  Converts a four byte ugly endianed integer
    1030             :  *  to our platform's integer.
    1031             :  */
    1032        1100 : static uint32_t xtolong (const uint8_t *ll)
    1033             : {
    1034        2200 :   return (uint32_t)( (ll [0] <<  0) |
    1035        2200 :                      (ll [1] <<  8) |
    1036        2200 :                      (ll [2] << 16) |
    1037        2200 :                      (ll [3] << 24) );
    1038             : }
    1039             : 
    1040             : /*
    1041             :  * GetModTime
    1042             :  *
    1043             :  * returns last modification time in microseconds
    1044             :  */
    1045           0 : static PRTime GetModTime(uint16_t aDate, uint16_t aTime)
    1046             : {
    1047             :   // Note that on DST shift we can't handle correctly the hour that is valid
    1048             :   // in both DST zones
    1049             :   PRExplodedTime time;
    1050             : 
    1051           0 :   time.tm_usec = 0;
    1052             : 
    1053           0 :   time.tm_hour = (aTime >> 11) & 0x1F;
    1054           0 :   time.tm_min = (aTime >> 5) & 0x3F;
    1055           0 :   time.tm_sec = (aTime & 0x1F) * 2;
    1056             : 
    1057           0 :   time.tm_year = (aDate >> 9) + 1980;
    1058           0 :   time.tm_month = ((aDate >> 5) & 0x0F) - 1;
    1059           0 :   time.tm_mday = aDate & 0x1F;
    1060             : 
    1061           0 :   time.tm_params.tp_gmt_offset = 0;
    1062           0 :   time.tm_params.tp_dst_offset = 0;
    1063             : 
    1064           0 :   PR_NormalizeTime(&time, PR_GMTParameters);
    1065           0 :   time.tm_params.tp_gmt_offset = PR_LocalTimeParameters(&time).tp_gmt_offset;
    1066           0 :   PR_NormalizeTime(&time, PR_GMTParameters);
    1067           0 :   time.tm_params.tp_dst_offset = PR_LocalTimeParameters(&time).tp_dst_offset;
    1068             : 
    1069           0 :   return PR_ImplodeTime(&time);
    1070             : }
    1071             : 
    1072           0 : nsZipItem::nsZipItem()
    1073             :   : next(nullptr)
    1074             :   , central(nullptr)
    1075             :   , nameLength(0)
    1076           0 :   , isSynthetic(false)
    1077           0 : {}
    1078             : 
    1079         100 : uint32_t nsZipItem::LocalOffset()
    1080             : {
    1081         100 :   return xtolong(central->localhdr_offset);
    1082             : }
    1083             : 
    1084         300 : uint32_t nsZipItem::Size()
    1085             : {
    1086         300 :   return isSynthetic ? 0 : xtolong(central->size);
    1087             : }
    1088             : 
    1089         200 : uint32_t nsZipItem::RealSize()
    1090             : {
    1091         200 :   return isSynthetic ? 0 : xtolong(central->orglen);
    1092             : }
    1093             : 
    1094         100 : uint32_t nsZipItem::CRC32()
    1095             : {
    1096         100 :   return isSynthetic ? 0 : xtolong(central->crc32);
    1097             : }
    1098             : 
    1099           0 : uint16_t nsZipItem::Date()
    1100             : {
    1101           0 :   return isSynthetic ? kSyntheticDate : xtoint(central->date);
    1102             : }
    1103             : 
    1104           0 : uint16_t nsZipItem::Time()
    1105             : {
    1106           0 :   return isSynthetic ? kSyntheticTime : xtoint(central->time);
    1107             : }
    1108             : 
    1109         800 : uint16_t nsZipItem::Compression()
    1110             : {
    1111         800 :   return isSynthetic ? STORED : xtoint(central->method);
    1112             : }
    1113             : 
    1114           0 : bool nsZipItem::IsDirectory()
    1115             : {
    1116           0 :   return isSynthetic || ((nameLength > 0) && ('/' == Name()[nameLength - 1]));
    1117             : }
    1118             : 
    1119           0 : uint16_t nsZipItem::Mode()
    1120             : {
    1121           0 :   if (isSynthetic) return 0755;
    1122           0 :   return ((uint16_t)(central->external_attributes[2]) | 0x100);
    1123             : }
    1124             : 
    1125           0 : const uint8_t * nsZipItem::GetExtraField(uint16_t aTag, uint16_t *aBlockSize)
    1126             : {
    1127           0 :   if (isSynthetic) return nullptr;
    1128             : MOZ_WIN_MEM_TRY_BEGIN
    1129           0 :   const unsigned char *buf = ((const unsigned char*)central) + ZIPCENTRAL_SIZE +
    1130           0 :                              nameLength;
    1131           0 :   uint32_t buflen = (uint32_t)xtoint(central->extrafield_len);
    1132           0 :   uint32_t pos = 0;
    1133             :   uint16_t tag, blocksize;
    1134             : 
    1135           0 :   while (buf && (pos + 4) <= buflen) {
    1136           0 :     tag = xtoint(buf + pos);
    1137           0 :     blocksize = xtoint(buf + pos + 2);
    1138             : 
    1139           0 :     if (aTag == tag && (pos + 4 + blocksize) <= buflen) {
    1140           0 :       *aBlockSize = blocksize;
    1141           0 :       return buf + pos;
    1142             :     }
    1143             : 
    1144           0 :     pos += blocksize + 4;
    1145             :   }
    1146             : 
    1147             : MOZ_WIN_MEM_TRY_CATCH(return nullptr)
    1148           0 :   return nullptr;
    1149             : }
    1150             : 
    1151             : 
    1152           0 : PRTime nsZipItem::LastModTime()
    1153             : {
    1154           0 :   if (isSynthetic) return GetModTime(kSyntheticDate, kSyntheticTime);
    1155             : 
    1156             :   // Try to read timestamp from extra field
    1157             :   uint16_t blocksize;
    1158           0 :   const uint8_t *tsField = GetExtraField(EXTENDED_TIMESTAMP_FIELD, &blocksize);
    1159           0 :   if (tsField && blocksize >= 5 && tsField[4] & EXTENDED_TIMESTAMP_MODTIME) {
    1160           0 :     return (PRTime)(xtolong(tsField + 5)) * PR_USEC_PER_SEC;
    1161             :   }
    1162             : 
    1163           0 :   return GetModTime(Date(), Time());
    1164             : }
    1165             : 
    1166             : #ifdef XP_UNIX
    1167           0 : bool nsZipItem::IsSymlink()
    1168             : {
    1169           0 :   if (isSynthetic) return false;
    1170           0 :   return (xtoint(central->external_attributes+2) & S_IFMT) == S_IFLNK;
    1171             : }
    1172             : #endif
    1173             : 
    1174         100 : nsZipCursor::nsZipCursor(nsZipItem *item, nsZipArchive *aZip, uint8_t* aBuf,
    1175         100 :                          uint32_t aBufSize, bool doCRC)
    1176             :   : mItem(item)
    1177             :   , mBuf(aBuf)
    1178             :   , mBufSize(aBufSize)
    1179             : #ifdef MOZ_JAR_BROTLI
    1180             :   , mBrotliState(nullptr)
    1181             : #endif
    1182             :   , mCRC(0)
    1183         100 :   , mDoCRC(doCRC)
    1184             : {
    1185         100 :   if (mItem->Compression() == DEFLATED) {
    1186             : #ifdef DEBUG
    1187             :     nsresult status =
    1188             : #endif
    1189         100 :       gZlibInit(&mZs);
    1190         100 :     NS_ASSERTION(status == NS_OK, "Zlib failed to initialize");
    1191         100 :     NS_ASSERTION(aBuf, "Must pass in a buffer for DEFLATED nsZipItem");
    1192             :   }
    1193             : 
    1194         100 :   mZs.avail_in = item->Size();
    1195         100 :   mZs.next_in = (Bytef*)aZip->GetData(item);
    1196             : 
    1197             : #ifdef MOZ_JAR_BROTLI
    1198         100 :   if (mItem->Compression() == MOZ_JAR_BROTLI) {
    1199           0 :     mBrotliState = BrotliCreateState(nullptr, nullptr, nullptr);
    1200             :   }
    1201             : #endif
    1202             : 
    1203         100 :   if (doCRC)
    1204         100 :     mCRC = crc32(0L, Z_NULL, 0);
    1205         100 : }
    1206             : 
    1207         200 : nsZipCursor::~nsZipCursor()
    1208             : {
    1209         100 :   if (mItem->Compression() == DEFLATED) {
    1210         100 :     inflateEnd(&mZs);
    1211             :   }
    1212             : #ifdef MOZ_JAR_BROTLI
    1213         100 :   if (mItem->Compression() == MOZ_JAR_BROTLI) {
    1214           0 :     BrotliDestroyState(mBrotliState);
    1215             :   }
    1216             : #endif
    1217         100 : }
    1218             : 
    1219         100 : uint8_t* nsZipCursor::ReadOrCopy(uint32_t *aBytesRead, bool aCopy) {
    1220             :   int zerr;
    1221         100 :   uint8_t *buf = nullptr;
    1222         100 :   bool verifyCRC = true;
    1223             : 
    1224         100 :   if (!mZs.next_in)
    1225           0 :     return nullptr;
    1226             : MOZ_WIN_MEM_TRY_BEGIN
    1227         100 :   switch (mItem->Compression()) {
    1228             :   case STORED:
    1229           0 :     if (!aCopy) {
    1230           0 :       *aBytesRead = mZs.avail_in;
    1231           0 :       buf = mZs.next_in;
    1232           0 :       mZs.next_in += mZs.avail_in;
    1233           0 :       mZs.avail_in = 0;
    1234             :     } else {
    1235           0 :       *aBytesRead = mZs.avail_in > mBufSize ? mBufSize : mZs.avail_in;
    1236           0 :       memcpy(mBuf, mZs.next_in, *aBytesRead);
    1237           0 :       mZs.avail_in -= *aBytesRead;
    1238           0 :       mZs.next_in += *aBytesRead;
    1239             :     }
    1240           0 :     break;
    1241             :   case DEFLATED:
    1242         100 :     buf = mBuf;
    1243         100 :     mZs.next_out = buf;
    1244         100 :     mZs.avail_out = mBufSize;
    1245             : 
    1246         100 :     zerr = inflate(&mZs, Z_PARTIAL_FLUSH);
    1247         100 :     if (zerr != Z_OK && zerr != Z_STREAM_END)
    1248           0 :       return nullptr;
    1249             : 
    1250         100 :     *aBytesRead = mZs.next_out - buf;
    1251         100 :     verifyCRC = (zerr == Z_STREAM_END);
    1252         100 :     break;
    1253             : #ifdef MOZ_JAR_BROTLI
    1254             :   case MOZ_JAR_BROTLI: {
    1255           0 :     buf = mBuf;
    1256           0 :     mZs.next_out = buf;
    1257             :     /* The brotli library wants size_t, but z_stream only contains
    1258             :      * unsigned int for avail_*. So use temporary stack values. */
    1259           0 :     size_t avail_out = mBufSize;
    1260           0 :     size_t avail_in = mZs.avail_in;
    1261           0 :     BrotliResult result = BrotliDecompressStream(
    1262           0 :       &avail_in, const_cast<const unsigned char**>(&mZs.next_in),
    1263           0 :       &avail_out, &mZs.next_out, nullptr, mBrotliState);
    1264             :     /* We don't need to update avail_out, it's not used outside this
    1265             :      * function. */
    1266           0 :     mZs.avail_in = avail_in;
    1267             : 
    1268           0 :     if (result == BROTLI_RESULT_ERROR) {
    1269           0 :       return nullptr;
    1270             :     }
    1271             : 
    1272           0 :     *aBytesRead = mZs.next_out - buf;
    1273           0 :     verifyCRC = (result == BROTLI_RESULT_SUCCESS);
    1274           0 :     break;
    1275             :   }
    1276             : #endif
    1277             :   default:
    1278           0 :     return nullptr;
    1279             :   }
    1280             : 
    1281         100 :   if (mDoCRC) {
    1282         100 :     mCRC = crc32(mCRC, (const unsigned char*)buf, *aBytesRead);
    1283         100 :     if (verifyCRC && mCRC != mItem->CRC32())
    1284           0 :       return nullptr;
    1285             :   }
    1286             : MOZ_WIN_MEM_TRY_CATCH(return nullptr)
    1287         100 :   return buf;
    1288             : }
    1289             : 
    1290         165 : nsZipItemPtr_base::nsZipItemPtr_base(nsZipArchive *aZip,
    1291         165 :                                      const char * aEntryName, bool doCRC)
    1292             :   : mReturnBuf(nullptr)
    1293         165 :   , mReadlen(0)
    1294             : {
    1295             :   // make sure the ziparchive hangs around
    1296         165 :   mZipHandle = aZip->GetFD();
    1297             : 
    1298         165 :   nsZipItem* item = aZip->GetItem(aEntryName);
    1299         165 :   if (!item)
    1300         130 :     return;
    1301             : 
    1302         100 :   uint32_t size = 0;
    1303         100 :   bool compressed = (item->Compression() == DEFLATED);
    1304             : #ifdef MOZ_JAR_BROTLI
    1305         100 :   compressed |= (item->Compression() == MOZ_JAR_BROTLI);
    1306             : #endif
    1307         100 :   if (compressed) {
    1308         100 :     size = item->RealSize();
    1309         100 :     mAutoBuf = MakeUniqueFallible<uint8_t[]>(size);
    1310         100 :     if (!mAutoBuf) {
    1311           0 :       return;
    1312             :     }
    1313             :   }
    1314             : 
    1315         200 :   nsZipCursor cursor(item, aZip, mAutoBuf.get(), size, doCRC);
    1316         100 :   mReturnBuf = cursor.Read(&mReadlen);
    1317         100 :   if (!mReturnBuf) {
    1318           0 :     return;
    1319             :   }
    1320             : 
    1321         100 :   if (mReadlen != item->RealSize()) {
    1322           0 :     NS_ASSERTION(mReadlen == item->RealSize(), "nsZipCursor underflow");
    1323           0 :     mReturnBuf = nullptr;
    1324           0 :     return;
    1325             :   }
    1326             : }
    1327             : 
    1328             : /* static */ const char*
    1329             : nsZipArchive::sFileCorruptedReason = nullptr;

Generated by: LCOV version 1.13