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;


Reply via email to