LCOV - code coverage report
Current view: top level - netwerk/cache - nsDiskCacheStreams.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 297 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : 
       8             : #include "nsCache.h"
       9             : #include "nsDiskCache.h"
      10             : #include "nsDiskCacheDevice.h"
      11             : #include "nsDiskCacheStreams.h"
      12             : #include "nsCacheService.h"
      13             : #include "mozilla/FileUtils.h"
      14             : #include "nsThreadUtils.h"
      15             : #include "mozilla/MemoryReporting.h"
      16             : #include "mozilla/Telemetry.h"
      17             : #include "mozilla/TimeStamp.h"
      18             : #include <algorithm>
      19             : 
      20             : // we pick 16k as the max buffer size because that is the threshold above which
      21             : //      we are unable to store the data in the cache block files
      22             : //      see nsDiskCacheMap.[cpp,h]
      23             : #define kMaxBufferSize      (16 * 1024)
      24             : 
      25             : // Assumptions:
      26             : //      - cache descriptors live for life of streams
      27             : //      - streams will only be used by FileTransport,
      28             : //         they will not be directly accessible to clients
      29             : //      - overlapped I/O is NOT supported
      30             : 
      31             : 
      32             : /******************************************************************************
      33             :  *  nsDiskCacheInputStream
      34             :  *****************************************************************************/
      35             : class nsDiskCacheInputStream : public nsIInputStream {
      36             : 
      37             : public:
      38             : 
      39             :     nsDiskCacheInputStream( nsDiskCacheStreamIO * parent,
      40             :                             PRFileDesc *          fileDesc,
      41             :                             const char *          buffer,
      42             :                             uint32_t              endOfStream);
      43             : 
      44             :     NS_DECL_THREADSAFE_ISUPPORTS
      45             :     NS_DECL_NSIINPUTSTREAM
      46             : 
      47             : private:
      48             :     virtual ~nsDiskCacheInputStream();
      49             : 
      50             :     nsDiskCacheStreamIO *           mStreamIO;  // backpointer to parent
      51             :     PRFileDesc *                    mFD;
      52             :     const char *                    mBuffer;
      53             :     uint32_t                        mStreamEnd;
      54             :     uint32_t                        mPos;       // stream position
      55             :     bool                            mClosed;
      56             : };
      57             : 
      58             : 
      59           0 : NS_IMPL_ISUPPORTS(nsDiskCacheInputStream, nsIInputStream)
      60             : 
      61             : 
      62           0 : nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO * parent,
      63             :                                                 PRFileDesc *          fileDesc,
      64             :                                                 const char *          buffer,
      65           0 :                                                 uint32_t              endOfStream)
      66             :     : mStreamIO(parent)
      67             :     , mFD(fileDesc)
      68             :     , mBuffer(buffer)
      69             :     , mStreamEnd(endOfStream)
      70             :     , mPos(0)
      71           0 :     , mClosed(false)
      72             : {
      73           0 :     NS_ADDREF(mStreamIO);
      74           0 :     mStreamIO->IncrementInputStreamCount();
      75           0 : }
      76             : 
      77             : 
      78           0 : nsDiskCacheInputStream::~nsDiskCacheInputStream()
      79             : {
      80           0 :     Close();
      81           0 :     mStreamIO->DecrementInputStreamCount();
      82           0 :     NS_RELEASE(mStreamIO);
      83           0 : }
      84             : 
      85             : 
      86             : NS_IMETHODIMP
      87           0 : nsDiskCacheInputStream::Close()
      88             : {
      89           0 :     if (!mClosed) {
      90           0 :         if (mFD) {
      91           0 :             (void) PR_Close(mFD);
      92           0 :             mFD = nullptr;
      93             :         }
      94           0 :         mClosed = true;
      95             :     }
      96           0 :     return NS_OK;
      97             : }
      98             : 
      99             : 
     100             : NS_IMETHODIMP
     101           0 : nsDiskCacheInputStream::Available(uint64_t * bytesAvailable)
     102             : {
     103           0 :     if (mClosed)  return NS_BASE_STREAM_CLOSED;
     104           0 :     if (mStreamEnd < mPos)  return NS_ERROR_UNEXPECTED;
     105             : 
     106           0 :     *bytesAvailable = mStreamEnd - mPos;
     107           0 :     return NS_OK;
     108             : }
     109             : 
     110             : 
     111             : NS_IMETHODIMP
     112           0 : nsDiskCacheInputStream::Read(char * buffer, uint32_t count, uint32_t * bytesRead)
     113             : {
     114           0 :     *bytesRead = 0;
     115             : 
     116           0 :     if (mClosed) {
     117           0 :         CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
     118             :                          "[stream=%p] stream was closed",
     119             :                          this));
     120           0 :         return NS_OK;
     121             :     }
     122             : 
     123           0 :     if (mPos == mStreamEnd) {
     124           0 :         CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
     125             :                          "[stream=%p] stream at end of file",
     126             :                          this));
     127           0 :         return NS_OK;
     128             :     }
     129           0 :     if (mPos > mStreamEnd) {
     130           0 :         CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
     131             :                          "[stream=%p] stream past end of file (!)",
     132             :                          this));
     133           0 :         return NS_ERROR_UNEXPECTED;
     134             :     }
     135             : 
     136           0 :     if (count > mStreamEnd - mPos)
     137           0 :         count = mStreamEnd - mPos;
     138             : 
     139           0 :     if (mFD) {
     140             :         // just read from file
     141           0 :         int32_t  result = PR_Read(mFD, buffer, count);
     142           0 :         if (result < 0) {
     143           0 :             nsresult rv = NS_ErrorAccordingToNSPR();
     144           0 :             CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read PR_Read failed"
     145             :                              "[stream=%p, rv=%d, NSPR error %s",
     146             :                              this, int(rv), PR_ErrorToName(PR_GetError())));
     147           0 :             return rv;
     148             :         }
     149             : 
     150           0 :         mPos += (uint32_t)result;
     151           0 :         *bytesRead = (uint32_t)result;
     152             : 
     153           0 :     } else if (mBuffer) {
     154             :         // read data from mBuffer
     155           0 :         memcpy(buffer, mBuffer + mPos, count);
     156           0 :         mPos += count;
     157           0 :         *bytesRead = count;
     158             :     } else {
     159             :         // no data source for input stream
     160             :     }
     161             : 
     162           0 :     CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
     163             :                      "[stream=%p, count=%ud, byteRead=%ud] ",
     164             :                      this, unsigned(count), unsigned(*bytesRead)));
     165           0 :     return NS_OK;
     166             : }
     167             : 
     168             : 
     169             : NS_IMETHODIMP
     170           0 : nsDiskCacheInputStream::ReadSegments(nsWriteSegmentFun writer,
     171             :                                      void *            closure,
     172             :                                      uint32_t          count,
     173             :                                      uint32_t *        bytesRead)
     174             : {
     175           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     176             : }
     177             : 
     178             : 
     179             : NS_IMETHODIMP
     180           0 : nsDiskCacheInputStream::IsNonBlocking(bool * nonBlocking)
     181             : {
     182           0 :     *nonBlocking = false;
     183           0 :     return NS_OK;
     184             : }
     185             : 
     186             : 
     187             : 
     188             : 
     189             : /******************************************************************************
     190             :  *  nsDiskCacheStreamIO
     191             :  *****************************************************************************/
     192           0 : NS_IMPL_ISUPPORTS(nsDiskCacheStreamIO, nsIOutputStream)
     193             : 
     194           0 : nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding *   binding)
     195             :     : mBinding(binding)
     196             :     , mInStreamCount(0)
     197             :     , mFD(nullptr)
     198             :     , mStreamEnd(0)
     199             :     , mBufSize(0)
     200             :     , mBuffer(nullptr)
     201           0 :     , mOutputStreamIsOpen(false)
     202             : {
     203           0 :     mDevice = (nsDiskCacheDevice *)mBinding->mCacheEntry->CacheDevice();
     204             : 
     205             :     // acquire "death grip" on cache service
     206           0 :     nsCacheService *service = nsCacheService::GlobalInstance();
     207           0 :     NS_ADDREF(service);
     208           0 : }
     209             : 
     210             : 
     211           0 : nsDiskCacheStreamIO::~nsDiskCacheStreamIO()
     212             : {
     213           0 :     nsCacheService::AssertOwnsLock();
     214             : 
     215             :     // Close the outputstream
     216           0 :     if (mBinding && mOutputStreamIsOpen) {
     217           0 :         (void)CloseOutputStream();
     218             :     }
     219             : 
     220             :     // release "death grip" on cache service
     221           0 :     nsCacheService *service = nsCacheService::GlobalInstance();
     222           0 :     NS_RELEASE(service);
     223             : 
     224             :     // assert streams closed
     225           0 :     NS_ASSERTION(!mOutputStreamIsOpen, "output stream still open");
     226           0 :     NS_ASSERTION(mInStreamCount == 0, "input stream still open");
     227           0 :     NS_ASSERTION(!mFD, "file descriptor not closed");
     228             : 
     229           0 :     DeleteBuffer();
     230           0 : }
     231             : 
     232             : 
     233             : // NOTE: called with service lock held
     234             : nsresult
     235           0 : nsDiskCacheStreamIO::GetInputStream(uint32_t offset, nsIInputStream ** inputStream)
     236             : {
     237           0 :     NS_ENSURE_ARG_POINTER(inputStream);
     238           0 :     NS_ENSURE_TRUE(offset == 0, NS_ERROR_NOT_IMPLEMENTED);
     239             : 
     240           0 :     *inputStream = nullptr;
     241             : 
     242           0 :     if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
     243             : 
     244           0 :     if (mOutputStreamIsOpen) {
     245           0 :         NS_WARNING("already have an output stream open");
     246           0 :         return NS_ERROR_NOT_AVAILABLE;
     247             :     }
     248             : 
     249             :     nsresult            rv;
     250           0 :     PRFileDesc *        fd = nullptr;
     251             : 
     252           0 :     mStreamEnd = mBinding->mCacheEntry->DataSize();
     253           0 :     if (mStreamEnd == 0) {
     254             :         // there's no data to read
     255           0 :         NS_ASSERTION(!mBinding->mRecord.DataLocationInitialized(), "storage allocated for zero data size");
     256           0 :     } else if (mBinding->mRecord.DataFile() == 0) {
     257             :         // open file desc for data
     258           0 :         rv = OpenCacheFile(PR_RDONLY, &fd);
     259           0 :         if (NS_FAILED(rv))  return rv;  // unable to open file
     260           0 :         NS_ASSERTION(fd, "cache stream lacking open file.");
     261             : 
     262           0 :     } else if (!mBuffer) {
     263             :         // read block file for data
     264           0 :         rv = ReadCacheBlocks(mStreamEnd);
     265           0 :         if (NS_FAILED(rv))  return rv;
     266             :     }
     267             :     // else, mBuffer already contains all of the data (left over from a
     268             :     // previous block-file read or write).
     269             : 
     270           0 :     NS_ASSERTION(!(fd && mBuffer), "ambiguous data sources for input stream");
     271             : 
     272             :     // create a new input stream
     273           0 :     nsDiskCacheInputStream * inStream = new nsDiskCacheInputStream(this, fd, mBuffer, mStreamEnd);
     274           0 :     if (!inStream)  return NS_ERROR_OUT_OF_MEMORY;
     275             : 
     276           0 :     NS_ADDREF(*inputStream = inStream);
     277           0 :     return NS_OK;
     278             : }
     279             : 
     280             : 
     281             : // NOTE: called with service lock held
     282             : nsresult
     283           0 : nsDiskCacheStreamIO::GetOutputStream(uint32_t offset, nsIOutputStream ** outputStream)
     284             : {
     285           0 :     NS_ENSURE_ARG_POINTER(outputStream);
     286           0 :     *outputStream = nullptr;
     287             : 
     288           0 :     if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
     289             : 
     290           0 :     NS_ASSERTION(!mOutputStreamIsOpen, "already have an output stream open");
     291           0 :     NS_ASSERTION(mInStreamCount == 0, "we already have input streams open");
     292           0 :     if (mOutputStreamIsOpen || mInStreamCount)  return NS_ERROR_NOT_AVAILABLE;
     293             : 
     294           0 :     mStreamEnd = mBinding->mCacheEntry->DataSize();
     295             : 
     296             :     // Inits file or buffer and truncate at the desired offset
     297           0 :     nsresult rv = SeekAndTruncate(offset);
     298           0 :     if (NS_FAILED(rv)) return rv;
     299             : 
     300           0 :     mOutputStreamIsOpen = true;
     301           0 :     NS_ADDREF(*outputStream = this);
     302           0 :     return NS_OK;
     303             : }
     304             : 
     305             : nsresult
     306           0 : nsDiskCacheStreamIO::ClearBinding()
     307             : {
     308           0 :     nsresult rv = NS_OK;
     309           0 :     if (mBinding && mOutputStreamIsOpen)
     310           0 :         rv = CloseOutputStream();
     311           0 :     mBinding = nullptr;
     312           0 :     return rv;
     313             : }
     314             : 
     315             : NS_IMETHODIMP
     316           0 : nsDiskCacheStreamIO::Close()
     317             : {
     318           0 :     if (!mOutputStreamIsOpen) return NS_OK;
     319             : 
     320             :     // grab service lock
     321           0 :     nsCacheServiceAutoLock lock;
     322             : 
     323           0 :     if (!mBinding) {    // if we're severed, just clear member variables
     324           0 :         mOutputStreamIsOpen = false;
     325           0 :         return NS_ERROR_NOT_AVAILABLE;
     326             :     }
     327             : 
     328           0 :     nsresult rv = CloseOutputStream();
     329           0 :     if (NS_FAILED(rv))
     330           0 :         NS_WARNING("CloseOutputStream() failed");
     331             : 
     332           0 :     return rv;
     333             : }
     334             : 
     335             : nsresult
     336           0 : nsDiskCacheStreamIO::CloseOutputStream()
     337             : {
     338           0 :     NS_ASSERTION(mBinding, "oops");
     339             : 
     340           0 :     CACHE_LOG_DEBUG(("CACHE: CloseOutputStream [%x doomed=%u]\n",
     341             :         mBinding->mRecord.HashNumber(), mBinding->mDoomed));
     342             : 
     343             :     // Mark outputstream as closed, even if saving the stream fails
     344           0 :     mOutputStreamIsOpen = false;
     345             : 
     346             :     // When writing to a file, just close the file
     347           0 :     if (mFD) {
     348           0 :         (void) PR_Close(mFD);
     349           0 :         mFD = nullptr;
     350           0 :         return NS_OK;
     351             :     }
     352             : 
     353             :     // write data to cache blocks, or flush mBuffer to file
     354           0 :     NS_ASSERTION(mStreamEnd <= kMaxBufferSize, "stream is bigger than buffer");
     355             : 
     356           0 :     nsDiskCacheMap *cacheMap = mDevice->CacheMap();  // get map reference
     357           0 :     nsDiskCacheRecord * record = &mBinding->mRecord;
     358           0 :     nsresult rv = NS_OK;
     359             : 
     360             :     // delete existing storage
     361           0 :     if (record->DataLocationInitialized()) {
     362           0 :         rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
     363           0 :         NS_ENSURE_SUCCESS(rv, rv);
     364             : 
     365             :         // Only call UpdateRecord when there is no data to write,
     366             :         // because WriteDataCacheBlocks / FlushBufferToFile calls it.
     367           0 :         if ((mStreamEnd == 0) && (!mBinding->mDoomed)) {
     368           0 :             rv = cacheMap->UpdateRecord(record);
     369           0 :             if (NS_FAILED(rv)) {
     370           0 :                 NS_WARNING("cacheMap->UpdateRecord() failed.");
     371           0 :                 return rv;   // XXX doom cache entry
     372             :             }
     373             :         }
     374             :     }
     375             : 
     376           0 :     if (mStreamEnd == 0) return NS_OK;     // nothing to write
     377             : 
     378             :     // try to write to the cache blocks
     379           0 :     rv = cacheMap->WriteDataCacheBlocks(mBinding, mBuffer, mStreamEnd);
     380           0 :     if (NS_FAILED(rv)) {
     381           0 :         NS_WARNING("WriteDataCacheBlocks() failed.");
     382             : 
     383             :         // failed to store in cacheblocks, save as separate file
     384           0 :         rv = FlushBufferToFile(); // initializes DataFileLocation() if necessary
     385           0 :         if (mFD) {
     386           0 :             UpdateFileSize();
     387           0 :             (void) PR_Close(mFD);
     388           0 :             mFD = nullptr;
     389             :         }
     390             :         else
     391           0 :             NS_WARNING("no file descriptor");
     392             :     }
     393             : 
     394           0 :     return rv;
     395             : }
     396             : 
     397             : 
     398             : // assumptions:
     399             : //      only one thread writing at a time
     400             : //      never have both output and input streams open
     401             : //      OnDataSizeChanged() will have already been called to update entry->DataSize()
     402             : 
     403             : NS_IMETHODIMP
     404           0 : nsDiskCacheStreamIO::Write( const char * buffer,
     405             :                             uint32_t     count,
     406             :                             uint32_t *   bytesWritten)
     407             : {
     408           0 :     NS_ENSURE_ARG_POINTER(buffer);
     409           0 :     NS_ENSURE_ARG_POINTER(bytesWritten);
     410           0 :     if (!mOutputStreamIsOpen) return NS_BASE_STREAM_CLOSED;
     411             : 
     412           0 :     *bytesWritten = 0;  // always initialize to zero in case of errors
     413             : 
     414           0 :     NS_ASSERTION(count, "Write called with count of zero");
     415           0 :     if (count == 0) {
     416           0 :         return NS_OK;   // nothing to write
     417             :     }
     418             : 
     419             :     // grab service lock
     420           0 :     nsCacheServiceAutoLock lock;
     421           0 :     if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
     422             : 
     423           0 :     if (mInStreamCount) {
     424             :         // we have open input streams already
     425             :         // this is an error until we support overlapped I/O
     426           0 :         NS_WARNING("Attempting to write to cache entry with open input streams.\n");
     427           0 :         return NS_ERROR_NOT_AVAILABLE;
     428             :     }
     429             : 
     430             :     // Not writing to file, and it will fit in the cachedatablocks?
     431           0 :     if (!mFD && (mStreamEnd + count <= kMaxBufferSize)) {
     432             : 
     433             :         // We have more data than the current buffer size?
     434           0 :         if ((mStreamEnd + count > mBufSize) && (mBufSize < kMaxBufferSize)) {
     435             :             // Increase buffer to the maximum size.
     436           0 :             mBuffer = (char *) moz_xrealloc(mBuffer, kMaxBufferSize);
     437           0 :             mBufSize = kMaxBufferSize;
     438             :         }
     439             : 
     440             :         // Store in the buffer but only if it fits
     441           0 :         if (mStreamEnd + count <= mBufSize) {
     442           0 :             memcpy(mBuffer + mStreamEnd, buffer, count);
     443           0 :             mStreamEnd += count;
     444           0 :             *bytesWritten = count;
     445           0 :             return NS_OK;
     446             :         }
     447             :     }
     448             : 
     449             :     // There are more bytes than fit in the buffer/cacheblocks, switch to file
     450           0 :     if (!mFD) {
     451             :         // Opens a cache file and write the buffer to it
     452           0 :         nsresult rv = FlushBufferToFile();
     453           0 :         if (NS_FAILED(rv)) {
     454           0 :             return rv;
     455             :         }
     456             :     }
     457             :     // Write directly to the file
     458           0 :     if (PR_Write(mFD, buffer, count) != (int32_t)count) {
     459           0 :         NS_WARNING("failed to write all data");
     460           0 :         return NS_ERROR_UNEXPECTED;     // NS_ErrorAccordingToNSPR()
     461             :     }
     462           0 :     mStreamEnd += count;
     463           0 :     *bytesWritten = count;
     464             : 
     465           0 :     UpdateFileSize();
     466           0 :     NS_ASSERTION(mBinding->mCacheEntry->DataSize() == mStreamEnd, "bad stream");
     467             : 
     468           0 :     return NS_OK;
     469             : }
     470             : 
     471             : 
     472             : void
     473           0 : nsDiskCacheStreamIO::UpdateFileSize()
     474             : {
     475           0 :     NS_ASSERTION(mFD, "nsDiskCacheStreamIO::UpdateFileSize should not have been called");
     476             : 
     477           0 :     nsDiskCacheRecord * record = &mBinding->mRecord;
     478           0 :     const uint32_t      oldSizeK  = record->DataFileSize();
     479           0 :     uint32_t            newSizeK  = (mStreamEnd + 0x03FF) >> 10;
     480             : 
     481             :     // make sure the size won't overflow (bug #651100)
     482           0 :     if (newSizeK > kMaxDataSizeK)
     483           0 :         newSizeK = kMaxDataSizeK;
     484             : 
     485           0 :     if (newSizeK == oldSizeK)  return;
     486             : 
     487           0 :     record->SetDataFileSize(newSizeK);
     488             : 
     489             :     // update cache size totals
     490           0 :     nsDiskCacheMap * cacheMap = mDevice->CacheMap();
     491           0 :     cacheMap->DecrementTotalSize(oldSizeK);       // decrement old size
     492           0 :     cacheMap->IncrementTotalSize(newSizeK);       // increment new size
     493             : 
     494           0 :     if (!mBinding->mDoomed) {
     495           0 :         nsresult rv = cacheMap->UpdateRecord(record);
     496           0 :         if (NS_FAILED(rv)) {
     497           0 :             NS_WARNING("cacheMap->UpdateRecord() failed.");
     498             :             // XXX doom cache entry?
     499             :         }
     500             :     }
     501             : }
     502             : 
     503             : 
     504             : nsresult
     505           0 : nsDiskCacheStreamIO::OpenCacheFile(int flags, PRFileDesc ** fd)
     506             : {
     507           0 :     NS_ENSURE_ARG_POINTER(fd);
     508             : 
     509           0 :     CACHE_LOG_DEBUG(("nsDiskCacheStreamIO::OpenCacheFile"));
     510             : 
     511             :     nsresult         rv;
     512           0 :     nsDiskCacheMap * cacheMap = mDevice->CacheMap();
     513           0 :     nsCOMPtr<nsIFile>           localFile;
     514             : 
     515           0 :     rv = cacheMap->GetLocalFileForDiskCacheRecord(&mBinding->mRecord,
     516             :                                                   nsDiskCache::kData,
     517           0 :                                                   !!(flags & PR_CREATE_FILE),
     518           0 :                                                   getter_AddRefs(localFile));
     519           0 :     if (NS_FAILED(rv))  return rv;
     520             : 
     521             :     // create PRFileDesc for input stream - the 00600 is just for consistency
     522           0 :     return localFile->OpenNSPRFileDesc(flags, 00600, fd);
     523             : }
     524             : 
     525             : 
     526             : nsresult
     527           0 : nsDiskCacheStreamIO::ReadCacheBlocks(uint32_t bufferSize)
     528             : {
     529           0 :     NS_ASSERTION(mStreamEnd == mBinding->mCacheEntry->DataSize(), "bad stream");
     530           0 :     NS_ASSERTION(bufferSize <= kMaxBufferSize, "bufferSize too large for buffer");
     531           0 :     NS_ASSERTION(mStreamEnd <= bufferSize, "data too large for buffer");
     532             : 
     533           0 :     nsDiskCacheRecord * record = &mBinding->mRecord;
     534           0 :     if (!record->DataLocationInitialized()) return NS_OK;
     535             : 
     536           0 :     NS_ASSERTION(record->DataFile() != kSeparateFile, "attempt to read cache blocks on separate file");
     537             : 
     538           0 :     if (!mBuffer) {
     539           0 :         mBuffer = (char *) moz_xmalloc(bufferSize);
     540           0 :         mBufSize = bufferSize;
     541             :     }
     542             : 
     543             :     // read data stored in cache block files
     544           0 :     nsDiskCacheMap *map = mDevice->CacheMap();  // get map reference
     545           0 :     return map->ReadDataCacheBlocks(mBinding, mBuffer, mStreamEnd);
     546             : }
     547             : 
     548             : 
     549             : nsresult
     550           0 : nsDiskCacheStreamIO::FlushBufferToFile()
     551             : {
     552             :     nsresult  rv;
     553           0 :     nsDiskCacheRecord * record = &mBinding->mRecord;
     554             : 
     555           0 :     if (!mFD) {
     556           0 :         if (record->DataLocationInitialized() && (record->DataFile() > 0)) {
     557             :             // remove cache block storage
     558           0 :             nsDiskCacheMap * cacheMap = mDevice->CacheMap();
     559           0 :             rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
     560           0 :             if (NS_FAILED(rv))  return rv;
     561             :         }
     562           0 :         record->SetDataFileGeneration(mBinding->mGeneration);
     563             : 
     564             :         // allocate file
     565           0 :         rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
     566           0 :         if (NS_FAILED(rv))  return rv;
     567             : 
     568           0 :         int64_t dataSize = mBinding->mCacheEntry->PredictedDataSize();
     569           0 :         if (dataSize != -1)
     570           0 :             mozilla::fallocate(mFD, std::min<int64_t>(dataSize, kPreallocateLimit));
     571             :     }
     572             : 
     573             :     // write buffer to the file when there is data in it
     574           0 :     if (mStreamEnd > 0) {
     575           0 :         if (!mBuffer) {
     576           0 :             MOZ_CRASH("Fix me!");
     577             :         }
     578           0 :         if (PR_Write(mFD, mBuffer, mStreamEnd) != (int32_t)mStreamEnd) {
     579           0 :             NS_WARNING("failed to flush all data");
     580           0 :             return NS_ERROR_UNEXPECTED;     // NS_ErrorAccordingToNSPR()
     581             :         }
     582             :     }
     583             : 
     584             :     // buffer is no longer valid
     585           0 :     DeleteBuffer();
     586             : 
     587           0 :     return NS_OK;
     588             : }
     589             : 
     590             : 
     591             : void
     592           0 : nsDiskCacheStreamIO::DeleteBuffer()
     593             : {
     594           0 :     if (mBuffer) {
     595           0 :         free(mBuffer);
     596           0 :         mBuffer = nullptr;
     597           0 :         mBufSize = 0;
     598             :     }
     599           0 : }
     600             : 
     601             : size_t
     602           0 : nsDiskCacheStreamIO::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
     603             : {
     604           0 :     size_t usage = aMallocSizeOf(this);
     605             : 
     606           0 :     usage += aMallocSizeOf(mFD);
     607           0 :     usage += aMallocSizeOf(mBuffer);
     608             : 
     609           0 :     return usage;
     610             : }
     611             : 
     612             : nsresult
     613           0 : nsDiskCacheStreamIO::SeekAndTruncate(uint32_t offset)
     614             : {
     615           0 :     if (!mBinding)  return NS_ERROR_NOT_AVAILABLE;
     616             : 
     617           0 :     if (uint32_t(offset) > mStreamEnd)  return NS_ERROR_FAILURE;
     618             : 
     619             :     // Set the current end to the desired offset
     620           0 :     mStreamEnd = offset;
     621             : 
     622             :     // Currently stored in file?
     623           0 :     if (mBinding->mRecord.DataLocationInitialized() &&
     624           0 :         (mBinding->mRecord.DataFile() == 0)) {
     625           0 :         if (!mFD) {
     626             :             // we need an mFD, we better open it now
     627           0 :             nsresult rv = OpenCacheFile(PR_RDWR | PR_CREATE_FILE, &mFD);
     628           0 :             if (NS_FAILED(rv))  return rv;
     629             :         }
     630           0 :         if (offset) {
     631           0 :             if (PR_Seek(mFD, offset, PR_SEEK_SET) == -1)
     632           0 :                 return NS_ErrorAccordingToNSPR();
     633             :         }
     634           0 :         nsDiskCache::Truncate(mFD, offset);
     635           0 :         UpdateFileSize();
     636             : 
     637             :         // When we starting at zero again, close file and start with buffer.
     638             :         // If offset is non-zero (and within buffer) an option would be
     639             :         // to read the file into the buffer, but chance is high that it is
     640             :         // rewritten to the file anyway.
     641           0 :         if (offset == 0) {
     642             :             // close file descriptor
     643           0 :             (void) PR_Close(mFD);
     644           0 :             mFD = nullptr;
     645             :         }
     646           0 :         return NS_OK;
     647             :     }
     648             : 
     649             :     // read data into mBuffer if not read yet.
     650           0 :     if (offset && !mBuffer) {
     651           0 :         nsresult rv = ReadCacheBlocks(kMaxBufferSize);
     652           0 :         if (NS_FAILED(rv))  return rv;
     653             :     }
     654             : 
     655             :     // stream buffer sanity check
     656           0 :     NS_ASSERTION(mStreamEnd <= kMaxBufferSize, "bad stream");
     657           0 :     return NS_OK;
     658             : }
     659             : 
     660             : 
     661             : NS_IMETHODIMP
     662           0 : nsDiskCacheStreamIO::Flush()
     663             : {
     664           0 :     if (!mOutputStreamIsOpen)  return NS_BASE_STREAM_CLOSED;
     665           0 :     return NS_OK;
     666             : }
     667             : 
     668             : 
     669             : NS_IMETHODIMP
     670           0 : nsDiskCacheStreamIO::WriteFrom(nsIInputStream *inStream, uint32_t count, uint32_t *bytesWritten)
     671             : {
     672           0 :     NS_NOTREACHED("WriteFrom");
     673           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     674             : }
     675             : 
     676             : 
     677             : NS_IMETHODIMP
     678           0 : nsDiskCacheStreamIO::WriteSegments( nsReadSegmentFun reader,
     679             :                                         void *           closure,
     680             :                                         uint32_t         count,
     681             :                                         uint32_t *       bytesWritten)
     682             : {
     683           0 :     NS_NOTREACHED("WriteSegments");
     684           0 :     return NS_ERROR_NOT_IMPLEMENTED;
     685             : }
     686             : 
     687             : 
     688             : NS_IMETHODIMP
     689           0 : nsDiskCacheStreamIO::IsNonBlocking(bool * nonBlocking)
     690             : {
     691           0 :     *nonBlocking = false;
     692           0 :     return NS_OK;
     693             : }

Generated by: LCOV version 1.13