Bug 488811 - nsIPermissionManager.removeAll() should delete DB and re-init rather than just bailing; r=dwitte sr=bzbarsky
authorEhsan Akhgari <ehsan.akhgari@gmail.com>
Sat, 18 Apr 2009 10:12:09 +0330
changeset 27447 2aecc6cf5b2a5d1e9eed2d14c8a1a95a62c16fae
parent 27446 1220ac9d5526001f1b0ea5be7dba4e8e3984ba20
child 27448 55b6298ff619738a8a6af98a177ea9906ce0a029
push idunknown
push userunknown
push dateunknown
reviewersdwitte, bzbarsky
bugs488811
milestone1.9.2a1pre
Bug 488811 - nsIPermissionManager.removeAll() should delete DB and re-init rather than just bailing; r=dwitte sr=bzbarsky
extensions/cookie/nsPermissionManager.cpp
extensions/cookie/nsPermissionManager.h
extensions/cookie/test/unit/test_permmanager_removeall.js
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -120,38 +120,48 @@ nsPermissionManager::Init()
 
   if (!mHostTable.Init()) {
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   // ignore failure here, since it's non-fatal (we can run fine without
   // persistent storage - e.g. if there's no profile).
   // XXX should we tell the user about this?
-  InitDB();
+  InitDB(PR_FALSE);
 
   mObserverService = do_GetService("@mozilla.org/observer-service;1", &rv);
   if (NS_SUCCEEDED(rv)) {
     mObserverService->AddObserver(this, "profile-before-change", PR_TRUE);
     mObserverService->AddObserver(this, "profile-do-change", PR_TRUE);
   }
 
   return NS_OK;
 }
 
 nsresult
-nsPermissionManager::InitDB()
+nsPermissionManager::InitDB(PRBool aRemoveFile)
 {
   nsCOMPtr<nsIFile> permissionsFile;
   NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(permissionsFile));
   if (!permissionsFile)
     return NS_ERROR_UNEXPECTED;
 
   nsresult rv = permissionsFile->AppendNative(NS_LITERAL_CSTRING(kPermissionsFileName));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  if (aRemoveFile) {
+    PRBool exists = PR_FALSE;
+    rv = permissionsFile->Exists(&exists);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (exists) {
+      rv = permissionsFile->Remove(PR_FALSE);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
   nsCOMPtr<mozIStorageService> storage = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
   if (!storage)
     return NS_ERROR_UNEXPECTED;
 
   // cache a connection to the hosts database
   rv = storage->OpenDatabase(permissionsFile, getter_AddRefs(mDBConn));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -449,17 +459,21 @@ nsresult
 nsPermissionManager::RemoveAllInternal()
 {
   RemoveAllFromMemory();
 
   // clear the db
   if (mDBConn) {
     nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DELETE FROM moz_hosts"));
     if (NS_FAILED(rv)) {
-      NS_WARNING("db delete failed");
+      mStmtInsert = nsnull;
+      mStmtDelete = nsnull;
+      mStmtUpdate = nsnull;
+      mDBConn = nsnull;
+      rv = InitDB(PR_TRUE);
       return rv;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -586,17 +600,17 @@ NS_IMETHODIMP nsPermissionManager::Obser
       // clear the permissions file
       RemoveAllInternal();
     } else {
       RemoveAllFromMemory();
     }
   }  
   else if (!nsCRT::strcmp(aTopic, "profile-do-change")) {
     // the profile has already changed; init the db from the new location
-    InitDB();
+    InitDB(PR_FALSE);
   }
 
   return NS_OK;
 }
 
 //*****************************************************************************
 //*** nsPermissionManager private methods
 //*****************************************************************************
--- a/extensions/cookie/nsPermissionManager.h
+++ b/extensions/cookie/nsPermissionManager.h
@@ -194,17 +194,17 @@ private:
                             PRUint32              aType,
                             PRBool                aExactHostMatch);
 
   nsresult CommonTestPermission(nsIURI     *aURI,
                                 const char *aType,
                                 PRUint32   *aPermission,
                                 PRBool      aExactHostMatch);
 
-  nsresult InitDB();
+  nsresult InitDB(PRBool aRemoveFile);
   nsresult CreateTable();
   nsresult Import();
   nsresult Read();
   void     NotifyObserversWithPermission(const nsACString &aHost,
                                          const nsCString  &aType,
                                          PRUint32          aPermission,
                                          const PRUnichar  *aData);
   void     NotifyObservers(nsIPermission *aPermission, const PRUnichar *aData);
new file mode 100644
--- /dev/null
+++ b/extensions/cookie/test/unit/test_permmanager_removeall.js
@@ -0,0 +1,63 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+function run_test() {
+  // setup a profile directory
+  var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+               getService(Ci.nsIProperties);
+  var leafRandomName = "PermMgr" + Math.floor(Math.random() * 10000);
+  var dir = dirSvc.get("TmpD", Ci.nsILocalFile);
+  dir.append(leafRandomName);
+  dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0700);
+  var provider = {
+    getFile: function(prop, persistent) {
+      persistent.value = true;
+      if (prop == "ProfLD" ||
+          prop == "ProfD")
+        return dir.clone();
+      throw Cr.NS_ERROR_FAILURE;
+    },
+    QueryInterface: function(iid) {
+      if (iid.equals(Ci.nsIDirectoryProvider) ||
+          iid.equals(Ci.nsISupports)) {
+        return this;
+      }
+      throw Cr.NS_ERROR_NO_INTERFACE;
+    }
+  };
+  dirSvc.QueryInterface(Ci.nsIDirectoryService).
+         registerProvider(provider);
+
+  // initialize the permission manager service
+  var pm = Cc["@mozilla.org/permissionmanager;1"].
+           getService(Ci.nsIPermissionManager);
+
+  // get the db file
+  var file = dir.clone();
+  file.append("permissions.sqlite");
+  do_check_true(file.exists());
+
+  // corrupt the file
+  var ostream = Cc["@mozilla.org/network/file-output-stream;1"].
+                createInstance(Ci.nsIFileOutputStream);
+  ostream.init(file, 0x02, 0666, 0);
+  var conv = Cc["@mozilla.org/intl/converter-output-stream;1"].
+             createInstance(Ci.nsIConverterOutputStream);
+  conv.init(ostream, "UTF-8", 0, 0);
+  for (var i = 0; i < file.fileSize; ++i)
+    conv.writeString("a");
+  conv.close();
+
+  // prepare an empty hostperm.1 file so that it can be used for importing
+  var hostperm = dir.clone();
+  hostperm.append("hostperm.1");
+  ostream.init(hostperm, 0x02 | 0x08, 0666, 0);
+  ostream.close();
+
+  // remove all should not throw
+  pm.removeAll();
+
+  // cleanup
+  dirSvc.unregisterProvider(provider);
+}
+