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"
46 #include "mozilla/FileUtils.h"
47 #include "nsIDiskCacheStreamInternal.h"
52 // - cache descriptors live for life of streams
53 // - streams will only be used by FileTransport,
54 // they will not be directly accessible to clients
55 // - overlapped I/O is NOT supported
58 /******************************************************************************
59 * nsDiskCacheInputStream
60 *****************************************************************************/
62 #pragma mark nsDiskCacheInputStream
64 class nsDiskCacheInputStream
: public nsIInputStream
{
68 nsDiskCacheInputStream( nsDiskCacheStreamIO
* parent
,
69 PRFileDesc
* fileDesc
,
71 PRUint32 endOfStream
);
73 virtual ~nsDiskCacheInputStream();
76 NS_DECL_NSIINPUTSTREAM
79 nsDiskCacheStreamIO
* mStreamIO
; // backpointer to parent
83 PRUint32 mPos
; // stream position
88 NS_IMPL_THREADSAFE_ISUPPORTS1(nsDiskCacheInputStream
, nsIInputStream
)
91 nsDiskCacheInputStream::nsDiskCacheInputStream( nsDiskCacheStreamIO
* parent
,
92 PRFileDesc
* fileDesc
,
98 , mStreamEnd(endOfStream
)
102 NS_ADDREF(mStreamIO
);
103 mStreamIO
->IncrementInputStreamCount();
107 nsDiskCacheInputStream::~nsDiskCacheInputStream()
110 mStreamIO
->DecrementInputStreamCount();
111 NS_RELEASE(mStreamIO
);
116 nsDiskCacheInputStream::Close()
120 (void) PR_Close(mFD
);
130 nsDiskCacheInputStream::Available(PRUint32
* bytesAvailable
)
132 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
133 if (mStreamEnd
< mPos
) return NS_ERROR_UNEXPECTED
;
135 *bytesAvailable
= mStreamEnd
- mPos
;
141 nsDiskCacheInputStream::Read(char * buffer
, PRUint32 count
, PRUint32
* bytesRead
)
148 if (mPos
== mStreamEnd
) return NS_OK
;
149 if (mPos
> mStreamEnd
) return NS_ERROR_UNEXPECTED
;
152 // just read from file
153 PRInt32 result
= PR_Read(mFD
, buffer
, count
);
154 if (result
< 0) return NS_ErrorAccordingToNSPR();
156 mPos
+= (PRUint32
)result
;
157 *bytesRead
= (PRUint32
)result
;
159 } else if (mBuffer
) {
160 // read data from mBuffer
161 if (count
> mStreamEnd
- mPos
)
162 count
= mStreamEnd
- mPos
;
164 memcpy(buffer
, mBuffer
+ mPos
, count
);
168 // no data source for input stream
176 nsDiskCacheInputStream::ReadSegments(nsWriteSegmentFun writer
,
179 PRUint32
* bytesRead
)
181 return NS_ERROR_NOT_IMPLEMENTED
;
186 nsDiskCacheInputStream::IsNonBlocking(PRBool
* nonBlocking
)
188 *nonBlocking
= PR_FALSE
;
193 /******************************************************************************
194 * nsDiskCacheOutputStream
195 *****************************************************************************/
198 #pragma mark nsDiskCacheOutputStream
200 class nsDiskCacheOutputStream
: public nsIOutputStream
201 , public nsIDiskCacheStreamInternal
204 nsDiskCacheOutputStream( nsDiskCacheStreamIO
* parent
);
205 virtual ~nsDiskCacheOutputStream();
208 NS_DECL_NSIOUTPUTSTREAM
209 NS_DECL_NSIDISKCACHESTREAMINTERNAL
211 void ReleaseStreamIO() { NS_IF_RELEASE(mStreamIO
); }
214 nsDiskCacheStreamIO
* mStreamIO
; // backpointer to parent
219 NS_IMPL_THREADSAFE_ISUPPORTS2(nsDiskCacheOutputStream
,
221 nsIDiskCacheStreamInternal
)
223 nsDiskCacheOutputStream::nsDiskCacheOutputStream( nsDiskCacheStreamIO
* parent
)
227 NS_ADDREF(mStreamIO
);
231 nsDiskCacheOutputStream::~nsDiskCacheOutputStream()
239 nsDiskCacheOutputStream::Close()
243 // tell parent streamIO we are closing
244 mStreamIO
->CloseOutputStream(this);
250 nsDiskCacheOutputStream::CloseInternal()
254 // tell parent streamIO we are closing
255 mStreamIO
->CloseOutputStreamInternal(this);
261 nsDiskCacheOutputStream::Flush()
263 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
264 // yeah, yeah, well get to it...eventually...
270 nsDiskCacheOutputStream::Write(const char *buf
, PRUint32 count
, PRUint32
*bytesWritten
)
272 if (mClosed
) return NS_BASE_STREAM_CLOSED
;
273 return mStreamIO
->Write(buf
, count
, bytesWritten
);
278 nsDiskCacheOutputStream::WriteFrom(nsIInputStream
*inStream
, PRUint32 count
, PRUint32
*bytesWritten
)
280 NS_NOTREACHED("WriteFrom");
281 return NS_ERROR_NOT_IMPLEMENTED
;
286 nsDiskCacheOutputStream::WriteSegments( nsReadSegmentFun reader
,
289 PRUint32
* bytesWritten
)
291 NS_NOTREACHED("WriteSegments");
292 return NS_ERROR_NOT_IMPLEMENTED
;
297 nsDiskCacheOutputStream::IsNonBlocking(PRBool
* nonBlocking
)
299 *nonBlocking
= PR_FALSE
;
305 /******************************************************************************
306 * nsDiskCacheStreamIO
307 *****************************************************************************/
310 #pragma mark nsDiskCacheStreamIO
313 NS_IMPL_THREADSAFE_ISUPPORTS0(nsDiskCacheStreamIO
)
315 // we pick 16k as the max buffer size because that is the threshold above which
316 // we are unable to store the data in the cache block files
317 // see nsDiskCacheMap.[cpp,h]
318 #define kMaxBufferSize (16 * 1024)
320 nsDiskCacheStreamIO::nsDiskCacheStreamIO(nsDiskCacheBinding
* binding
)
330 , mBufDirty(PR_FALSE
)
333 mDevice
= (nsDiskCacheDevice
*)mBinding
->mCacheEntry
->CacheDevice();
335 // acquire "death grip" on cache service
336 nsCacheService
*service
= nsCacheService::GlobalInstance();
341 nsDiskCacheStreamIO::~nsDiskCacheStreamIO()
345 // release "death grip" on cache service
346 nsCacheService
*service
= nsCacheService::GlobalInstance();
352 nsDiskCacheStreamIO::Close()
354 // this should only be called from our destructor
355 // no one is interested in us anymore, so we don't need to grab any locks
357 // assert streams closed
358 NS_ASSERTION(!mOutStream
, "output stream still open");
359 NS_ASSERTION(mInStreamCount
== 0, "input stream still open");
360 NS_ASSERTION(!mFD
, "file descriptor not closed");
366 // NOTE: called with service lock held
368 nsDiskCacheStreamIO::GetInputStream(PRUint32 offset
, nsIInputStream
** inputStream
)
370 NS_ENSURE_ARG_POINTER(inputStream
);
371 NS_ENSURE_TRUE(offset
== 0, NS_ERROR_NOT_IMPLEMENTED
);
373 *inputStream
= nsnull
;
375 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
378 NS_WARNING("already have an output stream open");
379 return NS_ERROR_NOT_AVAILABLE
;
383 PRFileDesc
* fd
= nsnull
;
385 mStreamEnd
= mBinding
->mCacheEntry
->DataSize();
386 if (mStreamEnd
== 0) {
387 // there's no data to read
388 NS_ASSERTION(!mBinding
->mRecord
.DataLocationInitialized(), "storage allocated for zero data size");
389 } else if (mBinding
->mRecord
.DataFile() == 0) {
390 // open file desc for data
391 rv
= OpenCacheFile(PR_RDONLY
, &fd
);
392 if (NS_FAILED(rv
)) return rv
; // unable to open file
393 NS_ASSERTION(fd
, "cache stream lacking open file.");
395 } else if (!mBuffer
) {
396 // read block file for data
397 rv
= ReadCacheBlocks();
398 if (NS_FAILED(rv
)) return rv
;
400 // else, mBuffer already contains all of the data (left over from a
401 // previous block-file read or write).
403 NS_ASSERTION(!(fd
&& mBuffer
), "ambiguous data sources for input stream");
405 // create a new input stream
406 nsDiskCacheInputStream
* inStream
= new nsDiskCacheInputStream(this, fd
, mBuffer
, mStreamEnd
);
407 if (!inStream
) return NS_ERROR_OUT_OF_MEMORY
;
409 NS_ADDREF(*inputStream
= inStream
);
414 // NOTE: called with service lock held
416 nsDiskCacheStreamIO::GetOutputStream(PRUint32 offset
, nsIOutputStream
** outputStream
)
418 NS_ENSURE_ARG_POINTER(outputStream
);
419 *outputStream
= nsnull
;
421 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
423 NS_ASSERTION(!mOutStream
, "already have an output stream open");
424 NS_ASSERTION(mInStreamCount
== 0, "we already have input streams open");
425 if (mOutStream
|| mInStreamCount
) return NS_ERROR_NOT_AVAILABLE
;
427 // mBuffer lazily allocated, but might exist if a previous stream already
431 mStreamEnd
= mBinding
->mCacheEntry
->DataSize();
435 rv
= Seek(PR_SEEK_SET
, offset
);
436 if (NS_FAILED(rv
)) return rv
;
439 if (NS_FAILED(rv
)) return rv
;
441 // create a new output stream
442 mOutStream
= new nsDiskCacheOutputStream(this);
443 if (!mOutStream
) return NS_ERROR_OUT_OF_MEMORY
;
445 NS_ADDREF(*outputStream
= mOutStream
);
450 nsDiskCacheStreamIO::ClearBinding()
452 if (mBinding
&& mOutStream
)
458 nsDiskCacheStreamIO::CloseOutputStream(nsDiskCacheOutputStream
* outputStream
)
460 nsCacheServiceAutoLock lock
; // grab service lock
461 return CloseOutputStreamInternal(outputStream
);
465 nsDiskCacheStreamIO::CloseOutputStreamInternal(
466 nsDiskCacheOutputStream
* outputStream
)
470 if (outputStream
!= mOutStream
) {
471 NS_WARNING("mismatched output streams");
472 return NS_ERROR_UNEXPECTED
;
475 // output stream is closing
476 if (!mBinding
) { // if we're severed, just clear member variables
477 NS_ASSERTION(!mBufDirty
, "oops");
479 outputStream
->ReleaseStreamIO();
480 return NS_ERROR_NOT_AVAILABLE
;
485 NS_WARNING("Flush() failed");
492 nsDiskCacheStreamIO::Flush()
494 NS_ASSERTION(mBinding
, "oops");
496 CACHE_LOG_DEBUG(("CACHE: Flush [%x doomed=%u]\n",
497 mBinding
->mRecord
.HashNumber(), mBinding
->mDoomed
));
502 // write data to cache blocks, or flush mBuffer to file
503 nsDiskCacheMap
*cacheMap
= mDevice
->CacheMap(); // get map reference
506 PRBool written
= PR_FALSE
;
508 if ((mStreamEnd
<= kMaxBufferSize
) &&
509 (mBinding
->mCacheEntry
->StoragePolicy() != nsICache::STORE_ON_DISK_AS_FILE
)) {
510 // store data (if any) in cache block files
512 mBufDirty
= PR_FALSE
;
514 // delete existing storage
515 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
516 if (record
->DataLocationInitialized()) {
517 rv
= cacheMap
->DeleteStorage(record
, nsDiskCache::kData
);
519 NS_WARNING("cacheMap->DeleteStorage() failed.");
520 cacheMap
->DeleteRecord(record
);
525 // flush buffer to block files
527 if (mStreamEnd
> 0) {
528 rv
= cacheMap
->WriteDataCacheBlocks(mBinding
, mBuffer
, mBufEnd
);
530 NS_WARNING("WriteDataCacheBlocks() failed.");
537 // make sure we save as separate file
538 rv
= FlushBufferToFile(); // initializes DataFileLocation() if necessary
541 // Update the file size of the disk file in the cache
544 // close file descriptor
545 (void) PR_Close(mFD
);
549 NS_WARNING("no file descriptor");
551 // close mFD first if possible before returning if FlushBufferToFile
553 NS_ENSURE_SUCCESS(rv
, rv
);
555 // since the data location is on disk as a single file, the only value
556 // in keeping mBuffer around is to avoid an extra malloc the next time
557 // we need to write to this file. reading will use a file descriptor.
558 // therefore, it's probably not worth optimizing for the subsequent
559 // write, so we unconditionally delete mBuffer here.
563 // XXX do we need this here? WriteDataCacheBlocks() calls UpdateRecord()
564 // update cache map if entry isn't doomed
565 if (!mBinding
->mDoomed
) {
566 rv
= cacheMap
->UpdateRecord(&mBinding
->mRecord
);
568 NS_WARNING("cacheMap->UpdateRecord() failed.");
569 return rv
; // XXX doom cache entry
578 // only one thread writing at a time
579 // never have both output and input streams open
580 // OnDataSizeChanged() will have already been called to update entry->DataSize()
583 nsDiskCacheStreamIO::Write( const char * buffer
,
585 PRUint32
* bytesWritten
)
588 nsCacheServiceAutoLock lock
; // grab service lock
589 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
591 if (mInStreamCount
) {
592 // we have open input streams already
593 // this is an error until we support overlapped I/O
594 NS_WARNING("Attempting to write to cache entry with open input streams.\n");
595 return NS_ERROR_NOT_AVAILABLE
;
598 NS_ASSERTION(count
, "Write called with count of zero");
599 NS_ASSERTION(mBufPos
<= mBufEnd
, "streamIO buffer corrupted");
601 PRUint32 bytesLeft
= count
;
602 PRBool flushed
= PR_FALSE
;
605 if (mBufPos
== mBufSize
) {
606 if (mBufSize
< kMaxBufferSize
) {
607 mBufSize
= kMaxBufferSize
;
608 char *buffer
= mBuffer
;
610 mBuffer
= (char *) realloc(mBuffer
, mBufSize
);
617 nsresult rv
= FlushBufferToFile();
618 if (NS_FAILED(rv
)) break;
623 PRUint32 chunkSize
= bytesLeft
;
624 if (chunkSize
> (mBufSize
- mBufPos
))
625 chunkSize
= mBufSize
- mBufPos
;
627 memcpy(mBuffer
+ mBufPos
, buffer
, chunkSize
);
629 mBufPos
+= chunkSize
;
630 bytesLeft
-= chunkSize
;
633 if (mBufEnd
< mBufPos
)
638 return NS_ERROR_FAILURE
;
640 *bytesWritten
= count
;
642 // update mStreamPos, mStreamEnd
644 if (mStreamEnd
< mStreamPos
) {
645 mStreamEnd
= mStreamPos
;
646 NS_ASSERTION(mBinding
->mCacheEntry
->DataSize() == mStreamEnd
, "bad stream");
648 // If we have flushed to a file, update the file size
649 if (flushed
&& mFD
) {
659 nsDiskCacheStreamIO::UpdateFileSize()
661 NS_ASSERTION(mFD
, "nsDiskCacheStreamIO::UpdateFileSize should not have been called");
663 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
664 const PRUint32 oldSizeK
= record
->DataFileSize();
665 const PRUint32 newSizeK
= (mStreamEnd
+ 0x03FF) >> 10;
667 if (newSizeK
== oldSizeK
) return;
669 record
->SetDataFileSize(newSizeK
);
671 // update cache size totals
672 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
673 cacheMap
->DecrementTotalSize(oldSizeK
); // decrement old size
674 cacheMap
->IncrementTotalSize(newSizeK
); // increment new size
676 if (!mBinding
->mDoomed
) {
677 nsresult rv
= cacheMap
->UpdateRecord(record
);
679 NS_WARNING("cacheMap->UpdateRecord() failed.");
680 // XXX doom cache entry?
687 nsDiskCacheStreamIO::OpenCacheFile(PRIntn flags
, PRFileDesc
** fd
)
689 NS_ENSURE_ARG_POINTER(fd
);
692 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
694 rv
= cacheMap
->GetLocalFileForDiskCacheRecord(&mBinding
->mRecord
,
696 !!(flags
& PR_CREATE_FILE
),
697 getter_AddRefs(mLocalFile
));
698 if (NS_FAILED(rv
)) return rv
;
700 // create PRFileDesc for input stream - the 00600 is just for consistency
701 rv
= mLocalFile
->OpenNSPRFileDesc(flags
, 00600, fd
);
702 if (NS_FAILED(rv
)) return rv
; // unable to open file
709 nsDiskCacheStreamIO::ReadCacheBlocks()
711 NS_ASSERTION(mStreamEnd
== mBinding
->mCacheEntry
->DataSize(), "bad stream");
712 NS_ASSERTION(mStreamEnd
<= kMaxBufferSize
, "data too large for buffer");
714 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
715 if (!record
->DataLocationInitialized()) return NS_OK
;
717 NS_ASSERTION(record
->DataFile() != kSeparateFile
, "attempt to read cache blocks on separate file");
721 mBuffer
= (char *) malloc(mStreamEnd
);
723 return NS_ERROR_OUT_OF_MEMORY
;
725 mBufSize
= mStreamEnd
;
728 // read data stored in cache block files
729 nsDiskCacheMap
*map
= mDevice
->CacheMap(); // get map reference
730 nsresult rv
= map
->ReadDataCacheBlocks(mBinding
, mBuffer
, mStreamEnd
);
731 if (NS_FAILED(rv
)) return rv
;
733 // update streamIO variables
735 mBufEnd
= mStreamEnd
;
742 nsDiskCacheStreamIO::FlushBufferToFile()
745 nsDiskCacheRecord
* record
= &mBinding
->mRecord
;
748 if (record
->DataLocationInitialized() && (record
->DataFile() > 0)) {
749 // remove cache block storage
750 nsDiskCacheMap
* cacheMap
= mDevice
->CacheMap();
751 rv
= cacheMap
->DeleteStorage(record
, nsDiskCache::kData
);
752 if (NS_FAILED(rv
)) return rv
;
754 record
->SetDataFileGeneration(mBinding
->mGeneration
);
757 rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
758 if (NS_FAILED(rv
)) return rv
;
760 PRInt64 dataSize
= mBinding
->mCacheEntry
->PredictedDataSize();
761 // Appears to cause bug 617123? Disabled for now.
764 mozilla::fallocate(mFD
, PR_MIN(dataSize
, kPreallocateLimit
));
769 PRInt32 bytesWritten
= PR_Write(mFD
, mBuffer
, mBufEnd
);
770 if (PRUint32(bytesWritten
) != mBufEnd
) {
771 NS_WARNING("failed to flush all data");
772 return NS_ERROR_UNEXPECTED
; // NS_ErrorAccordingToNSPR()
774 mBufDirty
= PR_FALSE
;
785 nsDiskCacheStreamIO::DeleteBuffer()
788 NS_ASSERTION(!mBufDirty
, "deleting dirty buffer");
798 // NOTE: called with service lock held
800 nsDiskCacheStreamIO::Seek(PRInt32 whence
, PRInt32 offset
)
803 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
805 if (PRUint32(offset
) > mStreamEnd
) return NS_ERROR_FAILURE
;
807 if (mBinding
->mRecord
.DataLocationInitialized()) {
808 if (mBinding
->mRecord
.DataFile() == 0) {
810 // we need an mFD, we better open it now
811 nsresult rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
812 if (NS_FAILED(rv
)) return rv
;
818 // do we have data in the buffer that needs to be flushed?
820 // XXX optimization: are we just moving within the current buffer?
821 nsresult rv
= FlushBufferToFile();
822 if (NS_FAILED(rv
)) return rv
;
825 newPos
= PR_Seek(mFD
, offset
, (PRSeekWhence
)whence
);
827 return NS_ErrorAccordingToNSPR();
829 mStreamPos
= (PRUint32
) newPos
;
835 // else, seek in mBuffer
842 case PR_SEEK_CUR
: // relative from current posistion
843 newPos
= offset
+ (PRUint32
)mStreamPos
;
846 case PR_SEEK_END
: // relative from end
847 newPos
= offset
+ (PRUint32
)mBufEnd
;
851 return NS_ERROR_INVALID_ARG
;
854 // read data into mBuffer if not read yet.
855 if (mStreamEnd
&& !mBufEnd
) {
857 nsresult rv
= ReadCacheBlocks();
858 if (NS_FAILED(rv
)) return rv
;
862 // stream buffer sanity checks
863 NS_ASSERTION(mBufEnd
<= kMaxBufferSize
, "bad stream");
864 NS_ASSERTION(mBufPos
<= mBufEnd
, "bad stream");
865 NS_ASSERTION(mStreamPos
== mBufPos
, "bad stream");
866 NS_ASSERTION(mStreamEnd
== mBufEnd
, "bad stream");
868 if ((newPos
< 0) || (PRUint32(newPos
) > mBufEnd
)) {
869 NS_WARNING("seek offset out of range");
870 return NS_ERROR_INVALID_ARG
;
879 // called only from nsDiskCacheOutputStream::Tell
881 nsDiskCacheStreamIO::Tell(PRUint32
* result
)
883 NS_ENSURE_ARG_POINTER(result
);
884 *result
= mStreamPos
;
889 // NOTE: called with service lock held
891 nsDiskCacheStreamIO::SetEOF()
894 PRBool needToCloseFD
= PR_FALSE
;
896 NS_ASSERTION(mStreamPos
<= mStreamEnd
, "bad stream");
897 if (!mBinding
) return NS_ERROR_NOT_AVAILABLE
;
899 if (mBinding
->mRecord
.DataLocationInitialized()) {
900 if (mBinding
->mRecord
.DataFile() == 0) {
902 // we need an mFD, we better open it now
903 rv
= OpenCacheFile(PR_RDWR
| PR_CREATE_FILE
, &mFD
);
904 if (NS_FAILED(rv
)) return rv
;
905 needToCloseFD
= PR_TRUE
;
908 // data in cache block files
909 if ((mStreamPos
!= 0) && (mStreamPos
!= mBufPos
)) {
910 // only read data if there will be some left after truncation
911 rv
= ReadCacheBlocks();
912 if (NS_FAILED(rv
)) return rv
;
915 // We need to make sure we reflect this change in Flush().
916 // In particular, if mStreamPos is 0 and we never write to
917 // the buffer, we want the storage to be deleted.
923 rv
= nsDiskCache::Truncate(mFD
, mStreamPos
);
925 PRUint32 oldSizeK
= (mStreamEnd
+ 0x03FF) >> 10;
926 NS_ASSERTION(mBinding
->mRecord
.DataFileSize() == oldSizeK
, "bad disk cache entry size");
928 // data stored in buffer.
929 NS_ASSERTION(mStreamEnd
<= kMaxBufferSize
, "buffer truncation inadequate");
930 NS_ASSERTION(mBufPos
== mStreamPos
, "bad stream");
931 NS_ASSERTION(mBuffer
? mBufEnd
== mStreamEnd
: PR_TRUE
, "bad stream");
935 NS_ASSERTION(mStreamEnd
== mBinding
->mCacheEntry
->DataSize(), "cache entry not updated");
936 // we expect nsCacheEntryDescriptor::TransportWrapper::OpenOutputStream()
937 // to eventually update the cache entry
939 mStreamEnd
= mStreamPos
;
945 (void) PR_Close(mFD
);