Author: toad
Date: 2006-03-03 19:33:35 +0000 (Fri, 03 Mar 2006)
New Revision: 8147
Added:
trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
Modified:
trunk/freenet/src/freenet/client/ArchiveManager.java
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/TextModeClientInterface.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/node/fcp/ClientPut.java
trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucketFactory.java
trunk/freenet/src/freenet/support/io/FileBucket.java
trunk/freenet/src/freenet/support/io/FileBucketFactory.java
trunk/freenet/src/freenet/support/io/TempFileBucket.java
Log:
485:
Infrastructure: persistent temporary file buckets.
Will be used by peristence code very soon.
Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -355,16 +355,12 @@
*/
private TempStoreElement makeTempStoreBucket(long size) {
File myFile = filenameGenerator.makeRandomFilename();
- FileBucket fb = new FileBucket(myFile, false, true, false);
+ FileBucket fb = new FileBucket(myFile, false, true, false,
true);
byte[] cipherKey = new byte[32];
random.nextBytes(cipherKey);
- try {
- PaddedEphemerallyEncryptedBucket encryptedBucket = new
PaddedEphemerallyEncryptedBucket(fb, 1024, random);
- return new TempStoreElement(myFile, fb,
encryptedBucket);
- } catch (UnsupportedCipherException e) {
- throw new Error("Unsupported cipher: AES 256/256!", e);
- }
+ PaddedEphemerallyEncryptedBucket encryptedBucket = new
PaddedEphemerallyEncryptedBucket(fb, 1024, random);
+ return new TempStoreElement(myFile, fb, encryptedBucket);
}
/**
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-03-03 18:47:25 UTC (rev
8146)
+++ trunk/freenet/src/freenet/node/Node.java 2006-03-03 19:33:35 UTC (rev
8147)
@@ -84,6 +84,7 @@
import freenet.support.PaddedEphemerallyEncryptedBucketFactory;
import freenet.support.SimpleFieldSet;
import freenet.support.io.FilenameGenerator;
+import freenet.support.io.PersistentTempBucketFactory;
import freenet.support.io.TempBucketFactory;
import freenet.transport.IPAddressDetector;
import freenet.transport.IPUtil;
@@ -247,6 +248,9 @@
FproxyToadlet fproxyServlet;
SimpleToadletServer toadletContainer;
+ // Persistent temporary buckets
+ public final PersistentTempBucketFactory persistentTempBucketFactory;
+
// Things that's needed to keep track of
public final PluginManager pluginManager;
@@ -681,7 +685,7 @@
public void set(String val) throws
InvalidConfigValueException {
if(tempDir.equals(new
File(val))) return;
// FIXME
- throw new
InvalidConfigValueException("Moving node directory on the fly not supported at
present");
+ throw new
InvalidConfigValueException("Moving temp directory on the fly not supported at
present");
}
});
@@ -694,16 +698,35 @@
try {
tempFilenameGenerator = new FilenameGenerator(random,
true, tempDir, "temp-");
} catch (IOException e) {
- Logger.error(this, "Could not create temp bucket
factory: "+e, e);
- System.exit(EXIT_TEMP_INIT_ERROR);
- throw new Error();
+ String msg = "Could not find or create temporary directory
(filename generator)";
+ throw new NodeInitException(EXIT_BAD_TEMP_DIR, msg);
}
tempBucketFactory = new
PaddedEphemerallyEncryptedBucketFactory(new
TempBucketFactory(tempFilenameGenerator), random, 1024);
-
+ // Persistent temp files
+
+ nodeConfig.register("persistentTempDir", new File(nodeDir,
"persistent-temp-"+portNumber).toString(), 7, true, "Persistent temp files
directory", "Name of directory to put persistent temp files in",
+ new StringCallback() {
+ public String get() {
+ return
persistentTempBucketFactory.getDir().toString();
+ }
+ public void set(String val) throws
InvalidConfigValueException {
+ if(!get().equals(val))
+ return;
+ // FIXME
+ throw new
InvalidConfigValueException("Moving persistent temp directory on the fly not
supported at present");
+ }
+ });
+ try {
+ persistentTempBucketFactory = new
PersistentTempBucketFactory(new
File(nodeConfig.getString("persistentTempDir")), "freenet-temp-", random);
+ } catch (IOException e2) {
+ String msg = "Could not find or create persistent temporary
directory";
+ throw new NodeInitException(EXIT_BAD_TEMP_DIR, msg);
+ }
+
// Datastore
- nodeConfig.register("storeSize", "1G", 5, false, "Store size in
bytes", "Store size in bytes",
+ nodeConfig.register("storeSize", "1G", 8, false, "Store size in
bytes", "Store size in bytes",
new LongCallback() {
public long get() {
@@ -731,7 +754,7 @@
maxStoreKeys = storeSize / sizePerKey;
- nodeConfig.register("storeDir", ".", 6, true, "Store directory", "Name
of directory to put store files in",
+ nodeConfig.register("storeDir", ".", 9, true, "Store directory", "Name
of directory to put store files in",
new StringCallback() {
public String get() {
return storeDir.getPath();
@@ -772,7 +795,7 @@
// Downloads directory
- nodeConfig.register("downloadsDir", "downloads", 8, false, "Default
download directory", "The directory to save downloaded files into by default",
new StringCallback() {
+ nodeConfig.register("downloadsDir", "downloads", 10, false, "Default
download directory", "The directory to save downloaded files into by default",
new StringCallback() {
public String get() {
return downloadDir.getPath();
@@ -798,7 +821,7 @@
// Name
- nodeConfig.register("name", myName, 9, false, "Node name for darknet",
"Node name; you may want to set this to something descriptive if running on
darknet e.g. Fred Blogg's Node; it is visible to any connecting node",
+ nodeConfig.register("name", myName, 11, false, "Node name for
darknet", "Node name; you may want to set this to something descriptive if
running on darknet e.g. Fred Blogg's Node; it is visible to any connecting
node",
new StringCallback() {
public String get() {
return myName;
@@ -813,6 +836,7 @@
writeNodeFile();
nodeConfig.finishedInitialization();
+ persistentTempBucketFactory.completedInit();
// FIXME make all the below arbitrary constants configurable!
Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -387,7 +387,7 @@
if(mimeType.equals(DefaultMIMETypes.DEFAULT_MIME_TYPE))
mimeType = ""; // don't need to override it
- FileBucket fb = new FileBucket(f, true, false, false);
+ FileBucket fb = new FileBucket(f, true, false, false, false);
InsertBlock block = new InsertBlock(fb, new
ClientMetadata(mimeType), FreenetURI.EMPTY_CHK_URI);
startTime = System.currentTimeMillis();
@@ -563,7 +563,7 @@
if (filelist[i].isFile()) {
File f = filelist[i];
- FileBucket bucket = new FileBucket(f, true, false,
false);
+ FileBucket bucket = new FileBucket(f, true, false,
false, false);
ret.put(f.getName(), bucket);
} else if(filelist[i].isDirectory()) {
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-03 18:47:25 UTC (rev
8146)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-03 19:33:35 UTC (rev
8147)
@@ -20,7 +20,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- private static final int buildNumber = 484;
+ private static final int buildNumber = 485;
/** Oldest build of Fred we will talk to */
private static final int lastGoodBuild = 475;
Modified: trunk/freenet/src/freenet/node/fcp/ClientPut.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-03-03 18:47:25 UTC
(rev 8146)
+++ trunk/freenet/src/freenet/node/fcp/ClientPut.java 2006-03-03 19:33:35 UTC
(rev 8147)
@@ -120,7 +120,7 @@
clientToken = fs.get("ClientToken");
fromDisk = true;
origFilename = new File(fs.get("Filename"));
- Bucket data = new FileBucket(origFilename, true, false, false);
+ Bucket data = new FileBucket(origFilename, true, false, false,
false);
ctx = new InserterContext(client.defaultInsertContext, new
SimpleEventProducer());
ctx.dontCompress = dontCompress;
ctx.eventProducer.addEventListener(this);
Modified: trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -106,7 +106,7 @@
if(!(f.exists() && f.isFile() && f.canRead()))
throw new
MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, null, identifier);
dataLength = f.length();
- FileBucket fileBucket = new FileBucket(f, true, false,
false);
+ FileBucket fileBucket = new FileBucket(f, true, false,
false, false);
this.bucket = fileBucket;
this.origFilename = f;
} else {
Modified:
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
2006-03-03 18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucket.java
2006-03-03 19:33:35 UTC (rev 8147)
@@ -34,11 +34,15 @@
* @param origRandom Hard random number generator from which to obtain
a seed for padding.
* @throws UnsupportedCipherException
*/
- public PaddedEphemerallyEncryptedBucket(Bucket bucket, int minSize,
RandomSource origRandom) throws UnsupportedCipherException {
+ public PaddedEphemerallyEncryptedBucket(Bucket bucket, int minSize,
RandomSource origRandom) {
this.origRandom = origRandom;
this.bucket = bucket;
if(bucket.size() != 0) throw new
IllegalArgumentException("Bucket must be empty");
- aes = new Rijndael(256, 256);
+ try {
+ aes = new Rijndael(256, 256);
+ } catch (UnsupportedCipherException e) {
+ throw new Error(e);
+ }
byte[] key = new byte[32];
origRandom.nextBytes(key);
aes.initialize(key);
@@ -49,6 +53,24 @@
lastOutputStream = 0;
}
+ public PaddedEphemerallyEncryptedBucket(Bucket bucket, int minSize,
byte[] key, RandomSource origRandom) {
+ this.origRandom = origRandom;
+ this.bucket = bucket;
+ if(bucket.size() != 0) throw new
IllegalArgumentException("Bucket must be empty");
+ try {
+ aes = new Rijndael(256, 256);
+ } catch (UnsupportedCipherException e) {
+ throw new Error(e);
+ }
+ origRandom.nextBytes(key);
+ aes.initialize(key);
+ // Might as well blank it
+ for(int i=0;i<key.length;i++) key[i] = 0;
+ this.minPaddedSize = minSize;
+ readOnly = false;
+ lastOutputStream = 0;
+ }
+
public OutputStream getOutputStream() throws IOException {
if(readOnly) throw new IOException("Read only");
OutputStream os = bucket.getOutputStream();
Modified:
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucketFactory.java
===================================================================
---
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucketFactory.java
2006-03-03 18:47:25 UTC (rev 8146)
+++
trunk/freenet/src/freenet/support/PaddedEphemerallyEncryptedBucketFactory.java
2006-03-03 19:33:35 UTC (rev 8147)
@@ -22,11 +22,7 @@
}
public Bucket makeBucket(long size) throws IOException {
- try {
- return new
PaddedEphemerallyEncryptedBucket(baseFactory.makeBucket(size), minSize, random);
- } catch (UnsupportedCipherException e) {
- throw new Error(e);
- }
+ return new
PaddedEphemerallyEncryptedBucket(baseFactory.makeBucket(size), minSize, random);
}
public void freeBucket(Bucket b) throws IOException {
Modified: trunk/freenet/src/freenet/support/io/FileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FileBucket.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/support/io/FileBucket.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -23,6 +23,7 @@
protected File file;
protected boolean readOnly;
protected boolean deleteOnFinalize;
+ protected boolean deleteOnFree;
protected long length;
// JVM caches File.size() and there is no way to flush the cache, so we
// need to track it ourselves
@@ -39,10 +40,11 @@
* @param deleteOnFinalize If true, delete the file on finalization.
Reversible.
* @param deleteOnExit If true, delete the file on a clean exit of the
JVM. Irreversible - use with care!
*/
- public FileBucket(File file, boolean readOnly, boolean
deleteOnFinalize, boolean deleteOnExit) {
+ public FileBucket(File file, boolean readOnly, boolean
deleteOnFinalize, boolean deleteOnExit, boolean deleteOnFree) {
this.readOnly = readOnly;
this.file = file;
this.deleteOnFinalize = deleteOnFinalize;
+ this.deleteOnFree = deleteOnFree;
if(deleteOnExit)
file.deleteOnExit();
// Useful for finding temp file leaks.
@@ -188,20 +190,8 @@
}
public void finalize() {
- if (Logger.shouldLog(Logger.DEBUG, this))
- Logger.debug(this,
- "FileBucket Finalizing " + file.getName());
- if (deleteOnFinalize && file.exists()) {
- Logger.debug(this,
- "Deleting bucket " + file.getName());
- deleteFile();
- if (file.exists())
- Logger.error(this,
- "Delete failed on bucket " +
file.getName());
- }
- if (Logger.shouldLog(Logger.DEBUG, this))
- Logger.debug(this,
- "FileBucket Finalized " + file.getName());
+ if(deleteOnFinalize)
+ free(deleteOnFinalize);
}
/**
@@ -317,6 +307,17 @@
}
public void free() {
- finalize();
+ free(false);
}
+
+ public void free(boolean forceFree) {
+ if ((deleteOnFree || forceFree) && file.exists()) {
+ Logger.debug(this,
+ "Deleting bucket " + file.getName());
+ deleteFile();
+ if (file.exists())
+ Logger.error(this,
+ "Delete failed on bucket " +
file.getName());
+ }
+ }
}
Modified: trunk/freenet/src/freenet/support/io/FileBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FileBucketFactory.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/support/io/FileBucketFactory.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -40,7 +40,7 @@
// e.printStackTrace();
// System.err.println("----------------------------------------");
} while (f.exists());
- Bucket b = new FileBucket(f, false, true, false);
+ Bucket b = new FileBucket(f, false, true, false, true);
files.addElement(f);
return b;
}
Added: trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-03-03 18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2006-03-03 19:33:35 UTC (rev 8147)
@@ -0,0 +1,115 @@
+package freenet.support.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import freenet.crypt.RandomSource;
+import freenet.support.Bucket;
+import freenet.support.BucketFactory;
+import freenet.support.Logger;
+import freenet.support.PaddedEphemerallyEncryptedBucket;
+
+/**
+ * Handles persistent temp files. These are used for e.g. persistent downloads.
+ * Fed a directory on startup.
+ * Finds all files in the directory.
+ * Keeps a list.
+ * On startup, clients are expected to claim a temp bucket.
+ * Once startup is completed, any unclaimed temp buckets which match the
+ * temporary file pattern will be deleted.
+ */
+public class PersistentTempBucketFactory implements BucketFactory {
+
+ /** Directory containing persistent temporary files */
+ private final File dir;
+
+ /** Temp file prefix; anything not matching this prefix will be ignored
*/
+ private final String prefix;
+
+ /** Original contents of directory */
+ private HashSet originalFiles;
+
+ /** Filename generator */
+ private final FilenameGenerator fg;
+
+ /** Random number generator */
+ private final RandomSource rand;
+
+ public PersistentTempBucketFactory(File dir, String prefix,
RandomSource rand) throws IOException {
+ this.dir = dir;
+ this.rand = rand;
+ this.prefix = prefix;
+ this.fg = new FilenameGenerator(rand, false, dir, prefix);
+ if(!dir.exists()) {
+ dir.mkdir();
+ if(!dir.exists()) {
+ throw new IOException("Directory does not exist
and cannot be created: "+dir);
+ }
+ }
+ if(!dir.isDirectory())
+ throw new IOException("Directory is not a directory:
"+dir);
+ originalFiles = new HashSet();
+ File[] files = dir.listFiles();
+ if(files != null && files.length > 0) {
+ for(int i=0;i<files.length;i++) {
+ File f = files[i];
+ String name = f.getName();
+ if(f.isDirectory()) continue;
+ if(!f.exists()) continue;
+ if(!name.startsWith(prefix)) {
+ Logger.minor(this, "Ignoring "+name);
+ continue;
+ }
+ originalFiles.add(f);
+ }
+ }
+ }
+
+ /**
+ * Called by a client to fetch the bucket denoted by a specific
filename,
+ * and to register this fact so that it is not deleted on startup
completion.
+ */
+ public Bucket register(String filename) {
+ File f = new File(filename);
+ Bucket b = new FileBucket(f, false, false, false, true);
+ originalFiles.remove(f);
+ return b;
+ }
+
+ /**
+ * Called when boot-up is complete.
+ * Deletes any old temp files still unclaimed.
+ */
+ public void completedInit() {
+ Iterator i = originalFiles.iterator();
+ while(i.hasNext()) {
+ String s = (String) (i.next());
+ File f = new File(s);
+ f.delete();
+ }
+ }
+
+ public Bucket makeBucket(long size) throws IOException {
+ return new FileBucket(fg.makeRandomFilename(), false, false,
false, true);
+ }
+
+ public Bucket makeEncryptedBucket() throws IOException {
+ Bucket b = makeBucket(-1);
+ return new PaddedEphemerallyEncryptedBucket(b, 1024, rand);
+ }
+
+ public Bucket registerEncryptedBucket(String filename, byte[] key) {
+ Bucket fileBucket = register(filename);
+ return new PaddedEphemerallyEncryptedBucket(fileBucket, 1024,
key, rand);
+ }
+
+ public void freeBucket(Bucket b) throws IOException {
+ b.free();
+ }
+
+ public File getDir() {
+ return dir;
+ }
+}
Modified: trunk/freenet/src/freenet/support/io/TempFileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/TempFileBucket.java 2006-03-03
18:47:25 UTC (rev 8146)
+++ trunk/freenet/src/freenet/support/io/TempFileBucket.java 2006-03-03
19:33:35 UTC (rev 8147)
@@ -37,7 +37,7 @@
long minAlloc,
float factor)
throws IOException {
- super(f, false, true, true);
+ super(f, false, true, true, true);
logDebug = Logger.shouldLog(Logger.DEBUG, this);
if (minAlloc > 0)
this.minAlloc = minAlloc;