aboutsummaryrefslogtreecommitdiffstats
path: root/netx/net
diff options
context:
space:
mode:
authorJiri Vanek <[email protected]>2013-12-02 16:04:32 +0100
committerJiri Vanek <[email protected]>2013-12-02 16:04:32 +0100
commit77f5431e3b77c3d16693de34c21189d3f960ec41 (patch)
treeecced48bc4b7d1de33ad38cb066a6c6db9b88504 /netx/net
parent57a108d5385a5810cf627d9d70792379d4c27000 (diff)
Better validation of crytical dirs with proper message on startup
Diffstat (limited to 'netx/net')
-rw-r--r--netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java28
-rw-r--r--netx/net/sourceforge/jnlp/config/DirectoryValidator.java379
-rw-r--r--netx/net/sourceforge/jnlp/resources/Messages.properties3
-rw-r--r--netx/net/sourceforge/jnlp/runtime/Boot.java9
4 files changed, 405 insertions, 14 deletions
diff --git a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java
index 02a4933..a132864 100644
--- a/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java
+++ b/netx/net/sourceforge/jnlp/config/DeploymentConfiguration.java
@@ -36,6 +36,7 @@ import java.util.Properties;
import java.util.Set;
import javax.naming.ConfigurationException;
+import javax.swing.JOptionPane;
import net.sourceforge.jnlp.cache.CacheLRUWrapper;
import net.sourceforge.jnlp.runtime.JNLPRuntime;
@@ -213,9 +214,9 @@ public final class DeploymentConfiguration {
/** is it mandatory to load the system properties? */
private boolean systemPropertiesMandatory = false;
- /** The system's deployment.config file */
+ /** The system's subdirResult deployment.config file */
private File systemPropertiesFile = null;
- /** The user's deployment.config file */
+ /** The user's subdirResult deployment.config file */
private File userPropertiesFile = null;
/*default user file*/
@@ -280,7 +281,7 @@ public final class DeploymentConfiguration {
Map<String, Setting<String>> systemProperties = null;
/*
- * First, try to read the system's deployment.config file to find if
+ * First, try to read the system's subdirResult deployment.config file to find if
* there is a system-level deployment.poperties file
*/
@@ -304,7 +305,7 @@ public final class DeploymentConfiguration {
}
/*
- * Third, read the user's deployment.properties file
+ * Third, read the user's subdirResult deployment.properties file
*/
userPropertiesFile = userFile;
Map<String, Setting<String>> userProperties = loadProperties(ConfigType.User, userPropertiesFile, false);
@@ -713,6 +714,8 @@ public final class DeploymentConfiguration {
int errors = 0;
String PRE_15_DEPLOYMENT_DIR = ".icedtea";
String LEGACY_USER_HOME = System.getProperty("user.home") + File.separator + PRE_15_DEPLOYMENT_DIR;
+ File configDir = new File(Defaults.USER_CONFIG_HOME);
+ File cacheDir = new File(Defaults.USER_CACHE_HOME);
File legacyUserDir = new File(LEGACY_USER_HOME);
if (legacyUserDir.exists()) {
OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Legacy configuration and cache found. Those will be now transported to new locations");
@@ -723,11 +726,9 @@ public final class DeploymentConfiguration {
OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, "Preparing new directories:");
OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, " " + Defaults.USER_CONFIG_HOME);
- File f1 = new File(Defaults.USER_CONFIG_HOME);
- errors += resultToStd(f1.mkdirs());
+ errors += resultToStd(configDir.mkdirs());
OutputController.getLogger().log(OutputController.Level.MESSAGE_ALL, " " + Defaults.USER_CACHE_HOME);
- File f2 = new File(Defaults.USER_CACHE_HOME);
- errors += resultToStd(f2.mkdirs());
+ errors += resultToStd(cacheDir.mkdirs());
String legacySecurity = LEGACY_USER_HOME + File.separator + "security";
String currentSecurity = Defaults.USER_SECURITY;
@@ -786,16 +787,23 @@ public final class DeploymentConfiguration {
} else {
OutputController.getLogger().log("System is already following XDG .cache and .config specifications");
try {
- OutputController.getLogger().log("config: " + Defaults.USER_CONFIG_HOME + " file exists: " + new File(Defaults.USER_CONFIG_HOME).exists());
+ OutputController.getLogger().log("config: " + Defaults.USER_CONFIG_HOME + " file exists: " + configDir.exists());
} catch (Exception ex) {
OutputController.getLogger().log(ex);
}
try {
- OutputController.getLogger().log("cache: " + Defaults.USER_CACHE_HOME + " file exists:" + new File(Defaults.USER_CACHE_HOME));
+ OutputController.getLogger().log("cache: " + Defaults.USER_CACHE_HOME + " file exists:" + cacheDir.exists());
} catch (Exception ex) {
OutputController.getLogger().log(ex);
}
}
+ //this call should endure even if (ever) will migration code be removed
+ DirectoryValidator.DirectoryCheckResults r = new DirectoryValidator().ensureDirs();
+ if (!JNLPRuntime.isHeadless()) {
+ if (r.getFailures() > 0) {
+ JOptionPane.showMessageDialog(null, r.getMessage());
+ }
+ }
}
diff --git a/netx/net/sourceforge/jnlp/config/DirectoryValidator.java b/netx/net/sourceforge/jnlp/config/DirectoryValidator.java
new file mode 100644
index 0000000..3d526fd
--- /dev/null
+++ b/netx/net/sourceforge/jnlp/config/DirectoryValidator.java
@@ -0,0 +1,379 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package net.sourceforge.jnlp.config;
+
+import static net.sourceforge.jnlp.runtime.Translator.R;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.util.FileUtils;
+import net.sourceforge.jnlp.util.logging.OutputController;
+
+/**
+ *
+ * @author jvanek
+ */
+public class DirectoryValidator {
+
+ /**
+ * This class is holding results of directory validation.
+ * Various errors like can not read, write create dir can apeear
+ * For sumaries of results are here getPasses, getFailures methods
+ *
+ * Individual results can be read from results field, or converted to string
+ */
+ public static class DirectoryCheckResults {
+ public final List<DirectoryCheckResult> results;
+
+ /**
+ * Wraps results so we can make some statistics or convert to message
+ * @param results
+ */
+ public DirectoryCheckResults(List<DirectoryCheckResult> results) {
+ this.results = results;
+ }
+
+ /**
+ *
+ * @return sum of passed checks, 0-3 per result
+ */
+ public int getPasses() {
+ int passes = 0;
+ for (DirectoryCheckResult directoryCheckResult : results) {
+ passes += directoryCheckResult.getPasses();
+ }
+ return passes;
+ }
+
+ /**
+ *
+ * @return sum of failed checks, 0-3 per results
+ */
+ public int getFailures() {
+ int failures = 0;
+ for (DirectoryCheckResult directoryCheckResult : results) {
+ failures += directoryCheckResult.getFailures();
+ }
+ return failures;
+ }
+
+ /**
+ * The result have one reuslt per line, separated by \n
+ * as is inherited from result.getMessage() method.
+ *
+ * @return all results connected.
+ */
+ public String getMessage(){
+ return resultsToString(results);
+ }
+
+ /**
+ * using getMessage
+ * @return
+ */
+ @Override
+ public String toString() {
+ return getMessage();
+ }
+
+
+
+ public static String resultsToString(List<DirectoryCheckResult> results) {
+ StringBuilder sb = new StringBuilder();
+ for (DirectoryCheckResult r : results) {
+ if (r.getFailures() >0 ){
+ sb.append(r.getMessage());
+ }
+ }
+ return sb.toString();
+ }
+
+ }
+
+ /**
+ * Is storing result of directory validation.
+ *
+ * validated are existence of directory
+ * whether it is directory
+ * if it have read/write permissions
+ */
+ public static class DirectoryCheckResult {
+
+ //do exist?
+ public boolean exists = true;
+ //is dir?
+ public boolean isDir = true;
+ //can be read, written to?
+ public boolean correctPermissions = true;
+ //have correct subdir? - this implies soe rules, when subdirecotry of some
+ //particular directory have weeker permissions
+ public DirectoryCheckResult subDir = null;
+ //actual tested directory
+ private final File testedDir;
+
+ public DirectoryCheckResult(File testedDir) {
+ this.testedDir = testedDir;
+ }
+
+ public static String notExistsMessage(File f) {
+ return R("DCmaindircheckNotexists", f.getAbsolutePath());
+ }
+
+ public static String notDirMessage(File f) {
+ return R("DCmaindircheckNotdir", f.getAbsolutePath());
+ }
+
+ public static String wrongPermissionsMessage(File f) {
+ return R("DCmaindircheckRwproblem", f.getAbsolutePath());
+ }
+
+ private static int booleanToInt(boolean b) {
+ if (b) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+
+ /**
+ * count passes of this result (0-3, both inclusive).
+ */
+ public int getPasses() {
+ int subdirs = 0;
+ if (subDir != null) {
+ subdirs = subDir.getPasses();
+ }
+ return booleanToInt(exists)
+ + booleanToInt(isDir)
+ + booleanToInt(correctPermissions)
+ + subdirs;
+ }
+
+ /*
+ * count failures of this result (0-3, both inclusive).
+ */
+ public int getFailures() {
+ int max = 3;
+ if (subDir != null) {
+ max = 2 * max;
+ }
+ return max - getPasses();
+ }
+
+ /**
+ * Convert results to string.
+ * Each failure by line. PAsses are not mentioned
+ * The subdirectory (and it subdirectories are included to )
+ *
+ * @return string with \n, or/and ended by \n
+ */
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder();
+ if (!exists) {
+ sb.append(notExistsMessage(testedDir)).append("\n");
+ }
+ if (!isDir) {
+ sb.append(notDirMessage(testedDir)).append("\n");
+ }
+ if (!correctPermissions) {
+ sb.append(wrongPermissionsMessage(testedDir)).append("\n");
+ }
+
+ if (subDir != null) {
+ String s = subDir.getMessage();
+ if (!s.isEmpty()) {
+ sb.append(s);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public String toString() {
+ return getMessage();
+ }
+ }
+
+
+ private final List<File> dirsToCheck;
+
+
+ /**
+ * Creates DirectoryValidator to ensure given directories
+ *
+ * @param dirsToCheck
+ */
+ public DirectoryValidator(List<File> dirsToCheck) {
+ this.dirsToCheck = dirsToCheck;
+ }
+
+
+ /**
+ * Creates DirectoryValidator to ensure directories read from
+ * user (if any - default otherwise ) settings via keys:
+ * <li>KEY_USER_CACHE_DIR</li>
+ * <li>KEY_USER_PERSISTENCE_CACHE_DIR</li>
+ * <li>KEY_SYSTEM_CACHE_DIR</li>
+ * <li>KEY_USER_LOG_DIR</li>
+ * <li>KEY_USER_TMP_DIR</li>
+ * <li>KEY_USER_LOCKS_DIR</li>
+ */
+ public DirectoryValidator() {
+ dirsToCheck = new ArrayList<File>(6);
+ DeploymentConfiguration dc = JNLPRuntime.getConfiguration();
+ String[] keys = new String[]{
+ DeploymentConfiguration.KEY_USER_CACHE_DIR,
+ DeploymentConfiguration.KEY_USER_PERSISTENCE_CACHE_DIR,
+ DeploymentConfiguration.KEY_SYSTEM_CACHE_DIR,
+ DeploymentConfiguration.KEY_USER_LOG_DIR,
+ DeploymentConfiguration.KEY_USER_TMP_DIR,
+ DeploymentConfiguration.KEY_USER_LOCKS_DIR};
+ for (String key : keys) {
+ String value = dc.getProperty(key);
+ if (value == null) {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "WARNING: key " + key + " has no value, setting to default value");
+ value = Defaults.getDefaults().get(key).getValue();
+ }
+ if (value == null) {
+ if (JNLPRuntime.isDebug()) {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "WARNING: key " + key + " has no value, skipping");
+ }
+ continue;
+ }
+ File f = new File(value);
+ dirsToCheck.add(f);
+ }
+ }
+
+ /**
+ * This method is ensuring, that specified directories will exists after
+ * call and will have enough permissions.
+ *
+ * This methods is trying to create the directories if they are not present
+ * and is testing if can be written inside. All checks are done in bulk. If
+ * one or more defect is found, user is warned via dialogue in gui mode
+ * (again in bulk). In headless mode stdout/stderr is enough, as application
+ * (both gui and headless) should not stop to work, but continue to run with
+ * hope that corrupted dirs will not be necessary
+ */
+ public DirectoryCheckResults ensureDirs() {
+ return ensureDirs(dirsToCheck);
+ }
+
+ static DirectoryCheckResults ensureDirs(List<File> dirs) {
+ List<DirectoryCheckResult> result = new ArrayList<DirectoryCheckResult>(dirs.size());
+ for (File f : dirs) {
+ if (f.exists()) {
+ DirectoryCheckResult r = testDir(f, true, true);
+ result.add(r);
+ continue;
+ }
+ if (!f.mkdirs()) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "ERROR: Directory " + f.getAbsolutePath() + " does not exist and has not been created");
+ } else {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG,"OK: Directory " + f.getAbsolutePath() + " did not exist but has been created");
+ }
+ DirectoryCheckResult r = testDir(f, true, true);
+ result.add(r);
+ }
+ return new DirectoryCheckResults(result);
+ }
+
+ /**
+ * This method is package private for testing purposes only.
+ *
+ * This method verify that directory exists, is directory, file and
+ * directory can be created, file can be written into, and subdirectory can
+ * be written into.
+ *
+ * Some steps may looks like redundant, but some permission settings really
+ * alow to create file but not directory and vice versa. Also some settings
+ * can allow to create file or directory which can not be written into. (eg
+ * ACL or network disks)
+ */
+ static DirectoryCheckResult testDir(File f, boolean verbose, boolean testSubdir) {
+ DirectoryCheckResult result = new DirectoryCheckResult(f);
+ if (!f.exists()) {
+ if (verbose) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, DirectoryCheckResult.notExistsMessage(f));
+ }
+ result.exists = false;
+ }
+ if (!f.isDirectory()) {
+ if (verbose) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, DirectoryCheckResult.notDirMessage(f));
+ }
+ result.isDir = false;
+ }
+ File testFile = null;
+ boolean correctPermissions = true;
+ try {
+ testFile = File.createTempFile("maindir", "check", f);
+ if (!testFile.exists()) {
+ correctPermissions = false;
+ }
+ try {
+ FileUtils.saveFile("ww", testFile);
+ String s = FileUtils.loadFileAsString(testFile);
+ if (!s.trim().equals("ww")) {
+ correctPermissions = false;
+ }
+ } catch (Exception ex) {
+ if (JNLPRuntime.isDebug()) {
+ ex.printStackTrace();
+ }
+ correctPermissions = false;
+ }
+ File[] canList = f.listFiles();
+ if (canList == null || canList.length == 0) {
+ correctPermissions = false;
+ }
+ testFile.delete();
+ if (testFile.exists()) {
+ correctPermissions = false;
+ } else {
+ boolean created = testFile.mkdir();
+ if (!created) {
+ correctPermissions = false;
+ }
+ if (testFile.exists()) {
+ if (testSubdir) {
+ DirectoryCheckResult subdirResult = testDir(testFile, verbose, false);
+ if (subdirResult.getFailures() != 0) {
+ result.subDir = subdirResult;
+ correctPermissions = false;
+ }
+ testFile.delete();
+ if (testFile.exists()) {
+ correctPermissions = false;
+ }
+ }
+ } else {
+ correctPermissions = false;
+ }
+ }
+ } catch (Exception ex) {
+ if (JNLPRuntime.isDebug()) {
+ ex.printStackTrace();
+ }
+ correctPermissions = false;
+ } finally {
+ if (testFile != null && testFile.exists()) {
+ testFile.delete();
+ }
+ }
+ if (!correctPermissions) {
+ if (verbose) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, DirectoryCheckResult.wrongPermissionsMessage(f));
+ }
+ result.correctPermissions = false;
+ }
+ return result;
+
+ }
+}
diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties
index 2e5fb82..15844e3 100644
--- a/netx/net/sourceforge/jnlp/resources/Messages.properties
+++ b/netx/net/sourceforge/jnlp/resources/Messages.properties
@@ -304,6 +304,9 @@ DCIncorrectValue=Property "{0}" has incorrect value "{1}". Possible values {2}.
DCInternal=Internal error: {0}
DCSourceInternal=<internal>
DCUnknownSettingWithName=Property "{0}" is unknown.
+DCmaindircheckNotexists=After all attempts, your configuration directory {0} do not exists.
+DCmaindircheckNotdir=Your configuration directory {0} is not directory.
+DCmaindircheckRwproblem=Your configuration directory {0} can not be read/written properly.
# Value Validator messages. Messages should follow "Possible values ..."
VVPossibleValues=Possible values {0}
diff --git a/netx/net/sourceforge/jnlp/runtime/Boot.java b/netx/net/sourceforge/jnlp/runtime/Boot.java
index 3f774cf..1ef0b6b 100644
--- a/netx/net/sourceforge/jnlp/runtime/Boot.java
+++ b/netx/net/sourceforge/jnlp/runtime/Boot.java
@@ -124,11 +124,15 @@ public final class Boot implements PrivilegedAction<Void> {
* Launch the JNLP file specified by the command-line arguments.
*/
public static void main(String[] argsIn) {
+ args = argsIn;
+
if (AppContext.getAppContext() == null) {
SunToolkit.createNewAppContext();
}
+ if (null != getOption("-headless"))
+ JNLPRuntime.setHeadless(true);
+
DeploymentConfiguration.move14AndOlderFilesTo15StructureCatched();
- args = argsIn;
if (null != getOption("-viewer")) {
@@ -170,9 +174,6 @@ public final class Boot implements PrivilegedAction<Void> {
JNLPRuntime.setDefaultUpdatePolicy(new UpdatePolicy(value * 1000l));
}
- if (null != getOption("-headless"))
- JNLPRuntime.setHeadless(true);
-
if (null != getOption("-noupdate"))
JNLPRuntime.setDefaultUpdatePolicy(UpdatePolicy.NEVER);