diff --git a/apps/BOB/src/net/i2p/BOB/BOB.java b/apps/BOB/src/net/i2p/BOB/BOB.java index 9f87e4f88f0f3a3ce66100241771f0c90869f09d..1aa432e2ebe4e37a0362f9f5308bea984d7ed3b2 100644 --- a/apps/BOB/src/net/i2p/BOB/BOB.java +++ b/apps/BOB/src/net/i2p/BOB/BOB.java @@ -23,6 +23,7 @@ */ package net.i2p.BOB; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -34,6 +35,8 @@ import java.net.Socket; import java.net.SocketTimeoutException; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; + +import net.i2p.I2PAppContext; import net.i2p.client.I2PClient; import net.i2p.client.streaming.RetransmissionTimer; import net.i2p.util.Log; @@ -186,16 +189,19 @@ public class BOB { i = Y2.hashCode(); try { { + File cfg = new File(configLocation); + if (!cfg.isAbsolute()) + cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation); try { - FileInputStream fi = new FileInputStream(configLocation); + FileInputStream fi = new FileInputStream(cfg); props.load(fi); fi.close(); } catch (FileNotFoundException fnfe) { - warn("Unable to load up the BOB config file " + configLocation + ", Using defaults."); + warn("Unable to load up the BOB config file " + cfg.getAbsolutePath() + ", Using defaults."); warn(fnfe.toString()); save = true; } catch (IOException ioe) { - warn("IOException on BOB config file " + configLocation + ", using defaults."); + warn("IOException on BOB config file " + cfg.getAbsolutePath() + ", using defaults."); warn(ioe.toString()); } } @@ -228,13 +234,16 @@ public class BOB { props.setProperty(PROP_BOB_HOST, "localhost"); } if (save) { + File cfg = new File(configLocation); + if (!cfg.isAbsolute()) + cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation); try { - warn("Writing new defaults file " + configLocation); - FileOutputStream fo = new FileOutputStream(configLocation); - props.store(fo, configLocation); + warn("Writing new defaults file " + cfg.getAbsolutePath()); + FileOutputStream fo = new FileOutputStream(cfg); + props.store(fo, cfg.getAbsolutePath()); fo.close(); } catch (IOException ioe) { - error("IOException on BOB config file " + configLocation + ", " + ioe); + error("IOException on BOB config file " + cfg.getAbsolutePath() + ", " + ioe); } } diff --git a/apps/addressbook/java/src/addressbook/AddressBook.java b/apps/addressbook/java/src/addressbook/AddressBook.java index a46c256c80dd14d128bdefa61e4fa2f8e61f71ed..2694cae781f98288025a12a8ec57ac6c0c3d7ee9 100644 --- a/apps/addressbook/java/src/addressbook/AddressBook.java +++ b/apps/addressbook/java/src/addressbook/AddressBook.java @@ -94,20 +94,21 @@ public class AddressBook { * @param proxyPort port number of proxy */ public AddressBook(Subscription subscription, String proxyHost, int proxyPort) { + File tmp = new File(I2PAppContext.getGlobalContext().getTempDir(), "addressbook.tmp"); this.location = subscription.getLocation(); EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true, - proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, "addressbook.tmp", null, + proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null, subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null); if (get.fetch()) { subscription.setEtag(get.getETag()); subscription.setLastModified(get.getLastModified()); } try { - this.addresses = ConfigParser.parse(new File("addressbook.tmp")); + this.addresses = ConfigParser.parse(tmp); } catch (IOException exp) { this.addresses = new HashMap(); } - new File("addressbook.tmp").delete(); + tmp.delete(); } /** diff --git a/apps/addressbook/java/src/addressbook/Daemon.java b/apps/addressbook/java/src/addressbook/Daemon.java index a1b1ae18a3266ac05b4e755f6906255202c5f351..a8a9a2da6ed54e1ac9b43155857a6c7ba7d178fa 100644 --- a/apps/addressbook/java/src/addressbook/Daemon.java +++ b/apps/addressbook/java/src/addressbook/Daemon.java @@ -28,6 +28,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import net.i2p.I2PAppContext; + /** * Main class of addressbook. Performs updates, and runs the main loop. * @@ -125,11 +127,13 @@ public class Daemon { public void run(String[] args) { String settingsLocation = "config.txt"; - String home; + File homeFile; if (args.length > 0) { - home = args[0]; + homeFile = new File(args[0]); + if (!homeFile.isAbsolute()) + homeFile = new File(I2PAppContext.getGlobalContext().getRouterDir(), args[0]); } else { - home = "."; + homeFile = new File(System.getProperty("user.dir")); } Map defaultSettings = new HashMap(); @@ -145,7 +149,6 @@ public class Daemon { defaultSettings.put("last_modified", "last_modified"); defaultSettings.put("update_delay", "12"); - File homeFile = new File(home); if (!homeFile.exists()) { boolean created = homeFile.mkdirs(); if (created) @@ -169,7 +172,7 @@ public class Daemon { delay = 1; } - update(settings, home); + update(settings, homeFile.getAbsolutePath()); try { synchronized (this) { wait(delay * 60 * 60 * 1000); diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index b7e623060ce0a910577098207960a925da8a7f0b..1a43514ded82ec1bc8bf508456388735d67211c8 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -73,7 +73,7 @@ public class I2PSnarkUtil { // This is used for both announce replies and .torrent file downloads, // so it must be available even if not connected to I2CP. // so much for multiple instances - _tmpDir = new File("tmp", "i2psnark"); + _tmpDir = new File(ctx.getTempDir(), "i2psnark"); FileUtil.rmdir(_tmpDir, false); _tmpDir.mkdirs(); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index a45bf5161a76958a28a9834a456e1a068de35dc1..79ea62ebc4ffa0d1000acad3c4517bb160c96380 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -31,7 +31,7 @@ public class SnarkManager implements Snark.CompleteListener { /** map of (canonical) filename to Snark instance (unsynchronized) */ private Map _snarks; private Object _addSnarkLock; - private String _configFile = "i2psnark.config"; + private File _configFile; private Properties _config; private I2PAppContext _context; private Log _log; @@ -51,6 +51,7 @@ public class SnarkManager implements Snark.CompleteListener { public static final String PROP_META_PREFIX = "i2psnark.zmeta."; public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; + private static final String CONFIG_FILE = "i2psnark.config"; public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops public static final String DEFAULT_AUTO_START = "false"; public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix"; @@ -66,6 +67,9 @@ public class SnarkManager implements Snark.CompleteListener { _log = _context.logManager().getLog(SnarkManager.class); _messages = new ArrayList(16); _util = new I2PSnarkUtil(_context); + _configFile = new File(CONFIG_FILE); + if (!_configFile.isAbsolute()) + _configFile = new File(_context.getConfigDir(), CONFIG_FILE); loadConfig(null); } @@ -112,10 +116,11 @@ public class SnarkManager implements Snark.CompleteListener { } private int getStartupDelayMinutes() { return 3; } public File getDataDir() { - String dir = _config.getProperty(PROP_DIR); - if ( (dir == null) || (dir.trim().length() <= 0) ) - dir = "i2psnark"; - return new File(dir); + String dir = _config.getProperty(PROP_DIR, "i2psnark"); + File f = new File(dir); + if (!f.isAbsolute()) + f = new File(_context.getAppDir(), dir); + return f; } /** null to set initial defaults */ @@ -123,8 +128,10 @@ public class SnarkManager implements Snark.CompleteListener { if (_config == null) _config = new Properties(); if (filename != null) { - _configFile = filename; File cfg = new File(filename); + if (!cfg.isAbsolute()) + cfg = new File(_context.getConfigDir(), filename); + _configFile = cfg; if (cfg.exists()) { try { DataHelper.loadProps(_config, cfg); @@ -352,10 +359,10 @@ public class SnarkManager implements Snark.CompleteListener { public void saveConfig() { try { synchronized (_configFile) { - DataHelper.storeProps(_config, new File(_configFile)); + DataHelper.storeProps(_config, _configFile); } } catch (IOException ioe) { - addMessage("Unable to save the config to '" + _configFile + "'"); + addMessage("Unable to save the config to '" + _configFile.getAbsolutePath() + "'"); } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 3923484a80901882de9735eff80905314df77516..410e804d981347304f8faab3ec10ca6ca12a0475 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -173,6 +173,7 @@ public class I2PSnarkServlet extends HttpServlet { } else if ("Add torrent".equals(action)) { String newFile = req.getParameter("newFile"); String newURL = req.getParameter("newURL"); + // NOTE - newFile currently disabled in HTML form - see below File f = null; if ( (newFile != null) && (newFile.trim().length() > 0) ) f = new File(newFile.trim()); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 486bcdead5cb7098ac9725c607f5b9fd70e16b81..e4f8453bc7f5c69114b8443f6844a24a8e9f71c6 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -372,6 +372,8 @@ public class I2PTunnel implements Logging, EventDispatcher { } privKeyFile = new File(args[2]); + if (!privKeyFile.isAbsolute()) + privKeyFile = new File(_context.getAppDir(), args[2]); if (!privKeyFile.canRead()) { l.log("private key file does not exist"); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); @@ -419,6 +421,8 @@ public class I2PTunnel implements Logging, EventDispatcher { } privKeyFile = new File(args[2]); + if (!privKeyFile.isAbsolute()) + privKeyFile = new File(_context.getAppDir(), args[2]); if (!privKeyFile.canRead()) { l.log("private key file does not exist"); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); @@ -476,6 +480,8 @@ public class I2PTunnel implements Logging, EventDispatcher { String spoofedHost = args[2]; privKeyFile = new File(args[3]); + if (!privKeyFile.isAbsolute()) + privKeyFile = new File(_context.getAppDir(), args[3]); if (!privKeyFile.canRead()) { l.log("private key file does not exist"); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]); @@ -870,6 +876,8 @@ public class I2PTunnel implements Logging, EventDispatcher { } File privKeyFile = new File(args[1]); + if (!privKeyFile.isAbsolute()) + privKeyFile = new File(_context.getAppDir(), args[1]); if (!privKeyFile.canRead()) { l.log("private key file does not exist"); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 59971e8f3d7b1d429928ed52a29ecc982bb12ba7..79270303b00ec6b8090b1d87aa13e981c6550465 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -3,6 +3,7 @@ */ package net.i2p.i2ptunnel; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -106,6 +107,8 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna /** used to assign unique IDs to the threads / clients. no logic or functionality */ private static volatile long __clientId = 0; + private static final File _errorDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs"); + /** * @throws IllegalArgumentException if the I2PTunnel does not contain * valid config to contact the router @@ -261,9 +264,9 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna String str; byte[] header; if (usingWWWProxy) - str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); else - str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfh-header.ht")).getAbsolutePath(), 100, true); if (str != null) header = str.getBytes(); else @@ -357,9 +360,9 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna String str; byte[] header; if (usingWWWProxy) - str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); else - str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true); if (str != null) header = str.getBytes(); else diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 7e16114adccbaa7b6e0bb4de15533c86b70beea7..cab438991d926d6112439f5cc266c380961d534a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -4,6 +4,7 @@ package net.i2p.i2ptunnel; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -136,6 +137,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable /** used to assign unique IDs to the threads / clients. no logic or functionality */ private static volatile long __clientId = 0; + private static final File _errorDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs"); + + /** * @throws IllegalArgumentException if the I2PTunnel does not contain * valid config to contact the router @@ -372,7 +376,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable { String str; byte[] header; - str = FileUtil.readTextFile("docs/ahelper-conflict-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "ahelper-conflict-header.ht")).getAbsolutePath(), 100, true); if (str != null) header = str.getBytes(); else header = ERR_AHELPER_CONFLICT; @@ -558,13 +562,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable byte[] header; boolean showAddrHelper = false; if (usingWWWProxy) - str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); else if(ahelper != 0) - str = FileUtil.readTextFile("docs/dnfb-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfb-header.ht")).getAbsolutePath(), 100, true); else if (destination.length() == 60 && destination.endsWith(".b32.i2p")) - str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true); else { - str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfh-header.ht")).getAbsolutePath(), 100, true); showAddrHelper = true; } if (str != null) @@ -733,9 +737,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable String str; byte[] header; if (usingWWWProxy) - str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); else - str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true); + str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true); if (str != null) header = str.getBytes(); else diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 1f67783e9b6578db5d1d803639be99d04834f652..3dbcfea3067cd106ffb6172146ef2eb754aa230d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -72,6 +72,8 @@ public class TunnelController implements Logging { } File keyFile = new File(getPrivKeyFile()); + if (!keyFile.isAbsolute()) + keyFile = new File(I2PAppContext.getGlobalContext().getAppDir(), getPrivKeyFile()); if (keyFile.exists()) { //log("Not overwriting existing private keys in " + keyFile.getAbsolutePath()); return; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index 16f418be9ed12b3c0983427ebf796ee700320a54..a0b8ea3f7ffe25c30c9e4e4495c03239724323fe 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -270,9 +270,11 @@ public class TunnelControllerGroup { */ private Properties loadConfig(String configFile) { File cfgFile = new File(configFile); + if (!cfgFile.isAbsolute()) + cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), configFile); if (!cfgFile.exists()) { if (_log.shouldLog(Log.ERROR)) - _log.error("Unable to load the controllers from " + configFile); + _log.error("Unable to load the controllers from " + cfgFile.getAbsolutePath()); return null; } @@ -282,7 +284,7 @@ public class TunnelControllerGroup { return props; } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) - _log.error("Error reading the controllers from " + configFile, ioe); + _log.error("Error reading the controllers from " + cfgFile.getAbsolutePath(), ioe); return null; } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java index 0dc4d1e62bed23908afb0192b477afaa9f433c73..195889fad295a59d565fa55b59de01e8e0120f8d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java @@ -41,7 +41,7 @@ public class ConfigServiceHandler extends FormHandler { } public void run() { try { - Router.killKeys(); + ContextHelper.getContext(null).router().killKeys(); WrapperManager.signalStopped(_exitCode); } catch (Throwable t) { t.printStackTrace(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ContentHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ContentHelper.java index ce29250b9fbdad83dca8d8c825fe88baa3435cf8..721655a512085fe5f682db95af760d027965b6c4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ContentHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ContentHelper.java @@ -3,7 +3,6 @@ package net.i2p.router.web; import java.io.File; import java.util.Locale; -import net.i2p.router.RouterContext; import net.i2p.util.FileUtil; public class ContentHelper extends HelperBase { @@ -14,6 +13,9 @@ public class ContentHelper extends HelperBase { public ContentHelper() {} + /** + * Caution, use absolute paths only, do not assume files are in CWD + */ public void setPage(String page) { _page = page; } public void setStartAtBeginning(String moo) { _startAtBeginning = Boolean.valueOf(""+moo).booleanValue(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java index e1fce8f3ecc2ecc763823fd922ea4e2aca8a982a..a4896cdb80a64e82f55bde6166014bee97a0f0ab 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java @@ -1,66 +1,70 @@ package net.i2p.router.web; +import java.io.File; import java.util.List; -import net.i2p.router.RouterContext; import net.i2p.util.FileUtil; public class LogsHelper extends HelperBase { public LogsHelper() {} public String getLogs() { - List msgs = _context.logManager().getBuffer().getMostRecentMessages(); - StringBuffer buf = new StringBuffer(16*1024); - buf.append("<ul>"); - buf.append("<code>\n"); - for (int i = msgs.size(); i > 0; i--) { - String msg = (String)msgs.get(i - 1); - msg = msg.replaceAll("<","<"); - buf.append("<li>"); - buf.append(msg); - buf.append("</li>\n"); - } - buf.append("</code></ul>\n"); - - return buf.toString(); + return formatMessages(_context.logManager().getBuffer().getMostRecentMessages()); } public String getCriticalLogs() { - List msgs = _context.logManager().getBuffer().getMostRecentCriticalMessages(); - StringBuffer buf = new StringBuffer(16*1024); - buf.append("<ul>"); - buf.append("<code>\n"); - for (int i = msgs.size(); i > 0; i--) { - String msg = (String)msgs.get(i - 1); - msg = msg.replaceAll("<","<"); - buf.append("<li>"); - buf.append(msg); - buf.append("</li>\n"); - } - buf.append("</code></ul>\n"); - - return buf.toString(); + return formatMessages(_context.logManager().getBuffer().getMostRecentCriticalMessages()); } public String getServiceLogs() { - String str = FileUtil.readTextFile("wrapper.log", 250, false); + // look in new and old place + File f = new File(_context.getLogDir(), "wrapper.log"); + if (!f.exists()) + f = new File(_context.getBaseDir(), "wrapper.log"); + String str = FileUtil.readTextFile(f.getAbsolutePath(), 250, false); if (str == null) return ""; else { - str = str.replaceAll("<","<"); + str = str.replaceAll("<", "<").replaceAll(">", ">"); return "<pre>" + str + "</pre>"; } } + /***** unused public String getConnectionLogs() { - List msgs = _context.commSystem().getMostRecentErrorMessages(); + return formatMessages(_context.commSystem().getMostRecentErrorMessages()); + } + ******/ + + private String formatMessages(List msgs) { + boolean colorize = Boolean.valueOf(_context.getProperty("routerconsole.logs.color")).booleanValue(); StringBuffer buf = new StringBuffer(16*1024); buf.append("<ul>"); buf.append("<code>\n"); for (int i = msgs.size(); i > 0; i--) { String msg = (String)msgs.get(i - 1); buf.append("<li>"); - buf.append(msg); + if (colorize) { + String color; + // Homeland Security Advisory System + // http://www.dhs.gov/xinfoshare/programs/Copy_of_press_release_0046.shtm + // but pink instead of yellow for WARN + if (msg.contains("CRIT")) + color = "#cc0000"; + else if (msg.contains("ERROR")) + color = "#ff3300"; + else if (msg.contains("WARN")) + color = "#ff00cc"; + else if (msg.contains("INFO")) + color = "#000099"; + else + color = "#006600"; + buf.append("<font color=\"").append(color).append("\">"); + buf.append(msg.replaceAll("<", "<").replaceAll(">", ">")); + buf.append("</font>"); + } else { + buf.append(msg); + } buf.append("</li>\n"); } buf.append("</code></ul>\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java index 98fac325d191b9b73e9d1261b980c39affbdadb9..fd7662caf42e85961dcbf37524acc6b2300113d4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java @@ -27,6 +27,8 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { private long _lastUpdated; private String _updateVersion; private String _lastModified; + private File _newsFile; + private File _tempFile; private static NewsFetcher _instance; //public static final synchronized NewsFetcher getInstance() { return _instance; } public static final synchronized NewsFetcher getInstance(I2PAppContext ctx) { @@ -35,25 +37,26 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { _instance = new NewsFetcher(ctx); return _instance; } - + private static final String NEWS_FILE = "docs/news.xml"; - private static final String TEMP_NEWS_FILE = "docs/news.xml.temp"; + private static final String TEMP_NEWS_FILE = "news.xml.temp"; private NewsFetcher(I2PAppContext ctx) { _context = ctx; _log = ctx.logManager().getLog(NewsFetcher.class); _instance = this; _lastFetch = 0; + _newsFile = new File(_context.getBaseDir(), NEWS_FILE); + _tempFile = new File(_context.getTempDir(), TEMP_NEWS_FILE); updateLastFetched(); _lastUpdated = _lastFetch; _updateVersion = ""; } private void updateLastFetched() { - File news = new File(NEWS_FILE); - if (news.exists()) { + if (_newsFile.exists()) { if (_lastFetch == 0) - _lastFetch = news.lastModified(); + _lastFetch = _newsFile.lastModified(); } else _lastFetch = 0; } @@ -82,7 +85,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); if ("notify".equals(policy)) return false; - File zip = new File(Router.UPDATE_FILE); + File zip = new File(_context.getRouterDir(), Router.UPDATE_FILE); return !zip.exists(); } @@ -114,18 +117,17 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { boolean shouldProxy = Boolean.valueOf(_context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY)).booleanValue(); String proxyHost = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_HOST, ConfigUpdateHandler.DEFAULT_PROXY_HOST); String port = _context.getProperty(ConfigUpdateHandler.PROP_PROXY_PORT, ConfigUpdateHandler.DEFAULT_PROXY_PORT); - File tempFile = new File(TEMP_NEWS_FILE); - if (tempFile.exists()) - tempFile.delete(); + if (_tempFile.exists()) + _tempFile.delete(); int proxyPort = -1; try { proxyPort = Integer.parseInt(port); EepGet get = null; if (shouldProxy) - get = new EepGet(_context, true, proxyHost, proxyPort, 2, TEMP_NEWS_FILE, newsURL, true, null, _lastModified); + get = new EepGet(_context, true, proxyHost, proxyPort, 2, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified); else - get = new EepGet(_context, false, null, 0, 0, TEMP_NEWS_FILE, newsURL, true, null, _lastModified); + get = new EepGet(_context, false, null, 0, 0, _tempFile.getAbsolutePath(), newsURL, true, null, _lastModified); get.addStatusListener(this); if (get.fetch()) _lastModified = get.getLastModified(); @@ -138,11 +140,10 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { private static final String VERSION_PREFIX = "version=\""; private void checkForUpdates() { _updateAvailable = false; - File news = new File(NEWS_FILE); - if ( (!news.exists()) || (news.length() <= 0) ) return; + if ( (!_newsFile.exists()) || (_newsFile.length() <= 0) ) return; FileInputStream in = null; try { - in = new FileInputStream(news); + in = new FileInputStream(_newsFile); StringBuffer buf = new StringBuffer(128); while (DataHelper.readLine(in, buf)) { int index = buf.indexOf(VERSION_PREFIX); @@ -220,13 +221,12 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { if (_log.shouldLog(Log.INFO)) _log.info("News fetched from " + url + " with " + (alreadyTransferred+bytesTransferred)); - File temp = new File(TEMP_NEWS_FILE); long now = _context.clock().now(); - if (temp.exists()) { - boolean copied = FileUtil.copy(TEMP_NEWS_FILE, NEWS_FILE, true); + if (_tempFile.exists()) { + boolean copied = FileUtil.copy(_tempFile.getAbsolutePath(), _newsFile.getAbsolutePath(), true); if (copied) { _lastUpdated = now; - temp.delete(); + _tempFile.delete(); checkForUpdates(); } else { if (_log.shouldLog(Log.ERROR)) @@ -242,8 +242,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) { if (_log.shouldLog(Log.WARN)) _log.warn("Failed to fetch the news from " + url); - File temp = new File(TEMP_NEWS_FILE); - temp.delete(); + _tempFile.delete(); } public void headerReceived(String url, int attemptNum, String key, String val) {} public void attempting(String url) {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java index e701ede9954e8925d1f2018014988859e3ad0fcc..c11c6150c28536ae829f88aff342483679ab8009 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ReseedHandler.java @@ -256,7 +256,7 @@ public class ReseedHandler { private void writeSeed(String name, byte data[]) throws Exception { String dirName = "netDb"; // _context.getProperty("router.networkDatabase.dbDir", "netDb"); - File netDbDir = new File(dirName); + File netDbDir = new File(_context.getRouterDir(), dirName); if (!netDbDir.exists()) { boolean ok = netDbDir.mkdirs(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index 862902b1f811a6eef2eed65cdec5319dcf4a00cb..f58aeb3082c53bd8c16e68769fb13f6fd38789b0 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -59,7 +59,7 @@ public class RouterConsoleRunner { } public void startConsole() { - File workDir = new File("work"); + File workDir = new File(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work"); boolean workDirRemoved = FileUtil.rmdir(workDir, false); if (!workDirRemoved) System.err.println("ERROR: Unable to remove Jetty temporary work directory"); @@ -95,8 +95,11 @@ public class RouterConsoleRunner { } _server.setRootWebApp(ROUTERCONSOLE); WebApplicationContext wac = _server.addWebApplication("/", _webAppsDir + ROUTERCONSOLE + ".war"); + File tmpdir = new File(workDir, ROUTERCONSOLE + "-" + _listenPort); + tmpdir.mkdir(); + wac.setTempDirectory(tmpdir); initialize(wac); - File dir = new File(_webAppsDir); + File dir = new File(I2PAppContext.getGlobalContext().getBaseDir(), _webAppsDir); String fileNames[] = dir.list(WarFilenameFilter.instance()); if (fileNames != null) { for (int i = 0; i < fileNames.length; i++) { @@ -106,6 +109,9 @@ public class RouterConsoleRunner { if (! "false".equals(enabled)) { String path = new File(dir, fileNames[i]).getCanonicalPath(); wac = _server.addWebApplication("/"+ appName, path); + tmpdir = new File(workDir, appName + "-" + _listenPort); + tmpdir.mkdir(); + wac.setTempDirectory(tmpdir); initialize(wac); if (enabled == null) { // do this so configclients.jsp knows about all apps from reading the config @@ -144,10 +150,10 @@ public class RouterConsoleRunner { // don't have an installation directory that they can put the flag in yet. File noReseedFile = new File(new File(System.getProperty("user.home")), ".i2pnoreseed"); File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p"); - File noReseedFileAlt2 = new File(".i2pnoreseed"); - File noReseedFileAlt3 = new File("noreseed.i2p"); + File noReseedFileAlt2 = new File(I2PAppContext.getGlobalContext().getConfigDir(), ".i2pnoreseed"); + File noReseedFileAlt3 = new File(I2PAppContext.getGlobalContext().getConfigDir(), "noreseed.i2p"); if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) { - File netDb = new File("netDb"); + File netDb = new File(I2PAppContext.getGlobalContext().getRouterDir(), "netDb"); // sure, some of them could be "my.info" or various leaseSet- files, but chances are, // if someone has those files, they've already been seeded (at least enough to let them // get i2p started - they can reseed later in the web console) @@ -216,7 +222,7 @@ public class RouterConsoleRunner { Properties rv = new Properties(); // String webappConfigFile = ctx.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME); String webappConfigFile = DEFAULT_WEBAPP_CONFIG_FILENAME; - File cfgFile = new File(webappConfigFile); + File cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), webappConfigFile); try { DataHelper.loadProps(rv, cfgFile); @@ -230,7 +236,7 @@ public class RouterConsoleRunner { public static void storeWebAppProperties(Properties props) { // String webappConfigFile = ctx.getProperty(PROP_WEBAPP_CONFIG_FILENAME, DEFAULT_WEBAPP_CONFIG_FILENAME); String webappConfigFile = DEFAULT_WEBAPP_CONFIG_FILENAME; - File cfgFile = new File(webappConfigFile); + File cfgFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), webappConfigFile); try { DataHelper.storeProps(props, cfgFile); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index 35edadfb6b6190fd4e500308bc38a1ddaace520c..267fe5a07c74551dd789b7b5ec6fb957e76e139d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -31,6 +31,7 @@ public class UpdateHandler { protected RouterContext _context; protected Log _log; protected DecimalFormat _pct = new DecimalFormat("00.0%"); + protected String _updateFile; protected static final String SIGNED_UPDATE_FILE = "i2pupdate.sud"; protected static final String PROP_UPDATE_IN_PROGRESS = "net.i2p.router.web.UpdateHandler.updateInProgress"; @@ -41,6 +42,7 @@ public class UpdateHandler { public UpdateHandler(RouterContext ctx) { _context = ctx; _log = ctx.logManager().getLog(UpdateHandler.class); + _updateFile = (new File(ctx.getRouterDir(), SIGNED_UPDATE_FILE)).getAbsolutePath(); } /** @@ -137,9 +139,9 @@ public class UpdateHandler { try { EepGet get = null; if (shouldProxy) - get = new EepGet(_context, proxyHost, proxyPort, 20, SIGNED_UPDATE_FILE, updateURL, false); + get = new EepGet(_context, proxyHost, proxyPort, 20, _updateFile, updateURL, false); else - get = new EepGet(_context, 1, SIGNED_UPDATE_FILE, updateURL, false); + get = new EepGet(_context, 1, _updateFile, updateURL, false); get.addStatusListener(UpdateRunner.this); get.fetch(); } catch (Throwable t) { @@ -167,8 +169,9 @@ public class UpdateHandler { public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) { _status = "<b>Update downloaded</b>"; TrustedUpdate up = new TrustedUpdate(_context); - String err = up.migrateVerified(RouterVersion.VERSION, SIGNED_UPDATE_FILE, Router.UPDATE_FILE); - File f = new File(SIGNED_UPDATE_FILE); + File f = new File(_updateFile); + File to = new File(_context.getBaseDir(), Router.UPDATE_FILE); + String err = up.migrateVerified(RouterVersion.VERSION, f, to); f.delete(); if (err == null) { String policy = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_POLICY); diff --git a/apps/routerconsole/jsp/flags.jsp b/apps/routerconsole/jsp/flags.jsp index 38d068d592bcfc817dcf032a7b04166c38a36fe8..c990ba27a3a87225b2f44c2a3845d35e97906edc 100644 --- a/apps/routerconsole/jsp/flags.jsp +++ b/apps/routerconsole/jsp/flags.jsp @@ -15,8 +15,11 @@ if (c != null && c.length() > 0) { java.io.OutputStream cout = response.getOutputStream(); response.setContentType("image/png"); response.setHeader("Cache-Control", "max-age=86400"); // cache for a day + String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath(); + String file = "docs" + java.io.File.separatorChar + "icons" + java.io.File.separatorChar + + "flags" + java.io.File.separatorChar + c + ".png"; try { - net.i2p.util.FileUtil.readFile(c + ".png", "docs/icons/flags", cout); + net.i2p.util.FileUtil.readFile(file, base, cout); rendered = true; } catch (java.io.IOException ioe) {} if (rendered) diff --git a/apps/routerconsole/jsp/viewtheme.jsp b/apps/routerconsole/jsp/viewtheme.jsp index 05ccfecbf91a6380acf27fa651f158eb481ba6e5..5785195c2933e6c9dda645d9ad7f1d90a691004d 100644 --- a/apps/routerconsole/jsp/viewtheme.jsp +++ b/apps/routerconsole/jsp/viewtheme.jsp @@ -1,4 +1,4 @@ -<% +% /* * USE CAUTION WHEN EDITING * Trailing whitespace OR NEWLINE on the last line will cause @@ -16,5 +16,7 @@ if (uri.endsWith(".css")) { response.setContentType("image/jpeg"); } -net.i2p.util.FileUtil.readFile(uri, "./docs", response.getOutputStream()); +String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath() + + java.io.File.separatorChar + "docs"; +net.i2p.util.FileUtil.readFile(uri, base, response.getOutputStream()); %> \ No newline at end of file diff --git a/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java b/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java index 15a2204f8ebf5bcfc81d55e95dd167fa038adbdb..8cddafdc42c624e030b16e4916c0eb3d5def1a7d 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/ConfigBean.java @@ -33,12 +33,16 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.Serializable; +import net.i2p.I2PAppContext; + public class ConfigBean implements Serializable { /* * as this is not provided as constant in addressbook, we define it here */ - public static final String addressbookPrefix = "addressbook/"; + public static final String addressbookPrefix = + (new File(I2PAppContext.getGlobalContext().getRouterDir(), "addressbook")).getAbsolutePath() + + File.separatorChar; public static final String configFileName = addressbookPrefix + "config.txt"; private String action, config; diff --git a/apps/susimail/build.xml b/apps/susimail/build.xml index 886f9471f6425982bb3f71a2747118fa02c0ac31..fb437161447213e59f855104977da02a648f7615 100644 --- a/apps/susimail/build.xml +++ b/apps/susimail/build.xml @@ -15,6 +15,7 @@ <classpath> <pathelement location="../jetty/jettylib/javax.servlet.jar" /> <pathelement location="../jetty/jettylib/org.mortbay.jetty.jar" /> + <pathelement location="../../core/java/build/i2p.jar" /> </classpath> </javac> </target> diff --git a/apps/susimail/src/src/i2p/susi/util/Config.java b/apps/susimail/src/src/i2p/susi/util/Config.java index 219ce71f3420839788b1716e3e377ed59f721183..723c56b992992be84f1a5625967677dc2ae95b86 100644 --- a/apps/susimail/src/src/i2p/susi/util/Config.java +++ b/apps/susimail/src/src/i2p/susi/util/Config.java @@ -25,10 +25,13 @@ package i2p.susi.util; import i2p.susi.debug.Debug; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Properties; +import net.i2p.I2PAppContext; + /** * @author susi */ @@ -81,7 +84,8 @@ public class Config { } FileInputStream fis = null; try { - fis = new FileInputStream( "susimail.config" ); + File cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), "susimail.config"); + fis = new FileInputStream(cfg); config.load( fis ); } catch (Exception e) { Debug.debug( Debug.DEBUG, "Could not open susimail.config, reason: " + e.getMessage() ); diff --git a/core/java/src/freenet/support/CPUInformation/CPUID.java b/core/java/src/freenet/support/CPUInformation/CPUID.java index 1d5c848828c4ce670dbe56ff7471d1a8d50b2c5a..58469c6d749bb889737b9c3b9d5992697ea9b597 100644 --- a/core/java/src/freenet/support/CPUInformation/CPUID.java +++ b/core/java/src/freenet/support/CPUInformation/CPUID.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import net.i2p.I2PAppContext; + /** * @author Iakin * A class for retrieveing details about the CPU using the CPUID assembly instruction. @@ -503,9 +505,10 @@ public class CPUID { FileOutputStream fos = null; try { InputStream libStream = resource.openStream(); - outFile = new File(libPrefix + "jcpuid" + libSuffix); + outFile = new File(I2PAppContext.getGlobalContext().getBaseDir(), libPrefix + "jcpuid" + libSuffix); fos = new FileOutputStream(outFile); - byte buf[] = new byte[4096*1024]; + // wtf this was 4096*1024 which is really excessive for a roughly 4KB file + byte buf[] = new byte[4096]; while (true) { int read = libStream.read(buf); if (read < 0) break; diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 3f44146b438c79a76f1f48cc1470cf4c20e315a7..56f774071c26f8a30987a5cc9feffd095765cc36 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -1,5 +1,6 @@ package net.i2p; +import java.io.File; import java.util.HashSet; import java.util.Properties; import java.util.Set; @@ -20,10 +21,12 @@ import net.i2p.crypto.KeyGenerator; import net.i2p.crypto.SHA256Generator; import net.i2p.crypto.SessionKeyManager; import net.i2p.crypto.TransientSessionKeyManager; + import net.i2p.data.DataHelper; import net.i2p.data.RoutingKeyGenerator; import net.i2p.stat.StatManager; import net.i2p.util.Clock; import net.i2p.util.ConcurrentHashSet; +import net.i2p.util.FileUtil; import net.i2p.util.FortunaRandomSource; import net.i2p.util.KeyRing; import net.i2p.util.LogManager; @@ -96,6 +99,13 @@ public class I2PAppContext { private volatile boolean _keyGeneratorInitialized; protected volatile boolean _keyRingInitialized; // used in RouterContext private Set<Runnable> _shutdownTasks; + private File _baseDir; + private File _configDir; + private File _routerDir; + private File _pidDir; + private File _logDir; + private File _appDir; + private File _tmpDir; /** @@ -155,8 +165,148 @@ public class I2PAppContext { _logManagerInitialized = false; _keyRingInitialized = false; _shutdownTasks = new ConcurrentHashSet(0); + initializeDirs(); } + /** + * Directories. These are all set at instantiation and will not be changed by + * subsequent property changes. + * All properties, if set, should be absolute paths. + * + * Name Property Method Files + * ----- -------- ----- ----- + * Base i2p.dir.base getBaseDir() lib/, webapps/, docs/, geoip/, licenses/, ... + * Temp i2p.dir.temp getTempDir() Temporary files + * Config i2p.dir.config getConfigDir() *.config, hosts.txt, addressbook/, ... + * + * (the following all default to the same as Config) + * + * Router i2p.dir.router getRouterDir() netDb/, peerProfiles/, router.*, keyBackup/, ... + * Log i2p.dir.log getLogDir() wrapper.log*, logs/ + * PID i2p.dir.pid getPIDDir() wrapper *.pid files, router.ping + * App i2p.dir.app getAppDir() eepsite/, ... + * + * Note that we can't control where the wrapper puts its files. + * + * The app dir is where all data files should be. Apps should always read and write files here, + * using a constructor such as: + * + * String path = mypath; + * File f = new File(path); + * if (!f.isAbsolute()) + * f = new File(_context.geAppDir(), path); + * + * and never attempt to access files in the CWD using + * + * File f = new File("foo"); + * + * An app should assume the CWD is not writable. + * + * Here in I2PAppContext, all the dirs default to CWD. + * However these will be different in RouterContext, as Router.java will set + * the properties in the RouterContext constructor. + * + * Apps should never need to access the base dir, which is the location of the base I2P install. + * However this is provided for the router's use, and for backward compatibility should an app + * need to look there as well. + * + * All dirs except the base are created if they don't exist, but the creation will fail silently. + */ + private void initializeDirs() { + String s = getProperty("i2p.dir.base", System.getProperty("user.dir")); + _baseDir = new File(s); + // config defaults to base + s = getProperty("i2p.dir.config"); + if (s != null) { + _configDir = new File(s); + if (!_configDir.exists()) + _configDir.mkdir(); + } else { + _configDir = _baseDir; + } + _configDir = new File(s); + // router defaults to config + s = getProperty("i2p.dir.router"); + if (s != null) { + _routerDir = new File(s); + if (!_routerDir.exists()) + _routerDir.mkdir(); + } else { + _routerDir = _configDir; + } + // these all default to router + s = getProperty("i2p.dir.pid"); + if (s != null) { + _pidDir = new File(s); + if (!_pidDir.exists()) + _pidDir.mkdir(); + } else { + _pidDir = _routerDir; + } + s = getProperty("i2p.dir.log"); + if (s != null) { + _logDir = new File(s); + if (!_logDir.exists()) + _logDir.mkdir(); + } else { + _logDir = _routerDir; + } + s = getProperty("i2p.dir.app"); + if (s != null) { + _appDir = new File(s); + if (!_appDir.exists()) + _appDir.mkdir(); + } else { + _appDir = _routerDir; + } + // comment these out later, don't want user names in the wrapper logs + System.err.println("Base directory: " + _baseDir.getAbsolutePath()); + System.err.println("Config directory: " + _configDir.getAbsolutePath()); + System.err.println("Router directory: " + _routerDir.getAbsolutePath()); + System.err.println("App directory: " + _appDir.getAbsolutePath()); + System.err.println("Log directory: " + _logDir.getAbsolutePath()); + System.err.println("PID directory: " + _pidDir.getAbsolutePath()); + System.err.println("Temp directory: " + getTempDir().getAbsolutePath()); + } + + public File getBaseDir() { return _baseDir; } + public File getConfigDir() { return _configDir; } + public File getRouterDir() { return _routerDir; } + public File getPIDDir() { return _pidDir; } + public File getLogDir() { return _logDir; } + public File getAppDir() { return _appDir; } + public File getTempDir() { + // fixme don't synchronize every time + synchronized (this) { + if (_tmpDir == null) { + String d = getProperty("i2p.dir.temp", System.getProperty("java.io.tmpdir")); + // our random() probably isn't warmed up yet + String f = "i2p-" + (new java.util.Random()).nextInt() + ".tmp"; + _tmpDir = new File(d, f); + if (_tmpDir.exists()) { + // good or bad ? + } else if (_tmpDir.mkdir()) { + _tmpDir.deleteOnExit(); + } else { + System.err.println("Could not create temp dir " + _tmpDir.getAbsolutePath()); + _tmpDir = new File(_routerDir, "tmp"); + _tmpDir.mkdir(); + } + } + } + return _tmpDir; + } + + /** don't rely on deleteOnExit() */ + public void deleteTempDir() { + synchronized (this) { + if (_tmpDir != null) { + FileUtil.rmdir(_tmpDir, false); + _tmpDir = null; + } + } + } + /** * Access the configuration attributes of this context, using properties * provided during the context construction, or falling back on diff --git a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java index 054bd9d8f10c03eff4d0df7bc6f4ecba58a5dc0b..f89d56d09d4153cf05c730b7a844db293200466c 100644 --- a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java +++ b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java @@ -89,7 +89,7 @@ public class HostsTxtNamingService extends NamingService { String hostsfile = (String)filenames.get(i); Properties hosts = new Properties(); try { - File f = new File(hostsfile); + File f = new File(_context.getRouterDir(), hostsfile); if ( (f.exists()) && (f.canRead()) ) { DataHelper.loadProps(hosts, f, true); @@ -119,7 +119,7 @@ public class HostsTxtNamingService extends NamingService { String hostsfile = (String)filenames.get(i); Properties hosts = new Properties(); try { - File f = new File(hostsfile); + File f = new File(_context.getRouterDir(), hostsfile); if ( (f.exists()) && (f.canRead()) ) { DataHelper.loadProps(hosts, f, true); Set keyset = hosts.keySet(); @@ -145,7 +145,7 @@ public class HostsTxtNamingService extends NamingService { String hostsfile = (String)filenames.get(i); Properties hosts = new Properties(); try { - File f = new File(hostsfile); + File f = new File(_context.getRouterDir(), hostsfile); if ( (f.exists()) && (f.canRead()) ) { DataHelper.loadProps(hosts, f, true); Set keyset = hosts.keySet(); diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java index 06e37544b37242e306465ed76bcf9091b92acfd7..6130fa78d59cc50424dbcce460e686376d55c4a4 100644 --- a/core/java/src/net/i2p/crypto/TrustedUpdate.java +++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java @@ -1,6 +1,7 @@ package net.i2p.crypto; import java.io.ByteArrayInputStream; +import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @@ -276,7 +277,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= } private static final void showVersionCLI(String signedFile) { - String versionString = new TrustedUpdate().getVersionString(signedFile); + String versionString = new TrustedUpdate().getVersionString(new File(signedFile)); if (versionString == "") System.out.println("No version string found in file '" + signedFile + "'"); @@ -294,7 +295,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= } private static final void verifySigCLI(String signedFile) { - boolean isValidSignature = new TrustedUpdate().verify(signedFile); + boolean isValidSignature = new TrustedUpdate().verify(new File(signedFile)); if (isValidSignature) System.out.println("Signature VALID"); @@ -303,7 +304,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= } private static final void verifyUpdateCLI(String signedFile) { - boolean isUpdate = new TrustedUpdate().isUpdatedVersion(CoreVersion.VERSION, signedFile); + boolean isUpdate = new TrustedUpdate().isUpdatedVersion(CoreVersion.VERSION, new File(signedFile)); if (isUpdate) System.out.println("File version is newer than current version."); @@ -347,7 +348,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= * @return The version string read, or an empty string if no version string * is present. */ - public String getVersionString(String signedFile) { + public String getVersionString(File signedFile) { FileInputStream fileInputStream = null; try { @@ -396,9 +397,9 @@ D8usM7Dxp5yrDrCYZ5AIijc= * @return <code>true</code> if the signed update file's version is newer * than the current version, otherwise <code>false</code>. */ - public boolean isUpdatedVersion(String currentVersion, String signedFile) { + public boolean isUpdatedVersion(String currentVersion, File signedFile) { _newVersion = getVersionString(signedFile); - return needsUpdate(currentVersion, getVersionString(signedFile)); + return needsUpdate(currentVersion, _newVersion); } /** @@ -413,7 +414,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= * @return <code>null</code> if the signature and version were valid and the * data was moved, and an error <code>String</code> otherwise. */ - public String migrateVerified(String currentVersion, String signedFile, String outputFile) { + public String migrateVerified(String currentVersion, File signedFile, File outputFile) { if (!isUpdatedVersion(currentVersion, signedFile)) return "Downloaded version is not greater than current version"; @@ -606,7 +607,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= * @return <code>true</code> if the file has a valid signature, otherwise * <code>false</code>. */ - public boolean verify(String signedFile) { + public boolean verify(File signedFile) { for (int i = 0; i < _trustedKeys.size(); i++) { SigningPublicKey signingPublicKey = new SigningPublicKey(); @@ -662,7 +663,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= } } - return verify(signedFile, signingPublicKey); + return verify(new File(signedFile), signingPublicKey); } /** @@ -676,7 +677,7 @@ D8usM7Dxp5yrDrCYZ5AIijc= * @return <code>true</code> if the file has a valid signature, otherwise * <code>false</code>. */ - public boolean verify(String signedFile, SigningPublicKey signingPublicKey) { + public boolean verify(File signedFile, SigningPublicKey signingPublicKey) { FileInputStream fileInputStream = null; try { diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index b5d68ee41194f8eb27bb5c7926ad461517281985..497733cc4e348aedbe250da35b4d5118eb8b4549 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -109,6 +109,10 @@ public class PrivateKeyFile { this(new File(file), I2PClientFactory.createClient()); } + public PrivateKeyFile(File file) { + this(file, I2PClientFactory.createClient()); + } + public PrivateKeyFile(File file, I2PClient client) { this.file = file; this.client = client; diff --git a/core/java/src/net/i2p/stat/BufferedStatLog.java b/core/java/src/net/i2p/stat/BufferedStatLog.java index 7fed2d09042bc40fb321cc9d758e9b5a2f4d457d..ca016622fa59921d846f16e71cfa4c120a8cb69e 100644 --- a/core/java/src/net/i2p/stat/BufferedStatLog.java +++ b/core/java/src/net/i2p/stat/BufferedStatLog.java @@ -1,6 +1,7 @@ package net.i2p.stat; import java.io.BufferedWriter; +import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.text.SimpleDateFormat; @@ -109,6 +110,9 @@ public class BufferedStatLog implements StatLog { String filename = _context.getProperty(StatManager.PROP_STAT_FILE); if (filename == null) filename = StatManager.DEFAULT_STAT_FILE; + File foo = new File(filename); + if (!foo.isAbsolute()) + filename = (new File(_context.getRouterDir(), filename)).getAbsolutePath(); if ( (_outFile != null) && (_outFile.equals(filename)) ) { // noop } else { diff --git a/core/java/src/net/i2p/util/FileUtil.java b/core/java/src/net/i2p/util/FileUtil.java index 677c500866edcf79474a3eb62267d177bb888af8..05346ccfe2a0d8785596b35a15d541560304efc9 100644 --- a/core/java/src/net/i2p/util/FileUtil.java +++ b/core/java/src/net/i2p/util/FileUtil.java @@ -18,6 +18,12 @@ import java.util.zip.ZipFile; /** * General helper methods for messing with files * + * These are static methods that do NOT convert arguments + * to absolute paths for a particular context and directtory. + * + * Callers should ALWAYS provide absolute paths as arguments, + * and should NEVER assume files are in the current working directory. + * */ public class FileUtil { /** diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java index 1f957515ca3a0722772a66c0e320e323c2d89127..c07445d9b5382948773793a1665312daf3db2c17 100644 --- a/core/java/src/net/i2p/util/LogManager.java +++ b/core/java/src/net/i2p/util/LogManager.java @@ -67,8 +67,8 @@ public class LogManager { /** when was the config file last read (or -1 if never) */ private long _configLastRead; - /** filename of the config file */ - private String _location; + /** the config file */ + private File _locationFile; /** Ordered list of LogRecord elements that have not been written out yet */ private List _records; /** List of explicit overrides of log levels (LogLimit objects) */ @@ -115,11 +115,11 @@ public class LogManager { _logs = new HashMap(128); _defaultLimit = Log.ERROR; _configLastRead = 0; - _location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT); _context = context; _log = getLog(LogManager.class); + String location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT); + setConfig(location); _consoleBuffer = new LogConsoleBuffer(context); - loadConfig(); _writer = new LogWriter(this); Thread t = new I2PThread(_writer); t.setName("LogWriter"); @@ -196,8 +196,9 @@ public class LogManager { } public void setConfig(String filename) { - _log.debug("Config filename set to " + filename); - _location = filename; + _locationFile = new File(filename); + if (!_locationFile.isAbsolute()) + _locationFile = new File(_context.getConfigDir(), filename); loadConfig(); } @@ -232,20 +233,12 @@ public class LogManager { loadConfig(); } - /// - /// - - // - // - // - private void loadConfig() { - File cfgFile = new File(_location); + File cfgFile = _locationFile; if (!cfgFile.exists()) { if (!_alreadyNoticedMissingConfig) { if (_log.shouldLog(Log.WARN)) - _log.warn("Log file " + _location + " does not exist"); - //System.err.println("Log file " + _location + " does not exist"); + _log.warn("Log file " + _locationFile.getAbsolutePath() + " does not exist"); _alreadyNoticedMissingConfig = true; } parseConfig(new Properties()); @@ -262,9 +255,6 @@ public class LogManager { return; } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Loading config from " + _location); - Properties p = new Properties(); FileInputStream fis = null; try { @@ -272,7 +262,7 @@ public class LogManager { p.load(fis); _configLastRead = _context.clock().now(); } catch (IOException ioe) { - System.err.println("Error loading logger config from " + new File(_location).getAbsolutePath()); + System.err.println("Error loading logger config from " + cfgFile.getAbsolutePath()); } finally { if (fis != null) try { fis.close(); @@ -540,7 +530,7 @@ public class LogManager { String config = createConfig(); FileOutputStream fos = null; try { - fos = new FileOutputStream(_location); + fos = new FileOutputStream(_locationFile); fos.write(config.getBytes()); return true; } catch (IOException ioe) { diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java index 29fcff7ccd962fc93bff0b10c76609eec337942d..c9f2cb7562ec6f0d405c7423deae786d8bb41063 100644 --- a/core/java/src/net/i2p/util/LogWriter.java +++ b/core/java/src/net/i2p/util/LogWriter.java @@ -15,6 +15,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.List; +import net.i2p.I2PAppContext; + /** * Log writer thread that pulls log records from the LogManager, writes them to * the current logfile, and rotates the logs as necessary. This also periodically @@ -22,6 +24,7 @@ import java.util.List; * */ class LogWriter implements Runnable { + /** every 10 seconds? why? Just have the gui force a reread after a change?? */ private final static long CONFIG_READ_ITERVAL = 10 * 1000; private long _lastReadConfig = 0; private long _numBytesInCurrentFile = 0; @@ -38,6 +41,7 @@ class LogWriter implements Runnable { public LogWriter(LogManager manager) { _manager = manager; + _lastReadConfig = Clock.getInstance().now(); } public void stopWriting() { @@ -168,15 +172,21 @@ class LogWriter implements Runnable { * */ private File getNextFile(String pattern) { - File f = null; + File f = new File(pattern); + File base = null; + if (!f.isAbsolute()) + base = I2PAppContext.getGlobalContext().getLogDir(); if ( (pattern.indexOf('#') < 0) && (pattern.indexOf('@') <= 0) ) { - return new File(pattern); + if (base != null) + return new File(base, pattern); + else + return f; } int max = _manager.getRotationLimit(); if (_rotationNum == -1) { - return getFirstFile(pattern, max); + return getFirstFile(base, pattern, max); } // we're in rotation, just go to the next @@ -190,9 +200,13 @@ class LogWriter implements Runnable { * Retrieve the first file, updating the rotation number accordingly * */ - private File getFirstFile(String pattern, int max) { + private File getFirstFile(File base, String pattern, int max) { for (int i = 0; i < max; i++) { - File f = new File(replace(pattern, i)); + File f; + if (base != null) + f = new File(base, replace(pattern, i)); + else + f = new File(replace(pattern, i)); if (!f.exists()) { _rotationNum = i; return f; @@ -202,7 +216,11 @@ class LogWriter implements Runnable { // all exist, pick the oldest to replace File oldest = null; for (int i = 0; i < max; i++) { - File f = new File(replace(pattern, i)); + File f; + if (base != null) + f = new File(base, replace(pattern, i)); + else + f = new File(replace(pattern, i)); if (oldest == null) { oldest = f; } else { diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java index a6d7e97925e9e4e3151f8a671a393b64821453c5..bafaa5e5c9dae80e96da8ce967cbcec1bf9db7c0 100644 --- a/core/java/src/net/i2p/util/NativeBigInteger.java +++ b/core/java/src/net/i2p/util/NativeBigInteger.java @@ -540,9 +540,10 @@ public class NativeBigInteger extends BigInteger { FileOutputStream fos = null; try { InputStream libStream = resource.openStream(); - outFile = new File(_libPrefix + "jbigi" + _libSuffix); + outFile = new File(I2PAppContext.getGlobalContext().getBaseDir(), _libPrefix + "jbigi" + _libSuffix); fos = new FileOutputStream(outFile); - byte buf[] = new byte[4096*1024]; + // wtf this was 4096*1024 which is really excessive for a roughly 50KB file + byte buf[] = new byte[4096]; while (true) { int read = libStream.read(buf); if (read < 0) break; diff --git a/core/java/src/net/i2p/util/RandomSource.java b/core/java/src/net/i2p/util/RandomSource.java index 550b37b8d2f092df5dc74c6494e63bf7f21245c6..c6ac80a65ca63f6410b178098d2933928e2c3a7a 100644 --- a/core/java/src/net/i2p/util/RandomSource.java +++ b/core/java/src/net/i2p/util/RandomSource.java @@ -142,7 +142,7 @@ public class RandomSource extends SecureRandom implements EntropyHarvester { private static final String SEEDFILE = "prngseed.rnd"; public static final void writeSeed(byte buf[]) { - File f = new File(SEEDFILE); + File f = new File(I2PAppContext.getGlobalContext().getConfigDir(), SEEDFILE); FileOutputStream fos = null; try { fos = new FileOutputStream(f); @@ -164,7 +164,7 @@ public class RandomSource extends SecureRandom implements EntropyHarvester { } private static final boolean seedFromFile(String filename, byte buf[]) { - File f = new File(filename); + File f = new File(I2PAppContext.getGlobalContext().getConfigDir(), filename); if (f.exists()) { FileInputStream fis = null; try { diff --git a/core/java/src/net/i2p/util/WorkingDir.java b/core/java/src/net/i2p/util/WorkingDir.java new file mode 100644 index 0000000000000000000000000000000000000000..4e47f6458c3c6b12ee9d9b07edf420b0c9378706 --- /dev/null +++ b/core/java/src/net/i2p/util/WorkingDir.java @@ -0,0 +1,481 @@ +package net.i2p.util; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.Properties; + +import net.i2p.data.DataHelper; + +/** + * Get a working directory for i2p. + * + * For the location, first try the system property i2p.dir.config + * Next try $HOME/.i2p on linux or %APPDATA%\I2P on Windows. + * + * If the dir exists, return it. + * Otherwise, attempt to create it, and copy files from the base directory. + * To successfully copy, the base install dir must be the system property i2p.dir.base + * or else must be in $CWD. + * + * If I2P was run from the install directory in the past, + * and migrateOldData = true, copy the + * necessary data files (except i2psnark/) over to the new working directory. + * + * Otherwise, just copy over a limited number of files over. + * + * Do not ever copy or move the old i2psnark/ directory, as if the + * old and new locations are on different file systems, this could + * be quite slow. + * + * Modify some files while copying, see methods below. + * + * After migration, the router will run using the new directory. + * The wrapper, however, must be stopped and restarted from the new script - until then, + * it will continue to write to wrapper.log* in the old directory. + * + * @param whether to copy all data over from an existing install + */ +public class WorkingDir { + + private final static String PROP_BASE_DIR = "i2p.dir.base"; + private final static String PROP_WORKING_DIR = "i2p.dir.config"; + private final static String WORKING_DIR_DEFAULT_WINDOWS = "I2P"; + private final static String WORKING_DIR_DEFAULT = ".i2p"; + + /** + * Only call this once on router invocation. + * Caller should store the return value for future reference. + */ + public static String getWorkingDir(boolean migrateOldData) { + String dir = System.getProperty(PROP_WORKING_DIR); + boolean isWindows = System.getProperty("os.name").startsWith("Win"); + File dirf = null; + if (dir != null) { + dirf = new File(dir); + } else { + String home = System.getProperty("user.home"); + if (isWindows) { + String appdata = System.getenv("APPDATA"); + if (appdata != null) + home = appdata; + dirf = new File(home, WORKING_DIR_DEFAULT_WINDOWS); + } else { + dirf = new File(home, WORKING_DIR_DEFAULT); + } + } + // where we are now + String cwd = System.getProperty(PROP_BASE_DIR); + if (cwd == null) + cwd = System.getProperty("user.dir"); + // where we want to go + String rv = dirf.getAbsolutePath(); + if (dirf.exists()) { + if (dirf.isDirectory()) + return rv; // all is good, we found the user directory + System.err.println("Wanted to use " + rv + " for a working directory but it is not a directory"); + return cwd; + } + if (!dirf.mkdir()) { + System.err.println("Wanted to use " + rv + " for a working directory but could not create it"); + return cwd; + } + + // Check for a hosts.txt file, if it exists then I2P is there + File oldDirf = new File(cwd); + File test = new File(oldDirf, "hosts.txt"); + if (!test.exists()) { + System.err.println("ERROR - Cannot find I2P installation in " + cwd); + return cwd; + } + + // Check for a router.keys file, if it exists it's an old install, + // and only migrate the data files if told to do so + test = new File(oldDirf, "router.keys"); + boolean oldInstall = test.exists(); + migrateOldData &= oldInstall; + + // Do the copying + if (migrateOldData) + System.err.println("Migrating data files to new user directory " + rv); + else + System.err.println("Setting up new user directory " + rv); + boolean success = migrate(MIGRATE_BASE, oldDirf, dirf); + // this one must be after MIGRATE_BASE + success &= migrateJettyXml(oldDirf, dirf); + success &= migrateWrapperConfig(oldDirf, dirf); + if (migrateOldData) { + success &= migrate(MIGRATE_DATA, oldDirf, dirf); + success &= migrateI2PTunnelKeys(oldDirf, dirf); + success &= migrateSnark(oldDirf, dirf); + // new installs will have updated scripts left in the install dir + // don't bother migrating runplain.sh or i2prouter.bat + if (!isWindows) + success &= migrateI2prouter(oldDirf, dirf); + } else if (!oldInstall) { + // copy the default i2psnark.config over + success &= migrate("i2psnark.config", oldDirf, dirf); + } + + // Report success or failure + if (success) { + System.err.println("Successfully copied data files to new user directory " + rv); + if (migrateOldData) { + System.err.println("Libraries and other files remain in the old directory " + cwd + ", do not remove them."); + System.err.println("You should manually move any non-standard files, such as additional eepsite directories and key files"); + System.err.println("After verifying that all is working, you may delete the following data files and directories in " + + cwd + ": " + MIGRATE_DATA.replace(',', ' ') + " i2psnark.config tmp work"); + if (System.getProperty("wrapper.version") != null) + System.err.println("Note that until you shutdown your router completely and restart, the wrapper will continue" + + " to log to the old wrapper logs in " + cwd); + if (!isWindows) + System.err.println("From now on, you should now use the i2prouter" + + " script in the " + rv + " directory to start i2p." + + " You may copy or move this script elsewhere, you need not run it from that directory."); + } + return rv; + } else { + System.err.println("FAILED copy of some or all data files to new directory " + rv); + System.err.println("Check logs for details"); + System.err.println("Continung to use data files in old directory " + cwd); + return cwd; + } + } + + /** + * files and directories from the base install to copy over + * None of these should be included in i2pupdate.zip + * + * The user should not delete these in the old location, leave them as templates for new users + */ + private static final String MIGRATE_BASE = + // base install - dirs + // We don't currently have a default addressbook/ in the base distribution, + // but distros might put one in + "addressbook,eepsite," + + // base install - files + // We don't currently have a default router.config or logger.config in the base distribution, + // but distros might put one in + "blocklist.txt,clients.config,hosts.txt,i2ptunnel.config,jetty-i2psnark.xml," + + "logger.config,router.config,systray.config"; + + /** + * files and directories from an old single-directory installation to copy over - NOT including snark + * None of these should be included in i2pupdate.zip + * + * The user can be advised to delete these from the old location + */ + private static final String MIGRATE_DATA = + // post install - dirs + // not required to copy - tmp/, work/ + // addressbook included in MIGRATE_BASE above + "keyBackup,logs,netDb,peerProfiles," + + // post install - files + // not required to copy - prngseed.rnd + // logger.config and router.config included in MIGRATE_BASE above + "bob.config,privatehosts.txt,router.info,router.keys," + + "sam.keys,susimail.config,userhosts.txt,webapps.config," + + "wrapper.log,wrapper.log.1,wrapper.log.2"; + + private static boolean migrate(String list, File olddir, File todir) { + boolean rv = true; + String files[] = list.split(","); + for (int i = 0; i < files.length; i++) { + File from = new File(olddir, files[i]); + if (!copy(from, todir)) { + System.err.println("Error copying " + from.getAbsolutePath()); + rv = false; + } + } + return rv; + } + + /** + * Copy over the i2psnark.config file with modifications + */ + private static boolean migrateSnark(File olddir, File todir) { + boolean rv = true; + File oldSnark = new File(olddir, "i2psnark"); + File newSnark = new File(todir, "i2psnark"); + File oldSnarkConfig = new File(olddir, "i2psnark.config"); + File newSnarkConfig = new File(todir, "i2psnark.config"); + boolean hasData = oldSnark.exists(); + if (hasData) { + File children[] = oldSnark.listFiles(); + hasData = children != null && children.length > 0; + } + if (oldSnarkConfig.exists()) { + if (hasData) { + // edit the snark config file to point to the old location, we aren't moving the data + try { + Properties props = new Properties(); + DataHelper.loadProps(props, oldSnarkConfig); + String dir = props.getProperty("i2psnark.dir"); + if (dir == null) + dir = "i2psnark"; + // change relative to absolute path + File f = new File(dir); + props.setProperty("i2psnark.dir", f.getAbsolutePath()); + DataHelper.storeProps(props, newSnarkConfig); + System.err.println("Copied i2psnark.config with modifications"); + } catch (IOException ioe) { + System.err.println("FAILED copy i2psnark.config"); + rv = false; + } + } else { + // copy the i2psnark config file over + copy(newSnarkConfig, todir); + System.err.println("Copied i2psnark.config"); + } + } else { + if (hasData) { + // data but no previous config file (unlikely) - make new config file + try { + Properties props = new Properties(); + File f = new File("i2psnark"); + props.setProperty("i2psnark.dir", f.getAbsolutePath()); + DataHelper.storeProps(props, newSnarkConfig); + } catch (IOException ioe) { + // ignore + } + } // else no config and no data + } + if (hasData) { + /************* + // crude attempt to detect same filesystem + if ((oldSnark.getAbsolutePath().startsWith("/home/") && newSnark.getAbsolutePath().startsWith("/home/")) || + (System.getProperty("os.name").toLowerCase.indexOf("windows") >= 0 && + oldSnark.getAbsolutePath().substring(0,1).equals(newSnark.getAbsolutePath().substring(0,1) && + oldSnark.getAbsolutePath().substring(1,2).equals(":\\") && + newSnark.getAbsolutePath().substring(1,2).equals(":\\"))) { + // OK, apparently in same file system + // move everything + } + **************/ + System.err.println("NOT moving the i2psnark data directory " + oldSnark.getAbsolutePath() + + " to the new directory " + newSnark.getAbsolutePath() + + ". You may move the directory contents manually WHILE I2P IS NOT RUNNING," + + " and edit the file " + newSnarkConfig.getAbsolutePath() + + " to configure i2psnark to use a different location by editing the i2psnark.dir configuration to be" + + " i2psnark.dir=" + oldSnark.getAbsolutePath() + + " and restart, or you may leave the i2psnark directory in its old location."); + } + return true; + } + + /** + * Copy over the i2prouter file with modifications + * The resulting script can be run from any location. + */ + private static boolean migrateI2prouter(File olddir, File todir) { + File oldFile = new File(olddir, "i2prouter"); + File newFile = new File(todir, "i2prouter"); + FileInputStream in = null; + PrintWriter out = null; + try { + in = new FileInputStream(oldFile); + out = new PrintWriter(new BufferedWriter(new FileWriter(newFile))); + boolean firstTime = true; + String s = null; + while ((s = DataHelper.readLine(in)) != null) { + if (s.equals("WRAPPER_CMD=\"./i2psvc\"")) { + // i2psvc in the old location + File f = new File("i2psvc"); + s = "WRAPPER_CMD=\"" + f.getAbsolutePath() + "\""; + } else if(s.equals("WRAPPER_CONF=\"wrapper.config\"")) { + // wrapper.config the new location + File f = new File(todir, "wrapper.config"); + s = "WRAPPER_CONF=\"" + f.getAbsolutePath() + "\""; + } else if(s.equals("PIDDIR=\".\"")) { + // i2p.pid in the new location + s = "PIDDIR=\"" + todir.getAbsolutePath() + "\""; + } + out.println(s); + if (firstTime) { + // first line was #!/bin/sh, so had to wait until now + out.println("# Modified by I2P User dir migration script"); + firstTime = false; + } + } + System.err.println("Copied i2prouter with modifications"); + return true; + } catch (IOException ioe) { + if (in != null) { + System.err.println("FAILED copy i2prouter"); + return false; + } + return true; + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) out.close(); + } + } + + /** + * Copy over the wrapper.config file with modifications + */ + private static boolean migrateWrapperConfig(File olddir, File todir) { + File oldFile = new File(olddir, "wrapper.config"); + File newFile = new File(todir, "wrapper.config"); + FileInputStream in = null; + PrintWriter out = null; + try { + in = new FileInputStream(oldFile); + out = new PrintWriter(new BufferedWriter(new FileWriter(newFile))); + out.println("# Modified by I2P User dir migration script"); + String s = null; + // Don't use replaceFirst because backslashes in the replacement string leads to havoc + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4689750 + // "Note that backslashes and dollar signs in the replacement string may cause the results + // to be different than if it were being treated as a literal replacement string. + // Dollar signs may be treated as references to captured subsequences as described above, + // and backslashes are used to escape literal characters in the replacement string." + while ((s = DataHelper.readLine(in)) != null) { + if (s.startsWith("wrapper.java.classpath.")) { + // libraries in the old location + s = s.replace("=lib/", '=' + olddir.getAbsolutePath() + File.separatorChar + "lib" + File.separatorChar); + } else if (s.startsWith("wrapper.java.library.path.")) { + // libraries in the old location + if (s.contains("=.")) + s = s.replace("=.", '=' + olddir.getAbsolutePath()); + else if (s.contains("=lib")) + s = s.replace("=lib", '=' + olddir.getAbsolutePath() + File.separatorChar + "lib"); + } else if (s.startsWith("wrapper.logfile=wrapper.log")) { + // wrapper logs in the new location + s = s.replace("=", '=' + todir.getAbsolutePath() + File.separatorChar); + } else if (s.startsWith("wrapper.pidfile=i2p.pid")) { + // i2p.pid in the new location + s = s.replace("=", '=' + todir.getAbsolutePath() + File.separatorChar); + } + out.println(s); + } + System.err.println("Copied wrapper.config with modifications"); + return true; + } catch (IOException ioe) { + if (in != null) { + System.err.println("FAILED copy wrapper.config"); + return false; + } + return false; + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) out.close(); + } + } + + /** + * Copy over the jetty.xml file with modifications + * It was already copied over once in migrate(), throw that out and + * do it again with modifications. + */ + private static boolean migrateJettyXml(File olddir, File todir) { + File eepsite1 = new File(olddir, "eepsite"); + File oldFile = new File(eepsite1, "jetty.xml"); + File eepsite2 = new File(todir, "eepsite"); + File newFile = new File(eepsite2, "jetty.xml"); + FileInputStream in = null; + PrintWriter out = null; + try { + in = new FileInputStream(oldFile); + out = new PrintWriter(new BufferedWriter(new FileWriter(newFile))); + String s = null; + while ((s = DataHelper.readLine(in)) != null) { + if (s.indexOf("./eepsite/") >= 0) { + s = s.replace("./eepsite/", todir.getAbsolutePath() + File.separatorChar + "eepsite" + File.separatorChar); + } + out.println(s); + } + out.println("<!-- Modified by I2P User dir migration script -->"); + System.err.println("Copied jetty.xml with modifications"); + return true; + } catch (IOException ioe) { + if (in != null) { + System.err.println("FAILED copy jetty.xml"); + return false; + } + return false; + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) out.close(); + } + } + + /** + * Relatively recent default i2ptunnel key file name + */ + private static boolean migrateI2PTunnelKeys(File olddir, File todir) { + for (int i = 0; i < 100; i++) { + copy(new File(olddir, "i2ptunnel" + i + "-privKeys.dat"), todir); + } + return true; + } + + /** + * Recursive copy a file or dir to a dir + * + * @param src file or directory, need not exist + * @param target the directory to copy to, will be created if it doesn't exist + * @return true for success OR if src does not exist + */ + public static final boolean copy(File src, File targetDir) { + if (!src.exists()) + return true; + if (!targetDir.exists()) { + if (!targetDir.mkdir()) { + System.err.println("FAILED copy " + src.getPath()); + return false; + } + } + File targetFile = new File(targetDir, src.getName()); + if (!src.isDirectory()) + return copyFile(src, targetFile); + File children[] = src.listFiles(); + if (children == null) { + System.err.println("FAILED copy " + src.getPath()); + return false; + } + boolean rv = true; + for (int i = 0; i < children.length; i++) { + rv &= copy(children[i], targetFile); + } + return rv; + } + + /** + * @param src not a directory, must exist + * @param dest not a directory, will be overwritten if existing + * @@reurn true if it was copied successfully + */ + public static boolean copyFile(File src, File dst) { + if (!src.exists()) return false; + boolean rv = true; + + byte buf[] = new byte[4096]; + FileInputStream in = null; + FileOutputStream out = null; + try { + in = new FileInputStream(src); + out = new FileOutputStream(dst); + + int read = 0; + while ( (read = in.read(buf)) != -1) + out.write(buf, 0, read); + + System.err.println("Copied " + src.getPath()); + } catch (IOException ioe) { + System.err.println("FAILED copy " + src.getPath()); + rv = false; + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) try { out.close(); } catch (IOException ioe) {} + } + if (rv) + dst.setLastModified(src.lastModified()); + return rv; + } +} diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index 7546ac4a713494b9b61de6da9efeda60996bb70a..6195d6a76914dbccea1f601afb8a289de1b1e939 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -166,6 +166,8 @@ public class Blocklist { */ private void readBlocklistFile(String file) { File BLFile = new File(file); + if (!BLFile.isAbsolute()) + BLFile = new File(_context.getConfigDir(), file); if (BLFile == null || (!BLFile.exists()) || BLFile.length() <= 0) { if (_log.shouldLog(Log.WARN)) _log.warn("Blocklist file not found: " + file); @@ -701,6 +703,8 @@ public class Blocklist { private synchronized void shitlistForever(Hash peer) { String file = _context.getProperty(PROP_BLOCKLIST_FILE, BLOCKLIST_FILE_DEFAULT); File BLFile = new File(file); + if (!BLFile.isAbsolute()) + BLFile = new File(_context.getConfigDir(), file); if (BLFile == null || (!BLFile.exists()) || BLFile.length() <= 0) { if (_log.shouldLog(Log.ERROR)) _log.error("Blocklist file not found: " + file); diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java index 9fc62a70f29a0213f450a8109faa26d13cd80e3d..711759a408deab886f51d59426efc6a93352729a 100644 --- a/router/java/src/net/i2p/router/KeyManager.java +++ b/router/java/src/net/i2p/router/KeyManager.java @@ -147,10 +147,8 @@ public class KeyManager { super(KeyManager.this._context); } public void runJob() { - String keyDir = getContext().getProperty(PROP_KEYDIR); - if (keyDir == null) - keyDir = DEFAULT_KEYDIR; - File dir = new File(keyDir); + String keyDir = getContext().getProperty(PROP_KEYDIR, DEFAULT_KEYDIR); + File dir = new File(getContext().getRouterDir(), keyDir); if (!dir.exists()) dir.mkdirs(); if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) { diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 1e8e905528ced8738ee0c6cc3a5c11afd0ffc916..35518feda31186bee210c5bfd426b15cda6c7b9b 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -44,6 +44,7 @@ import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; +import net.i2p.util.WorkingDir; /** * Main driver for the router. @@ -53,6 +54,7 @@ public class Router { private Log _log; private RouterContext _context; private final Properties _config; + /** full path */ private String _configFilename; private RouterInfo _routerInfo; private long _started; @@ -104,14 +106,6 @@ public class Router { public Router(Properties envProps) { this(null, envProps); } public Router(String configFilename) { this(configFilename, null); } public Router(String configFilename, Properties envProps) { - if (!beginMarkingLiveliness(envProps)) { - System.err.println("ERROR: There appears to be another router already running!"); - System.err.println(" Please make sure to shut down old instances before starting up"); - System.err.println(" a new one. If you are positive that no other instance is running,"); - System.err.println(" please delete the file " + getPingFile(envProps)); - System.exit(-1); - } - _gracefulExitCode = -1; _config = new Properties(); @@ -125,7 +119,35 @@ public class Router { _configFilename = configFilename; } + // we need the user directory figured out by now, so figure it out here rather than + // in the RouterContext() constructor. + // + // Fixme read config file before migration? or before? or both? + // + // Then add it to envProps (but not _config, we don't want it in the router.config file) + // where it will then be available to all via _context.dir() + // + // This call also migrates all files to the new working directory, + // including router.config + // + + // Do we copy all the data files to the new directory? default false + String migrate = System.getProperty("i2p.dir.migrate"); + boolean migrateFiles = Boolean.valueOf(migrate).booleanValue(); + String userDir = WorkingDir.getWorkingDir(migrateFiles); + + // Use the router.config file specified in the router.configLocation property + // (default "router.config"), + // if it is an abolute path, otherwise look in the userDir returned by getWorkingDir + // replace relative path with absolute + File cf = new File(_configFilename); + if (!cf.isAbsolute()) { + cf = new File(userDir, _configFilename); + _configFilename = cf.getAbsolutePath(); + } + readConfig(); + if (envProps == null) { envProps = _config; } else { @@ -135,11 +157,42 @@ public class Router { envProps.setProperty(k, v); } } + // This doesn't work, guess it has to be in the static block above? // if (Boolean.valueOf(envProps.getProperty("router.disableIPv6")).booleanValue()) // System.setProperty("java.net.preferIPv4Stack", "true"); + if (envProps.getProperty("i2p.dir.config") == null) + envProps.setProperty("i2p.dir.config", userDir); + + // The important thing that happens here is the directory paths are set and created + // i2p.dir.router defaults to i2p.dir.config + // i2p.dir.app defaults to i2p.dir.router + // i2p.dir.log defaults to i2p.dir.router + // i2p.dir.pid defaults to i2p.dir.router + // i2p.dir.base defaults to user.dir == $CWD _context = new RouterContext(this, envProps); + + // This is here so that we can get the directory location from the context + // for the ping file + if (!beginMarkingLiveliness()) { + System.err.println("ERROR: There appears to be another router already running!"); + System.err.println(" Please make sure to shut down old instances before starting up"); + System.err.println(" a new one. If you are positive that no other instance is running,"); + System.err.println(" please delete the file " + getPingFile().getAbsolutePath()); + System.exit(-1); + } + + // This is here so that we can get the directory location from the context + // for the zip file and the base location to unzip to. + // If it does an update, it never returns. + // I guess it's better to have the other-router check above this, we don't want to + // overwrite an existing running router's jar files. Other than ours. + installUpdates(); + + // NOW we start all the activity + _context.initAll(); + _routerInfo = null; _higherVersionSeen = false; _log = _context.logManager().getLog(Router.class); @@ -245,6 +298,7 @@ public class Router { _context.keyManager().startup(); + // why are we reading this again, it's read in the constructor readConfig(); setupHandlers(); @@ -285,6 +339,7 @@ public class Router { } } + /** this does not use ctx.getConfigDir(), must provide a full path in filename */ private static Properties getConfig(RouterContext ctx, String filename) { Log log = null; if (ctx != null) { @@ -456,11 +511,11 @@ public class Router { }; static final String IDENTLOG = "identlog.txt"; - public static void killKeys() { + public void killKeys() { new Exception("Clearing identity files").printStackTrace(); int remCount = 0; for (int i = 0; i < _rebuildFiles.length; i++) { - File f = new File(_rebuildFiles[i]); + File f = new File(_context.getRouterDir(),_rebuildFiles[i]); if (f.exists()) { boolean removed = f.delete(); if (removed) { @@ -474,7 +529,7 @@ public class Router { if (remCount > 0) { FileOutputStream log = null; try { - log = new FileOutputStream(IDENTLOG, true); + log = new FileOutputStream(new File(_context.getRouterDir(), IDENTLOG), true); log.write((new Date() + ": Old router identity keys cleared\n").getBytes()); } catch (IOException ioe) { // ignore @@ -814,8 +869,9 @@ public class Router { try { _context.messageValidator().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the message validator", t); } try { _context.inNetMessagePool().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the inbound net pool", t); } //try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); } + _context.deleteTempDir(); RouterContext.listContexts().remove(_context); - dumpStats(); + //dumpStats(); finalShutdown(exitCode); } @@ -833,7 +889,7 @@ public class Router { killKeys(); } - File f = new File(getPingFile()); + File f = getPingFile(); f.delete(); if (_killVMOnEnd) { try { Thread.sleep(1000); } catch (InterruptedException ie) {} @@ -1003,8 +1059,9 @@ public class Router { public static void main(String args[]) { System.out.println("Starting I2P " + RouterVersion.FULL_VERSION); - installUpdates(); - verifyWrapperConfig(); + // installUpdates() moved to constructor so we can get file locations from the context + // installUpdates(); + //verifyWrapperConfig(); Router r = new Router(); if ( (args != null) && (args.length == 1) && ("rebuild".equals(args[0])) ) { r.rebuildNewIdentity(); @@ -1015,11 +1072,30 @@ public class Router { public static final String UPDATE_FILE = "i2pupdate.zip"; - private static void installUpdates() { - File updateFile = new File(UPDATE_FILE); - if (updateFile.exists()) { + /** + * Unzip update file found in the router dir OR base dir, to the base dir + * + * If we can't write to the base dir, complain. + */ + private void installUpdates() { + File updateFile = new File(_context.getRouterDir(), UPDATE_FILE); + boolean exists = updateFile.exists(); + if (!exists) { + updateFile = new File(_context.getBaseDir(), UPDATE_FILE); + exists = updateFile.exists(); + } + if (exists) { + File test = new File(_context.getBaseDir(), "history.txt"); + if ((!test.canWrite()) || (!_context.getBaseDir().canWrite())) { + String msg = "ERROR: No write permissions on " + _context.getBaseDir() + + " to extract software update file"; + System.out.println(msg); + _log.log(Log.CRIT, msg); + // carry on + return; + } System.out.println("INFO: Update file exists [" + UPDATE_FILE + "] - installing"); - boolean ok = FileUtil.extractZip(updateFile, new File(".")); + boolean ok = FileUtil.extractZip(updateFile, _context.getBaseDir()); if (ok) System.out.println("INFO: Update installed"); else @@ -1037,6 +1113,7 @@ public class Router { } } +/******* private static void verifyWrapperConfig() { File cfgUpdated = new File("wrapper.config.updated"); if (cfgUpdated.exists()) { @@ -1046,15 +1123,22 @@ public class Router { System.exit(EXIT_HARD); } } +*******/ +/* private static String getPingFile(Properties envProps) { if (envProps != null) return envProps.getProperty("router.pingFile", "router.ping"); else return "router.ping"; } - private String getPingFile() { - return _context.getProperty("router.pingFile", "router.ping"); +*/ + private File getPingFile() { + String s = _context.getProperty("router.pingFile", "router.ping"); + File f = new File(s); + if (!f.isAbsolute()) + f = new File(_context.getPIDDir(), s); + return f; } static final long LIVELINESS_DELAY = 60*1000; @@ -1066,9 +1150,8 @@ public class Router { * * @return true if the router is the only one running */ - private boolean beginMarkingLiveliness(Properties envProps) { - String filename = getPingFile(envProps); - File f = new File(filename); + private boolean beginMarkingLiveliness() { + File f = getPingFile(); if (f.exists()) { long lastWritten = f.lastModified(); if (System.currentTimeMillis()-lastWritten > LIVELINESS_DELAY) { @@ -1376,15 +1459,14 @@ private static class PersistRouterInfoJob extends JobImpl { if (_log.shouldLog(Log.DEBUG)) _log.debug("Persisting updated router info"); - String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME); - if (infoFilename == null) - infoFilename = Router.PROP_INFO_FILENAME_DEFAULT; + String infoFilename = getContext().getProperty(PROP_INFO_FILENAME, PROP_INFO_FILENAME_DEFAULT); + File infoFile = new File(getContext().getRouterDir(), infoFilename); RouterInfo info = getContext().router().getRouterInfo(); FileOutputStream fos = null; try { - fos = new FileOutputStream(infoFilename); + fos = new FileOutputStream(infoFile); info.writeBytes(fos); } catch (DataFormatException dfe) { _log.error("Error rebuilding the router information", dfe); diff --git a/router/java/src/net/i2p/router/RouterContext.java b/router/java/src/net/i2p/router/RouterContext.java index 719224058b501f5b5eadcccd75b4ab31134617e5..656b1299bd5f06372dcb8309c1e4b7b9f1dbf2ea 100644 --- a/router/java/src/net/i2p/router/RouterContext.java +++ b/router/java/src/net/i2p/router/RouterContext.java @@ -70,7 +70,11 @@ public class RouterContext extends I2PAppContext { public RouterContext(Router router, Properties envProps) { super(filterProps(envProps)); _router = router; - initAll(); + // Disabled here so that the router can get a context and get the + // directory locations from it, to do an update, without having + // to init everything. Caller MUST call initAll() afterwards. + // Sorry, this breaks some main() unit tests out there. + //initAll(); _contexts.add(this); } /** @@ -86,7 +90,7 @@ public class RouterContext extends I2PAppContext { envProps.setProperty("time.disabled", "false"); return envProps; } - private void initAll() { + public void initAll() { //_adminManager = new AdminManager(this); if ("false".equals(getProperty("i2p.dummyClientFacade", "false"))) _clientManagerFacade = new ClientManagerFacadeImpl(this); diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java index 282b67e0cdc0973045144633a4cac6a29ac17914..92124d69010545391858f37bcd2617239cad060c 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java @@ -410,7 +410,7 @@ class PersistentDataStore extends TransientDataStore { private File getDbDir() throws IOException { - File f = new File(_dbDir); + File f = new File(_context.getRouterDir(), _dbDir); if (!f.exists()) { boolean created = f.mkdirs(); if (!created) diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java index 4f5d23611622b5213b2cfc2442308b0f99ea449d..e1f265d8f1499c03f30df5f3b2704a36b077019a 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java +++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java @@ -297,18 +297,8 @@ class ProfilePersistenceHelper { private File getProfileDir() { if (_profileDir == null) { - String dir = null; - if (_context.router() == null) { - dir = _context.getProperty(PROP_PEER_PROFILE_DIR, DEFAULT_PEER_PROFILE_DIR); - } else { - dir = _context.router().getConfigSetting(PROP_PEER_PROFILE_DIR); - if (dir == null) { - _log.info("No peer profile dir specified [" + PROP_PEER_PROFILE_DIR - + "], using [" + DEFAULT_PEER_PROFILE_DIR + "]"); - dir = DEFAULT_PEER_PROFILE_DIR; - } - } - _profileDir = new File(dir); + String dir = _context.getProperty(PROP_PEER_PROFILE_DIR, DEFAULT_PEER_PROFILE_DIR); + _profileDir = new File(_context.getRouterDir(), dir); } return _profileDir; } diff --git a/router/java/src/net/i2p/router/startup/ClientAppConfig.java b/router/java/src/net/i2p/router/startup/ClientAppConfig.java index 316c0b5006760708546cd0705408b47fbb607f5d..f5d48cb1f2dd109612a26463c6e1cfcaaa97096b 100644 --- a/router/java/src/net/i2p/router/startup/ClientAppConfig.java +++ b/router/java/src/net/i2p/router/startup/ClientAppConfig.java @@ -43,6 +43,8 @@ public class ClientAppConfig { Properties rv = new Properties(); String clientConfigFile = ctx.getProperty(PROP_CLIENT_CONFIG_FILENAME, DEFAULT_CLIENT_CONFIG_FILENAME); File cfgFile = new File(clientConfigFile); + if (!cfgFile.isAbsolute()) + cfgFile = new File(ctx.getConfigDir(), clientConfigFile); // fall back to use router.config's clientApp.* lines if (!cfgFile.exists()) @@ -91,9 +93,12 @@ public class ClientAppConfig { public static void writeClientAppConfig(RouterContext ctx, List apps) { String clientConfigFile = ctx.getProperty(PROP_CLIENT_CONFIG_FILENAME, DEFAULT_CLIENT_CONFIG_FILENAME); + File cfgFile = new File(clientConfigFile); + if (!cfgFile.isAbsolute()) + cfgFile = new File(ctx.getConfigDir(), clientConfigFile); FileOutputStream fos = null; try { - fos = new FileOutputStream(clientConfigFile); + fos = new FileOutputStream(cfgFile); StringBuffer buf = new StringBuffer(2048); for(int i = 0; i < apps.size(); i++) { ClientAppConfig app = (ClientAppConfig) apps.get(i); diff --git a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java index 92b176c30fd50d66a309ca02c93df308e5afe973..979cefa78f6d470d595581c5013e7cc52b34bd7a 100644 --- a/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/CreateRouterInfoJob.java @@ -8,6 +8,7 @@ package net.i2p.router.startup; * */ +import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashSet; @@ -76,16 +77,14 @@ public class CreateRouterInfoJob extends JobImpl { info.sign(signingPrivKey); - String infoFilename = getContext().router().getConfigSetting(Router.PROP_INFO_FILENAME); - if (infoFilename == null) - infoFilename = Router.PROP_INFO_FILENAME_DEFAULT; - fos1 = new FileOutputStream(infoFilename); + String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT); + File ifile = new File(getContext().getRouterDir(), infoFilename); + fos1 = new FileOutputStream(ifile); info.writeBytes(fos1); - String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME); - if (keyFilename == null) - keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT; - fos2 = new FileOutputStream(keyFilename); + String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT); + File kfile = new File(getContext().getRouterDir(), keyFilename); + fos2 = new FileOutputStream(kfile); privkey.writeBytes(fos2); signingPrivKey.writeBytes(fos2); pubkey.writeBytes(fos2); @@ -96,7 +95,7 @@ public class CreateRouterInfoJob extends JobImpl { getContext().keyManager().setPrivateKey(privkey); getContext().keyManager().setPublicKey(pubkey); - _log.info("Router info created and stored at " + infoFilename + " with private keys stored at " + keyFilename + " [" + info + "]"); + _log.info("Router info created and stored at " + ifile.getAbsolutePath() + " with private keys stored at " + kfile.getAbsolutePath() + " [" + info + "]"); } catch (DataFormatException dfe) { _log.error("Error building the new router information", dfe); } catch (IOException ioe) { diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java index 0374922afdbb8bfcff5222d0335f65e6b3aeae7b..f3428c4474886f08dc6a8b9edca93cf5fcf6f086 100644 --- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java @@ -51,21 +51,17 @@ public class LoadRouterInfoJob extends JobImpl { } private void loadRouterInfo() { - String routerInfoFile = getContext().router().getConfigSetting(Router.PROP_INFO_FILENAME); - if (routerInfoFile == null) - routerInfoFile = Router.PROP_INFO_FILENAME_DEFAULT; + String routerInfoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT); RouterInfo info = null; boolean failedRead = false; - String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME); - if (keyFilename == null) - keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT; + String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT); - File rif = new File(routerInfoFile); + File rif = new File(getContext().getRouterDir(), routerInfoFile); if (rif.exists()) _infoExists = true; - File rkf = new File(keyFilename); + File rkf = new File(getContext().getRouterDir(), keyFilename); if (rkf.exists()) _keysExist = true; @@ -98,14 +94,14 @@ public class LoadRouterInfoJob extends JobImpl { _us = info; } catch (IOException ioe) { - _log.error("Error reading the router info from " + routerInfoFile + " and the keys from " + keyFilename, ioe); + _log.error("Error reading the router info from " + rif.getAbsolutePath() + " and the keys from " + rkf.getAbsolutePath(), ioe); _us = null; rif.delete(); rkf.delete(); _infoExists = false; _keysExist = false; } catch (DataFormatException dfe) { - _log.error("Corrupt router info or keys at " + routerInfoFile + " / " + keyFilename, dfe); + _log.error("Corrupt router info or keys at " + rif.getAbsolutePath() + " / " + rkf.getAbsolutePath(), dfe); _us = null; rif.delete(); rkf.delete(); diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java index 967bc7a797bc7e175261b4f6539e5af88e722d87..fda82de8e595e3a84fb3a6999406de0c7995f27a 100644 --- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java @@ -57,18 +57,11 @@ public class RebuildRouterInfoJob extends JobImpl { public void runJob() { _log.debug("Testing to rebuild router info"); - String infoFile = getContext().router().getConfigSetting(Router.PROP_INFO_FILENAME); - if (infoFile == null) { - _log.debug("Info filename not configured, defaulting to " + Router.PROP_INFO_FILENAME_DEFAULT); - infoFile = Router.PROP_INFO_FILENAME_DEFAULT; - } - - String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME); - if (keyFilename == null) - keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT; - File keyFile = new File(keyFilename); + String infoFile = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT); + File info = new File(getContext().getRouterDir(), infoFile); + String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT); + File keyFile = new File(getContext().getRouterDir(), keyFilename); - File info = new File(infoFile); if (!info.exists() || !keyFile.exists()) { _log.info("Router info file [" + info.getAbsolutePath() + "] or private key file [" + keyFile.getAbsolutePath() + "] deleted, rebuilding"); rebuildRouterInfo(); @@ -86,14 +79,10 @@ public class RebuildRouterInfoJob extends JobImpl { _log.debug("Rebuilding the new router info"); boolean fullRebuild = false; RouterInfo info = null; - String infoFilename = getContext().router().getConfigSetting(Router.PROP_INFO_FILENAME); - if (infoFilename == null) - infoFilename = Router.PROP_INFO_FILENAME_DEFAULT; - - String keyFilename = getContext().router().getConfigSetting(Router.PROP_KEYS_FILENAME); - if (keyFilename == null) - keyFilename = Router.PROP_KEYS_FILENAME_DEFAULT; - File keyFile = new File(keyFilename); + String infoFilename = getContext().getProperty(Router.PROP_INFO_FILENAME, Router.PROP_INFO_FILENAME_DEFAULT); + File infoFile = new File(getContext().getRouterDir(), infoFilename); + String keyFilename = getContext().getProperty(Router.PROP_KEYS_FILENAME, Router.PROP_KEYS_FILENAME_DEFAULT); + File keyFile = new File(getContext().getRouterDir(), keyFilename); if (keyFile.exists()) { // ok, no need to rebuild a brand new identity, just update what we can @@ -146,7 +135,7 @@ public class RebuildRouterInfoJob extends JobImpl { FileOutputStream fos = null; try { - fos = new FileOutputStream(infoFilename); + fos = new FileOutputStream(infoFile); info.writeBytes(fos); } catch (DataFormatException dfe) { _log.error("Error rebuilding the router information", dfe); diff --git a/router/java/src/net/i2p/router/transport/GeoIP.java b/router/java/src/net/i2p/router/transport/GeoIP.java index a7da9fad8617366f3de79763be416abac5efb737..fb4984978d99b1f7f55aa9740e3342cd6e25628d 100644 --- a/router/java/src/net/i2p/router/transport/GeoIP.java +++ b/router/java/src/net/i2p/router/transport/GeoIP.java @@ -130,7 +130,8 @@ public class GeoIP { * */ private void readCountryFile() { - File GeoFile = new File(GEOIP_DIR_DEFAULT, COUNTRY_FILE_DEFAULT); + File GeoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT); + GeoFile = new File(GeoFile, COUNTRY_FILE_DEFAULT); if (GeoFile == null || (!GeoFile.exists())) { if (_log.shouldLog(Log.WARN)) _log.warn("Country file not found: " + GeoFile.getAbsolutePath()); @@ -188,7 +189,8 @@ public class GeoIP { * */ private String[] readGeoIPFile(Long[] search) { - File GeoFile = new File(GEOIP_DIR_DEFAULT, GEOIP_FILE_DEFAULT); + File GeoFile = new File(_context.getBaseDir(), GEOIP_DIR_DEFAULT); + GeoFile = new File(GeoFile, GEOIP_FILE_DEFAULT); if (GeoFile == null || (!GeoFile.exists())) { if (_log.shouldLog(Log.WARN)) _log.warn("GeoIP file not found: " + GeoFile.getAbsolutePath());