[tbb-commits] [tor-browser/tor-browser-31.5.0esr-4.5-1] Bug 14631: Improve profile access error messages.

mikeperry at torproject.org mikeperry at torproject.org
Wed Mar 18 03:58:48 UTC 2015


commit bebc69b8e8e919abec272f9cff6ab13fb9ea51f7
Author: Kathy Brade <brade at pearlcrescent.com>
Date:   Tue Feb 24 13:50:23 2015 -0500

    Bug 14631: Improve profile access error messages.
    
    Instead of always reporting that the profile is locked, display specific
    messages for "access denied" and "read-only file system".
---
 .../mozapps/profile/profileSelection.properties    |    5 +
 toolkit/xre/nsAppRunner.cpp                        |  112 +++++++++++++++++---
 2 files changed, 103 insertions(+), 14 deletions(-)

diff --git a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
index adac95a..3cf48ff 100644
--- a/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
+++ b/toolkit/locales/en-US/chrome/mozapps/profile/profileSelection.properties
@@ -12,6 +12,11 @@ restartMessageUnlocker=%S is already running, but is not responding. The old %S
 restartMessageNoUnlockerMac=A copy of %S is already open. Only one copy of %S can be open at a time.
 restartMessageUnlockerMac=A copy of %S is already open. The running copy of %S will quit in order to open this one.
 
+# LOCALIZATION NOTE (profileProblemTitle, profileReadOnly, profileReadOnlyMac, profileAccessDenied):  Messages displayed when the browser profile cannot be accessed or written to. %S is the application name.
+profileProblemTitle=%S Profile Problem
+profileReadOnly=You cannot run %S from a read-only file system.  Please copy %S to another location before trying to use it.
+profileReadOnlyMac=You cannot run %S from a read-only file system.  Please copy %S to your Desktop or Applications folder before trying to use it.
+profileAccessDenied=%S does not have permission to access the profile. Please adjust your file system permissions and try again.
 # Profile manager
 # LOCALIZATION NOTE (profileTooltip): First %S is the profile name, second %S is the path to the profile folder.
 profileTooltip=Profile: '%S' - Path: '%S'
diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp
index cadc46d..dbd1376 100644
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1682,12 +1682,20 @@ static nsresult LaunchChild(nsINativeAppSupport* aNative,
   return NS_ERROR_LAUNCHED_CHILD_PROCESS;
 }
 
+enum ProfileStatus {
+  PROFILE_STATUS_OK,
+  PROFILE_STATUS_ACCESS_DENIED,
+  PROFILE_STATUS_READ_ONLY,
+  PROFILE_STATUS_IS_LOCKED,
+  PROFILE_STATUS_OTHER_ERROR
+};
+
 static const char kProfileProperties[] =
   "chrome://mozapps/locale/profile/profileSelection.properties";
 
 static nsresult
-ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
-                    nsIProfileUnlocker* aUnlocker,
+ProfileErrorDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
+                    ProfileStatus aStatus, nsIProfileUnlocker* aUnlocker,
                     nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
 {
   nsresult rv;
@@ -1717,17 +1725,29 @@ ProfileLockedDialog(nsIFile* aProfileDir, nsIFile* aProfileLocalDir,
 #ifndef XP_MACOSX
     static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','\0'}; // "restartMessageNoUnlocker"
     static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','\0'}; // "restartMessageUnlocker"
+    static const char16_t kReadOnly[] = {'p','r','o','f','i','l','e','R','e','a','d','O','n','l','y','\0'}; // "profileReadOnly"
 #else
     static const char16_t kRestartNoUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','N','o','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageNoUnlockerMac"
     static const char16_t kRestartUnlocker[] = {'r','e','s','t','a','r','t','M','e','s','s','a','g','e','U','n','l','o','c','k','e','r','M','a','c','\0'}; // "restartMessageUnlockerMac"
+    static const char16_t kReadOnly[] = {'p','r','o','f','i','l','e','R','e','a','d','O','n','l','y','M','a','c','\0'}; // "profileReadOnlyMac"
 #endif
 
-    sb->FormatStringFromName(aUnlocker ? kRestartUnlocker : kRestartNoUnlocker,
-                             params, 2, getter_Copies(killMessage));
+    static const char16_t kAccessDenied[] = {'p','r','o','f','i','l','e','A','c','c','e','s','s','D','e','n','i','e','d','\0'}; // "profileAccessDenied"
 
+    const char16_t *errorKey = aUnlocker ? kRestartUnlocker
+                                         : kRestartNoUnlocker;
+    if (PROFILE_STATUS_READ_ONLY == aStatus)
+      errorKey = kReadOnly;
+    else if (PROFILE_STATUS_ACCESS_DENIED == aStatus)
+      errorKey = kAccessDenied;
+    sb->FormatStringFromName(errorKey, params, 2, getter_Copies(killMessage));
+
+    const char16_t *titleKey = ((PROFILE_STATUS_READ_ONLY == aStatus) ||
+                                (PROFILE_STATUS_ACCESS_DENIED == aStatus))
+                                   ? MOZ_UTF16("profileProblemTitle")
+                                   : MOZ_UTF16("restartTitle");
     nsXPIDLString killTitle;
-    sb->FormatStringFromName(MOZ_UTF16("restartTitle"),
-                             params, 1, getter_Copies(killTitle));
+    sb->FormatStringFromName(titleKey, params, 1, getter_Copies(killTitle));
 
     if (!killMessage || !killTitle)
       return NS_ERROR_FAILURE;
@@ -1828,8 +1848,9 @@ ProfileMissingDialog(nsINativeAppSupport* aNative)
 }
 
 static nsresult
-ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker,
-                    nsINativeAppSupport* aNative, nsIProfileLock* *aResult)
+ProfileErrorDialog(nsIToolkitProfile* aProfile, ProfileStatus aStatus,
+                   nsIProfileUnlocker* aUnlocker, nsINativeAppSupport* aNative,
+                   nsIProfileLock* *aResult)
 {
   nsCOMPtr<nsIFile> profileDir;
   nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
@@ -1845,8 +1866,8 @@ ProfileLockedDialog(nsIToolkitProfile* aProfile, nsIProfileUnlocker* aUnlocker,
   rv = aProfile->GetLocalDir(getter_AddRefs(profileLocalDir));
   if (NS_FAILED(rv)) return rv;
 
-  return ProfileLockedDialog(profileDir, profileLocalDir, aUnlocker, aNative,
-                             aResult);
+  return ProfileErrorDialog(profileDir, profileLocalDir, aStatus, aUnlocker,
+                            aNative, aResult);
 }
 
 static const char kProfileManagerURL[] =
@@ -2007,6 +2028,53 @@ SetCurrentProfileAsDefault(nsIToolkitProfileService* aProfileSvc,
   return rv;
 }
 
+// Check for write permission to the profile directory by trying to create a
+// new file (after ensuring that no file with the same name exists).
+static ProfileStatus CheckProfileWriteAccess(nsIFile* aProfileDir)
+{
+#if defined(XP_UNIX)
+  NS_NAMED_LITERAL_STRING(writeTestFileName, ".parentwritetest");
+#else
+  NS_NAMED_LITERAL_STRING(writeTestFileName, "parent.writetest");
+#endif
+
+  nsCOMPtr<nsIFile> writeTestFile;
+  nsresult rv = aProfileDir->Clone(getter_AddRefs(writeTestFile));
+  if (NS_SUCCEEDED(rv))
+    rv = writeTestFile->Append(writeTestFileName);
+
+  if (NS_SUCCEEDED(rv)) {
+    bool doesExist = false;
+    rv = writeTestFile->Exists(&doesExist);
+    if (NS_SUCCEEDED(rv) && doesExist)
+      rv = writeTestFile->Remove(true);
+  }
+
+  if (NS_SUCCEEDED(rv)) {
+    rv = writeTestFile->Create(nsIFile::NORMAL_FILE_TYPE, 0666);
+    (void)writeTestFile->Remove(true);
+  }
+
+  ProfileStatus status = NS_SUCCEEDED(rv) ? PROFILE_STATUS_OK
+                                          : PROFILE_STATUS_OTHER_ERROR;
+  if (NS_ERROR_FILE_ACCESS_DENIED == rv)
+    status = PROFILE_STATUS_ACCESS_DENIED;
+  else if (NS_ERROR_FILE_READ_ONLY == rv)
+    status = PROFILE_STATUS_READ_ONLY;
+
+  return status;
+}
+
+static ProfileStatus CheckProfileWriteAccess(nsIToolkitProfile* aProfile)
+{
+  nsCOMPtr<nsIFile> profileDir;
+  nsresult rv = aProfile->GetRootDir(getter_AddRefs(profileDir));
+  if (NS_FAILED(rv))
+    return PROFILE_STATUS_OTHER_ERROR;
+
+  return CheckProfileWriteAccess(profileDir);
+}
+
 static bool gDoMigration = false;
 static bool gDoProfileReset = false;
 
@@ -2140,13 +2208,18 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
+    ProfileStatus status = CheckProfileWriteAccess(lf);
+    if (PROFILE_STATUS_OK != status)
+      return ProfileErrorDialog(lf, lf, status, nullptr, aNative, aResult);
+
     // If a profile path is specified directory on the command line, then
     // assume that the temp directory is the same as the given directory.
     rv = NS_LockProfilePath(lf, lf, getter_AddRefs(unlocker), aResult);
     if (NS_SUCCEEDED(rv))
       return rv;
 
-    return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
+    return ProfileErrorDialog(lf, lf, PROFILE_STATUS_IS_LOCKED, unlocker,
+                              aNative, aResult);
   }
 
   ar = CheckArg("createprofile", true, &arg);
@@ -2231,6 +2304,10 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
         gDoProfileReset = false;
       }
 
+      ProfileStatus status = CheckProfileWriteAccess(profile);
+      if (PROFILE_STATUS_OK != status)
+        return ProfileErrorDialog(profile, status, nullptr, aNative, aResult);
+
       nsCOMPtr<nsIProfileUnlocker> unlocker;
       rv = profile->Lock(getter_AddRefs(unlocker), aResult);
       if (NS_SUCCEEDED(rv)) {
@@ -2239,7 +2316,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
         return NS_OK;
       }
 
-      return ProfileLockedDialog(profile, unlocker, aNative, aResult);
+      return ProfileErrorDialog(profile, PROFILE_STATUS_IS_LOCKED, unlocker,
+                                aNative, aResult);
     }
 
     if (CanShowProfileManager()) {
@@ -2293,7 +2371,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
           nsCOMPtr<nsIProfileUnlocker> unlocker;
           rv = profile->Lock(getter_AddRefs(unlocker), &tempProfileLock);
           if (NS_FAILED(rv))
-            return ProfileLockedDialog(profile, unlocker, aNative, &tempProfileLock);
+            return ProfileErrorDialog(profile, PROFILE_STATUS_IS_LOCKED,
+                                      unlocker, aNative, &tempProfileLock);
         }
 
         nsCOMPtr<nsIToolkitProfile> newProfile;
@@ -2304,6 +2383,10 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
           gDoProfileReset = false;
       }
 
+      ProfileStatus status = CheckProfileWriteAccess(profile);
+      if (PROFILE_STATUS_OK != status)
+        return ProfileErrorDialog(profile, status, nullptr, aNative, aResult);
+
       // If you close Firefox and very quickly reopen it, the old Firefox may
       // still be closing down. Rather than immediately showing the
       // "Firefox is running but is not responding" message, we spend a few
@@ -2329,7 +2412,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
         PR_Sleep(kLockRetrySleepMS);
       } while (TimeStamp::Now() - start < TimeDuration::FromSeconds(kLockRetrySeconds));
 
-      return ProfileLockedDialog(profile, unlocker, aNative, aResult);
+      return ProfileErrorDialog(profile, PROFILE_STATUS_IS_LOCKED, unlocker,
+                                aNative, aResult);
     }
   }
 





More information about the tbb-commits mailing list