1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is nsDiskCacheStreams.cpp, released
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 2001
22 * the Initial Developer. All Rights Reserved.
25 * Gordon Sheridan <gordon@netscape.com>
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 #include "nsDiskCache.h"
43 #include "nsDiskCacheDevice.h"
44 #include "nsDiskCacheStreams.h"
45 #include "nsCacheService.h"
50 // - cache descriptors live for life of streams
51 // - streams will only be used by FileTransport,
52 // they will not be directly accessible to clients
53 // - overlapped I/O is NOT supported
56 /******************************************************************************
57 * nsDiskCacheInputStream
58 *****************************************************************************/
60 #pragma mark nsDiskCacheInputStream
62 class nsDiskCacheInputStream
: public nsIInputStream
{
66 nsDiskCacheInputStream( nsDiskCacheStreamIO
* parent
,
67 PRFileDesc
* fileDesc
,
69 PRUint32 endOfStream
);
71 virtual ~nsDiskCacheInputStream();
74 NS_DECL_NSIINPUTSTREAM
77 nsDiskCacheStreamIO
* mStreamIO
; // backpointer to parent
81 PRUint32 mPos
; // stream position
86 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheInputStream
, nsIInputStream
)
89 nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO
* parent
,
90 PRFileDesc
* fileDesc
,
96 , mStreamEnd(endOfStream
)
100 NS_ADDREF(mStreamIO
);
101 mStreamIO
->IncrementInputStreamCount();
105 nsDiskCacheInputStream::~nsDiskCacheInputStream()
108 mStreamIO
->DecrementInputStreamCount();
109 NS_RELEASE(mStreamIO
);
114 nsDiskCacheInputStream::Close()
118 (void) PR_Close(mFD
);
128 nsDiskCacheInputStream::Available(PRUint32
* bytesAvailable
)
130 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
131 if (mStreamEnd
< mPos
) return NS_ERROR_UNEXPECTED
;
133 *bytesAvailable
= mStreamEnd
- mPos
;
139 nsDiskCacheInputStream::Read(char * buffer
, PRUint32 count
, PRUint32
* bytesRead
)
146 if (mPos
== mStreamEnd
) return NS_OK
;
147 if (mPos
> mStreamEnd
) return NS_ERROR_UNEXPECTED
;
150 // just read from file
151 PRInt32 result
= PR_Read(mFD
, buffer
, count
);
152 if (result
< 0) return NS_ErrorAccordingToNSPR();
154 mPos
+= (PRUint32
)result
;
155 *bytesRead
= (PRUint32
)result
;
157 } else if (mBuffer
) {
158 // read data from mBuffer
159 if (count
> mStreamEnd
- mPos
)
160 count
= mStreamEnd
- mPos
;
162 memcpy(buffer
, mBuffer
+ mPos
, count
);
166 // no data source for input stream
174 nsDiskCacheInputStream::ReadSegments(nsWriteSegmentFun writer
,
177 PRUint32
* bytesRead
)
179 return NS_ERROR_NOT_IMPLEMENTED
;
184 nsDiskCacheInputStream::IsNonBlocking(PRBool
* nonBlocking
)
186 *nonBlocking
= PR_FALSE
;
191 /******************************************************************************
192 * nsDiskCacheOutputStream
193 *****************************************************************************/
196 #pragma mark nsDiskCacheOutputStream
198 class nsDiskCacheOutputStream
: public nsIOutputStream
{
200 nsDiskCacheOutputStream( nsDiskCacheStreamIO
* parent
);
201 virtual ~nsDiskCacheOutputStream();
204 NS_DECL_NSIOUTPUTSTREAM
206 void ReleaseStreamIO() { NS_IF_RELEASE(mStreamIO
); }
209 nsDiskCacheStreamIO
* mStreamIO
; // backpointer to parent
214 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheOutputStream
,
217 nsDiskCacheOutputStream::nsDiskCacheOutputStream( nsDiskCacheStreamIO
* parent
)
221 NS_ADDREF(mStreamIO
);
225 nsDiskCacheOutputStream::~nsDiskCacheOutputStream()
233 nsDiskCacheOutputStream::Close()
237 // tell parent streamIO we are closing
238 mStreamIO
->CloseOutputStream(this);
245 nsDiskCacheOutputStream::Flush()
247 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
248 // yeah, yeah, well get to it...eventually...
254 nsDiskCacheOutputStream::Write(const char *buf
, PRUint32 count
, PRUint32
*bytesWritten
)
256 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
257 return mStreamIO
->Write(buf
, count
, bytesWritten
);
262 nsDiskCacheOutputStream::WriteFrom(nsIInputStream
*inStream
, PRUint32 count
, PRUint32
*bytesWritten
)
264 NS_NOTREACHED("WriteFrom");
265 return NS_ERROR_NOT_IMPLEMENTED
;
270 nsDiskCacheOutputStream::WriteSegments( nsReadSegmentFun reader
,
273 PRUint32
* bytesWritten
)
275 NS_NOTREACHED("WriteSegments");
276 return NS_ERROR_NOT_IMPLEMENTED
;
281 nsDiskCacheOutputStream::IsNonBlocking(PRBool
* nonBlocking
)
283 *nonBlocking
= PR_FALSE
;
289 /******************************************************************************
290 * nsDiskCacheStreamIO
291 *****************************************************************************/
294 #pragma mark nsDiskCacheStreamIO
297 NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheStreamIO
)
299 // we pick 16k as the max buffer size because that is the threshold above which
300 // we are unable to store the data in the cache block files
301 // see nsDiskCacheMap.[cpp,h]
302 #define kMaxBufferSize (16 * 1024)
304 nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding
* binding
)
314 , mBufDirty(PR_FALSE
)
317 mDevice
= (nsDiskCacheDevice
*)mBinding
->mCacheEntry
->CacheDevice();
319 // acquire "death grip" on cache service
320 nsCacheService
*service
= nsCacheService::GlobalInstance();
325 nsDiskCacheStreamIO::~nsDiskCacheStreamIO()
329 // release "death grip" on cache service
330 nsCacheService
*service
= nsCacheService::GlobalInstance();
336 nsDiskCacheStreamIO::Close()
338 // this should only be called from our destructor
339 // no one is interested in us anymore, so we don't need to grab any locks
341 // assert streams closed
342 NS_ASSERTION(!mOutStream
, "output stream still open");
343 NS_ASSERTION(mInStreamCount
== 0, "input stream still open");
344 NS_ASSERTION(!mFD
, "file descriptor not closed");
350 // NOTE: called with service lock held
352 nsDiskCacheStreamIO::GetInputStream(PRUint32 offset
, nsIInputStream
** inputStream
)
354 NS_ENSURE_ARG_POINTER(inputStream
);
355 NS_ENSURE_TRUE(offset
== 0, NS_ERROR_NOT_IMPLEMENTED
);
357 *inputStream
= nsnull
;
359 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
362 NS_WARNING("already have an output stream open");
363 return NS_ERROR_NOT_AVAILABLE
;
367 PRFileDesc
* fd
= nsnull
;
369 mStreamEnd
= mBinding
->mCacheEntry
->DataSize();
370 if (mStreamEnd
== 0) {
371 // there's no data to read
372 NS_ASSERTION(!mBinding
->mRecord
.DataLocationInitialized(), "storage allocated for zero data size");
373 } else if (mBinding
->mRecord
.DataFile() == 0) {
374 // open file desc for data
375 rv
= OpenCacheFile(PR_RDONLY
, &fd
);
376 if (NS_FAILED(rv
)) return rv
; // unable to open file
377 NS_ASSERTION(fd
, "cache stream lacking open file.");
379 } else if (!mBuffer
) {
380 // read block file for data
381 rv
= ReadCacheBlocks();
382 if (NS_FAILED(rv
)) return rv
;
384 // else, mBuffer already contains all of the data (left over from a
385 // previous block-file read or write).
387 NS_ASSERTION(!(fd
&& mBuffer
), "ambiguous data sources for input stream");
389 // create a new input stream
390 nsDiskCacheInputStream
* inStream
= new nsDiskCacheInputStream(this, fd
, mBuffer
, mStreamEnd
);
391 if (!inStream
) return NS_ERROR_OUT_OF_MEMORY
;
393 NS_ADDREF(*inputStream
= inStream
);
398 // NOTE: called with service lock held
400 nsDiskCacheStreamIO::GetOutputStream(PRUint32 offset
, nsIOutputStream
** outputStream
)
402 NS_ENSURE_ARG_POINTER(outputStream
);
403 *outputStream
= nsnull
;
405 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
407 NS_ASSERTION(!mOutStream
, "already have an output stream open");
408 NS_ASSERTION(mInStreamCount
== 0, "we already have input streams open");
409 if (mOutStream
|| mInStreamCount
) return NS_ERROR_NOT_AVAILABLE
;
411 // mBuffer lazily allocated, but might exist if a previous stream already
415 mStreamEnd
= mBinding
->mCacheEntry
->DataSize();
419 rv
= Seek(PR_SEEK_SET
, offset
);
420 if (NS_FAILED(rv
)) return rv
;
423 if (NS_FAILED(rv
)) return rv
;
425 // create a new output stream
426 mOutStream
= new nsDiskCacheOutputStream(this);
427 if (!mOutStream
) return NS_ERROR_OUT_OF_MEMORY
;
429 NS_ADDREF(*outputStream
= mOutStream
);
434 nsDiskCacheStreamIO::ClearBinding()
436 if (mBinding
&& mOutStream
)
442 nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream
* outputStream
)
444 nsCacheServiceAutoLock lock
; // grab service lock
447 if (outputStream
!= mOutStream
) {
448 NS_WARNING("mismatched output streams");
449 return NS_ERROR_UNEXPECTED
;
452 // output stream is closing
453 if (!mBinding
) { // if we're severed, just clear member variables
454 NS_ASSERTION(!mBufDirty
, "oops");
456 outputStream
->ReleaseStreamIO();
457 return NS_ERROR_NOT_AVAILABLE
;
461 NS_ASSERTION(NS_SUCCEEDED(rv
), "Flush() failed");
468 nsDiskCacheStreamIO::Flush()
470 NS_ASSERTION(mBinding
, "oops");
472 CACHE_LOG_DEBUG(("CACHE: Flush [%x doomed=%u]\n",
473 mBinding
->mRecord
.HashNumber(), mBinding
->mDoomed
));
478 // write data to cache blocks, or flush mBuffer to file
479 nsDiskCacheMap
*cacheMap
= mDevice
->CacheMap(); // get map reference
482 if ((mStreamEnd
> kMaxBufferSize
) ||
483 (mBinding
->mCacheEntry
->StoragePolicy() == nsICache::STORE_ON_DISK_AS_FILE
)) {
484 // make sure we save as separate file
485 rv
= FlushBufferToFile(); // will initialize DataFileLocation() if necessary
488 // Update the file size of the disk file in the cache
491 // close file descriptor
492 (void) PR_Close(mFD
);
496 NS_WARNING("no file descriptor");
498 // close mFD first if possible before returning if FlushBufferToFile
500 NS_ENSURE_SUCCESS(rv
, rv
);
502 // since the data location is on disk as a single file, the only value
503 // in keeping mBuffer around is to avoid an extra malloc the next time
504 // we need to write to this file. reading will use a file descriptor.
505 // therefore, it's probably not worth optimizing for the subsequent
506 // write, so we unconditionally delete mBuffer here.
510 // store data (if any) in cache block files
512 // delete existing storage
513 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
514 if (record
->DataLocationInitialized()) {
515 rv
= cacheMap
->DeleteStorage(record
, nsDiskCache::kData
);
517 NS_WARNING("cacheMap->DeleteStorage() failed.");
518 cacheMap
->DeleteRecord(record
);
523 // flush buffer to block files
524 if (mStreamEnd
> 0) {
525 rv
= cacheMap
->WriteDataCacheBlocks(mBinding
, mBuffer
, mBufEnd
);
527 NS_WARNING("WriteDataCacheBlocks() failed.");
528 return rv
; // XXX doom cache entry?
533 mBufDirty
= PR_FALSE
;
536 // XXX do we need this here? WriteDataCacheBlocks() calls UpdateRecord()
537 // update cache map if entry isn't doomed
538 if (!mBinding
->mDoomed
) {
539 rv
= cacheMap
->UpdateRecord(&mBinding
->mRecord
);
541 NS_WARNING("cacheMap->UpdateRecord() failed.");
542 return rv
; // XXX doom cache entry
551 // only one thread writing at a time
552 // never have both output and input streams open
553 // OnDataSizeChanged() will have already been called to update entry->DataSize()
556 nsDiskCacheStreamIO::Write( const char * buffer
,
558 PRUint32
* bytesWritten
)
561 nsCacheServiceAutoLock lock
; // grab service lock
562 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
564 if (mInStreamCount
) {
565 // we have open input streams already
566 // this is an error until we support overlapped I/O
567 NS_WARNING("Attempting to write to cache entry with open input streams.\n");
568 return NS_ERROR_NOT_AVAILABLE
;
571 NS_ASSERTION(count
, "Write called with count of zero");
572 NS_ASSERTION(mBufPos
<= mBufEnd
, "streamIO buffer corrupted");
574 PRUint32 bytesLeft
= count
;
575 PRBool flushed
= PR_FALSE
;
578 if (mBufPos
== mBufSize
) {
579 if (mBufSize
< kMaxBufferSize
) {
580 mBufSize
= kMaxBufferSize
;
581 mBuffer
= (char *) realloc(mBuffer
, mBufSize
);
587 nsresult rv
= FlushBufferToFile();
588 if (NS_FAILED(rv
)) break;
593 PRUint32 chunkSize
= bytesLeft
;
594 if (chunkSize
> (mBufSize
- mBufPos
))
595 chunkSize
= mBufSize
- mBufPos
;
597 memcpy(mBuffer
+ mBufPos
, buffer
, chunkSize
);
599 mBufPos
+= chunkSize
;
600 bytesLeft
-= chunkSize
;
603 if (mBufEnd
< mBufPos
)
608 return NS_ERROR_FAILURE
;
610 *bytesWritten
= count
;
612 // update mStreamPos, mStreamEnd
614 if (mStreamEnd
< mStreamPos
) {
615 mStreamEnd
= mStreamPos
;
616 NS_ASSERTION(mBinding
->mCacheEntry
->DataSize() == mStreamEnd
, "bad stream");
618 // If we have flushed to a file, update the file size
619 if (flushed
&& mFD
) {
629 nsDiskCacheStreamIO::UpdateFileSize()
631 NS_ASSERTION(mFD
, "nsDiskCacheStreamIO::UpdateFileSize should not have been called");
633 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
634 const PRUint32 oldSizeK
= record
->DataFileSize();
635 const PRUint32 newSizeK
= (mStreamEnd
+ 0x03FF) >> 10;
637 if (newSizeK
== oldSizeK
) return;
639 record
->SetDataFileSize(newSizeK
);
641 // update cache size totals
642 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
643 cacheMap
->DecrementTotalSize(oldSizeK
); // decrement old size
644 cacheMap
->IncrementTotalSize(newSizeK
); // increment new size
646 if (!mBinding
->mDoomed
) {
647 nsresult rv
= cacheMap
->UpdateRecord(record
);
649 NS_WARNING("cacheMap->UpdateRecord() failed.");
650 // XXX doom cache entry?
657 nsDiskCacheStreamIO::OpenCacheFile(PRIntn flags
, PRFileDesc
** fd
)
659 NS_ENSURE_ARG_POINTER(fd
);
662 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
664 rv
= cacheMap
->GetLocalFileForDiskCacheRecord(&mBinding
->mRecord
,
666 getter_AddRefs(mLocalFile
));
667 if (NS_FAILED(rv
)) return rv
;
669 // create PRFileDesc for input stream - the 00600 is just for consistency
670 rv
= mLocalFile
->OpenNSPRFileDesc(flags
, 00600, fd
);
671 if (NS_FAILED(rv
)) return rv
; // unable to open file
678 nsDiskCacheStreamIO::ReadCacheBlocks()
680 NS_ASSERTION(mStreamEnd
== mBinding
->mCacheEntry
->DataSize(), "bad stream");
681 NS_ASSERTION(mStreamEnd
<= kMaxBufferSize
, "data too large for buffer");
683 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
684 if (!record
->DataLocationInitialized()) return NS_OK
;
686 NS_ASSERTION(record
->DataFile() != kSeparateFile
, "attempt to read cache blocks on separate file");
690 mBuffer
= (char *) malloc(mStreamEnd
);
692 return NS_ERROR_OUT_OF_MEMORY
;
694 mBufSize
= mStreamEnd
;
697 // read data stored in cache block files
698 nsDiskCacheMap
*map
= mDevice
->CacheMap(); // get map reference
699 nsresult rv
= map
->ReadDataCacheBlocks(mBinding
, mBuffer
, mStreamEnd
);
700 if (NS_FAILED(rv
)) return rv
;
702 // update streamIO variables
704 mBufEnd
= mStreamEnd
;
711 nsDiskCacheStreamIO::FlushBufferToFile()
714 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
717 if (record
->DataLocationInitialized() && (record
->DataFile() > 0)) {
718 // remove cache block storage
719 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
720 rv
= cacheMap
->DeleteStorage(record
, nsDiskCache::kData
);
721 if (NS_FAILED(rv
)) return rv
;
723 record
->SetDataFileGeneration(mBinding
->mGeneration
);
726 rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
727 if (NS_FAILED(rv
)) return rv
;
731 PRInt32 bytesWritten
= PR_Write(mFD
, mBuffer
, mBufEnd
);
732 if (PRUint32(bytesWritten
) != mBufEnd
) {
733 NS_WARNING("failed to flush all data");
734 return NS_ERROR_UNEXPECTED
; // NS_ErrorAccordingToNSPR()
736 mBufDirty
= PR_FALSE
;
747 nsDiskCacheStreamIO::DeleteBuffer()
750 NS_ASSERTION(mBufDirty
== PR_FALSE
, "deleting dirty buffer");
760 // NOTE: called with service lock held
762 nsDiskCacheStreamIO::Seek(PRInt32 whence
, PRInt32 offset
)
765 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
767 if (PRUint32(offset
) > mStreamEnd
) return NS_ERROR_FAILURE
;
769 if (mBinding
->mRecord
.DataLocationInitialized()) {
770 if (mBinding
->mRecord
.DataFile() == 0) {
772 // we need an mFD, we better open it now
773 nsresult rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
774 if (NS_FAILED(rv
)) return rv
;
780 // do we have data in the buffer that needs to be flushed?
782 // XXX optimization: are we just moving within the current buffer?
783 nsresult rv
= FlushBufferToFile();
784 if (NS_FAILED(rv
)) return rv
;
787 newPos
= PR_Seek(mFD
, offset
, (PRSeekWhence
)whence
);
789 return NS_ErrorAccordingToNSPR();
791 mStreamPos
= (PRUint32
) newPos
;
797 // else, seek in mBuffer
804 case PR_SEEK_CUR
: // relative from current posistion
805 newPos
= offset
+ (PRUint32
)mStreamPos
;
808 case PR_SEEK_END
: // relative from end
809 newPos
= offset
+ (PRUint32
)mBufEnd
;
813 return NS_ERROR_INVALID_ARG
;
816 // read data into mBuffer if not read yet.
817 if (mStreamEnd
&& !mBufEnd
) {
819 nsresult rv
= ReadCacheBlocks();
820 if (NS_FAILED(rv
)) return rv
;
824 // stream buffer sanity checks
825 NS_ASSERTION(mBufEnd
<= kMaxBufferSize
, "bad stream");
826 NS_ASSERTION(mBufPos
<= mBufEnd
, "bad stream");
827 NS_ASSERTION(mStreamPos
== mBufPos
, "bad stream");
828 NS_ASSERTION(mStreamEnd
== mBufEnd
, "bad stream");
830 if ((newPos
< 0) || (PRUint32(newPos
) > mBufEnd
)) {
831 NS_WARNING("seek offset out of range");
832 return NS_ERROR_INVALID_ARG
;
841 // called only from nsDiskCacheOutputStream::Tell
843 nsDiskCacheStreamIO::Tell(PRUint32
* result
)
845 NS_ENSURE_ARG_POINTER(result
);
846 *result
= mStreamPos
;
851 // NOTE: called with service lock held
853 nsDiskCacheStreamIO::SetEOF()
856 PRBool needToCloseFD
= PR_FALSE
;
858 NS_ASSERTION(mStreamPos
<= mStreamEnd
, "bad stream");
859 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
861 if (mBinding
->mRecord
.DataLocationInitialized()) {
862 if (mBinding
->mRecord
.DataFile() == 0) {
864 // we need an mFD, we better open it now
865 rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
866 if (NS_FAILED(rv
)) return rv
;
867 needToCloseFD
= PR_TRUE
;
870 // data in cache block files
871 if ((mStreamPos
!= 0) && (mStreamPos
!= mBufPos
)) {
872 // only read data if there will be some left after truncation
873 rv
= ReadCacheBlocks();
874 if (NS_FAILED(rv
)) return rv
;
877 // We need to make sure we reflect this change in Flush().
878 // In particular, if mStreamPos is 0 and we never write to
879 // the buffer, we want the storage to be deleted.
885 rv
= nsDiskCache::Truncate(mFD
, mStreamPos
);
887 PRUint32 oldSizeK
= (mStreamEnd
+ 0x03FF) >> 10;
888 NS_ASSERTION(mBinding
->mRecord
.DataFileSize() == oldSizeK
, "bad disk cache entry size");
890 // data stored in buffer.
891 NS_ASSERTION(mStreamEnd
<= kMaxBufferSize
, "buffer truncation inadequate");
892 NS_ASSERTION(mBufPos
== mStreamPos
, "bad stream");
893 NS_ASSERTION(mBuffer
? mBufEnd
== mStreamEnd
: PR_TRUE
, "bad stream");
897 NS_ASSERTION(mStreamEnd
== mBinding
->mCacheEntry
->DataSize(), "cache entry not updated");
898 // we expect nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream()
899 // to eventually update the cache entry
901 mStreamEnd
= mStreamPos
;
907 (void) PR_Close(mFD
);