nsresult nsCacheEntryDescriptor:: nsInputStreamWrapper::LazyInit() { nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_LAZYINIT)); nsCacheAccessMode mode; nsresult rv = mDescriptor->GetAccessGranted(&mode); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED); nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode, mStartOffset, getter_AddRefs(mInput)); CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit " "[entry=%p, wrapper=%p, mInput=%p, rv=%d]", mDescriptor, this, mInput.get(), int(rv))); if (NS_FAILED(rv)) return rv; mInitialized = true; return NS_OK; }
NS_INTERFACE_MAP_END_THREADSAFE nsresult nsCacheEntryDescriptor:: nsInputStreamWrapper::LazyInit() { // Check if we have the descriptor. If not we can't even grab the cache // lock since it is not ensured that the cache service still exists. if (!mDescriptor) return NS_ERROR_NOT_AVAILABLE; nsCacheServiceAutoLock lock(LOCK_TELEM(NSINPUTSTREAMWRAPPER_LAZYINIT)); nsCacheAccessMode mode; nsresult rv = mDescriptor->GetAccessGranted(&mode); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(mode & nsICache::ACCESS_READ, NS_ERROR_UNEXPECTED); nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode, mStartOffset, getter_AddRefs(mInput)); CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit " "[entry=%p, wrapper=%p, mInput=%p, rv=%d]", mDescriptor, this, mInput.get(), int(rv))); if (NS_FAILED(rv)) return rv; mInitialized = true; return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::OpenOutputStream(uint32_t offset, nsIOutputStream ** result) { NS_ENSURE_ARG_POINTER(result); { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENOUTPUTSTREAM)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; // ensure valid permissions if (!(mAccessGranted & nsICache::ACCESS_WRITE)) return NS_ERROR_CACHE_WRITE_ACCESS_DENIED; } nsOutputStreamWrapper* cacheOutput = nullptr; int32_t compressionLevel = nsCacheService::CacheCompressionLevel(); const char *val; val = mCacheEntry->GetMetaDataElement("uncompressed-len"); if ((compressionLevel > 0) && val) { cacheOutput = new nsCompressOutputStreamWrapper(this, offset); } else { // clear compression flag when compression disabled - see bug #715198 if (val) { mCacheEntry->SetMetaDataElement("uncompressed-len", nullptr); } cacheOutput = new nsOutputStreamWrapper(this, offset); } if (!cacheOutput) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*result = cacheOutput); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::OpenInputStream(uint32_t offset, nsIInputStream ** result) { NS_ENSURE_ARG_POINTER(result); nsInputStreamWrapper* cacheInput = nullptr; { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_OPENINPUTSTREAM)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (!mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_NOT_STREAM; // Don't open any new stream when closing descriptor or clearing entries if (mClosingDescriptor || nsCacheService::GetClearingEntries()) return NS_ERROR_NOT_AVAILABLE; // ensure valid permissions if (!(mAccessGranted & nsICache::ACCESS_READ)) return NS_ERROR_CACHE_READ_ACCESS_DENIED; const char *val; val = mCacheEntry->GetMetaDataElement("uncompressed-len"); if (val) { cacheInput = new nsDecompressInputStreamWrapper(this, offset); } else { cacheInput = new nsInputStreamWrapper(this, offset); } if (!cacheInput) return NS_ERROR_OUT_OF_MEMORY; mInputWrappers.AppendElement(cacheInput); } NS_ADDREF(*result = cacheInput); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::Doom() { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOM)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return nsCacheService::DoomEntry(mCacheEntry); }
NS_IMETHODIMP nsCacheEntryDescriptor::GetKey(nsACString &result) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETKEY)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return ClientKeyFromCacheKey(*(mCacheEntry->Key()), result); }
NS_IMETHODIMP nsCacheEntryDescriptor::DoomAndFailPendingRequests(nsresult status) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_DOOMANDFAILPENDINGREQUESTS)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return NS_ERROR_NOT_IMPLEMENTED; }
NS_IMETHODIMP nsCacheEntryDescriptor::Close() { nsRefPtr<nsOutputStreamWrapper> outputWrapper; nsTArray<nsRefPtr<nsInputStreamWrapper> > inputWrappers; { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; // Make sure no other stream can be opened mClosingDescriptor = true; outputWrapper = mOutputWrapper; for (int32_t i = 0 ; i < mInputWrappers.Count() ; i++) inputWrappers.AppendElement(static_cast<nsInputStreamWrapper *>( mInputWrappers[i])); } // Call Close() on the streams outside the lock since it might need to call // methods that grab the cache service lock, e.g. compressed output stream // when it finalizes the entry if (outputWrapper) { if (NS_FAILED(outputWrapper->Close())) { NS_WARNING("Dooming entry because Close() failed!!!"); Doom(); } outputWrapper = nullptr; } for (uint32_t i = 0 ; i < inputWrappers.Length() ; i++) inputWrappers[i]->Close(); inputWrappers.Clear(); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; // XXX perhaps closing descriptors should clear/sever transports // tell nsCacheService we're going away nsCacheService::CloseDescriptor(this); NS_ASSERTION(mCacheEntry == nullptr, "mCacheEntry not null"); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetFile(nsIFile ** result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFILE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return nsCacheService::GetFileForEntry(mCacheEntry, result); }
NS_IMETHODIMP nsCacheEntryDescriptor::SetPredictedDataSize(int64_t predictedSize) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETPREDICTEDDATASIZE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; mCacheEntry->SetPredictedDataSize(predictedSize); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETCACHEELEMENT)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM; return nsCacheService::SetCacheElement(mCacheEntry, cacheElement); }
NS_IMETHODIMP nsCacheEntryDescriptor::GetPredictedDataSize(int64_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETPREDICTEDDATASIZE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->PredictedDataSize(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::MarkValid() { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_MARKVALID)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; nsresult rv = nsCacheService::ValidateEntry(mCacheEntry); return rv; }
NS_IMETHODIMP nsCacheEntryDescriptor::IsStreamBased(bool *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_ISSTREAMBASED)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->IsStreamData(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetStoragePolicy(nsCacheStoragePolicy *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEPOLICY)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->StoragePolicy(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetClientID(char ** result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCLIENTID)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return ClientIDFromCacheKey(*(mCacheEntry->Key()), result); }
NS_IMETHODIMP nsCacheEntryDescriptor::GetFetchCount(int32_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETFETCHCOUNT)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->FetchCount(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetStorageDataSize(uint32_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSTORAGEDATASIZE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->DataSize(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetLastModified(uint32_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETLASTMODIFIED)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->LastModified(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetExpirationTime(uint32_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETEXPIRATIONTIME)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->ExpirationTime(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::SetExpirationTime(uint32_t expirationTime) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETEXPIRATIONTIME)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; mCacheEntry->SetExpirationTime(expirationTime); mCacheEntry->MarkEntryDirty(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::SetSecurityInfo(nsISupports * securityInfo) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETSECURITYINFO)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; mCacheEntry->SetSecurityInfo(securityInfo); mCacheEntry->MarkEntryDirty(); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::VisitMetaData(nsICacheMetaDataVisitor * visitor) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_VISITMETADATA)); // XXX check callers, we're calling out of module NS_ENSURE_ARG_POINTER(visitor); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; return mCacheEntry->VisitMetaDataElements(visitor); }
NS_INTERFACE_MAP_END_THREADSAFE nsresult nsCacheEntryDescriptor:: nsOutputStreamWrapper::LazyInit() { // Check if we have the descriptor. If not we can't even grab the cache // lock since it is not ensured that the cache service still exists. if (!mDescriptor) return NS_ERROR_NOT_AVAILABLE; nsCacheServiceAutoLock lock(LOCK_TELEM(NSOUTPUTSTREAMWRAPPER_LAZYINIT)); nsCacheAccessMode mode; nsresult rv = mDescriptor->GetAccessGranted(&mode); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(mode & nsICache::ACCESS_WRITE, NS_ERROR_UNEXPECTED); nsCacheEntry* cacheEntry = mDescriptor->CacheEntry(); if (!cacheEntry) return NS_ERROR_NOT_AVAILABLE; NS_ASSERTION(mOutput == nullptr, "mOutput set in LazyInit"); nsCOMPtr<nsIOutputStream> stream; rv = nsCacheService::OpenOutputStreamForEntry(cacheEntry, mode, mStartOffset, getter_AddRefs(stream)); if (NS_FAILED(rv)) return rv; nsCacheDevice* device = cacheEntry->CacheDevice(); if (device) { // the entry has been truncated to mStartOffset bytes, inform device int32_t size = cacheEntry->DataSize(); rv = device->OnDataSizeChange(cacheEntry, mStartOffset - size); if (NS_SUCCEEDED(rv)) cacheEntry->SetDataSize(mStartOffset); } else { rv = NS_ERROR_NOT_AVAILABLE; } // If anything above failed, clean up internal state and get out of here // (see bug #654926)... if (NS_FAILED(rv)) { nsCacheService::ReleaseObject_Locked(stream.forget().take()); mDescriptor->mOutputWrapper = nullptr; nsCacheService::ReleaseObject_Locked(mDescriptor); mDescriptor = nullptr; mInitialized = false; return rv; } mOutput = stream; mInitialized = true; return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetCacheElement(nsISupports ** result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETCACHEELEMENT)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; if (mCacheEntry->IsStreamData()) return NS_ERROR_CACHE_DATA_IS_STREAM; NS_IF_ADDREF(*result = mCacheEntry->Data()); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetSecurityInfo(nsISupports ** result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETSECURITYINFO)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; *result = mCacheEntry->SecurityInfo(); NS_IF_ADDREF(*result); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::Close() { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_CLOSE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; // XXX perhaps closing descriptors should clear/sever transports // tell nsCacheService we're going away nsCacheService::CloseDescriptor(this); NS_ASSERTION(mCacheEntry == nullptr, "mCacheEntry not null"); return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::GetDataSize(uint32_t *result) { NS_ENSURE_ARG_POINTER(result); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_GETDATASIZE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; const char* val = mCacheEntry->GetMetaDataElement("uncompressed-len"); if (!val) { *result = mCacheEntry->DataSize(); } else { *result = atol(val); } return NS_OK; }
NS_IMETHODIMP nsCacheEntryDescriptor::SetMetaDataElement(const char *key, const char *value) { NS_ENSURE_ARG_POINTER(key); nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_SETMETADATAELEMENT)); NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_AVAILABLE); // XXX allow null value, for clearing key? nsresult rv = mCacheEntry->SetMetaDataElement(key, value); if (NS_SUCCEEDED(rv)) mCacheEntry->TouchMetaData(); return rv; }
nsresult nsCacheEntryDescriptor::RequestDataSizeChange(int32_t deltaSize) { nsCacheServiceAutoLock lock(LOCK_TELEM(NSCACHEENTRYDESCRIPTOR_REQUESTDATASIZECHANGE)); if (!mCacheEntry) return NS_ERROR_NOT_AVAILABLE; nsresult rv; rv = nsCacheService::OnDataSizeChange(mCacheEntry, deltaSize); if (NS_SUCCEEDED(rv)) { // XXX review for signed/unsigned math errors uint32_t newDataSize = mCacheEntry->DataSize() + deltaSize; mCacheEntry->SetDataSize(newDataSize); mCacheEntry->TouchData(); } return rv; }