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.

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

mercurial