1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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/. */
7 #include "nsJARInputStream.h"
10 #include "nsIObserverService.h"
11 #include "mozilla/DebugOnly.h"
12 #include "mozilla/Logging.h"
13 #include "mozilla/Omnijar.h"
14 #include "mozilla/Unused.h"
17 # include <sys/stat.h>
22 using namespace mozilla
;
24 static LazyLogModule
gJarLog("nsJAR");
33 #define LOG(args) MOZ_LOG(gJarLog, mozilla::LogLevel::Debug, args)
34 #define LOG_ENABLED() MOZ_LOG_TEST(gJarLog, mozilla::LogLevel::Debug)
36 //----------------------------------------------
37 // nsJAR constructor/destructor
38 //----------------------------------------------
40 // The following initialization makes a guess of 10 entries per jarfile.
42 : mReleaseTime(PR_INTERVAL_NO_TIMEOUT
),
43 mLock("nsJAR::mLock"),
46 nsJAR::~nsJAR() { Close(); }
48 NS_IMPL_QUERY_INTERFACE(nsJAR
, nsIZipReader
)
51 // Custom Release method works with nsZipReaderCache...
52 // Release might be called from multi-thread, we have to
53 // take this function carefully to avoid delete-after-use.
54 MozExternalRefCountType
nsJAR::Release(void) {
56 MOZ_ASSERT(0 != mRefCnt
, "dup release");
58 RefPtr
<nsZipReaderCache
> cache
;
59 if (mRefCnt
== 2) { // don't use a lock too frequently
60 // Use a mutex here to guarantee mCache is not racing and the target
61 // instance is still valid to increase ref-count.
62 RecursiveMutexAutoLock
lock(mLock
);
67 DebugOnly
<nsresult
> rv
= cache
->ReleaseZip(this);
68 MOZ_ASSERT(NS_SUCCEEDED(rv
), "failed to release zip file");
71 count
= --mRefCnt
; // don't access any member variable after this line
72 NS_LOG_RELEASE(this, count
, "nsJAR");
74 mRefCnt
= 1; /* stabilize */
75 /* enable this to find non-threadsafe destructors: */
76 /* NS_ASSERT_OWNINGTHREAD(nsJAR); */
84 //----------------------------------------------
85 // nsIZipReader implementation
86 //----------------------------------------------
89 nsJAR::Open(nsIFile
* zipFile
) {
90 NS_ENSURE_ARG_POINTER(zipFile
);
91 RecursiveMutexAutoLock
lock(mLock
);
92 LOG(("Open[%p] %s", this, zipFile
->HumanReadablePath().get()));
93 if (mZip
) return NS_ERROR_FAILURE
; // Already open!
96 mOuterZipEntry
.Truncate();
98 // The omnijar is special, it is opened early on and closed late
99 RefPtr
<nsZipArchive
> zip
= mozilla::Omnijar::GetReader(zipFile
);
101 zip
= nsZipArchive::OpenArchive(zipFile
);
104 return mZip
? NS_OK
: NS_ERROR_FAILURE
;
108 nsJAR::OpenInner(nsIZipReader
* aZipReader
, const nsACString
& aZipEntry
) {
111 LOG(("OpenInner[%p] %s", this, PromiseFlatCString(aZipEntry
).get()));
112 NS_ENSURE_ARG_POINTER(aZipReader
);
114 nsCOMPtr
<nsIFile
> zipFile
;
115 rv
= aZipReader
->GetFile(getter_AddRefs(zipFile
));
116 NS_ENSURE_SUCCESS(rv
, rv
);
118 RefPtr
<nsZipArchive
> innerZip
=
119 mozilla::Omnijar::GetInnerReader(zipFile
, aZipEntry
);
121 RecursiveMutexAutoLock
lock(mLock
);
123 return NS_ERROR_FAILURE
;
130 rv
= aZipReader
->HasEntry(aZipEntry
, &exist
);
131 NS_ENSURE_SUCCESS(rv
, rv
);
132 NS_ENSURE_TRUE(exist
, NS_ERROR_FILE_NOT_FOUND
);
134 RefPtr
<nsZipHandle
> handle
;
136 nsJAR
* outerJAR
= static_cast<nsJAR
*>(aZipReader
);
137 RecursiveMutexAutoLock
outerLock(outerJAR
->mLock
);
138 rv
= nsZipHandle::Init(outerJAR
->mZip
.get(),
139 PromiseFlatCString(aZipEntry
).get(),
140 getter_AddRefs(handle
));
141 NS_ENSURE_SUCCESS(rv
, rv
);
144 RecursiveMutexAutoLock
lock(mLock
);
145 MOZ_ASSERT(!mZip
, "Another thread tried to open this nsJAR racily!");
146 mZipFile
= zipFile
.forget();
147 mOuterZipEntry
.Assign(aZipEntry
);
148 mZip
= nsZipArchive::OpenArchive(handle
);
149 return mZip
? NS_OK
: NS_ERROR_FAILURE
;
153 nsJAR::OpenMemory(void* aData
, uint32_t aLength
) {
154 NS_ENSURE_ARG_POINTER(aData
);
155 RecursiveMutexAutoLock
lock(mLock
);
156 if (mZip
) return NS_ERROR_FAILURE
; // Already open!
158 RefPtr
<nsZipHandle
> handle
;
159 nsresult rv
= nsZipHandle::Init(static_cast<uint8_t*>(aData
), aLength
,
160 getter_AddRefs(handle
));
161 if (NS_FAILED(rv
)) return rv
;
163 mZip
= nsZipArchive::OpenArchive(handle
);
164 return mZip
? NS_OK
: NS_ERROR_FAILURE
;
168 nsJAR::GetFile(nsIFile
** result
) {
169 RecursiveMutexAutoLock
lock(mLock
);
170 LOG(("GetFile[%p]", this));
172 NS_IF_ADDREF(*result
);
178 RecursiveMutexAutoLock
lock(mLock
);
179 LOG(("Close[%p]", this));
181 return NS_ERROR_FAILURE
; // Never opened or already closed.
189 nsJAR::Test(const nsACString
& aEntryName
) {
190 RecursiveMutexAutoLock
lock(mLock
);
192 return NS_ERROR_FAILURE
;
195 aEntryName
.IsEmpty() ? nullptr : PromiseFlatCString(aEntryName
).get());
199 nsJAR::Extract(const nsACString
& aEntryName
, nsIFile
* outFile
) {
200 // nsZipArchive and zlib are not thread safe
201 // we need to use a lock to prevent bug #51267
202 RecursiveMutexAutoLock
lock(mLock
);
204 return NS_ERROR_FAILURE
;
207 LOG(("Extract[%p] %s", this, PromiseFlatCString(aEntryName
).get()));
208 nsZipItem
* item
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get());
209 NS_ENSURE_TRUE(item
, NS_ERROR_FILE_NOT_FOUND
);
211 // Remove existing file or directory so we set permissions correctly.
212 // If it's a directory that already exists and contains files, throw
213 // an exception and return.
215 nsresult rv
= outFile
->Remove(false);
216 if (rv
== NS_ERROR_FILE_DIR_NOT_EMPTY
|| rv
== NS_ERROR_FAILURE
) return rv
;
218 if (item
->IsDirectory()) {
219 rv
= outFile
->Create(nsIFile::DIRECTORY_TYPE
, item
->Mode());
220 // XXX Do this in nsZipArchive? It would be nice to keep extraction
221 // XXX code completely there, but that would require a way to get a
222 // XXX PRDir from outFile.
225 rv
= outFile
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
, item
->Mode(),
227 if (NS_FAILED(rv
)) return rv
;
229 // ExtractFile also closes the fd handle and resolves the symlink if needed
230 rv
= mZip
->ExtractFile(item
, outFile
, fd
);
232 if (NS_FAILED(rv
)) return rv
;
234 // nsIFile needs milliseconds, while prtime is in microseconds.
235 // non-fatal if this fails, ignore errors
236 outFile
->SetLastModifiedTime(item
->LastModTime() / PR_USEC_PER_MSEC
);
242 nsJAR::GetEntry(const nsACString
& aEntryName
, nsIZipEntry
** result
) {
243 RecursiveMutexAutoLock
lock(mLock
);
244 LOG(("GetEntry[%p] %s", this, PromiseFlatCString(aEntryName
).get()));
246 return NS_ERROR_FAILURE
;
248 nsZipItem
* zipItem
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get());
249 NS_ENSURE_TRUE(zipItem
, NS_ERROR_FILE_NOT_FOUND
);
251 nsJARItem
* jarItem
= new nsJARItem(zipItem
);
253 NS_ADDREF(*result
= jarItem
);
258 nsJAR::HasEntry(const nsACString
& aEntryName
, bool* result
) {
259 RecursiveMutexAutoLock
lock(mLock
);
260 LOG(("HasEntry[%p] %s", this, PromiseFlatCString(aEntryName
).get()));
262 return NS_ERROR_FAILURE
;
264 *result
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get()) != nullptr;
269 nsJAR::FindEntries(const nsACString
& aPattern
,
270 nsIUTF8StringEnumerator
** result
) {
271 NS_ENSURE_ARG_POINTER(result
);
272 RecursiveMutexAutoLock
lock(mLock
);
273 LOG(("FindEntries[%p] %s", this, PromiseFlatCString(aPattern
).get()));
275 return NS_ERROR_FAILURE
;
279 nsresult rv
= mZip
->FindInit(
280 aPattern
.IsEmpty() ? nullptr : PromiseFlatCString(aPattern
).get(), &find
);
281 NS_ENSURE_SUCCESS(rv
, rv
);
283 nsIUTF8StringEnumerator
* zipEnum
= new nsJAREnumerator(find
);
285 NS_ADDREF(*result
= zipEnum
);
290 nsJAR::GetInputStream(const nsACString
& aEntryName
, nsIInputStream
** result
) {
291 NS_ENSURE_ARG_POINTER(result
);
292 RecursiveMutexAutoLock
lock(mLock
);
294 return NS_ERROR_FAILURE
;
297 LOG(("GetInputStream[%p] %s", this, PromiseFlatCString(aEntryName
).get()));
298 // Watch out for the jar:foo.zip!/ (aDir is empty) top-level special case!
299 nsZipItem
* item
= nullptr;
300 const nsCString
& entry
= PromiseFlatCString(aEntryName
);
302 // First check if item exists in jar
303 item
= mZip
->GetItem(entry
.get());
304 if (!item
) return NS_ERROR_FILE_NOT_FOUND
;
306 nsJARInputStream
* jis
= new nsJARInputStream();
307 // addref now so we can call InitFile/InitDirectory()
308 NS_ADDREF(*result
= jis
);
311 if (!item
|| item
->IsDirectory()) {
312 rv
= jis
->InitDirectory(this, entry
.get());
314 RefPtr
<nsZipHandle
> fd
= mZip
->GetFD();
315 rv
= jis
->InitFile(fd
, mZip
->GetData(item
), item
);
323 nsresult
nsJAR::GetFullJarPath(nsACString
& aResult
) {
324 RecursiveMutexAutoLock
lock(mLock
);
325 NS_ENSURE_ARG_POINTER(mZipFile
);
327 nsresult rv
= mZipFile
->GetPersistentDescriptor(aResult
);
332 if (mOuterZipEntry
.IsEmpty()) {
333 aResult
.InsertLiteral("file:", 0);
335 aResult
.InsertLiteral("jar:", 0);
336 aResult
.AppendLiteral("!/");
337 aResult
.Append(mOuterZipEntry
);
342 nsresult
nsJAR::GetNSPRFileDesc(PRFileDesc
** aNSPRFileDesc
) {
343 RecursiveMutexAutoLock
lock(mLock
);
344 if (!aNSPRFileDesc
) {
345 return NS_ERROR_ILLEGAL_VALUE
;
347 *aNSPRFileDesc
= nullptr;
350 return NS_ERROR_FAILURE
;
353 RefPtr
<nsZipHandle
> handle
= mZip
->GetFD();
355 return NS_ERROR_FAILURE
;
358 return handle
->GetNSPRFileDesc(aNSPRFileDesc
);
361 //----------------------------------------------
362 // nsJAR private implementation
363 //----------------------------------------------
364 nsresult
nsJAR::LoadEntry(const nsACString
& aFilename
, nsCString
& aBuf
) {
365 //-- Get a stream for reading the file
367 nsCOMPtr
<nsIInputStream
> manifestStream
;
368 rv
= GetInputStream(aFilename
, getter_AddRefs(manifestStream
));
369 if (NS_FAILED(rv
)) return NS_ERROR_FILE_NOT_FOUND
;
371 //-- Read the manifest file into memory
374 rv
= manifestStream
->Available(&len64
);
375 if (NS_FAILED(rv
)) return rv
;
376 NS_ENSURE_TRUE(len64
< UINT32_MAX
, NS_ERROR_FILE_CORRUPTED
); // bug 164695
377 uint32_t len
= (uint32_t)len64
;
378 buf
= (char*)malloc(len
+ 1);
379 if (!buf
) return NS_ERROR_OUT_OF_MEMORY
;
381 rv
= manifestStream
->Read(buf
, len
, &bytesRead
);
382 if (bytesRead
!= len
) {
383 rv
= NS_ERROR_FILE_CORRUPTED
;
389 buf
[len
] = '\0'; // Null-terminate the buffer
390 aBuf
.Adopt(buf
, len
);
394 int32_t nsJAR::ReadLine(const char** src
) {
399 //--Moves pointer to beginning of next line and returns line length
400 // not including CR/LF.
402 const char* eol
= strpbrk(*src
, "\r\n");
404 if (eol
== nullptr) // Probably reached end of file before newline
406 length
= strlen(*src
);
407 if (length
== 0) // immediate end-of-file
409 else // some data left on this line
413 if (eol
[0] == '\r' && eol
[1] == '\n') // CR LF, so skip 2
415 else // Either CR or LF, so skip 1
421 NS_IMPL_ISUPPORTS(nsJAREnumerator
, nsIUTF8StringEnumerator
, nsIStringEnumerator
)
423 //----------------------------------------------
424 // nsJAREnumerator::HasMore
425 //----------------------------------------------
427 nsJAREnumerator::HasMore(bool* aResult
) {
428 // try to get the next element
430 NS_ASSERTION(mFind
, "nsJAREnumerator: Missing zipFind.");
431 nsresult rv
= mFind
->FindNext(&mName
, &mNameLen
);
432 if (rv
== NS_ERROR_FILE_NOT_FOUND
) {
433 *aResult
= false; // No more matches available
436 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
); // no error translation
443 //----------------------------------------------
444 // nsJAREnumerator::GetNext
445 //----------------------------------------------
447 nsJAREnumerator::GetNext(nsACString
& aResult
) {
448 // check if the current item is "stale"
451 nsresult rv
= HasMore(&bMore
);
452 if (NS_FAILED(rv
) || !bMore
)
453 return NS_ERROR_FAILURE
; // no error translation
455 aResult
.Assign(mName
, mNameLen
);
456 mName
= 0; // we just gave this one away
460 NS_IMPL_ISUPPORTS(nsJARItem
, nsIZipEntry
)
462 nsJARItem::nsJARItem(nsZipItem
* aZipItem
)
463 : mSize(aZipItem
->Size()),
464 mRealsize(aZipItem
->RealSize()),
465 mCrc32(aZipItem
->CRC32()),
466 mLastModTime(aZipItem
->LastModTime()),
467 mCompression(aZipItem
->Compression()),
468 mPermissions(aZipItem
->Mode()),
469 mIsDirectory(aZipItem
->IsDirectory()),
470 mIsSynthetic(aZipItem
->isSynthetic
) {}
472 //------------------------------------------
473 // nsJARItem::GetCompression
474 //------------------------------------------
476 nsJARItem::GetCompression(uint16_t* aCompression
) {
477 NS_ENSURE_ARG_POINTER(aCompression
);
479 *aCompression
= mCompression
;
483 //------------------------------------------
484 // nsJARItem::GetSize
485 //------------------------------------------
487 nsJARItem::GetSize(uint32_t* aSize
) {
488 NS_ENSURE_ARG_POINTER(aSize
);
494 //------------------------------------------
495 // nsJARItem::GetRealSize
496 //------------------------------------------
498 nsJARItem::GetRealSize(uint32_t* aRealsize
) {
499 NS_ENSURE_ARG_POINTER(aRealsize
);
501 *aRealsize
= mRealsize
;
505 //------------------------------------------
506 // nsJARItem::GetCrc32
507 //------------------------------------------
509 nsJARItem::GetCRC32(uint32_t* aCrc32
) {
510 NS_ENSURE_ARG_POINTER(aCrc32
);
516 //------------------------------------------
517 // nsJARItem::GetIsDirectory
518 //------------------------------------------
520 nsJARItem::GetIsDirectory(bool* aIsDirectory
) {
521 NS_ENSURE_ARG_POINTER(aIsDirectory
);
523 *aIsDirectory
= mIsDirectory
;
527 //------------------------------------------
528 // nsJARItem::GetIsSynthetic
529 //------------------------------------------
531 nsJARItem::GetIsSynthetic(bool* aIsSynthetic
) {
532 NS_ENSURE_ARG_POINTER(aIsSynthetic
);
534 *aIsSynthetic
= mIsSynthetic
;
538 //------------------------------------------
539 // nsJARItem::GetLastModifiedTime
540 //------------------------------------------
542 nsJARItem::GetLastModifiedTime(PRTime
* aLastModTime
) {
543 NS_ENSURE_ARG_POINTER(aLastModTime
);
545 *aLastModTime
= mLastModTime
;
549 //------------------------------------------
550 // nsJARItem::GetPermissions
551 //------------------------------------------
553 nsJARItem::GetPermissions(uint32_t* aPermissions
) {
554 NS_ENSURE_ARG_POINTER(aPermissions
);
556 *aPermissions
= mPermissions
;
560 ////////////////////////////////////////////////////////////////////////////////
563 NS_IMPL_ISUPPORTS(nsZipReaderCache
, nsIZipReaderCache
, nsIObserver
,
564 nsISupportsWeakReference
)
566 nsZipReaderCache::nsZipReaderCache()
567 : mLock("nsZipReaderCache.mLock"),
570 #ifdef ZIP_CACHE_HIT_RATE
581 nsZipReaderCache::Init(uint32_t cacheSize
) {
582 MutexAutoLock
lock(mLock
);
583 mCacheSize
= cacheSize
;
585 // Register as a memory pressure observer
586 nsCOMPtr
<nsIObserverService
> os
=
587 do_GetService("@mozilla.org/observer-service;1");
589 os
->AddObserver(this, "memory-pressure", true);
590 os
->AddObserver(this, "chrome-flush-caches", true);
591 os
->AddObserver(this, "flush-cache-entry", true);
593 // ignore failure of the observer registration.
598 nsZipReaderCache::~nsZipReaderCache() {
599 for (const auto& zip
: mZips
.Values()) {
600 zip
->SetZipReaderCache(nullptr);
603 #ifdef ZIP_CACHE_HIT_RATE
605 "nsZipReaderCache size=%d hits=%d lookups=%d rate=%f%% flushes=%d missed "
607 mCacheSize
, mZipCacheHits
, mZipCacheLookups
,
608 (float)mZipCacheHits
/ mZipCacheLookups
, mZipCacheFlushes
,
614 nsZipReaderCache::IsCached(nsIFile
* zipFile
, bool* aResult
) {
615 NS_ENSURE_ARG_POINTER(zipFile
);
617 MutexAutoLock
lock(mLock
);
620 rv
= zipFile
->GetPersistentDescriptor(uri
);
621 if (NS_FAILED(rv
)) return rv
;
623 uri
.InsertLiteral("file:", 0);
625 *aResult
= mZips
.Contains(uri
);
629 nsresult
nsZipReaderCache::GetZip(nsIFile
* zipFile
, nsIZipReader
** result
,
631 NS_ENSURE_ARG_POINTER(zipFile
);
633 MutexAutoLock
lock(mLock
);
635 #ifdef ZIP_CACHE_HIT_RATE
640 rv
= zipFile
->GetPersistentDescriptor(uri
);
641 if (NS_FAILED(rv
)) return rv
;
643 uri
.InsertLiteral("file:", 0);
646 mZips
.Get(uri
, getter_AddRefs(zip
));
648 #ifdef ZIP_CACHE_HIT_RATE
651 zip
->ClearReleaseTime();
654 return NS_ERROR_CACHE_KEY_NOT_FOUND
;
658 zip
->SetZipReaderCache(this);
659 rv
= zip
->Open(zipFile
);
664 MOZ_ASSERT(!mZips
.Contains(uri
));
665 mZips
.InsertOrUpdate(uri
, RefPtr
{zip
});
672 nsZipReaderCache::GetZipIfCached(nsIFile
* zipFile
, nsIZipReader
** result
) {
673 return GetZip(zipFile
, result
, true);
677 nsZipReaderCache::GetZip(nsIFile
* zipFile
, nsIZipReader
** result
) {
678 return GetZip(zipFile
, result
, false);
682 nsZipReaderCache::GetInnerZip(nsIFile
* zipFile
, const nsACString
& entry
,
683 nsIZipReader
** result
) {
684 NS_ENSURE_ARG_POINTER(zipFile
);
686 nsCOMPtr
<nsIZipReader
> outerZipReader
;
687 nsresult rv
= GetZip(zipFile
, getter_AddRefs(outerZipReader
));
688 NS_ENSURE_SUCCESS(rv
, rv
);
690 MutexAutoLock
lock(mLock
);
692 #ifdef ZIP_CACHE_HIT_RATE
697 rv
= zipFile
->GetPersistentDescriptor(uri
);
698 if (NS_FAILED(rv
)) return rv
;
700 uri
.InsertLiteral("jar:", 0);
701 uri
.AppendLiteral("!/");
705 mZips
.Get(uri
, getter_AddRefs(zip
));
707 #ifdef ZIP_CACHE_HIT_RATE
710 zip
->ClearReleaseTime();
713 zip
->SetZipReaderCache(this);
715 rv
= zip
->OpenInner(outerZipReader
, entry
);
720 MOZ_ASSERT(!mZips
.Contains(uri
));
721 mZips
.InsertOrUpdate(uri
, RefPtr
{zip
});
728 nsZipReaderCache::GetFd(nsIFile
* zipFile
, PRFileDesc
** aRetVal
) {
730 MOZ_CRASH("Not implemented");
731 return NS_ERROR_NOT_IMPLEMENTED
;
734 return NS_ERROR_FAILURE
;
739 rv
= zipFile
->GetPersistentDescriptor(uri
);
743 uri
.InsertLiteral("file:", 0);
745 MutexAutoLock
lock(mLock
);
747 mZips
.Get(uri
, getter_AddRefs(zip
));
749 return NS_ERROR_FAILURE
;
752 zip
->ClearReleaseTime();
753 rv
= zip
->GetNSPRFileDesc(aRetVal
);
754 // Do this to avoid possible deadlock on mLock with ReleaseZip().
756 MutexAutoUnlock
unlock(mLock
);
763 nsresult
nsZipReaderCache::ReleaseZip(nsJAR
* zip
) {
765 MutexAutoLock
lock(mLock
);
767 // It is possible that two thread compete for this zip. The dangerous
768 // case is where one thread Releases the zip and discovers that the ref
769 // count has gone to one. Before it can call this ReleaseZip method
770 // another thread calls our GetZip method. The ref count goes to two. That
771 // second thread then Releases the zip and the ref count goes to one. It
772 // then tries to enter this ReleaseZip method and blocks while the first
773 // thread is still here. The first thread continues and remove the zip from
774 // the cache and calls its Release method sending the ref count to 0 and
775 // deleting the zip. However, the second thread is still blocked at the
776 // start of ReleaseZip, but the 'zip' param now hold a reference to a
779 // So, we are going to try safeguarding here by searching our hashtable while
780 // locked here for the zip. We return fast if it is not found.
783 for (const auto& current
: mZips
.Values()) {
784 if (zip
== current
) {
791 #ifdef ZIP_CACHE_HIT_RATE
797 zip
->SetReleaseTime();
799 if (mZips
.Count() <= mCacheSize
) return NS_OK
;
801 // Find the oldest zip.
802 nsJAR
* oldest
= nullptr;
803 for (const auto& current
: mZips
.Values()) {
804 PRIntervalTime currentReleaseTime
= current
->GetReleaseTime();
805 if (currentReleaseTime
!= PR_INTERVAL_NO_TIMEOUT
) {
806 if (oldest
== nullptr || currentReleaseTime
< oldest
->GetReleaseTime()) {
812 // Because of the craziness above it is possible that there is no zip that
814 if (!oldest
) return NS_OK
;
816 #ifdef ZIP_CACHE_HIT_RATE
820 // remove from hashtable
822 rv
= oldest
->GetFullJarPath(uri
);
827 // Retrieving and removing the JAR should be done without an extra AddRef
828 // and Release, or we'll trigger nsJAR::Release's magic refcount 1 case
830 RefPtr
<nsJAR
> removed
;
831 mZips
.Remove(uri
, getter_AddRefs(removed
));
832 NS_ASSERTION(removed
, "botched");
833 NS_ASSERTION(oldest
== removed
, "removed wrong entry");
835 if (removed
) removed
->SetZipReaderCache(nullptr);
841 nsZipReaderCache::Observe(nsISupports
* aSubject
, const char* aTopic
,
842 const char16_t
* aSomeData
) {
843 if (strcmp(aTopic
, "memory-pressure") == 0) {
844 MutexAutoLock
lock(mLock
);
845 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
846 RefPtr
<nsJAR
>& current
= iter
.Data();
847 if (current
->GetReleaseTime() != PR_INTERVAL_NO_TIMEOUT
) {
848 current
->SetZipReaderCache(nullptr);
852 } else if (strcmp(aTopic
, "chrome-flush-caches") == 0) {
853 MutexAutoLock
lock(mLock
);
854 for (const auto& current
: mZips
.Values()) {
855 current
->SetZipReaderCache(nullptr);
858 } else if (strcmp(aTopic
, "flush-cache-entry") == 0) {
859 nsCOMPtr
<nsIFile
> file
;
861 file
= do_QueryInterface(aSubject
);
862 } else if (aSomeData
) {
863 nsDependentString
fileName(aSomeData
);
864 Unused
<< NS_NewLocalFile(fileName
, false, getter_AddRefs(file
));
867 if (!file
) return NS_OK
;
870 if (NS_FAILED(file
->GetPersistentDescriptor(uri
))) return NS_OK
;
872 uri
.InsertLiteral("file:", 0);
874 MutexAutoLock
lock(mLock
);
877 mZips
.Get(uri
, getter_AddRefs(zip
));
878 if (!zip
) return NS_OK
;
880 #ifdef ZIP_CACHE_HIT_RATE
884 zip
->SetZipReaderCache(nullptr);
891 ////////////////////////////////////////////////////////////////////////////////