mobile/android/base/GeckoProfileDirectories.java

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 package org.mozilla.gecko;
     7 import java.io.File;
     8 import java.util.Enumeration;
     9 import java.util.HashMap;
    10 import java.util.Map;
    12 import org.mozilla.gecko.util.INIParser;
    13 import org.mozilla.gecko.util.INISection;
    15 import android.content.Context;
    17 /**
    18  * <code>GeckoProfileDirectories</code> manages access to mappings from profile
    19  * names to salted profile directory paths, as well as the default profile name.
    20  *
    21  * This class will eventually come to encapsulate the remaining logic embedded
    22  * in profiles.ini; for now it's a read-only wrapper.
    23  */
    24 public class GeckoProfileDirectories {
    25     @SuppressWarnings("serial")
    26     public static class NoMozillaDirectoryException extends Exception {
    27         public NoMozillaDirectoryException(Throwable cause) {
    28             super(cause);
    29         }
    31         public NoMozillaDirectoryException(String reason) {
    32             super(reason);
    33         }
    35         public NoMozillaDirectoryException(String reason, Throwable cause) {
    36             super(reason, cause);
    37         }
    38     }
    40     @SuppressWarnings("serial")
    41     public static class NoSuchProfileException extends Exception {
    42         public NoSuchProfileException(String detailMessage, Throwable cause) {
    43             super(detailMessage, cause);
    44         }
    46         public NoSuchProfileException(String detailMessage) {
    47             super(detailMessage);
    48         }
    49     }
    51     private interface INISectionPredicate {
    52         public boolean matches(INISection section);
    53     }
    55     private static final String MOZILLA_DIR_NAME = "mozilla";
    57     /**
    58      * Returns true if the supplied profile entry represents the default profile.
    59      */
    60     private static INISectionPredicate sectionIsDefault = new INISectionPredicate() {
    61         @Override
    62         public boolean matches(INISection section) {
    63             return section.getIntProperty("Default") == 1;
    64         }
    65     };
    67     /**
    68      * Returns true if the supplied profile entry has a 'Name' field.
    69      */
    70     private static INISectionPredicate sectionHasName = new INISectionPredicate() {
    71         @Override
    72         public boolean matches(INISection section) {
    73             final String name = section.getStringProperty("Name");
    74             return name != null;
    75         }
    76     };
    78     /**
    79      * Package-scoped because GeckoProfile needs to dig into this in order to do writes.
    80      * This will be fixed in Bug 975212.
    81      */
    82     static INIParser getProfilesINI(File mozillaDir) {
    83         return new INIParser(new File(mozillaDir, "profiles.ini"));
    84     }
    86     /**
    87      * Utility method to compute a salted profile name: eight random alphanumeric
    88      * characters, followed by a period, followed by the profile name.
    89      */
    90     public static String saltProfileName(final String name) {
    91         if (name == null) {
    92             throw new IllegalArgumentException("Cannot salt null profile name.");
    93         }
    95         final String allowedChars = "abcdefghijklmnopqrstuvwxyz0123456789";
    96         final int scale = allowedChars.length();
    97         final int saltSize = 8;
    99         final StringBuilder saltBuilder = new StringBuilder(saltSize + 1 + name.length());
   100         for (int i = 0; i < saltSize; i++) {
   101             saltBuilder.append(allowedChars.charAt((int)(Math.random() * scale)));
   102         }
   103         saltBuilder.append('.');
   104         saltBuilder.append(name);
   105         return saltBuilder.toString();
   106     }
   108     /**
   109      * Return the Mozilla directory within the files directory of the provided
   110      * context. This should always be the same within a running application.
   111      *
   112      * This method is package-scoped so that new {@link GeckoProfile} instances can
   113      * contextualize themselves.
   114      *
   115      * @return a new File object for the Mozilla directory.
   116      * @throws NoMozillaDirectoryException
   117      *             if the directory did not exist and could not be created.
   118      */
   119     static File getMozillaDirectory(Context context) throws NoMozillaDirectoryException {
   120         final File mozillaDir = new File(context.getFilesDir(), MOZILLA_DIR_NAME);
   121         if (mozillaDir.exists() || mozillaDir.mkdirs()) {
   122             return mozillaDir;
   123         }
   125         // Although this leaks a path to the system log, the path is
   126         // predictable (unlike a profile directory), so this is fine.
   127         throw new NoMozillaDirectoryException("Unable to create mozilla directory at " + mozillaDir.getAbsolutePath());
   128     }
   130     /**
   131      * Discover the default profile name by examining profiles.ini.
   132      *
   133      * Package-scoped because {@link GeckoProfile} needs access to it.
   134      *
   135      * @return null if there is no "Default" entry in profiles.ini, or the profile
   136      *         name if there is.
   137      * @throws NoMozillaDirectoryException
   138      *             if the Mozilla directory did not exist and could not be created.
   139      */
   140     static String findDefaultProfileName(final Context context) throws NoMozillaDirectoryException {
   141       final INIParser parser = GeckoProfileDirectories.getProfilesINI(getMozillaDirectory(context));
   143       for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements();) {
   144           final INISection section = e.nextElement();
   145           if (section.getIntProperty("Default") == 1) {
   146               return section.getStringProperty("Name");
   147           }
   148       }
   150       return null;
   151     }
   153     static Map<String, String> getDefaultProfile(final File mozillaDir) {
   154         return getMatchingProfiles(mozillaDir, sectionIsDefault, true);
   155     }
   157     static Map<String, String> getProfilesNamed(final File mozillaDir, final String name) {
   158         final INISectionPredicate predicate = new INISectionPredicate() {
   159             @Override
   160             public boolean matches(final INISection section) {
   161                 return name.equals(section.getStringProperty("Name"));
   162             }
   163         };
   164         return getMatchingProfiles(mozillaDir, predicate, true);
   165     }
   167     /**
   168      * Calls {@link GeckoProfileDirectories#getMatchingProfiles(File, INISectionPredicate, boolean)}
   169      * with a filter to ensure that all profiles are named.
   170      */
   171     static Map<String, String> getAllProfiles(final File mozillaDir) {
   172         return getMatchingProfiles(mozillaDir, sectionHasName, false);
   173     }
   175     /**
   176      * Return a mapping from the names of all matching profiles (that is,
   177      * profiles appearing in profiles.ini that match the supplied predicate) to
   178      * their absolute paths on disk.
   179      *
   180      * @param mozillaDir
   181      *            a directory containing profiles.ini.
   182      * @param predicate
   183      *            a predicate to use when evaluating whether to include a
   184      *            particular INI section.
   185      * @param stopOnSuccess
   186      *            if true, this method will return with the first result that
   187      *            matches the predicate; if false, all matching results are
   188      *            included.
   189      * @return a {@link Map} from name to path.
   190      */
   191     public static Map<String, String> getMatchingProfiles(final File mozillaDir, INISectionPredicate predicate, boolean stopOnSuccess) {
   192         final HashMap<String, String> result = new HashMap<String, String>();
   193         final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
   195         for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements();) {
   196             final INISection section = e.nextElement();
   197             if (predicate == null || predicate.matches(section)) {
   198                 final String name = section.getStringProperty("Name");
   199                 final String pathString = section.getStringProperty("Path");
   200                 final boolean isRelative = section.getIntProperty("IsRelative") == 1;
   201                 final File path = isRelative ? new File(mozillaDir, pathString) : new File(pathString);
   202                 result.put(name, path.getAbsolutePath());
   204                 if (stopOnSuccess) {
   205                     return result;
   206                 }
   207             }
   208         }
   209         return result;
   210     }
   212     public static File findProfileDir(final File mozillaDir, final String profileName) throws NoSuchProfileException {
   213         // Open profiles.ini to find the correct path.
   214         final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
   216         for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements();) {
   217             final INISection section = e.nextElement();
   218             final String name = section.getStringProperty("Name");
   219             if (name != null && name.equals(profileName)) {
   220                 if (section.getIntProperty("IsRelative") == 1) {
   221                     return new File(mozillaDir, section.getStringProperty("Path"));
   222                 }
   223                 return new File(section.getStringProperty("Path"));
   224             }
   225         }
   227         throw new NoSuchProfileException("No profile " + profileName);
   228     }
   229 }

mercurial