netwerk/cache/nsDiskCacheStreams.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial