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/Omnijar.h"
13 #include "mozilla/Unused.h"
16 # include <sys/stat.h>
21 using namespace mozilla
;
23 //----------------------------------------------
24 // nsJAR constructor/destructor
25 //----------------------------------------------
27 // The following initialization makes a guess of 10 entries per jarfile.
29 : mZip(new nsZipArchive()),
30 mReleaseTime(PR_INTERVAL_NO_TIMEOUT
),
32 mLock("nsJAR::mLock"),
35 mSkipArchiveClosing(false) {}
37 nsJAR::~nsJAR() { Close(); }
39 NS_IMPL_QUERY_INTERFACE(nsJAR
, nsIZipReader
)
42 // Custom Release method works with nsZipReaderCache...
43 // Release might be called from multi-thread, we have to
44 // take this function carefully to avoid delete-after-use.
45 MozExternalRefCountType
nsJAR::Release(void) {
47 MOZ_ASSERT(0 != mRefCnt
, "dup release");
49 RefPtr
<nsZipReaderCache
> cache
;
50 if (mRefCnt
== 2) { // don't use a lock too frequently
51 // Use a mutex here to guarantee mCache is not racing and the target
52 // instance is still valid to increase ref-count.
53 MutexAutoLock
lock(mLock
);
58 DebugOnly
<nsresult
> rv
= cache
->ReleaseZip(this);
59 MOZ_ASSERT(NS_SUCCEEDED(rv
), "failed to release zip file");
62 count
= --mRefCnt
; // don't access any member variable after this line
63 NS_LOG_RELEASE(this, count
, "nsJAR");
65 mRefCnt
= 1; /* stabilize */
66 /* enable this to find non-threadsafe destructors: */
67 /* NS_ASSERT_OWNINGTHREAD(nsJAR); */
75 //----------------------------------------------
76 // nsIZipReader implementation
77 //----------------------------------------------
80 nsJAR::Open(nsIFile
* zipFile
) {
81 NS_ENSURE_ARG_POINTER(zipFile
);
82 if (mOpened
) return NS_ERROR_FAILURE
; // Already open!
85 mOuterZipEntry
.Truncate();
88 // The omnijar is special, it is opened early on and closed late
89 // this avoids reopening it
90 RefPtr
<nsZipArchive
> zip
= mozilla::Omnijar::GetReader(zipFile
);
93 mSkipArchiveClosing
= true;
96 return mZip
->OpenArchive(zipFile
);
100 nsJAR::OpenInner(nsIZipReader
* aZipReader
, const nsACString
& aZipEntry
) {
101 NS_ENSURE_ARG_POINTER(aZipReader
);
102 if (mOpened
) return NS_ERROR_FAILURE
; // Already open!
104 nsJAR
* outerJAR
= static_cast<nsJAR
*>(aZipReader
);
105 RefPtr
<nsZipArchive
> innerZip
=
106 mozilla::Omnijar::GetInnerReader(outerJAR
->mZipFile
, aZipEntry
);
110 mSkipArchiveClosing
= true;
115 nsresult rv
= aZipReader
->HasEntry(aZipEntry
, &exist
);
116 NS_ENSURE_SUCCESS(rv
, rv
);
117 NS_ENSURE_TRUE(exist
, NS_ERROR_FILE_NOT_FOUND
);
119 rv
= aZipReader
->GetFile(getter_AddRefs(mZipFile
));
120 NS_ENSURE_SUCCESS(rv
, rv
);
124 mOuterZipEntry
.Assign(aZipEntry
);
126 RefPtr
<nsZipHandle
> handle
;
127 rv
= nsZipHandle::Init(static_cast<nsJAR
*>(aZipReader
)->mZip
.get(),
128 PromiseFlatCString(aZipEntry
).get(),
129 getter_AddRefs(handle
));
130 if (NS_FAILED(rv
)) return rv
;
132 return mZip
->OpenArchive(handle
);
136 nsJAR::OpenMemory(void* aData
, uint32_t aLength
) {
137 NS_ENSURE_ARG_POINTER(aData
);
138 if (mOpened
) return NS_ERROR_FAILURE
; // Already open!
142 RefPtr
<nsZipHandle
> handle
;
143 nsresult rv
= nsZipHandle::Init(static_cast<uint8_t*>(aData
), aLength
,
144 getter_AddRefs(handle
));
145 if (NS_FAILED(rv
)) return rv
;
147 return mZip
->OpenArchive(handle
);
151 nsJAR::GetFile(nsIFile
** result
) {
153 NS_IF_ADDREF(*result
);
160 return NS_ERROR_FAILURE
; // Never opened or already closed.
165 if (mSkipArchiveClosing
) {
166 // Reset state, but don't close the omnijar because we did not open it.
167 mSkipArchiveClosing
= false;
168 mZip
= new nsZipArchive();
172 return mZip
->CloseArchive();
176 nsJAR::Test(const nsACString
& aEntryName
) {
178 aEntryName
.IsEmpty() ? nullptr : PromiseFlatCString(aEntryName
).get());
182 nsJAR::Extract(const nsACString
& aEntryName
, nsIFile
* outFile
) {
183 // nsZipArchive and zlib are not thread safe
184 // we need to use a lock to prevent bug #51267
185 MutexAutoLock
lock(mLock
);
187 nsZipItem
* item
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get());
188 NS_ENSURE_TRUE(item
, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
);
190 // Remove existing file or directory so we set permissions correctly.
191 // If it's a directory that already exists and contains files, throw
192 // an exception and return.
194 nsresult rv
= outFile
->Remove(false);
195 if (rv
== NS_ERROR_FILE_DIR_NOT_EMPTY
|| rv
== NS_ERROR_FAILURE
) return rv
;
197 if (item
->IsDirectory()) {
198 rv
= outFile
->Create(nsIFile::DIRECTORY_TYPE
, item
->Mode());
199 // XXX Do this in nsZipArchive? It would be nice to keep extraction
200 // XXX code completely there, but that would require a way to get a
201 // XXX PRDir from outFile.
204 rv
= outFile
->OpenNSPRFileDesc(PR_WRONLY
| PR_CREATE_FILE
, item
->Mode(),
206 if (NS_FAILED(rv
)) return rv
;
208 // ExtractFile also closes the fd handle and resolves the symlink if needed
209 rv
= mZip
->ExtractFile(item
, outFile
, fd
);
211 if (NS_FAILED(rv
)) return rv
;
213 // nsIFile needs milliseconds, while prtime is in microseconds.
214 // non-fatal if this fails, ignore errors
215 outFile
->SetLastModifiedTime(item
->LastModTime() / PR_USEC_PER_MSEC
);
221 nsJAR::GetEntry(const nsACString
& aEntryName
, nsIZipEntry
** result
) {
222 nsZipItem
* zipItem
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get());
223 NS_ENSURE_TRUE(zipItem
, NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
);
225 nsJARItem
* jarItem
= new nsJARItem(zipItem
);
227 NS_ADDREF(*result
= jarItem
);
232 nsJAR::HasEntry(const nsACString
& aEntryName
, bool* result
) {
233 *result
= mZip
->GetItem(PromiseFlatCString(aEntryName
).get()) != nullptr;
238 nsJAR::FindEntries(const nsACString
& aPattern
,
239 nsIUTF8StringEnumerator
** result
) {
240 NS_ENSURE_ARG_POINTER(result
);
243 nsresult rv
= mZip
->FindInit(
244 aPattern
.IsEmpty() ? nullptr : PromiseFlatCString(aPattern
).get(), &find
);
245 NS_ENSURE_SUCCESS(rv
, rv
);
247 nsIUTF8StringEnumerator
* zipEnum
= new nsJAREnumerator(find
);
249 NS_ADDREF(*result
= zipEnum
);
254 nsJAR::GetInputStream(const nsACString
& aFilename
, nsIInputStream
** result
) {
255 return GetInputStreamWithSpec(EmptyCString(), aFilename
, result
);
259 nsJAR::GetInputStreamWithSpec(const nsACString
& aJarDirSpec
,
260 const nsACString
& aEntryName
,
261 nsIInputStream
** result
) {
262 NS_ENSURE_ARG_POINTER(result
);
264 // Watch out for the jar:foo.zip!/ (aDir is empty) top-level special case!
265 nsZipItem
* item
= nullptr;
266 const nsCString
& entry
= PromiseFlatCString(aEntryName
);
268 // First check if item exists in jar
269 item
= mZip
->GetItem(entry
.get());
270 if (!item
) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
;
272 nsJARInputStream
* jis
= new nsJARInputStream();
273 // addref now so we can call InitFile/InitDirectory()
274 NS_ADDREF(*result
= jis
);
277 if (!item
|| item
->IsDirectory()) {
278 rv
= jis
->InitDirectory(this, aJarDirSpec
, entry
.get());
280 rv
= jis
->InitFile(this, item
);
288 nsresult
nsJAR::GetJarPath(nsACString
& aResult
) {
289 NS_ENSURE_ARG_POINTER(mZipFile
);
291 return mZipFile
->GetPersistentDescriptor(aResult
);
294 nsresult
nsJAR::GetNSPRFileDesc(PRFileDesc
** aNSPRFileDesc
) {
295 if (!aNSPRFileDesc
) {
296 return NS_ERROR_ILLEGAL_VALUE
;
298 *aNSPRFileDesc
= nullptr;
301 return NS_ERROR_FAILURE
;
304 RefPtr
<nsZipHandle
> handle
= mZip
->GetFD();
306 return NS_ERROR_FAILURE
;
309 return handle
->GetNSPRFileDesc(aNSPRFileDesc
);
312 //----------------------------------------------
313 // nsJAR private implementation
314 //----------------------------------------------
315 nsresult
nsJAR::LoadEntry(const nsACString
& aFilename
, nsCString
& aBuf
) {
316 //-- Get a stream for reading the file
318 nsCOMPtr
<nsIInputStream
> manifestStream
;
319 rv
= GetInputStream(aFilename
, getter_AddRefs(manifestStream
));
320 if (NS_FAILED(rv
)) return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
;
322 //-- Read the manifest file into memory
325 rv
= manifestStream
->Available(&len64
);
326 if (NS_FAILED(rv
)) return rv
;
327 NS_ENSURE_TRUE(len64
< UINT32_MAX
, NS_ERROR_FILE_CORRUPTED
); // bug 164695
328 uint32_t len
= (uint32_t)len64
;
329 buf
= (char*)malloc(len
+ 1);
330 if (!buf
) return NS_ERROR_OUT_OF_MEMORY
;
332 rv
= manifestStream
->Read(buf
, len
, &bytesRead
);
333 if (bytesRead
!= len
) {
334 rv
= NS_ERROR_FILE_CORRUPTED
;
340 buf
[len
] = '\0'; // Null-terminate the buffer
341 aBuf
.Adopt(buf
, len
);
345 int32_t nsJAR::ReadLine(const char** src
) {
350 //--Moves pointer to beginning of next line and returns line length
351 // not including CR/LF.
353 char* eol
= PL_strpbrk(*src
, "\r\n");
355 if (eol
== nullptr) // Probably reached end of file before newline
357 length
= strlen(*src
);
358 if (length
== 0) // immediate end-of-file
360 else // some data left on this line
364 if (eol
[0] == '\r' && eol
[1] == '\n') // CR LF, so skip 2
366 else // Either CR or LF, so skip 1
372 NS_IMPL_ISUPPORTS(nsJAREnumerator
, nsIUTF8StringEnumerator
, nsIStringEnumerator
)
374 //----------------------------------------------
375 // nsJAREnumerator::HasMore
376 //----------------------------------------------
378 nsJAREnumerator::HasMore(bool* aResult
) {
379 // try to get the next element
381 NS_ASSERTION(mFind
, "nsJAREnumerator: Missing zipFind.");
382 nsresult rv
= mFind
->FindNext(&mName
, &mNameLen
);
383 if (rv
== NS_ERROR_FILE_TARGET_DOES_NOT_EXIST
) {
384 *aResult
= false; // No more matches available
387 NS_ENSURE_SUCCESS(rv
, NS_ERROR_FAILURE
); // no error translation
394 //----------------------------------------------
395 // nsJAREnumerator::GetNext
396 //----------------------------------------------
398 nsJAREnumerator::GetNext(nsACString
& aResult
) {
399 // check if the current item is "stale"
402 nsresult rv
= HasMore(&bMore
);
403 if (NS_FAILED(rv
) || !bMore
)
404 return NS_ERROR_FAILURE
; // no error translation
406 aResult
.Assign(mName
, mNameLen
);
407 mName
= 0; // we just gave this one away
411 NS_IMPL_ISUPPORTS(nsJARItem
, nsIZipEntry
)
413 nsJARItem::nsJARItem(nsZipItem
* aZipItem
)
414 : mSize(aZipItem
->Size()),
415 mRealsize(aZipItem
->RealSize()),
416 mCrc32(aZipItem
->CRC32()),
417 mLastModTime(aZipItem
->LastModTime()),
418 mCompression(aZipItem
->Compression()),
419 mPermissions(aZipItem
->Mode()),
420 mIsDirectory(aZipItem
->IsDirectory()),
421 mIsSynthetic(aZipItem
->isSynthetic
) {}
423 //------------------------------------------
424 // nsJARItem::GetCompression
425 //------------------------------------------
427 nsJARItem::GetCompression(uint16_t* aCompression
) {
428 NS_ENSURE_ARG_POINTER(aCompression
);
430 *aCompression
= mCompression
;
434 //------------------------------------------
435 // nsJARItem::GetSize
436 //------------------------------------------
438 nsJARItem::GetSize(uint32_t* aSize
) {
439 NS_ENSURE_ARG_POINTER(aSize
);
445 //------------------------------------------
446 // nsJARItem::GetRealSize
447 //------------------------------------------
449 nsJARItem::GetRealSize(uint32_t* aRealsize
) {
450 NS_ENSURE_ARG_POINTER(aRealsize
);
452 *aRealsize
= mRealsize
;
456 //------------------------------------------
457 // nsJARItem::GetCrc32
458 //------------------------------------------
460 nsJARItem::GetCRC32(uint32_t* aCrc32
) {
461 NS_ENSURE_ARG_POINTER(aCrc32
);
467 //------------------------------------------
468 // nsJARItem::GetIsDirectory
469 //------------------------------------------
471 nsJARItem::GetIsDirectory(bool* aIsDirectory
) {
472 NS_ENSURE_ARG_POINTER(aIsDirectory
);
474 *aIsDirectory
= mIsDirectory
;
478 //------------------------------------------
479 // nsJARItem::GetIsSynthetic
480 //------------------------------------------
482 nsJARItem::GetIsSynthetic(bool* aIsSynthetic
) {
483 NS_ENSURE_ARG_POINTER(aIsSynthetic
);
485 *aIsSynthetic
= mIsSynthetic
;
489 //------------------------------------------
490 // nsJARItem::GetLastModifiedTime
491 //------------------------------------------
493 nsJARItem::GetLastModifiedTime(PRTime
* aLastModTime
) {
494 NS_ENSURE_ARG_POINTER(aLastModTime
);
496 *aLastModTime
= mLastModTime
;
500 //------------------------------------------
501 // nsJARItem::GetPermissions
502 //------------------------------------------
504 nsJARItem::GetPermissions(uint32_t* aPermissions
) {
505 NS_ENSURE_ARG_POINTER(aPermissions
);
507 *aPermissions
= mPermissions
;
511 ////////////////////////////////////////////////////////////////////////////////
514 NS_IMPL_ISUPPORTS(nsZipReaderCache
, nsIZipReaderCache
, nsIObserver
,
515 nsISupportsWeakReference
)
517 nsZipReaderCache::nsZipReaderCache()
518 : mLock("nsZipReaderCache.mLock"),
521 #ifdef ZIP_CACHE_HIT_RATE
532 nsZipReaderCache::Init(uint32_t cacheSize
) {
533 mCacheSize
= cacheSize
;
535 // Register as a memory pressure observer
536 nsCOMPtr
<nsIObserverService
> os
=
537 do_GetService("@mozilla.org/observer-service;1");
539 os
->AddObserver(this, "memory-pressure", true);
540 os
->AddObserver(this, "chrome-flush-caches", true);
541 os
->AddObserver(this, "flush-cache-entry", true);
543 // ignore failure of the observer registration.
548 nsZipReaderCache::~nsZipReaderCache() {
549 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
550 iter
.UserData()->SetZipReaderCache(nullptr);
553 #ifdef ZIP_CACHE_HIT_RATE
555 "nsZipReaderCache size=%d hits=%d lookups=%d rate=%f%% flushes=%d missed "
557 mCacheSize
, mZipCacheHits
, mZipCacheLookups
,
558 (float)mZipCacheHits
/ mZipCacheLookups
, mZipCacheFlushes
,
564 nsZipReaderCache::IsCached(nsIFile
* zipFile
, bool* aResult
) {
565 NS_ENSURE_ARG_POINTER(zipFile
);
567 MutexAutoLock
lock(mLock
);
570 rv
= zipFile
->GetPersistentDescriptor(uri
);
571 if (NS_FAILED(rv
)) return rv
;
573 uri
.InsertLiteral("file:", 0);
575 *aResult
= mZips
.Contains(uri
);
579 nsresult
nsZipReaderCache::GetZip(nsIFile
* zipFile
, nsIZipReader
** result
,
581 NS_ENSURE_ARG_POINTER(zipFile
);
583 MutexAutoLock
lock(mLock
);
585 #ifdef ZIP_CACHE_HIT_RATE
590 rv
= zipFile
->GetPersistentDescriptor(uri
);
591 if (NS_FAILED(rv
)) return rv
;
593 uri
.InsertLiteral("file:", 0);
596 mZips
.Get(uri
, getter_AddRefs(zip
));
598 #ifdef ZIP_CACHE_HIT_RATE
601 zip
->ClearReleaseTime();
604 return NS_ERROR_CACHE_KEY_NOT_FOUND
;
608 zip
->SetZipReaderCache(this);
609 rv
= zip
->Open(zipFile
);
614 MOZ_ASSERT(!mZips
.Contains(uri
));
615 mZips
.Put(uri
, RefPtr
{zip
});
622 nsZipReaderCache::GetZipIfCached(nsIFile
* zipFile
, nsIZipReader
** result
) {
623 return GetZip(zipFile
, result
, true);
627 nsZipReaderCache::GetZip(nsIFile
* zipFile
, nsIZipReader
** result
) {
628 return GetZip(zipFile
, result
, false);
632 nsZipReaderCache::GetInnerZip(nsIFile
* zipFile
, const nsACString
& entry
,
633 nsIZipReader
** result
) {
634 NS_ENSURE_ARG_POINTER(zipFile
);
636 nsCOMPtr
<nsIZipReader
> outerZipReader
;
637 nsresult rv
= GetZip(zipFile
, getter_AddRefs(outerZipReader
));
638 NS_ENSURE_SUCCESS(rv
, rv
);
640 MutexAutoLock
lock(mLock
);
642 #ifdef ZIP_CACHE_HIT_RATE
647 rv
= zipFile
->GetPersistentDescriptor(uri
);
648 if (NS_FAILED(rv
)) return rv
;
650 uri
.InsertLiteral("jar:", 0);
651 uri
.AppendLiteral("!/");
655 mZips
.Get(uri
, getter_AddRefs(zip
));
657 #ifdef ZIP_CACHE_HIT_RATE
660 zip
->ClearReleaseTime();
663 zip
->SetZipReaderCache(this);
665 rv
= zip
->OpenInner(outerZipReader
, entry
);
670 MOZ_ASSERT(!mZips
.Contains(uri
));
671 mZips
.Put(uri
, RefPtr
{zip
});
678 nsZipReaderCache::GetFd(nsIFile
* zipFile
, PRFileDesc
** aRetVal
) {
680 MOZ_CRASH("Not implemented");
681 return NS_ERROR_NOT_IMPLEMENTED
;
684 return NS_ERROR_FAILURE
;
689 rv
= zipFile
->GetPersistentDescriptor(uri
);
693 uri
.InsertLiteral("file:", 0);
695 MutexAutoLock
lock(mLock
);
697 mZips
.Get(uri
, getter_AddRefs(zip
));
699 return NS_ERROR_FAILURE
;
702 zip
->ClearReleaseTime();
703 rv
= zip
->GetNSPRFileDesc(aRetVal
);
704 // Do this to avoid possible deadlock on mLock with ReleaseZip().
706 MutexAutoUnlock
unlock(mLock
);
713 nsresult
nsZipReaderCache::ReleaseZip(nsJAR
* zip
) {
715 MutexAutoLock
lock(mLock
);
717 // It is possible that two thread compete for this zip. The dangerous
718 // case is where one thread Releases the zip and discovers that the ref
719 // count has gone to one. Before it can call this ReleaseZip method
720 // another thread calls our GetZip method. The ref count goes to two. That
721 // second thread then Releases the zip and the ref count goes to one. It
722 // then tries to enter this ReleaseZip method and blocks while the first
723 // thread is still here. The first thread continues and remove the zip from
724 // the cache and calls its Release method sending the ref count to 0 and
725 // deleting the zip. However, the second thread is still blocked at the
726 // start of ReleaseZip, but the 'zip' param now hold a reference to a
729 // So, we are going to try safeguarding here by searching our hashtable while
730 // locked here for the zip. We return fast if it is not found.
733 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
734 if (zip
== iter
.UserData()) {
741 #ifdef ZIP_CACHE_HIT_RATE
747 zip
->SetReleaseTime();
749 if (mZips
.Count() <= mCacheSize
) return NS_OK
;
751 // Find the oldest zip.
752 nsJAR
* oldest
= nullptr;
753 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
754 nsJAR
* current
= iter
.UserData();
755 PRIntervalTime currentReleaseTime
= current
->GetReleaseTime();
756 if (currentReleaseTime
!= PR_INTERVAL_NO_TIMEOUT
) {
757 if (oldest
== nullptr || currentReleaseTime
< oldest
->GetReleaseTime()) {
763 // Because of the craziness above it is possible that there is no zip that
765 if (!oldest
) return NS_OK
;
767 #ifdef ZIP_CACHE_HIT_RATE
771 // remove from hashtable
773 rv
= oldest
->GetJarPath(uri
);
774 if (NS_FAILED(rv
)) return rv
;
776 if (oldest
->mOuterZipEntry
.IsEmpty()) {
777 uri
.InsertLiteral("file:", 0);
779 uri
.InsertLiteral("jar:", 0);
780 uri
.AppendLiteral("!/");
781 uri
.Append(oldest
->mOuterZipEntry
);
784 // Retrieving and removing the JAR must be done without an extra AddRef
785 // and Release, or we'll trigger nsJAR::Release's magic refcount 1 case
786 // an extra time and trigger a deadlock.
787 RefPtr
<nsJAR
> removed
;
788 mZips
.Remove(uri
, getter_AddRefs(removed
));
789 NS_ASSERTION(removed
, "botched");
790 NS_ASSERTION(oldest
== removed
, "removed wrong entry");
792 if (removed
) removed
->SetZipReaderCache(nullptr);
798 nsZipReaderCache::Observe(nsISupports
* aSubject
, const char* aTopic
,
799 const char16_t
* aSomeData
) {
800 if (strcmp(aTopic
, "memory-pressure") == 0) {
801 MutexAutoLock
lock(mLock
);
802 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
803 RefPtr
<nsJAR
>& current
= iter
.Data();
804 if (current
->GetReleaseTime() != PR_INTERVAL_NO_TIMEOUT
) {
805 current
->SetZipReaderCache(nullptr);
809 } else if (strcmp(aTopic
, "chrome-flush-caches") == 0) {
810 MutexAutoLock
lock(mLock
);
811 for (auto iter
= mZips
.Iter(); !iter
.Done(); iter
.Next()) {
812 iter
.UserData()->SetZipReaderCache(nullptr);
815 } else if (strcmp(aTopic
, "flush-cache-entry") == 0) {
816 nsCOMPtr
<nsIFile
> file
;
818 file
= do_QueryInterface(aSubject
);
819 } else if (aSomeData
) {
820 nsDependentString
fileName(aSomeData
);
821 Unused
<< NS_NewLocalFile(fileName
, false, getter_AddRefs(file
));
824 if (!file
) return NS_OK
;
827 if (NS_FAILED(file
->GetPersistentDescriptor(uri
))) return NS_OK
;
829 uri
.InsertLiteral("file:", 0);
831 MutexAutoLock
lock(mLock
);
834 mZips
.Get(uri
, getter_AddRefs(zip
));
835 if (!zip
) return NS_OK
;
837 #ifdef ZIP_CACHE_HIT_RATE
841 zip
->SetZipReaderCache(nullptr);
848 ////////////////////////////////////////////////////////////////////////////////