LCOV - code coverage report
Current view: top level - dom/cache - FileUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 261 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       6             : 
       7             : #include "mozilla/dom/cache/FileUtils.h"
       8             : 
       9             : #include "mozilla/dom/quota/FileStreams.h"
      10             : #include "mozilla/dom/quota/QuotaManager.h"
      11             : #include "mozilla/SnappyCompressOutputStream.h"
      12             : #include "mozilla/Unused.h"
      13             : #include "nsIFile.h"
      14             : #include "nsIUUIDGenerator.h"
      15             : #include "nsNetCID.h"
      16             : #include "nsISimpleEnumerator.h"
      17             : #include "nsServiceManagerUtils.h"
      18             : #include "nsString.h"
      19             : #include "nsThreadUtils.h"
      20             : 
      21             : namespace mozilla {
      22             : namespace dom {
      23             : namespace cache {
      24             : 
      25             : using mozilla::dom::quota::FileInputStream;
      26             : using mozilla::dom::quota::FileOutputStream;
      27             : using mozilla::dom::quota::PERSISTENCE_TYPE_DEFAULT;
      28             : using mozilla::dom::quota::QuotaManager;
      29             : 
      30             : namespace {
      31             : 
      32             : enum BodyFileType
      33             : {
      34             :   BODY_FILE_FINAL,
      35             :   BODY_FILE_TMP
      36             : };
      37             : 
      38             : nsresult
      39             : BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
      40             :              nsIFile** aBodyFileOut);
      41             : 
      42             : } // namespace
      43             : 
      44             : // static
      45             : nsresult
      46           0 : BodyCreateDir(nsIFile* aBaseDir)
      47             : {
      48           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
      49             : 
      50           0 :   nsCOMPtr<nsIFile> aBodyDir;
      51           0 :   nsresult rv = aBaseDir->Clone(getter_AddRefs(aBodyDir));
      52           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      53             : 
      54           0 :   rv = aBodyDir->Append(NS_LITERAL_STRING("morgue"));
      55           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      56             : 
      57           0 :   rv = aBodyDir->Create(nsIFile::DIRECTORY_TYPE, 0755);
      58           0 :   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
      59           0 :     return NS_OK;
      60             :   }
      61           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      62             : 
      63           0 :   return rv;
      64             : }
      65             : 
      66             : // static
      67             : nsresult
      68           0 : BodyDeleteDir(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir)
      69             : {
      70           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
      71             : 
      72           0 :   nsCOMPtr<nsIFile> aBodyDir;
      73           0 :   nsresult rv = aBaseDir->Clone(getter_AddRefs(aBodyDir));
      74           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      75             : 
      76           0 :   rv = aBodyDir->Append(NS_LITERAL_STRING("morgue"));
      77           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      78             : 
      79           0 :   rv = RemoveNsIFileRecursively(aQuotaInfo, aBodyDir);
      80           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      81             : 
      82           0 :   return rv;
      83             : }
      84             : 
      85             : // static
      86             : nsresult
      87           0 : BodyGetCacheDir(nsIFile* aBaseDir, const nsID& aId, nsIFile** aCacheDirOut)
      88             : {
      89           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
      90           0 :   MOZ_DIAGNOSTIC_ASSERT(aCacheDirOut);
      91             : 
      92           0 :   *aCacheDirOut = nullptr;
      93             : 
      94           0 :   nsresult rv = aBaseDir->Clone(aCacheDirOut);
      95           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
      96           0 :   MOZ_DIAGNOSTIC_ASSERT(*aCacheDirOut);
      97             : 
      98           0 :   rv = (*aCacheDirOut)->Append(NS_LITERAL_STRING("morgue"));
      99           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     100             : 
     101             :   // Some file systems have poor performance when there are too many files
     102             :   // in a single directory.  Mitigate this issue by spreading the body
     103             :   // files out into sub-directories.  We use the last byte of the ID for
     104             :   // the name of the sub-directory.
     105           0 :   nsAutoString subDirName;
     106           0 :   subDirName.AppendInt(aId.m3[7]);
     107           0 :   rv = (*aCacheDirOut)->Append(subDirName);
     108           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     109             : 
     110           0 :   rv = (*aCacheDirOut)->Create(nsIFile::DIRECTORY_TYPE, 0755);
     111           0 :   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
     112           0 :     return NS_OK;
     113             :   }
     114           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     115             : 
     116           0 :   return rv;
     117             : }
     118             : 
     119             : // static
     120             : nsresult
     121           0 : BodyStartWriteStream(const QuotaInfo& aQuotaInfo,
     122             :                      nsIFile* aBaseDir, nsIInputStream* aSource,
     123             :                      void* aClosure,
     124             :                      nsAsyncCopyCallbackFun aCallback, nsID* aIdOut,
     125             :                      nsISupports** aCopyContextOut)
     126             : {
     127           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     128           0 :   MOZ_DIAGNOSTIC_ASSERT(aSource);
     129           0 :   MOZ_DIAGNOSTIC_ASSERT(aClosure);
     130           0 :   MOZ_DIAGNOSTIC_ASSERT(aCallback);
     131           0 :   MOZ_DIAGNOSTIC_ASSERT(aIdOut);
     132           0 :   MOZ_DIAGNOSTIC_ASSERT(aCopyContextOut);
     133             : 
     134             :   nsresult rv;
     135             :   nsCOMPtr<nsIUUIDGenerator> idGen =
     136           0 :     do_GetService("@mozilla.org/uuid-generator;1", &rv);
     137           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     138             : 
     139           0 :   rv = idGen->GenerateUUIDInPlace(aIdOut);
     140           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     141             : 
     142           0 :   nsCOMPtr<nsIFile> finalFile;
     143           0 :   rv = BodyIdToFile(aBaseDir, *aIdOut, BODY_FILE_FINAL,
     144           0 :                     getter_AddRefs(finalFile));
     145           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     146             : 
     147             :   bool exists;
     148           0 :   rv = finalFile->Exists(&exists);
     149           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     150           0 :   if (NS_WARN_IF(exists)) { return NS_ERROR_FILE_ALREADY_EXISTS; }
     151             : 
     152           0 :   nsCOMPtr<nsIFile> tmpFile;
     153           0 :   rv = BodyIdToFile(aBaseDir, *aIdOut, BODY_FILE_TMP, getter_AddRefs(tmpFile));
     154           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     155             : 
     156           0 :   rv = tmpFile->Exists(&exists);
     157           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     158           0 :   if (NS_WARN_IF(exists)) { return NS_ERROR_FILE_ALREADY_EXISTS; }
     159             : 
     160             :   nsCOMPtr<nsIOutputStream> fileStream =
     161           0 :     FileOutputStream::Create(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
     162           0 :                              aQuotaInfo.mOrigin, tmpFile);
     163           0 :   if (NS_WARN_IF(!fileStream)) { return NS_ERROR_UNEXPECTED; }
     164             : 
     165             :   RefPtr<SnappyCompressOutputStream> compressed =
     166           0 :     new SnappyCompressOutputStream(fileStream);
     167             : 
     168             :   nsCOMPtr<nsIEventTarget> target =
     169           0 :     do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
     170             : 
     171           0 :   rv = NS_AsyncCopy(aSource, compressed, target, NS_ASYNCCOPY_VIA_WRITESEGMENTS,
     172           0 :                     compressed->BlockSize(), aCallback, aClosure,
     173             :                     true, true, // close streams
     174           0 :                     aCopyContextOut);
     175           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     176             : 
     177           0 :   return rv;
     178             : }
     179             : 
     180             : // static
     181             : void
     182           0 : BodyCancelWrite(nsIFile* aBaseDir, nsISupports* aCopyContext)
     183             : {
     184           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     185           0 :   MOZ_DIAGNOSTIC_ASSERT(aCopyContext);
     186             : 
     187           0 :   nsresult rv = NS_CancelAsyncCopy(aCopyContext, NS_ERROR_ABORT);
     188           0 :   Unused << NS_WARN_IF(NS_FAILED(rv));
     189             : 
     190             :   // The partially written file must be cleaned up after the async copy
     191             :   // makes its callback.
     192           0 : }
     193             : 
     194             : // static
     195             : nsresult
     196           0 : BodyFinalizeWrite(nsIFile* aBaseDir, const nsID& aId)
     197             : {
     198           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     199             : 
     200           0 :   nsCOMPtr<nsIFile> tmpFile;
     201           0 :   nsresult rv = BodyIdToFile(aBaseDir, aId, BODY_FILE_TMP, getter_AddRefs(tmpFile));
     202           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     203             : 
     204           0 :   nsCOMPtr<nsIFile> finalFile;
     205           0 :   rv = BodyIdToFile(aBaseDir, aId, BODY_FILE_FINAL, getter_AddRefs(finalFile));
     206           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     207             : 
     208           0 :   nsAutoString finalFileName;
     209           0 :   rv = finalFile->GetLeafName(finalFileName);
     210           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     211             : 
     212             :   // It's fine to not notify the QuotaManager that the path has been changed,
     213             :   // because its path will be updated and its size will be recalculated when
     214             :   // opening file next time.
     215           0 :   rv = tmpFile->RenameTo(nullptr, finalFileName);
     216           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     217             : 
     218           0 :   return rv;
     219             : }
     220             : 
     221             : // static
     222             : nsresult
     223           0 : BodyOpen(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir, const nsID& aId,
     224             :          nsIInputStream** aStreamOut)
     225             : {
     226           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     227           0 :   MOZ_DIAGNOSTIC_ASSERT(aStreamOut);
     228             : 
     229           0 :   nsCOMPtr<nsIFile> finalFile;
     230           0 :   nsresult rv = BodyIdToFile(aBaseDir, aId, BODY_FILE_FINAL,
     231           0 :                              getter_AddRefs(finalFile));
     232           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     233             : 
     234             :   bool exists;
     235           0 :   rv = finalFile->Exists(&exists);
     236           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     237           0 :   if (NS_WARN_IF(!exists)) { return NS_ERROR_FILE_NOT_FOUND; }
     238             : 
     239             :   nsCOMPtr<nsIInputStream> fileStream =
     240           0 :     FileInputStream::Create(PERSISTENCE_TYPE_DEFAULT, aQuotaInfo.mGroup,
     241           0 :                             aQuotaInfo.mOrigin, finalFile);
     242           0 :   if (NS_WARN_IF(!fileStream)) { return NS_ERROR_UNEXPECTED; }
     243             : 
     244           0 :   fileStream.forget(aStreamOut);
     245             : 
     246           0 :   return rv;
     247             : }
     248             : 
     249             : // static
     250             : nsresult
     251           0 : BodyDeleteFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
     252             :                 const nsTArray<nsID>& aIdList)
     253             : {
     254           0 :   nsresult rv = NS_OK;
     255             : 
     256           0 :   for (uint32_t i = 0; i < aIdList.Length(); ++i) {
     257           0 :     nsCOMPtr<nsIFile> tmpFile;
     258           0 :     rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_TMP,
     259           0 :                       getter_AddRefs(tmpFile));
     260           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     261             : 
     262           0 :     rv = RemoveNsIFile(aQuotaInfo, tmpFile);
     263             :     // Only treat file deletion as a hard failure in DEBUG builds.  Users
     264             :     // can unfortunately hit this on windows if anti-virus is scanning files,
     265             :     // etc.
     266           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
     267             : 
     268           0 :     nsCOMPtr<nsIFile> finalFile;
     269           0 :     rv = BodyIdToFile(aBaseDir, aIdList[i], BODY_FILE_FINAL,
     270           0 :                       getter_AddRefs(finalFile));
     271           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     272             : 
     273           0 :     rv = RemoveNsIFile(aQuotaInfo, finalFile);
     274             :     // Again, only treat removal as hard failure in debug build.
     275           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv));
     276             :   }
     277             : 
     278           0 :   return NS_OK;
     279             : }
     280             : 
     281             : namespace {
     282             : 
     283             : nsresult
     284           0 : BodyIdToFile(nsIFile* aBaseDir, const nsID& aId, BodyFileType aType,
     285             :              nsIFile** aBodyFileOut)
     286             : {
     287           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     288           0 :   MOZ_DIAGNOSTIC_ASSERT(aBodyFileOut);
     289             : 
     290           0 :   *aBodyFileOut = nullptr;
     291             : 
     292           0 :   nsresult rv = BodyGetCacheDir(aBaseDir, aId, aBodyFileOut);
     293           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     294           0 :   MOZ_DIAGNOSTIC_ASSERT(*aBodyFileOut);
     295             : 
     296             :   char idString[NSID_LENGTH];
     297           0 :   aId.ToProvidedString(idString);
     298             : 
     299           0 :   NS_ConvertASCIItoUTF16 fileName(idString);
     300             : 
     301           0 :   if (aType == BODY_FILE_FINAL) {
     302           0 :     fileName.AppendLiteral(".final");
     303             :   } else {
     304           0 :     fileName.AppendLiteral(".tmp");
     305             :   }
     306             : 
     307           0 :   rv = (*aBodyFileOut)->Append(fileName);
     308           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     309             : 
     310           0 :   return rv;
     311             : }
     312             : 
     313             : } // namespace
     314             : 
     315             : nsresult
     316           0 : BodyDeleteOrphanedFiles(const QuotaInfo& aQuotaInfo, nsIFile* aBaseDir,
     317             :                         nsTArray<nsID>& aKnownBodyIdList)
     318             : {
     319           0 :   MOZ_DIAGNOSTIC_ASSERT(aBaseDir);
     320             : 
     321             :   // body files are stored in a directory structure like:
     322             :   //
     323             :   //  /morgue/01/{01fdddb2-884d-4c3d-95ba-0c8062f6c325}.final
     324             :   //  /morgue/02/{02fdddb2-884d-4c3d-95ba-0c8062f6c325}.tmp
     325             : 
     326           0 :   nsCOMPtr<nsIFile> dir;
     327           0 :   nsresult rv = aBaseDir->Clone(getter_AddRefs(dir));
     328           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     329             : 
     330             :   // Add the root morgue directory
     331           0 :   rv = dir->Append(NS_LITERAL_STRING("morgue"));
     332           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     333             : 
     334           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
     335           0 :   rv = dir->GetDirectoryEntries(getter_AddRefs(entries));
     336           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     337             : 
     338             :   // Iterate over all the intermediate morgue subdirs
     339           0 :   bool hasMore = false;
     340           0 :   while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore) {
     341           0 :     nsCOMPtr<nsISupports> entry;
     342           0 :     rv = entries->GetNext(getter_AddRefs(entry));
     343           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     344             : 
     345           0 :     nsCOMPtr<nsIFile> subdir = do_QueryInterface(entry);
     346             : 
     347           0 :     bool isDir = false;
     348           0 :     rv = subdir->IsDirectory(&isDir);
     349           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     350             : 
     351             :     // If a file got in here somehow, try to remove it and move on
     352           0 :     if (NS_WARN_IF(!isDir)) {
     353           0 :       rv = RemoveNsIFile(aQuotaInfo, subdir);
     354           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
     355           0 :       continue;
     356             :     }
     357             : 
     358           0 :     nsCOMPtr<nsISimpleEnumerator> subEntries;
     359           0 :     rv = subdir->GetDirectoryEntries(getter_AddRefs(subEntries));
     360           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     361             : 
     362             :     // Now iterate over all the files in the subdir
     363           0 :     bool subHasMore = false;
     364           0 :     while(NS_SUCCEEDED(rv = subEntries->HasMoreElements(&subHasMore)) &&
     365             :           subHasMore) {
     366           0 :       nsCOMPtr<nsISupports> subEntry;
     367           0 :       rv = subEntries->GetNext(getter_AddRefs(subEntry));
     368           0 :       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     369             : 
     370           0 :       nsCOMPtr<nsIFile> file = do_QueryInterface(subEntry);
     371             : 
     372           0 :       nsAutoCString leafName;
     373           0 :       rv = file->GetNativeLeafName(leafName);
     374           0 :       if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     375             : 
     376             :       // Delete all tmp files regardless of known bodies.  These are
     377             :       // all considered orphans.
     378           0 :       if (StringEndsWith(leafName, NS_LITERAL_CSTRING(".tmp"))) {
     379             :         // remove recursively in case its somehow a directory
     380           0 :         rv = RemoveNsIFileRecursively(aQuotaInfo, file);
     381           0 :         MOZ_ASSERT(NS_SUCCEEDED(rv));
     382           0 :         continue;
     383             :       }
     384             : 
     385           0 :       nsCString suffix(NS_LITERAL_CSTRING(".final"));
     386             : 
     387             :       // Otherwise, it must be a .final file.  If its not, then just
     388             :       // skip it.
     389           0 :       if (NS_WARN_IF(!StringEndsWith(leafName, suffix) ||
     390             :                      leafName.Length() != NSID_LENGTH - 1 + suffix.Length())) {
     391           0 :         continue;
     392             :       }
     393             : 
     394             :       // Finally, parse the uuid out of the name.  If its fails to parse,
     395             :       // the ignore the file.
     396             :       nsID id;
     397           0 :       if (NS_WARN_IF(!id.Parse(leafName.BeginReading()))) {
     398           0 :         continue;
     399             :       }
     400             : 
     401           0 :       if (!aKnownBodyIdList.Contains(id)) {
     402             :         // remove recursively in case its somehow a directory
     403           0 :         rv = RemoveNsIFileRecursively(aQuotaInfo, file);
     404           0 :         MOZ_ASSERT(NS_SUCCEEDED(rv));
     405             :       }
     406             :     }
     407             :   }
     408             : 
     409           0 :   return rv;
     410             : }
     411             : 
     412             : namespace {
     413             : 
     414             : nsresult
     415           0 : GetMarkerFileHandle(const QuotaInfo& aQuotaInfo, nsIFile** aFileOut)
     416             : {
     417           0 :   MOZ_DIAGNOSTIC_ASSERT(aFileOut);
     418             : 
     419           0 :   nsCOMPtr<nsIFile> marker;
     420           0 :   nsresult rv = aQuotaInfo.mDir->Clone(getter_AddRefs(marker));
     421           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     422             : 
     423           0 :   rv = marker->Append(NS_LITERAL_STRING("cache"));
     424           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     425             : 
     426           0 :   rv = marker->Append(NS_LITERAL_STRING("context_open.marker"));
     427           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     428             : 
     429           0 :   marker.forget(aFileOut);
     430             : 
     431           0 :   return rv;
     432             : }
     433             : 
     434             : } // namespace
     435             : 
     436             : nsresult
     437           0 : CreateMarkerFile(const QuotaInfo& aQuotaInfo)
     438             : {
     439           0 :   nsCOMPtr<nsIFile> marker;
     440           0 :   nsresult rv = GetMarkerFileHandle(aQuotaInfo, getter_AddRefs(marker));
     441           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     442             : 
     443           0 :   rv = marker->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
     444           0 :   if (rv == NS_ERROR_FILE_ALREADY_EXISTS) {
     445           0 :     rv = NS_OK;
     446             :   }
     447             : 
     448             :   // Note, we don't need to fsync here.  We only care about actually
     449             :   // writing the marker if later modifications to the Cache are
     450             :   // actually flushed to the disk.  If the OS crashes before the marker
     451             :   // is written then we are ensured no other changes to the Cache were
     452             :   // flushed either.
     453             : 
     454           0 :   return rv;
     455             : }
     456             : 
     457             : nsresult
     458           0 : DeleteMarkerFile(const QuotaInfo& aQuotaInfo)
     459             : {
     460           0 :   nsCOMPtr<nsIFile> marker;
     461           0 :   nsresult rv = GetMarkerFileHandle(aQuotaInfo, getter_AddRefs(marker));
     462           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     463             : 
     464           0 :   rv = RemoveNsIFile(aQuotaInfo, marker);
     465           0 :   MOZ_ASSERT(NS_SUCCEEDED(rv));
     466             : 
     467             :   // Again, no fsync is necessary.  If the OS crashes before the file
     468             :   // removal is flushed, then the Cache will search for stale data on
     469             :   // startup.  This will cause the next Cache access to be a bit slow, but
     470             :   // it seems appropriate after an OS crash.
     471             : 
     472           0 :   return NS_OK;
     473             : }
     474             : 
     475             : bool
     476           0 : MarkerFileExists(const QuotaInfo& aQuotaInfo)
     477             : {
     478           0 :   nsCOMPtr<nsIFile> marker;
     479           0 :   nsresult rv = GetMarkerFileHandle(aQuotaInfo, getter_AddRefs(marker));
     480           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
     481             : 
     482           0 :   bool exists = false;
     483           0 :   rv = marker->Exists(&exists);
     484           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return false; }
     485             : 
     486           0 :   return exists;
     487             : }
     488             : 
     489             : // static
     490             : nsresult
     491           0 : RemoveNsIFileRecursively(const QuotaInfo& aQuotaInfo, nsIFile* aFile)
     492             : {
     493           0 :   MOZ_DIAGNOSTIC_ASSERT(aFile);
     494             : 
     495           0 :   bool isDirectory = false;
     496           0 :   nsresult rv = aFile->IsDirectory(&isDirectory);
     497           0 :   if (rv == NS_ERROR_FILE_NOT_FOUND ||
     498             :       rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
     499           0 :     return NS_OK;
     500             :   }
     501           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     502             : 
     503           0 :   if (!isDirectory) {
     504           0 :     return RemoveNsIFile(aQuotaInfo, aFile);
     505             :   }
     506             : 
     507             :   // Unfortunately, we need to traverse all the entries and delete files one by
     508             :   // one to update their usages to the QuotaManager.
     509           0 :   nsCOMPtr<nsISimpleEnumerator> entries;
     510           0 :   rv = aFile->GetDirectoryEntries(getter_AddRefs(entries));
     511           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     512             : 
     513           0 :   bool hasMore = false;
     514           0 :   while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore) {
     515           0 :     nsCOMPtr<nsISupports> entry;
     516           0 :     rv = entries->GetNext(getter_AddRefs(entry));
     517           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     518             : 
     519           0 :     nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
     520           0 :     MOZ_ASSERT(file);
     521             : 
     522           0 :     rv = RemoveNsIFileRecursively(aQuotaInfo, file);
     523           0 :     if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     524             :   }
     525           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     526             : 
     527             :   // In the end, remove the folder
     528           0 :   rv = aFile->Remove(/* recursive */ false);
     529           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     530             : 
     531           0 :   return rv;
     532             : }
     533             : 
     534             : // static
     535             : nsresult
     536           0 : RemoveNsIFile(const QuotaInfo& aQuotaInfo, nsIFile* aFile)
     537             : {
     538           0 :   MOZ_DIAGNOSTIC_ASSERT(aFile);
     539             : 
     540           0 :   int64_t fileSize = 0;
     541           0 :   nsresult rv = aFile->GetFileSize(&fileSize);
     542           0 :   if (rv == NS_ERROR_FILE_NOT_FOUND ||
     543             :       rv == NS_ERROR_FILE_TARGET_DOES_NOT_EXIST) {
     544           0 :     return NS_OK;
     545             :   }
     546           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     547             : 
     548           0 :   rv = aFile->Remove( /* recursive */ false);
     549           0 :   if (NS_WARN_IF(NS_FAILED(rv))) { return rv; }
     550             : 
     551           0 :   QuotaManager* quotaManager = QuotaManager::Get();
     552           0 :   MOZ_DIAGNOSTIC_ASSERT(quotaManager);
     553             : 
     554           0 :   quotaManager->DecreaseUsageForOrigin(PERSISTENCE_TYPE_DEFAULT,
     555             :                                        aQuotaInfo.mGroup, aQuotaInfo.mOrigin,
     556           0 :                                        fileSize);
     557             : 
     558           0 :   return rv;
     559             : }
     560             : 
     561             : } // namespace cache
     562             : } // namespace dom
     563             : } // namespace mozilla

Generated by: LCOV version 1.13