diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index 203f6019578646d128b2d961174a9889e97aef6a..2a43b6cebb6b0f8c635a3e8a17ca426515f80ee1 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -1243,8 +1243,13 @@ public class Snark } catch (IOException ioe) { if (storage != null) { try { storage.close(); } catch (IOException ioee) {} + // clear storage, we have a mess if we have non-null storage and null metainfo, + // as on restart, Storage.reopen() will throw an ioe + storage = null; } - fatal("Could not check or create storage", ioe); + // TODO we're still in an inconsistent state, won't work if restarted + // (PeerState "disconnecting seed that connects to seeds" + fatal("Could not create data files", ioe); } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index cc379357e117c3aac545dc64e655f0ca58d53d51..77964cb6b4a7beac058f779e352cd7da8698dbb9 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -731,7 +731,7 @@ public class SnarkManager implements CompleteListener, ClientApp { return new SHA1Hash(ih); } - /** null to set initial defaults */ + /** @param filename null to set initial defaults */ public void loadConfig(String filename) { synchronized(_configLock) { locked_loadConfig(filename); @@ -896,7 +896,14 @@ public class SnarkManager implements CompleteListener, ClientApp { _util.setRatingsEnabled(Boolean.parseBoolean(_config.getProperty(PROP_RATINGS, "true"))); _util.setCommentsEnabled(Boolean.parseBoolean(_config.getProperty(PROP_COMMENTS, "true"))); _util.setCommentsName(_config.getProperty(PROP_COMMENTS_NAME, "")); - getDataDir().mkdirs(); + File dd = getDataDir(); + if (dd.isDirectory()) { + if (!dd.canWrite()) + addMessage(_t("No write permissions for data directory") + ": " + dd); + } else { + if (!dd.mkdirs()) + addMessage(_t("Data directory cannot be created") + ": " + dd); + } initTrackerMap(); } @@ -1031,6 +1038,8 @@ public class SnarkManager implements CompleteListener, ClientApp { } else if (!dd.canRead()) { addMessage(_t("Unreadable") + ": " + dataDir); } else { + if (!dd.canWrite()) + addMessage(_t("No write permissions for data directory") + ": " + dataDir); changed = true; interruptMonitor = true; _config.setProperty(PROP_DIR, dataDir); @@ -2640,6 +2649,7 @@ public class SnarkManager implements CompleteListener, ClientApp { /** * If not connected, thread it, otherwise inline + * @throws RuntimeException via Snark.fatal() * @since 0.9.1 */ public void startTorrent(byte[] infoHash) { @@ -2654,6 +2664,7 @@ public class SnarkManager implements CompleteListener, ClientApp { /** * If not connected, thread it, otherwise inline + * @throws RuntimeException via Snark.fatal() * @since 0.9.23 */ public void startTorrent(Snark snark) { @@ -2701,17 +2712,14 @@ public class SnarkManager implements CompleteListener, ClientApp { private final Snark snark; public ThreadedStarter(Snark s) { snark = s; } public void run() { - try { - run2(); - } catch (RuntimeException e) { - _log.error("Error starting", e); - } - } - - private void run2() { if (snark != null) { - if (snark.isStopped()) - snark.startTorrent(); + if (snark.isStopped()) { + try { + snark.startTorrent(); + } catch (RuntimeException re) { + // Snark.fatal() will log and call fatal() here for user message before throwing + } + } } else { startAll(); } @@ -2724,8 +2732,13 @@ public class SnarkManager implements CompleteListener, ClientApp { */ private void startAll() { for (Snark snark : _snarks.values()) { - if (snark.isStopped()) - snark.startTorrent(); + if (snark.isStopped()) { + try { + snark.startTorrent(); + } catch (RuntimeException re) { + // Snark.fatal() will log and call fatal() here for user message before throwing + } + } } } 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 4a73cb27bf7ccd4a12285807926bc7b47ade6f00..1612ff2fab011324916a05b4c9c5c63d0407d93a 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -987,6 +987,11 @@ public class I2PSnarkServlet extends BasicServlet { } } } + File dd = _manager.getDataDir(); + if (!dd.canWrite()) { + _manager.addMessage(_t("No write permissions for data directory") + ": " + dd); + return; + } if (newURL.startsWith("http://")) { FetchAndAdd fetch = new FetchAndAdd(_context, _manager, newURL, dir); _manager.addDownloader(fetch); @@ -1045,12 +1050,18 @@ public class I2PSnarkServlet extends BasicServlet { _manager.addMessage(_t("Magnet deleted: {0}", name)); return; } - _manager.stopTorrent(snark, true); - // should we delete the torrent file? - // yeah, need to, otherwise it'll get autoadded again (at the moment File f = new File(name); - f.delete(); - _manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath())); + File dd = _manager.getDataDir(); + boolean canDelete = dd.canWrite() || !f.exists(); + _manager.stopTorrent(snark, canDelete); + // TODO race here with the DirMonitor, could get re-added + if (f.delete()) { + _manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath())); + } else if (f.exists()) { + if (!canDelete) + _manager.addMessage(_t("No write permissions for data directory") + ": " + dd); + _manager.addMessage(_t("Torrent file could not be deleted: {0}", f.getAbsolutePath())); + } break; } } @@ -1074,10 +1085,19 @@ public class I2PSnarkServlet extends BasicServlet { _manager.addMessage(_t("Magnet deleted: {0}", name)); return; } - _manager.stopTorrent(snark, true); File f = new File(name); - f.delete(); - _manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath())); + File dd = _manager.getDataDir(); + boolean canDelete = dd.canWrite() || !f.exists(); + _manager.stopTorrent(snark, canDelete); + // TODO race here with the DirMonitor, could get re-added + if (f.delete()) { + _manager.addMessage(_t("Torrent file deleted: {0}", f.getAbsolutePath())); + } else if (f.exists()) { + if (!canDelete) + _manager.addMessage(_t("No write permissions for data directory") + ": " + dd); + _manager.addMessage(_t("Torrent file could not be deleted: {0}", f.getAbsolutePath())); + return; + } Storage storage = snark.getStorage(); if (storage == null) break; @@ -1178,6 +1198,11 @@ public class I2PSnarkServlet extends BasicServlet { // announceURL = announceURLOther; if (baseFile.exists()) { + File dd = _manager.getDataDir(); + if (!dd.canWrite()) { + _manager.addMessage(_t("No write permissions for data directory") + ": " + dd); + return; + } String torrentName = baseFile.getName(); if (torrentName.toLowerCase(Locale.US).endsWith(".torrent")) { _manager.addMessage(_t("Cannot add a torrent ending in \".torrent\": {0}", baseFile.getAbsolutePath()));