LCOV - code coverage report
Current view: top level - netwerk/cache2 - CacheFileMetadata.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 313 534 58.6 %
Date: 2017-07-14 16:53:18 Functions: 28 45 62.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "CacheLog.h"
       6             : #include "CacheFileMetadata.h"
       7             : 
       8             : #include "CacheFileIOManager.h"
       9             : #include "nsICacheEntry.h"
      10             : #include "CacheHashUtils.h"
      11             : #include "CacheFileChunk.h"
      12             : #include "CacheFileUtils.h"
      13             : #include "nsILoadContextInfo.h"
      14             : #include "nsICacheEntry.h" // for nsICacheEntryMetaDataVisitor
      15             : #include "../cache/nsCacheUtils.h"
      16             : #include "nsIFile.h"
      17             : #include "mozilla/Telemetry.h"
      18             : #include "mozilla/DebugOnly.h"
      19             : #include "mozilla/IntegerPrintfMacros.h"
      20             : #include "prnetdb.h"
      21             : 
      22             : 
      23             : namespace mozilla {
      24             : namespace net {
      25             : 
      26             : #define kMinMetadataRead 1024  // TODO find optimal value from telemetry
      27             : #define kAlignSize       4096
      28             : 
      29             : // Most of the cache entries fit into one chunk due to current chunk size. Make
      30             : // sure to tweak this value if kChunkSize is going to change.
      31             : #define kInitialHashArraySize 1
      32             : 
      33             : // Initial elements buffer size.
      34             : #define kInitialBufSize 64
      35             : 
      36             : // Max size of elements in bytes.
      37             : #define kMaxElementsSize 64*1024
      38             : 
      39             : #define NOW_SECONDS() (uint32_t(PR_Now() / PR_USEC_PER_SEC))
      40             : 
      41          40 : NS_IMPL_ISUPPORTS(CacheFileMetadata, CacheFileIOListener)
      42             : 
      43           5 : CacheFileMetadata::CacheFileMetadata(CacheFileHandle *aHandle, const nsACString &aKey)
      44             :   : CacheMemoryConsumer(NORMAL)
      45             :   , mHandle(aHandle)
      46             :   , mHashArray(nullptr)
      47             :   , mHashArraySize(0)
      48             :   , mHashCount(0)
      49             :   , mOffset(-1)
      50             :   , mBuf(nullptr)
      51             :   , mBufSize(0)
      52             :   , mWriteBuf(nullptr)
      53             :   , mElementsSize(0)
      54             :   , mIsDirty(false)
      55             :   , mAnonymous(false)
      56             :   , mAllocExactSize(false)
      57           5 :   , mFirstRead(true)
      58             : {
      59           5 :   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, handle=%p, key=%s]",
      60             :        this, aHandle, PromiseFlatCString(aKey).get()));
      61             : 
      62           5 :   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
      63           5 :   mMetaHdr.mVersion = kCacheEntryVersion;
      64           5 :   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
      65           5 :   mKey = aKey;
      66             : 
      67          10 :   DebugOnly<nsresult> rv;
      68           5 :   rv = ParseKey(aKey);
      69           5 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
      70           5 : }
      71             : 
      72           0 : CacheFileMetadata::CacheFileMetadata(bool aMemoryOnly, bool aPinned, const nsACString &aKey)
      73             :   : CacheMemoryConsumer(aMemoryOnly ? MEMORY_ONLY : NORMAL)
      74             :   , mHandle(nullptr)
      75             :   , mHashArray(nullptr)
      76             :   , mHashArraySize(0)
      77             :   , mHashCount(0)
      78             :   , mOffset(0)
      79             :   , mBuf(nullptr)
      80             :   , mBufSize(0)
      81             :   , mWriteBuf(nullptr)
      82             :   , mElementsSize(0)
      83             :   , mIsDirty(true)
      84             :   , mAnonymous(false)
      85             :   , mAllocExactSize(false)
      86           0 :   , mFirstRead(true)
      87             : {
      88           0 :   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p, key=%s]",
      89             :        this, PromiseFlatCString(aKey).get()));
      90             : 
      91           0 :   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
      92           0 :   mMetaHdr.mVersion = kCacheEntryVersion;
      93           0 :   if (aPinned) {
      94           0 :     AddFlags(kCacheEntryIsPinned);
      95             :   }
      96           0 :   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
      97           0 :   mKey = aKey;
      98           0 :   mMetaHdr.mKeySize = mKey.Length();
      99             : 
     100           0 :   DebugOnly<nsresult> rv;
     101           0 :   rv = ParseKey(aKey);
     102           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     103           0 : }
     104             : 
     105           0 : CacheFileMetadata::CacheFileMetadata()
     106             :   : CacheMemoryConsumer(DONT_REPORT /* This is a helper class */)
     107             :   , mHandle(nullptr)
     108             :   , mHashArray(nullptr)
     109             :   , mHashArraySize(0)
     110             :   , mHashCount(0)
     111             :   , mOffset(0)
     112             :   , mBuf(nullptr)
     113             :   , mBufSize(0)
     114             :   , mWriteBuf(nullptr)
     115             :   , mElementsSize(0)
     116             :   , mIsDirty(false)
     117             :   , mAnonymous(false)
     118             :   , mAllocExactSize(false)
     119           0 :   , mFirstRead(true)
     120             : {
     121           0 :   LOG(("CacheFileMetadata::CacheFileMetadata() [this=%p]", this));
     122             : 
     123           0 :   memset(&mMetaHdr, 0, sizeof(CacheFileMetadataHeader));
     124           0 : }
     125             : 
     126           0 : CacheFileMetadata::~CacheFileMetadata()
     127             : {
     128           0 :   LOG(("CacheFileMetadata::~CacheFileMetadata() [this=%p]", this));
     129             : 
     130           0 :   MOZ_ASSERT(!mListener);
     131             : 
     132           0 :   if (mHashArray) {
     133           0 :     CacheFileUtils::FreeBuffer(mHashArray);
     134           0 :     mHashArray = nullptr;
     135           0 :     mHashArraySize = 0;
     136             :   }
     137             : 
     138           0 :   if (mBuf) {
     139           0 :     CacheFileUtils::FreeBuffer(mBuf);
     140           0 :     mBuf = nullptr;
     141           0 :     mBufSize = 0;
     142             :   }
     143           0 : }
     144             : 
     145             : void
     146           0 : CacheFileMetadata::SetHandle(CacheFileHandle *aHandle)
     147             : {
     148           0 :   LOG(("CacheFileMetadata::SetHandle() [this=%p, handle=%p]", this, aHandle));
     149             : 
     150           0 :   MOZ_ASSERT(!mHandle);
     151             : 
     152           0 :   mHandle = aHandle;
     153           0 : }
     154             : 
     155             : nsresult
     156           0 : CacheFileMetadata::GetKey(nsACString &_retval)
     157             : {
     158           0 :   _retval = mKey;
     159           0 :   return NS_OK;
     160             : }
     161             : 
     162             : nsresult
     163           5 : CacheFileMetadata::ReadMetadata(CacheFileMetadataListener *aListener)
     164             : {
     165           5 :   LOG(("CacheFileMetadata::ReadMetadata() [this=%p, listener=%p]", this, aListener));
     166             : 
     167           5 :   MOZ_ASSERT(!mListener);
     168           5 :   MOZ_ASSERT(!mHashArray);
     169           5 :   MOZ_ASSERT(!mBuf);
     170           5 :   MOZ_ASSERT(!mWriteBuf);
     171             : 
     172             :   nsresult rv;
     173             : 
     174           5 :   int64_t size = mHandle->FileSize();
     175           5 :   MOZ_ASSERT(size != -1);
     176             : 
     177           5 :   if (size == 0) {
     178             :     // this is a new entry
     179           2 :     LOG(("CacheFileMetadata::ReadMetadata() - Filesize == 0, creating empty "
     180             :          "metadata. [this=%p]", this));
     181             : 
     182           2 :     InitEmptyMetadata();
     183           2 :     aListener->OnMetadataRead(NS_OK);
     184           2 :     return NS_OK;
     185             :   }
     186             : 
     187           3 :   if (size < int64_t(sizeof(CacheFileMetadataHeader) + 2*sizeof(uint32_t))) {
     188             :     // there must be at least checksum, header and offset
     189           0 :     LOG(("CacheFileMetadata::ReadMetadata() - File is corrupted, creating "
     190             :          "empty metadata. [this=%p, filesize=%" PRId64 "]", this, size));
     191             : 
     192           0 :     InitEmptyMetadata();
     193           0 :     aListener->OnMetadataRead(NS_OK);
     194           0 :     return NS_OK;
     195             :   }
     196             : 
     197             :   // Set offset so that we read at least kMinMetadataRead if the file is big
     198             :   // enough.
     199             :   int64_t offset;
     200           3 :   if (size < kMinMetadataRead) {
     201           1 :     offset = 0;
     202             :   } else {
     203           2 :     offset = size - kMinMetadataRead;
     204             :   }
     205             : 
     206             :   // round offset to kAlignSize blocks
     207           3 :   offset = (offset / kAlignSize) * kAlignSize;
     208             : 
     209           3 :   mBufSize = size - offset;
     210           3 :   mBuf = static_cast<char *>(moz_xmalloc(mBufSize));
     211             : 
     212           3 :   DoMemoryReport(MemoryUsage());
     213             : 
     214           3 :   LOG(("CacheFileMetadata::ReadMetadata() - Reading metadata from disk, trying "
     215             :        "offset=%" PRId64 ", filesize=%" PRId64 " [this=%p]", offset, size, this));
     216             : 
     217           3 :   mReadStart = mozilla::TimeStamp::Now();
     218           3 :   mListener = aListener;
     219           3 :   rv = CacheFileIOManager::Read(mHandle, offset, mBuf, mBufSize, this);
     220           3 :   if (NS_FAILED(rv)) {
     221           0 :     LOG(("CacheFileMetadata::ReadMetadata() - CacheFileIOManager::Read() failed"
     222             :          " synchronously, creating empty metadata. [this=%p, rv=0x%08" PRIx32 "]",
     223             :          this, static_cast<uint32_t>(rv)));
     224             : 
     225           0 :     mListener = nullptr;
     226           0 :     InitEmptyMetadata();
     227           0 :     aListener->OnMetadataRead(NS_OK);
     228           0 :     return NS_OK;
     229             :   }
     230             : 
     231           3 :   return NS_OK;
     232             : }
     233             : 
     234             : uint32_t
     235           7 : CacheFileMetadata::CalcMetadataSize(uint32_t aElementsSize, uint32_t aHashCount)
     236             : {
     237             :   return sizeof(uint32_t) +                         // hash of the metadata
     238             :          aHashCount * sizeof(CacheHash::Hash16_t) + // array of chunk hashes
     239          14 :          sizeof(CacheFileMetadataHeader) +          // metadata header
     240          14 :          mKey.Length() + 1 +                        // key with trailing null
     241             :          aElementsSize +                            // elements
     242           7 :          sizeof(uint32_t);                          // offset
     243             : }
     244             : 
     245             : nsresult
     246           4 : CacheFileMetadata::WriteMetadata(uint32_t aOffset,
     247             :                                  CacheFileMetadataListener *aListener)
     248             : {
     249           4 :   LOG(("CacheFileMetadata::WriteMetadata() [this=%p, offset=%d, listener=%p]",
     250             :        this, aOffset, aListener));
     251             : 
     252           4 :   MOZ_ASSERT(!mListener);
     253           4 :   MOZ_ASSERT(!mWriteBuf);
     254             : 
     255             :   nsresult rv;
     256             : 
     257           4 :   mIsDirty = false;
     258             : 
     259           4 :   mWriteBuf = static_cast<char *>(malloc(CalcMetadataSize(mElementsSize,
     260             :                                                           mHashCount)));
     261           4 :   if (!mWriteBuf) {
     262           0 :     return NS_ERROR_OUT_OF_MEMORY;
     263             :   }
     264             : 
     265           4 :   char *p = mWriteBuf + sizeof(uint32_t);
     266           4 :   memcpy(p, mHashArray, mHashCount * sizeof(CacheHash::Hash16_t));
     267           4 :   p += mHashCount * sizeof(CacheHash::Hash16_t);
     268           4 :   mMetaHdr.WriteToBuf(p);
     269           4 :   p += sizeof(CacheFileMetadataHeader);
     270           4 :   memcpy(p, mKey.get(), mKey.Length());
     271           4 :   p += mKey.Length();
     272           4 :   *p = 0;
     273           4 :   p++;
     274           4 :   memcpy(p, mBuf, mElementsSize);
     275           4 :   p += mElementsSize;
     276             : 
     277             :   CacheHash::Hash32_t hash;
     278           4 :   hash = CacheHash::Hash(mWriteBuf + sizeof(uint32_t),
     279           8 :                          p - mWriteBuf - sizeof(uint32_t));
     280           4 :   NetworkEndian::writeUint32(mWriteBuf, hash);
     281             : 
     282           4 :   NetworkEndian::writeUint32(p, aOffset);
     283           4 :   p += sizeof(uint32_t);
     284             : 
     285           4 :   char * writeBuffer = mWriteBuf;
     286           4 :   if (aListener) {
     287           4 :     mListener = aListener;
     288             :   } else {
     289             :     // We are not going to pass |this| as a callback so the buffer will be
     290             :     // released by CacheFileIOManager. Just null out mWriteBuf here.
     291           0 :     mWriteBuf = nullptr;
     292             :   }
     293             : 
     294           4 :   rv = CacheFileIOManager::Write(mHandle, aOffset, writeBuffer, p - writeBuffer,
     295           4 :                                  true, true, aListener ? this : nullptr);
     296           4 :   if (NS_FAILED(rv)) {
     297           0 :     LOG(("CacheFileMetadata::WriteMetadata() - CacheFileIOManager::Write() "
     298             :          "failed synchronously. [this=%p, rv=0x%08" PRIx32 "]",
     299             :          this, static_cast<uint32_t>(rv)));
     300             : 
     301           0 :     mListener = nullptr;
     302           0 :     if (mWriteBuf) {
     303           0 :       CacheFileUtils::FreeBuffer(mWriteBuf);
     304           0 :       mWriteBuf = nullptr;
     305             :     }
     306           0 :     NS_ENSURE_SUCCESS(rv, rv);
     307             :   }
     308             : 
     309           4 :   DoMemoryReport(MemoryUsage());
     310             : 
     311           4 :   return NS_OK;
     312             : }
     313             : 
     314             : nsresult
     315           0 : CacheFileMetadata::SyncReadMetadata(nsIFile *aFile)
     316             : {
     317           0 :   LOG(("CacheFileMetadata::SyncReadMetadata() [this=%p]", this));
     318             : 
     319           0 :   MOZ_ASSERT(!mListener);
     320           0 :   MOZ_ASSERT(!mHandle);
     321           0 :   MOZ_ASSERT(!mHashArray);
     322           0 :   MOZ_ASSERT(!mBuf);
     323           0 :   MOZ_ASSERT(!mWriteBuf);
     324           0 :   MOZ_ASSERT(mKey.IsEmpty());
     325             : 
     326             :   nsresult rv;
     327             : 
     328             :   int64_t fileSize;
     329           0 :   rv = aFile->GetFileSize(&fileSize);
     330           0 :   if (NS_FAILED(rv)) {
     331             :     // Don't bloat the console
     332           0 :     return rv;
     333             :   }
     334             : 
     335             :   PRFileDesc *fd;
     336           0 :   rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0600, &fd);
     337           0 :   NS_ENSURE_SUCCESS(rv, rv);
     338             : 
     339           0 :   int64_t offset = PR_Seek64(fd, fileSize - sizeof(uint32_t), PR_SEEK_SET);
     340           0 :   if (offset == -1) {
     341           0 :     PR_Close(fd);
     342           0 :     return NS_ERROR_FAILURE;
     343             :   }
     344             : 
     345             :   uint32_t metaOffset;
     346           0 :   int32_t bytesRead = PR_Read(fd, &metaOffset, sizeof(uint32_t));
     347           0 :   if (bytesRead != sizeof(uint32_t)) {
     348           0 :     PR_Close(fd);
     349           0 :     return NS_ERROR_FAILURE;
     350             :   }
     351             : 
     352           0 :   metaOffset = NetworkEndian::readUint32(&metaOffset);
     353           0 :   if (metaOffset > fileSize) {
     354           0 :     PR_Close(fd);
     355           0 :     return NS_ERROR_FAILURE;
     356             :   }
     357             : 
     358           0 :   mBuf = static_cast<char *>(malloc(fileSize - metaOffset));
     359           0 :   if (!mBuf) {
     360           0 :     return NS_ERROR_OUT_OF_MEMORY;
     361             :   }
     362           0 :   mBufSize = fileSize - metaOffset;
     363             : 
     364           0 :   DoMemoryReport(MemoryUsage());
     365             : 
     366           0 :   offset = PR_Seek64(fd, metaOffset, PR_SEEK_SET);
     367           0 :   if (offset == -1) {
     368           0 :     PR_Close(fd);
     369           0 :     return NS_ERROR_FAILURE;
     370             :   }
     371             : 
     372           0 :   bytesRead = PR_Read(fd, mBuf, mBufSize);
     373           0 :   PR_Close(fd);
     374           0 :   if (bytesRead != static_cast<int32_t>(mBufSize)) {
     375           0 :     return NS_ERROR_FAILURE;
     376             :   }
     377             : 
     378           0 :   rv = ParseMetadata(metaOffset, 0, false);
     379           0 :   NS_ENSURE_SUCCESS(rv, rv);
     380             : 
     381           0 :   return NS_OK;
     382             : }
     383             : 
     384             : const char *
     385          72 : CacheFileMetadata::GetElement(const char *aKey)
     386             : {
     387          72 :   const char *data = mBuf;
     388          72 :   const char *limit = mBuf + mElementsSize;
     389             : 
     390         580 :   while (data != limit) {
     391         286 :     size_t maxLen = limit - data;
     392         286 :     size_t keyLen = strnlen(data, maxLen);
     393         286 :     MOZ_RELEASE_ASSERT(keyLen != maxLen, "Metadata elements corrupted. Key "
     394             :                        "isn't null terminated!");
     395         286 :     MOZ_RELEASE_ASSERT(keyLen + 1 != maxLen, "Metadata elements corrupted. "
     396             :                        "There is no value for the key!");
     397             : 
     398         286 :     const char *value = data + keyLen + 1;
     399         286 :     maxLen = limit - value;
     400         286 :     size_t valueLen = strnlen(value, maxLen);
     401         286 :     MOZ_RELEASE_ASSERT(valueLen != maxLen, "Metadata elements corrupted. Value "
     402             :                        "isn't null terminated!");
     403             : 
     404         286 :     if (strcmp(data, aKey) == 0) {
     405          32 :       LOG(("CacheFileMetadata::GetElement() - Key found [this=%p, key=%s]",
     406             :            this, aKey));
     407          32 :       return value;
     408             :     }
     409             : 
     410             :     // point to next pair
     411         254 :     data += keyLen + valueLen + 2;
     412             :   }
     413          40 :   LOG(("CacheFileMetadata::GetElement() - Key not found [this=%p, key=%s]",
     414             :        this, aKey));
     415          40 :   return nullptr;
     416             : }
     417             : 
     418             : nsresult
     419          19 : CacheFileMetadata::SetElement(const char *aKey, const char *aValue)
     420             : {
     421          19 :   LOG(("CacheFileMetadata::SetElement() [this=%p, key=%s, value=%p]",
     422             :        this, aKey, aValue));
     423             : 
     424          19 :   MarkDirty();
     425             : 
     426             :   nsresult rv;
     427             : 
     428          19 :   const uint32_t keySize = strlen(aKey) + 1;
     429          19 :   char *pos = const_cast<char *>(GetElement(aKey));
     430             : 
     431          19 :   if (!aValue) {
     432             :     // No value means remove the key/value pair completely, if existing
     433           0 :     if (pos) {
     434           0 :       uint32_t oldValueSize = strlen(pos) + 1;
     435           0 :       uint32_t offset = pos - mBuf;
     436           0 :       uint32_t remainder = mElementsSize - (offset + oldValueSize);
     437             : 
     438           0 :       memmove(pos - keySize, pos + oldValueSize, remainder);
     439           0 :       mElementsSize -= keySize + oldValueSize;
     440             :     }
     441           0 :     return NS_OK;
     442             :   }
     443             : 
     444          19 :   const uint32_t valueSize = strlen(aValue) + 1;
     445          19 :   uint32_t newSize = mElementsSize + valueSize;
     446          19 :   if (pos) {
     447           4 :     const uint32_t oldValueSize = strlen(pos) + 1;
     448           4 :     const uint32_t offset = pos - mBuf;
     449           4 :     const uint32_t remainder = mElementsSize - (offset + oldValueSize);
     450             : 
     451             :     // Update the value in place
     452           4 :     newSize -= oldValueSize;
     453           4 :     rv = EnsureBuffer(newSize);
     454           4 :     if (NS_FAILED(rv)) {
     455           0 :       return rv;
     456             :     }
     457             : 
     458             :     // Move the remainder to the right place
     459           4 :     pos = mBuf + offset;
     460           4 :     memmove(pos + valueSize, pos + oldValueSize, remainder);
     461             :   } else {
     462             :     // allocate new meta data element
     463          15 :     newSize += keySize;
     464          15 :     rv = EnsureBuffer(newSize);
     465          15 :     if (NS_FAILED(rv)) {
     466           0 :       return rv;
     467             :     }
     468             : 
     469             :     // Add after last element
     470          15 :     pos = mBuf + mElementsSize;
     471          15 :     memcpy(pos, aKey, keySize);
     472          15 :     pos += keySize;
     473             :   }
     474             : 
     475             :   // Update value
     476          19 :   memcpy(pos, aValue, valueSize);
     477          19 :   mElementsSize = newSize;
     478             : 
     479          19 :   return NS_OK;
     480             : }
     481             : 
     482             : nsresult
     483           1 : CacheFileMetadata::Visit(nsICacheEntryMetaDataVisitor *aVisitor)
     484             : {
     485           1 :   const char *data = mBuf;
     486           1 :   const char *limit = mBuf + mElementsSize;
     487             : 
     488           7 :   while (data < limit) {
     489             :     // Point to the value part
     490           3 :     const char *value = data + strlen(data) + 1;
     491           3 :     MOZ_ASSERT(value < limit, "Metadata elements corrupted");
     492             : 
     493           3 :     aVisitor->OnMetaDataElement(data, value);
     494             : 
     495             :     // Skip value part
     496           3 :     data = value + strlen(value) + 1;
     497             :   }
     498             : 
     499           1 :   MOZ_ASSERT(data == limit, "Metadata elements corrupted");
     500             : 
     501           1 :   return NS_OK;
     502             : }
     503             : 
     504             : CacheHash::Hash16_t
     505           2 : CacheFileMetadata::GetHash(uint32_t aIndex)
     506             : {
     507           2 :   MOZ_ASSERT(aIndex < mHashCount);
     508           2 :   return NetworkEndian::readUint16(&mHashArray[aIndex]);
     509             : }
     510             : 
     511             : nsresult
     512           4 : CacheFileMetadata::SetHash(uint32_t aIndex, CacheHash::Hash16_t aHash)
     513             : {
     514           4 :   LOG(("CacheFileMetadata::SetHash() [this=%p, idx=%d, hash=%x]",
     515             :        this, aIndex, aHash));
     516             : 
     517           4 :   MarkDirty();
     518             : 
     519           4 :   MOZ_ASSERT(aIndex <= mHashCount);
     520             : 
     521           4 :   if (aIndex > mHashCount) {
     522           0 :     return NS_ERROR_INVALID_ARG;
     523           4 :   } else if (aIndex == mHashCount) {
     524           2 :     if ((aIndex + 1) * sizeof(CacheHash::Hash16_t) > mHashArraySize) {
     525             :       // reallocate hash array buffer
     526           2 :       if (mHashArraySize == 0) {
     527           2 :         mHashArraySize = kInitialHashArraySize * sizeof(CacheHash::Hash16_t);
     528             :       } else {
     529           0 :         mHashArraySize *= 2;
     530             :       }
     531           2 :       mHashArray = static_cast<CacheHash::Hash16_t *>(
     532           2 :                      moz_xrealloc(mHashArray, mHashArraySize));
     533             :     }
     534             : 
     535           2 :     mHashCount++;
     536             :   }
     537             : 
     538           4 :   NetworkEndian::writeUint16(&mHashArray[aIndex], aHash);
     539             : 
     540           4 :   DoMemoryReport(MemoryUsage());
     541             : 
     542           4 :   return NS_OK;
     543             : }
     544             : 
     545             : nsresult
     546           0 : CacheFileMetadata::RemoveHash(uint32_t aIndex)
     547             : {
     548           0 :   LOG(("CacheFileMetadata::RemoveHash() [this=%p, idx=%d]", this, aIndex));
     549             : 
     550           0 :   MarkDirty();
     551             : 
     552           0 :   MOZ_ASSERT((aIndex + 1) == mHashCount, "Can remove only last hash!");
     553             : 
     554           0 :   if (aIndex + 1 != mHashCount) {
     555           0 :     return NS_ERROR_INVALID_ARG;
     556             :   }
     557             : 
     558           0 :   mHashCount--;
     559           0 :   return NS_OK;
     560             : }
     561             : 
     562             : nsresult
     563           0 : CacheFileMetadata::AddFlags(uint32_t aFlags)
     564             : {
     565           0 :   MarkDirty(false);
     566           0 :   mMetaHdr.mFlags |= aFlags;
     567           0 :   return NS_OK;
     568             : }
     569             : 
     570             : nsresult
     571           0 : CacheFileMetadata::RemoveFlags(uint32_t aFlags)
     572             : {
     573           0 :   MarkDirty(false);
     574           0 :   mMetaHdr.mFlags &= ~aFlags;
     575           0 :   return NS_OK;
     576             : }
     577             : 
     578             : nsresult
     579           0 : CacheFileMetadata::GetFlags(uint32_t *_retval)
     580             : {
     581           0 :   *_retval = mMetaHdr.mFlags;
     582           0 :   return NS_OK;
     583             : }
     584             : 
     585             : nsresult
     586           2 : CacheFileMetadata::SetExpirationTime(uint32_t aExpirationTime)
     587             : {
     588           2 :   LOG(("CacheFileMetadata::SetExpirationTime() [this=%p, expirationTime=%d]",
     589             :        this, aExpirationTime));
     590             : 
     591           2 :   MarkDirty(false);
     592           2 :   mMetaHdr.mExpirationTime = aExpirationTime;
     593           2 :   return NS_OK;
     594             : }
     595             : 
     596             : nsresult
     597          11 : CacheFileMetadata::GetExpirationTime(uint32_t *_retval)
     598             : {
     599          11 :   *_retval = mMetaHdr.mExpirationTime;
     600          11 :   return NS_OK;
     601             : }
     602             : 
     603             : nsresult
     604           6 : CacheFileMetadata::SetFrecency(uint32_t aFrecency)
     605             : {
     606           6 :   LOG(("CacheFileMetadata::SetFrecency() [this=%p, frecency=%f]",
     607             :        this, (double)aFrecency));
     608             : 
     609           6 :   MarkDirty(false);
     610           6 :   mMetaHdr.mFrecency = aFrecency;
     611           6 :   return NS_OK;
     612             : }
     613             : 
     614             : nsresult
     615           8 : CacheFileMetadata::GetFrecency(uint32_t *_retval)
     616             : {
     617           8 :   *_retval = mMetaHdr.mFrecency;
     618           8 :   return NS_OK;
     619             : }
     620             : 
     621             : nsresult
     622           4 : CacheFileMetadata::GetLastModified(uint32_t *_retval)
     623             : {
     624           4 :   *_retval = mMetaHdr.mLastModified;
     625           4 :   return NS_OK;
     626             : }
     627             : 
     628             : nsresult
     629           8 : CacheFileMetadata::GetLastFetched(uint32_t *_retval)
     630             : {
     631           8 :   *_retval = mMetaHdr.mLastFetched;
     632           8 :   return NS_OK;
     633             : }
     634             : 
     635             : nsresult
     636           8 : CacheFileMetadata::GetFetchCount(uint32_t *_retval)
     637             : {
     638           8 :   *_retval = mMetaHdr.mFetchCount;
     639           8 :   return NS_OK;
     640             : }
     641             : 
     642             : nsresult
     643           6 : CacheFileMetadata::OnFetched()
     644             : {
     645           6 :   MarkDirty(false);
     646             : 
     647           6 :   mMetaHdr.mLastFetched = NOW_SECONDS();
     648           6 :   ++mMetaHdr.mFetchCount;
     649           6 :   return NS_OK;
     650             : }
     651             : 
     652             : void
     653          42 : CacheFileMetadata::MarkDirty(bool aUpdateLastModified)
     654             : {
     655          42 :   mIsDirty = true;
     656          42 :   if (aUpdateLastModified) {
     657          28 :     mMetaHdr.mLastModified = NOW_SECONDS();
     658             :   }
     659          42 : }
     660             : 
     661             : nsresult
     662           0 : CacheFileMetadata::OnFileOpened(CacheFileHandle *aHandle, nsresult aResult)
     663             : {
     664           0 :   MOZ_CRASH("CacheFileMetadata::OnFileOpened should not be called!");
     665             :   return NS_ERROR_UNEXPECTED;
     666             : }
     667             : 
     668             : nsresult
     669           4 : CacheFileMetadata::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
     670             :                                  nsresult aResult)
     671             : {
     672           4 :   LOG(("CacheFileMetadata::OnDataWritten() [this=%p, handle=%p, result=0x%08" PRIx32 "]",
     673             :        this, aHandle, static_cast<uint32_t>(aResult)));
     674             : 
     675           4 :   MOZ_ASSERT(mListener);
     676           4 :   MOZ_ASSERT(mWriteBuf);
     677             : 
     678           4 :   CacheFileUtils::FreeBuffer(mWriteBuf);
     679           4 :   mWriteBuf = nullptr;
     680             : 
     681           8 :   nsCOMPtr<CacheFileMetadataListener> listener;
     682             : 
     683           4 :   mListener.swap(listener);
     684           4 :   listener->OnMetadataWritten(aResult);
     685             : 
     686           4 :   DoMemoryReport(MemoryUsage());
     687             : 
     688           8 :   return NS_OK;
     689             : }
     690             : 
     691             : nsresult
     692           3 : CacheFileMetadata::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
     693             :                               nsresult aResult)
     694             : {
     695           3 :   LOG(("CacheFileMetadata::OnDataRead() [this=%p, handle=%p, result=0x%08" PRIx32 "]",
     696             :        this, aHandle, static_cast<uint32_t>(aResult)));
     697             : 
     698           3 :   MOZ_ASSERT(mListener);
     699             : 
     700             :   nsresult rv;
     701           6 :   nsCOMPtr<CacheFileMetadataListener> listener;
     702             : 
     703           3 :   if (NS_FAILED(aResult)) {
     704           0 :     LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() failed"
     705             :          ", creating empty metadata. [this=%p, rv=0x%08" PRIx32 "]",
     706             :          this, static_cast<uint32_t>(aResult)));
     707             : 
     708           0 :     InitEmptyMetadata();
     709             : 
     710           0 :     mListener.swap(listener);
     711           0 :     listener->OnMetadataRead(NS_OK);
     712           0 :     return NS_OK;
     713             :   }
     714             : 
     715           3 :   if (mFirstRead) {
     716           3 :     Telemetry::AccumulateTimeDelta(
     717           3 :       Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_TIME_MS, mReadStart);
     718           3 :     Telemetry::Accumulate(
     719           3 :       Telemetry::NETWORK_CACHE_METADATA_FIRST_READ_SIZE, mBufSize);
     720             :   } else {
     721           0 :     Telemetry::AccumulateTimeDelta(
     722           0 :       Telemetry::NETWORK_CACHE_METADATA_SECOND_READ_TIME_MS, mReadStart);
     723             :   }
     724             : 
     725             :   // check whether we have read all necessary data
     726           6 :   uint32_t realOffset = NetworkEndian::readUint32(mBuf + mBufSize -
     727           6 :                                                   sizeof(uint32_t));
     728             : 
     729           3 :   int64_t size = mHandle->FileSize();
     730           3 :   MOZ_ASSERT(size != -1);
     731             : 
     732           3 :   if (realOffset >= size) {
     733           0 :     LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, creating "
     734             :          "empty metadata. [this=%p, realOffset=%u, size=%" PRId64 "]", this,
     735             :          realOffset, size));
     736             : 
     737           0 :     InitEmptyMetadata();
     738             : 
     739           0 :     mListener.swap(listener);
     740           0 :     listener->OnMetadataRead(NS_OK);
     741           0 :     return NS_OK;
     742             :   }
     743             : 
     744           3 :   uint32_t maxHashCount = size / kChunkSize;
     745           3 :   uint32_t maxMetadataSize = CalcMetadataSize(kMaxElementsSize, maxHashCount);
     746           3 :   if (size - realOffset > maxMetadataSize) {
     747           0 :     LOG(("CacheFileMetadata::OnDataRead() - Invalid realOffset, metadata would "
     748             :          "be too big, creating empty metadata. [this=%p, realOffset=%u, "
     749             :          "maxMetadataSize=%u, size=%" PRId64 "]", this, realOffset, maxMetadataSize,
     750             :          size));
     751             : 
     752           0 :     InitEmptyMetadata();
     753             : 
     754           0 :     mListener.swap(listener);
     755           0 :     listener->OnMetadataRead(NS_OK);
     756           0 :     return NS_OK;
     757             :   }
     758             : 
     759           3 :   uint32_t usedOffset = size - mBufSize;
     760             : 
     761           3 :   if (realOffset < usedOffset) {
     762           0 :     uint32_t missing = usedOffset - realOffset;
     763             :     // we need to read more data
     764           0 :     char *newBuf = static_cast<char *>(realloc(mBuf, mBufSize + missing));
     765           0 :     if (!newBuf) {
     766           0 :       LOG(("CacheFileMetadata::OnDataRead() - Error allocating %d more bytes "
     767             :            "for the missing part of the metadata, creating empty metadata. "
     768             :            "[this=%p]", missing, this));
     769             : 
     770           0 :       InitEmptyMetadata();
     771             : 
     772           0 :       mListener.swap(listener);
     773           0 :       listener->OnMetadataRead(NS_OK);
     774           0 :       return NS_OK;
     775             :     }
     776             : 
     777           0 :     mBuf = newBuf;
     778           0 :     memmove(mBuf + missing, mBuf, mBufSize);
     779           0 :     mBufSize += missing;
     780             : 
     781           0 :     DoMemoryReport(MemoryUsage());
     782             : 
     783           0 :     LOG(("CacheFileMetadata::OnDataRead() - We need to read %d more bytes to "
     784             :          "have full metadata. [this=%p]", missing, this));
     785             : 
     786           0 :     mFirstRead = false;
     787           0 :     mReadStart = mozilla::TimeStamp::Now();
     788           0 :     rv = CacheFileIOManager::Read(mHandle, realOffset, mBuf, missing, this);
     789           0 :     if (NS_FAILED(rv)) {
     790           0 :       LOG(("CacheFileMetadata::OnDataRead() - CacheFileIOManager::Read() "
     791             :            "failed synchronously, creating empty metadata. [this=%p, "
     792             :            "rv=0x%08" PRIx32 "]", this, static_cast<uint32_t>(rv)));
     793             : 
     794           0 :       InitEmptyMetadata();
     795             : 
     796           0 :       mListener.swap(listener);
     797           0 :       listener->OnMetadataRead(NS_OK);
     798           0 :       return NS_OK;
     799             :     }
     800             : 
     801           0 :     return NS_OK;
     802             :   }
     803             : 
     804           3 :   Telemetry::Accumulate(Telemetry::NETWORK_CACHE_METADATA_SIZE,
     805           3 :                         size - realOffset);
     806             : 
     807             :   // We have all data according to offset information at the end of the entry.
     808             :   // Try to parse it.
     809           3 :   rv = ParseMetadata(realOffset, realOffset - usedOffset, true);
     810           3 :   if (NS_FAILED(rv)) {
     811           0 :     LOG(("CacheFileMetadata::OnDataRead() - Error parsing metadata, creating "
     812             :          "empty metadata. [this=%p]", this));
     813           0 :     InitEmptyMetadata();
     814             :   } else {
     815             :     // Shrink elements buffer.
     816           3 :     mBuf = static_cast<char *>(moz_xrealloc(mBuf, mElementsSize));
     817           3 :     mBufSize = mElementsSize;
     818             : 
     819             :     // There is usually no or just one call to SetMetadataElement() when the
     820             :     // metadata is parsed from disk. Avoid allocating power of two sized buffer
     821             :     // which we do in case of newly created metadata.
     822           3 :     mAllocExactSize = true;
     823             :   }
     824             : 
     825           3 :   mListener.swap(listener);
     826           3 :   listener->OnMetadataRead(NS_OK);
     827             : 
     828           3 :   return NS_OK;
     829             : }
     830             : 
     831             : nsresult
     832           0 : CacheFileMetadata::OnFileDoomed(CacheFileHandle *aHandle, nsresult aResult)
     833             : {
     834           0 :   MOZ_CRASH("CacheFileMetadata::OnFileDoomed should not be called!");
     835             :   return NS_ERROR_UNEXPECTED;
     836             : }
     837             : 
     838             : nsresult
     839           0 : CacheFileMetadata::OnEOFSet(CacheFileHandle *aHandle, nsresult aResult)
     840             : {
     841           0 :   MOZ_CRASH("CacheFileMetadata::OnEOFSet should not be called!");
     842             :   return NS_ERROR_UNEXPECTED;
     843             : }
     844             : 
     845             : nsresult
     846           0 : CacheFileMetadata::OnFileRenamed(CacheFileHandle *aHandle, nsresult aResult)
     847             : {
     848           0 :   MOZ_CRASH("CacheFileMetadata::OnFileRenamed should not be called!");
     849             :   return NS_ERROR_UNEXPECTED;
     850             : }
     851             : 
     852             : void
     853           2 : CacheFileMetadata::InitEmptyMetadata()
     854             : {
     855           2 :   if (mBuf) {
     856           0 :     CacheFileUtils::FreeBuffer(mBuf);
     857           0 :     mBuf = nullptr;
     858           0 :     mBufSize = 0;
     859             :   }
     860           2 :   mAllocExactSize = false;
     861           2 :   mOffset = 0;
     862           2 :   mMetaHdr.mVersion = kCacheEntryVersion;
     863           2 :   mMetaHdr.mFetchCount = 0;
     864           2 :   mMetaHdr.mExpirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
     865           2 :   mMetaHdr.mKeySize = mKey.Length();
     866             : 
     867             :   // Deliberately not touching the "kCacheEntryIsPinned" flag.
     868             : 
     869           2 :   DoMemoryReport(MemoryUsage());
     870             : 
     871             :   // We're creating a new entry. If there is any old data truncate it.
     872           2 :   if (mHandle) {
     873           2 :     mHandle->SetPinned(Pinned());
     874             :     // We can pronounce the handle as invalid now, because it simply
     875             :     // doesn't have the correct metadata.  This will cause IO operations
     876             :     // be bypassed during shutdown (mainly dooming it, when a channel
     877             :     // is canceled by closing the window.)
     878           2 :     mHandle->SetInvalid();
     879           2 :     if (mHandle->FileExists() && mHandle->FileSize()) {
     880           0 :       CacheFileIOManager::TruncateSeekSetEOF(mHandle, 0, 0, nullptr);
     881             :     }
     882             :   }
     883           2 : }
     884             : 
     885             : nsresult
     886           3 : CacheFileMetadata::ParseMetadata(uint32_t aMetaOffset, uint32_t aBufOffset,
     887             :                                  bool aHaveKey)
     888             : {
     889           3 :   LOG(("CacheFileMetadata::ParseMetadata() [this=%p, metaOffset=%d, "
     890             :        "bufOffset=%d, haveKey=%u]", this, aMetaOffset, aBufOffset, aHaveKey));
     891             : 
     892             :   nsresult rv;
     893             : 
     894           3 :   uint32_t metaposOffset = mBufSize - sizeof(uint32_t);
     895           3 :   uint32_t hashesOffset = aBufOffset + sizeof(uint32_t);
     896           3 :   uint32_t hashCount = aMetaOffset / kChunkSize;
     897           3 :   if (aMetaOffset % kChunkSize)
     898           2 :     hashCount++;
     899           3 :   uint32_t hashesLen = hashCount * sizeof(CacheHash::Hash16_t);
     900           3 :   uint32_t hdrOffset = hashesOffset + hashesLen;
     901           3 :   uint32_t keyOffset = hdrOffset + sizeof(CacheFileMetadataHeader);
     902             : 
     903           3 :   LOG(("CacheFileMetadata::ParseMetadata() [this=%p]\n  metaposOffset=%d\n  "
     904             :        "hashesOffset=%d\n  hashCount=%d\n  hashesLen=%d\n  hdfOffset=%d\n  "
     905             :        "keyOffset=%d\n", this, metaposOffset, hashesOffset, hashCount,
     906             :        hashesLen,hdrOffset, keyOffset));
     907             : 
     908           3 :   if (keyOffset > metaposOffset) {
     909           0 :     LOG(("CacheFileMetadata::ParseMetadata() - Wrong keyOffset! [this=%p]",
     910             :          this));
     911           0 :     return NS_ERROR_FILE_CORRUPTED;
     912             :   }
     913             : 
     914           3 :   mMetaHdr.ReadFromBuf(mBuf + hdrOffset);
     915             : 
     916           3 :   if (mMetaHdr.mVersion == 1) {
     917             :     // Backward compatibility before we've added flags to the header
     918           0 :     keyOffset -= sizeof(uint32_t);
     919           3 :   } else if (mMetaHdr.mVersion == 2) {
     920             :     // Version 2 just lacks the ability to store alternative data. Nothing to do
     921             :     // here.
     922           3 :   } else if (mMetaHdr.mVersion != kCacheEntryVersion) {
     923           0 :     LOG(("CacheFileMetadata::ParseMetadata() - Not a version we understand to. "
     924             :          "[version=0x%x, this=%p]", mMetaHdr.mVersion, this));
     925           0 :     return NS_ERROR_UNEXPECTED;
     926             :   }
     927             : 
     928             :   // Update the version stored in the header to make writes
     929             :   // store the header in the current version form.
     930           3 :   mMetaHdr.mVersion = kCacheEntryVersion;
     931             : 
     932           3 :   uint32_t elementsOffset = mMetaHdr.mKeySize + keyOffset + 1;
     933             : 
     934           3 :   if (elementsOffset > metaposOffset) {
     935           0 :     LOG(("CacheFileMetadata::ParseMetadata() - Wrong elementsOffset %d "
     936             :          "[this=%p]", elementsOffset, this));
     937           0 :     return NS_ERROR_FILE_CORRUPTED;
     938             :   }
     939             : 
     940             :   // check that key ends with \0
     941           3 :   if (mBuf[elementsOffset - 1] != 0) {
     942           0 :     LOG(("CacheFileMetadata::ParseMetadata() - Elements not null terminated. "
     943             :          "[this=%p]", this));
     944           0 :     return NS_ERROR_FILE_CORRUPTED;
     945             :   }
     946             : 
     947             : 
     948           3 :   if (!aHaveKey) {
     949             :     // get the key form metadata
     950           0 :     mKey.Assign(mBuf + keyOffset, mMetaHdr.mKeySize);
     951             : 
     952           0 :     rv = ParseKey(mKey);
     953           0 :     if (NS_FAILED(rv))
     954           0 :       return rv;
     955             :   }
     956             :   else {
     957           3 :     if (mMetaHdr.mKeySize != mKey.Length()) {
     958           0 :       LOG(("CacheFileMetadata::ParseMetadata() - Key collision (1), key=%s "
     959             :            "[this=%p]", nsCString(mBuf + keyOffset, mMetaHdr.mKeySize).get(),
     960             :            this));
     961           0 :       return NS_ERROR_FILE_CORRUPTED;
     962             :     }
     963             : 
     964           3 :     if (memcmp(mKey.get(), mBuf + keyOffset, mKey.Length()) != 0) {
     965           0 :       LOG(("CacheFileMetadata::ParseMetadata() - Key collision (2), key=%s "
     966             :            "[this=%p]", nsCString(mBuf + keyOffset, mMetaHdr.mKeySize).get(),
     967             :            this));
     968           0 :       return NS_ERROR_FILE_CORRUPTED;
     969             :     }
     970             :   }
     971             : 
     972             :   // check metadata hash (data from hashesOffset to metaposOffset)
     973             :   CacheHash::Hash32_t hashComputed, hashExpected;
     974           3 :   hashComputed = CacheHash::Hash(mBuf + hashesOffset,
     975           3 :                                  metaposOffset - hashesOffset);
     976           3 :   hashExpected = NetworkEndian::readUint32(mBuf + aBufOffset);
     977             : 
     978           3 :   if (hashComputed != hashExpected) {
     979           0 :     LOG(("CacheFileMetadata::ParseMetadata() - Metadata hash mismatch! Hash of "
     980             :          "the metadata is %x, hash in file is %x [this=%p]", hashComputed,
     981             :          hashExpected, this));
     982           0 :     return NS_ERROR_FILE_CORRUPTED;
     983             :   }
     984             : 
     985             :   // check elements
     986           3 :   rv = CheckElements(mBuf + elementsOffset, metaposOffset - elementsOffset);
     987           3 :   if (NS_FAILED(rv))
     988           0 :     return rv;
     989             : 
     990           3 :   if (mHandle) {
     991           3 :     if (!mHandle->SetPinned(Pinned())) {
     992           0 :       LOG(("CacheFileMetadata::ParseMetadata() - handle was doomed for this "
     993             :            "pinning state, truncate the file [this=%p, pinned=%d]", this, Pinned()));
     994           0 :       return NS_ERROR_FILE_CORRUPTED;
     995             :     }
     996             :   }
     997             : 
     998           3 :   mHashArraySize = hashesLen;
     999           3 :   mHashCount = hashCount;
    1000           3 :   if (mHashArraySize) {
    1001           2 :     mHashArray = static_cast<CacheHash::Hash16_t *>(
    1002           2 :                    moz_xmalloc(mHashArraySize));
    1003           2 :     memcpy(mHashArray, mBuf + hashesOffset, mHashArraySize);
    1004             :   }
    1005             : 
    1006           3 :   MarkDirty();
    1007             : 
    1008           3 :   mElementsSize = metaposOffset - elementsOffset;
    1009           3 :   memmove(mBuf, mBuf + elementsOffset, mElementsSize);
    1010           3 :   mOffset = aMetaOffset;
    1011             : 
    1012           3 :   DoMemoryReport(MemoryUsage());
    1013             : 
    1014           3 :   return NS_OK;
    1015             : }
    1016             : 
    1017             : nsresult
    1018           3 : CacheFileMetadata::CheckElements(const char *aBuf, uint32_t aSize)
    1019             : {
    1020           3 :   if (aSize) {
    1021             :     // Check if the metadata ends with a zero byte.
    1022           3 :     if (aBuf[aSize - 1] != 0) {
    1023           0 :       NS_ERROR("Metadata elements are not null terminated");
    1024           0 :       LOG(("CacheFileMetadata::CheckElements() - Elements are not null "
    1025             :            "terminated. [this=%p]", this));
    1026           0 :       return NS_ERROR_FILE_CORRUPTED;
    1027             :     }
    1028             :     // Check that there are an even number of zero bytes
    1029             :     // to match the pattern { key \0 value \0 }
    1030           3 :     bool odd = false;
    1031        1264 :     for (uint32_t i = 0; i < aSize; i++) {
    1032        1261 :       if (aBuf[i] == 0)
    1033          34 :         odd = !odd;
    1034             :     }
    1035           3 :     if (odd) {
    1036           0 :       NS_ERROR("Metadata elements are malformed");
    1037           0 :       LOG(("CacheFileMetadata::CheckElements() - Elements are malformed. "
    1038             :            "[this=%p]", this));
    1039           0 :       return NS_ERROR_FILE_CORRUPTED;
    1040             :     }
    1041             :   }
    1042           3 :   return NS_OK;
    1043             : }
    1044             : 
    1045             : nsresult
    1046          19 : CacheFileMetadata::EnsureBuffer(uint32_t aSize)
    1047             : {
    1048          19 :   if (aSize > kMaxElementsSize) {
    1049           0 :     return NS_ERROR_FAILURE;
    1050             :   }
    1051             : 
    1052          19 :   if (mBufSize < aSize) {
    1053           6 :     if (mAllocExactSize) {
    1054             :       // If this is not the only allocation, use power of two for following
    1055             :       // allocations.
    1056           0 :       mAllocExactSize = false;
    1057             :     } else {
    1058             :       // find smallest power of 2 greater than or equal to aSize
    1059           6 :       --aSize;
    1060           6 :       aSize |= aSize >> 1;
    1061           6 :       aSize |= aSize >> 2;
    1062           6 :       aSize |= aSize >> 4;
    1063           6 :       aSize |= aSize >> 8;
    1064           6 :       aSize |= aSize >> 16;
    1065           6 :       ++aSize;
    1066             :     }
    1067             : 
    1068           6 :     if (aSize < kInitialBufSize) {
    1069           2 :       aSize = kInitialBufSize;
    1070             :     }
    1071             : 
    1072           6 :     char *newBuf = static_cast<char *>(realloc(mBuf, aSize));
    1073           6 :     if (!newBuf) {
    1074           0 :       return NS_ERROR_OUT_OF_MEMORY;
    1075             :     }
    1076           6 :     mBufSize = aSize;
    1077           6 :     mBuf = newBuf;
    1078             : 
    1079           6 :     DoMemoryReport(MemoryUsage());
    1080             :   }
    1081             : 
    1082          19 :   return NS_OK;
    1083             : }
    1084             : 
    1085             : nsresult
    1086           5 : CacheFileMetadata::ParseKey(const nsACString &aKey)
    1087             : {
    1088          10 :   nsCOMPtr<nsILoadContextInfo> info = CacheFileUtils::ParseKey(aKey);
    1089           5 :   NS_ENSURE_TRUE(info, NS_ERROR_FAILURE);
    1090             : 
    1091           5 :   mAnonymous =  info->IsAnonymous();
    1092           5 :   mOriginAttributes = *info->OriginAttributesPtr();
    1093             : 
    1094           5 :   return NS_OK;
    1095             : }
    1096             : 
    1097             : // Memory reporting
    1098             : 
    1099             : size_t
    1100           0 : CacheFileMetadata::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
    1101             : {
    1102           0 :   size_t n = 0;
    1103             :   // mHandle reported via CacheFileIOManager.
    1104           0 :   n += mKey.SizeOfExcludingThisIfUnshared(mallocSizeOf);
    1105           0 :   n += mallocSizeOf(mHashArray);
    1106           0 :   n += mallocSizeOf(mBuf);
    1107           0 :   n += mallocSizeOf(mWriteBuf);
    1108             :   // mListener is usually the owning CacheFile.
    1109             : 
    1110           0 :   return n;
    1111             : }
    1112             : 
    1113             : size_t
    1114           0 : CacheFileMetadata::SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
    1115             : {
    1116           0 :   return mallocSizeOf(this) + SizeOfExcludingThis(mallocSizeOf);
    1117             : }
    1118             : 
    1119             : } // namespace net
    1120             : } // namespace mozilla

Generated by: LCOV version 1.13