Author: toad
Date: 2007-07-21 01:42:16 +0000 (Sat, 21 Jul 2007)
New Revision: 14222
Added:
trunk/freenet/src/freenet/support/io/BaseFileBucket.java
trunk/freenet/src/freenet/support/io/PersistentTempFileBucket.java
Removed:
trunk/freenet/src/freenet/support/io/SpyInputStream.java
trunk/freenet/src/freenet/support/io/SpyOutputStream.java
trunk/freenet/src/freenet/support/io/TempBucketHook.java
Modified:
trunk/freenet/src/freenet/client/ArchiveManager.java
trunk/freenet/src/freenet/client/TempStoreElement.java
trunk/freenet/src/freenet/support/io/FileBucket.java
trunk/freenet/src/freenet/support/io/FilenameGenerator.java
trunk/freenet/src/freenet/support/io/NullPersistentFileTracker.java
trunk/freenet/src/freenet/support/io/PersistentFileTracker.java
trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
trunk/freenet/src/freenet/support/io/SerializableToFieldSetBucketUtil.java
trunk/freenet/src/freenet/support/io/TempBucketFactory.java
trunk/freenet/src/freenet/support/io/TempFileBucket.java
Log:
Untested significant refactoring of FileBucket/TempFileBucket.
Will save some memory, also code simplifications.
Modified: trunk/freenet/src/freenet/client/ArchiveManager.java
===================================================================
--- trunk/freenet/src/freenet/client/ArchiveManager.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/client/ArchiveManager.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -22,6 +22,7 @@
import freenet.support.io.FileBucket;
import freenet.support.io.FilenameGenerator;
import freenet.support.io.PaddedEphemerallyEncryptedBucket;
+import freenet.support.io.TempFileBucket;
/**
* Cache of recently decoded archives:
@@ -441,8 +442,9 @@
* go over the maximum size. Will obviously keep its key when we move
it to main.
*/
private TempStoreElement makeTempStoreBucket(long size) {
- File myFile = filenameGenerator.makeRandomFilename();
- FileBucket fb = new FileBucket(myFile, false, false, true,
true, true);
+ long id = filenameGenerator.makeRandomFilename();
+ File myFile = filenameGenerator.getFilename(id);
+ TempFileBucket fb = new TempFileBucket(id, filenameGenerator);
byte[] cipherKey = new byte[32];
random.nextBytes(cipherKey);
Modified: trunk/freenet/src/freenet/client/TempStoreElement.java
===================================================================
--- trunk/freenet/src/freenet/client/TempStoreElement.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/client/TempStoreElement.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -5,15 +5,15 @@
import java.io.File;
-import freenet.support.io.FileBucket;
import freenet.support.io.PaddedEphemerallyEncryptedBucket;
+import freenet.support.io.TempFileBucket;
class TempStoreElement {
final File myFilename;
final PaddedEphemerallyEncryptedBucket bucket;
- final FileBucket underBucket;
+ final TempFileBucket underBucket;
- TempStoreElement(File myFile, FileBucket fb,
PaddedEphemerallyEncryptedBucket encryptedBucket) {
+ TempStoreElement(File myFile, TempFileBucket fb,
PaddedEphemerallyEncryptedBucket encryptedBucket) {
this.myFilename = myFile;
this.underBucket = fb;
this.bucket = encryptedBucket;
Added: trunk/freenet/src/freenet/support/io/BaseFileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/BaseFileBucket.java
(rev 0)
+++ trunk/freenet/src/freenet/support/io/BaseFileBucket.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -0,0 +1,372 @@
+package freenet.support.io;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+import freenet.support.api.Bucket;
+
+public abstract class BaseFileBucket implements Bucket,
SerializableToFieldSetBucket {
+
+ protected long length;
+ // JVM caches File.size() and there is no way to flush the cache, so we
+ // need to track it ourselves
+ protected long fileRestartCounter;
+
+ protected static String tempDir = null;
+
+ public BaseFileBucket(File file) {
+ this.length = file.length();
+ if(deleteOnExit()) {
+ try {
+ file.deleteOnExit();
+ } catch (NullPointerException e) {
+ Logger.error(this, "Impossible: "+e, e);
+ System.err.println("Impossible: "+e);
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ synchronized (this) {
+ File file = getFile();
+ if(isReadOnly())
+ throw new IOException("Bucket is read-only");
+
+ if(createFileOnly() && file.exists())
+ throw new FileExistsException(file);
+
+ // FIXME: behaviour depends on UNIX semantics, to
totally abstract
+ // it out we would have to kill the old write streams
here
+ // FIXME: what about existing streams? Will ones on
append append
+ // to the new truncated file? Do we want them to? What
about
+ // truncated ones? We should kill old streams here,
right?
+ return newFileBucketOutputStream(createFileOnly() ?
getTempfile() : file, file.getPath(), ++fileRestartCounter);
+ }
+ }
+
+ protected abstract boolean createFileOnly();
+
+ protected abstract boolean deleteOnExit();
+
+ protected abstract boolean deleteOnFinalize();
+
+ protected abstract boolean deleteOnFree();
+
+ /**
+ * Create a temporary file in the same directory as this file.
+ */
+ protected File getTempfile() throws IOException {
+ File file = getFile();
+ File f = File.createTempFile(file.getName(), ".freenet-tmp",
file.getParentFile());
+ if(deleteOnExit()) f.deleteOnExit();
+ return f;
+ }
+
+ protected FileBucketOutputStream newFileBucketOutputStream(
+ File tempfile, String s, long streamNumber) throws IOException {
+ return new FileBucketOutputStream(tempfile, s, streamNumber);
+ }
+
+ protected synchronized void resetLength() {
+ length = 0;
+ }
+
+ /**
+ * Internal OutputStream impl.
+ * If createFileOnly is set, we won't overwrite an existing file, and
we write to a temp file
+ * then rename over the target. Note that we can't use createNewFile
then new FOS() because while
+ * createNewFile is atomic, the combination is not, so if we do it we
are vulnerable to symlink
+ * attacks.
+ * @author toad
+ */
+ class FileBucketOutputStream extends FileOutputStream {
+
+ private long restartCount;
+ private File tempfile;
+ private boolean closed;
+
+ protected FileBucketOutputStream(
+ File tempfile, String s, long restartCount)
+ throws FileNotFoundException {
+ super(tempfile, false);
+ if(Logger.shouldLog(Logger.MINOR, this))
+ Logger.minor(this, "Writing to "+tempfile+" for
"+getFile());
+ this.tempfile = tempfile;
+ resetLength();
+ this.restartCount = restartCount;
+ closed = false;
+ }
+
+ protected void confirmWriteSynchronized() throws IOException {
+ if (fileRestartCounter > restartCount)
+ throw new IllegalStateException("writing to
file after restart");
+ if(isReadOnly())
+ throw new IOException("File is read-only");
+ }
+
+ public void write(byte[] b) throws IOException {
+ synchronized (BaseFileBucket.this) {
+ confirmWriteSynchronized();
+ super.write(b);
+ length += b.length;
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws
IOException {
+ synchronized (BaseFileBucket.this) {
+ confirmWriteSynchronized();
+ super.write(b, off, len);
+ length += len;
+ }
+ }
+
+ public void write(int b) throws IOException {
+ synchronized (BaseFileBucket.this) {
+ confirmWriteSynchronized();
+ super.write(b);
+ length++;
+ }
+ }
+
+ public void close() throws IOException {
+ File file;
+ synchronized(this) {
+ if(closed) return;
+ closed = true;
+ file = getFile();
+ }
+ boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
+ if(logMINOR)
+ Logger.minor(this, "Closing
"+BaseFileBucket.this);
+ try {
+ super.close();
+ } catch (IOException e) {
+ if(logMINOR)
+ Logger.minor(this, "Failed closing
"+BaseFileBucket.this+" : "+e, e);
+ if(createFileOnly()) tempfile.delete();
+ throw e;
+ }
+ if(createFileOnly()) {
+ if(file.exists()) {
+ if(logMINOR)
+ Logger.minor(this, "File exists
creating file for "+this);
+ tempfile.delete();
+ throw new FileExistsException(file);
+ }
+ if(!tempfile.renameTo(file)) {
+ if(logMINOR)
+ Logger.minor(this, "Cannot
rename file for "+this);
+ if(file.exists()) throw new
FileExistsException(file);
+ tempfile.delete();
+ if(logMINOR)
+ Logger.minor(this, "Deleted,
cannot rename file for "+this);
+ throw new IOException("Cannot rename
file");
+ }
+ }
+ }
+ }
+
+ class FileBucketInputStream extends FileInputStream {
+ Exception e;
+
+ public FileBucketInputStream(File f) throws IOException {
+ super(f);
+ if (Logger.shouldLog(Logger.DEBUG, this))
+ e = new Exception("debug");
+ }
+ }
+
+ public synchronized InputStream getInputStream() throws IOException {
+ File file = getFile();
+ if(!file.exists()) {
+ Logger.normal(this, "File does not exist: "+file+" for
"+this);
+ return new NullInputStream();
+ } else
+ return new FileBucketInputStream(file);
+ }
+
+ /**
+ * @return the name of the file.
+ */
+ public synchronized String getName() {
+ return getFile().getName();
+ }
+
+ public synchronized long size() {
+ return length;
+ }
+
+ /**
+ * Actually delete the underlying file. Called by finalizer, will not be
+ * called twice. But length must still be valid when calling it.
+ */
+ protected synchronized void deleteFile() {
+ getFile().delete();
+ }
+
+ public void finalize() {
+ if(deleteOnFinalize())
+ free(true);
+ }
+
+ /**
+ * Return directory used for temp files.
+ */
+ public final synchronized static String getTempDir() {
+ return tempDir; // **FIXME**/TODO: locking on tempDir needs to
be checked by a Java guru for consistency
+ }
+
+ /**
+ * Set temp file directory.
+ * <p>
+ * The directory must exist.
+ */
+ public final synchronized static void setTempDir(String dirName) {
+ File dir = new File(dirName);
+ if (!(dir.exists() && dir.isDirectory() && dir.canWrite())) {
+ throw new IllegalArgumentException(
+ "Bad Temp Directory: " + dir.getAbsolutePath());
+ }
+ tempDir = dirName; // **FIXME**/TODO: locking on tempDir needs
to be checked by a Java guru for consistency
+ }
+
+ // determine the temp directory in one of several ways
+
+ static {
+ // Try the Java property (1.2 and above)
+ tempDir = System.getProperty("java.io.tmpdir");
+
+ // Deprecated calls removed.
+
+ // Try TEMP and TMP
+ // if (tempDir == null) {
+ // tempDir = System.getenv("TEMP");
+ // }
+
+ // if (tempDir == null) {
+ // tempDir = System.getenv("TMP");
+ // }
+
+ // make some semi-educated guesses based on OS.
+
+ if (tempDir == null) {
+ String os = System.getProperty("os.name");
+ if (os != null) {
+
+ String[] candidates = null;
+
+ // XXX: Add more possible OSes here.
+ if (os.equalsIgnoreCase("Linux")
+ || os.equalsIgnoreCase("FreeBSD")) {
+ String[] linuxCandidates = { "/tmp",
"/var/tmp" };
+ candidates = linuxCandidates;
+ } else if (os.equalsIgnoreCase("Windows")) {
+ String[] windowsCandidates =
+ { "C:\\TEMP",
"C:\\WINDOWS\\TEMP" };
+ candidates = windowsCandidates;
+ }
+
+ if (candidates != null) {
+ for (int i = 0; i < candidates.length;
i++) {
+ File path = new
File(candidates[i]);
+ if (path.exists()
+ && path.isDirectory()
+ && path.canWrite()) {
+ tempDir = candidates[i];
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // last resort -- use current working directory
+
+ if (tempDir == null) {
+ // This can be null -- but that's OK, null => cwd for
File
+ // constructor, anyways.
+ tempDir = System.getProperty("user.dir");
+ }
+ }
+
+ public synchronized Bucket[] split(int splitSize) {
+ if(length > ((long)Integer.MAX_VALUE) * splitSize)
+ throw new IllegalArgumentException("Way too big!:
"+length+" for "+splitSize);
+ int bucketCount = (int) (length / splitSize);
+ if(length % splitSize > 0) bucketCount++;
+ Bucket[] buckets = new Bucket[bucketCount];
+ File file = getFile();
+ for(int i=0;i<buckets.length;i++) {
+ long startAt = i * splitSize * 1L;
+ long endAt = Math.min(startAt + splitSize * 1L, length);
+ long len = endAt - startAt;
+ buckets[i] = new ReadOnlyFileSliceBucket(file, startAt,
len);
+ }
+ return buckets;
+ }
+
+ public void free() {
+ free(false);
+ }
+
+ public synchronized void free(boolean forceFree) {
+ File file = getFile();
+ 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());
+ }
+ }
+
+ public synchronized String toString() {
+ return super.toString()+ ':' +getFile().getPath();
+ }
+
+ /**
+ * Returns the file object this buckets data is kept in.
+ */
+ public abstract File getFile();
+
+ public synchronized SimpleFieldSet toFieldSet() {
+ if(deleteOnFinalize()) return null;
+ SimpleFieldSet fs = new SimpleFieldSet(false);
+ fs.putSingle("Type", "FileBucket");
+ fs.putSingle("Filename", getFile().toString());
+ fs.put("Length", size());
+ return fs;
+ }
+
+ public static Bucket create(SimpleFieldSet fs, PersistentFileTracker f)
throws CannotCreateFromFieldSetException {
+ String tmp = fs.get("Filename");
+ if(tmp == null) throw new CannotCreateFromFieldSetException("No
filename");
+ File file = FileUtil.getCanonicalFile(new File(tmp));
+ if(f.matches(file)) {
+ return PersistentTempFileBucket.create(fs, f);
+ }
+ tmp = fs.get("Length");
+ if(tmp == null) throw new CannotCreateFromFieldSetException("No
length");
+ try {
+ long length = Long.parseLong(tmp);
+ if(length != file.length())
+ throw new
CannotCreateFromFieldSetException("Invalid length: should be "+length+"
actually "+file.length()+" on "+file);
+ } catch (NumberFormatException e) {
+ throw new CannotCreateFromFieldSetException("Corrupt
length "+tmp, e);
+ }
+ FileBucket bucket = new FileBucket(file, false, true, false,
false, false);
+ if(file.exists()) // no point otherwise!
+ f.register(file);
+ return bucket;
+ }
+
+}
Modified: trunk/freenet/src/freenet/support/io/FileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FileBucket.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/FileBucket.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -4,16 +4,7 @@
package freenet.support.io;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import freenet.crypt.RandomSource;
-import freenet.support.Logger;
-import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
/**
@@ -21,7 +12,7 @@
*
* @author oskar
*/
-public class FileBucket implements Bucket, SerializableToFieldSetBucket {
+public class FileBucket extends BaseFileBucket implements Bucket,
SerializableToFieldSetBucket {
protected final File file;
protected boolean readOnly;
@@ -29,7 +20,6 @@
protected boolean deleteOnFree;
protected final boolean deleteOnExit;
protected final boolean createFileOnly;
- protected long length;
// JVM caches File.size() and there is no way to flush the cache, so we
// need to track it ourselves
protected long fileRestartCounter;
@@ -52,6 +42,7 @@
* @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 createFileOnly,
boolean deleteOnFinalize, boolean deleteOnExit, boolean deleteOnFree) {
+ super(file);
if(file == null) throw new NullPointerException();
file = file.getAbsoluteFile();
this.readOnly = readOnly;
@@ -60,323 +51,22 @@
this.deleteOnFinalize = deleteOnFinalize;
this.deleteOnFree = deleteOnFree;
this.deleteOnExit = deleteOnExit;
- if(deleteOnExit) {
- try {
- file.deleteOnExit();
- } catch (NullPointerException e) {
- Logger.error(this, "Impossible: "+e, e);
- System.err.println("Impossible: "+e);
- e.printStackTrace();
- }
- }
// Useful for finding temp file leaks.
// System.err.println("-- FileBucket.ctr(0) -- " +
// file.getAbsolutePath());
// (new Exception("get stack")).printStackTrace();
fileRestartCounter = 0;
- if(file.exists()) {
- length = file.length();
- if(!file.canWrite())
- readOnly = true;
- }
- else length = 0;
+ if(!file.canRead())
+ this.readOnly = true;
}
/**
- * Creates a new FileBucket in a random temporary file in the temporary
- * directory.
- * @throws IOException
- */
- public FileBucket(RandomSource random) throws IOException {
- // **FIXME**/TODO: locking on tempDir needs to be checked by a
Java guru for consistency
- file = File.createTempFile(tempDir, ".freenet.tmp");
- createFileOnly = true;
- // Useful for finding temp file leaks.
- //System.err.println("-- FileBucket.ctr(1) -- " +
- // file.getAbsolutePath());
- //(new Exception("get stack")).printStackTrace();
- deleteOnFinalize = true;
- deleteOnExit = true;
- length = 0;
- file.deleteOnExit();
- }
-
- public FileBucket(SimpleFieldSet fs, PersistentFileTracker f) throws
CannotCreateFromFieldSetException {
- createFileOnly = true;
- deleteOnExit = false;
- String tmp = fs.get("Filename");
- if(tmp == null) throw new CannotCreateFromFieldSetException("No
filename");
- this.file = FileUtil.getCanonicalFile(new File(tmp));
- tmp = fs.get("Length");
- if(tmp == null) throw new CannotCreateFromFieldSetException("No
length");
- try {
- length = Long.parseLong(tmp);
- if(length != file.length())
- throw new
CannotCreateFromFieldSetException("Invalid length: should be "+length+"
actually "+file.length()+" on "+file);
- } catch (NumberFormatException e) {
- throw new CannotCreateFromFieldSetException("Corrupt
length "+tmp, e);
- }
- if(file.exists()) // no point otherwise!
- f.register(file);
- }
-
- public OutputStream getOutputStream() throws IOException {
- synchronized (this) {
- if(readOnly)
- throw new IOException("Bucket is read-only");
-
- if(createFileOnly && file.exists())
- throw new FileExistsException(file);
-
- // FIXME: behaviour depends on UNIX semantics, to
totally abstract
- // it out we would have to kill the old write streams
here
- // FIXME: what about existing streams? Will ones on
append append
- // to the new truncated file? Do we want them to? What
about
- // truncated ones? We should kill old streams here,
right?
- return newFileBucketOutputStream(createFileOnly ?
getTempfile() : file, file.getPath(), ++fileRestartCounter);
- }
- }
-
- /**
- * Create a temporary file in the same directory as this file.
- */
- protected File getTempfile() throws IOException {
- File f = File.createTempFile(file.getName(), ".freenet-tmp",
file.getParentFile());
- if(deleteOnExit) f.deleteOnExit();
- return f;
- }
-
- protected FileBucketOutputStream newFileBucketOutputStream(
- File tempfile, String s, long streamNumber) throws IOException {
- return new FileBucketOutputStream(tempfile, s, streamNumber);
- }
-
- protected synchronized void resetLength() {
- length = 0;
- }
-
- /**
- * Internal OutputStream impl.
- * If createFileOnly is set, we won't overwrite an existing file, and
we write to a temp file
- * then rename over the target. Note that we can't use createNewFile
then new FOS() because while
- * createNewFile is atomic, the combination is not, so if we do it we
are vulnerable to symlink
- * attacks.
- * @author toad
- */
- class FileBucketOutputStream extends FileOutputStream {
-
- private long restartCount;
- private File tempfile;
- private boolean closed;
-
- protected FileBucketOutputStream(
- File tempfile, String s, long restartCount)
- throws FileNotFoundException {
- super(tempfile, false);
- if(Logger.shouldLog(Logger.MINOR, this))
- Logger.minor(this, "Writing to "+tempfile+" for
"+file);
- this.tempfile = tempfile;
- resetLength();
- this.restartCount = restartCount;
- closed = false;
- }
-
- protected void confirmWriteSynchronized() throws IOException {
- if (fileRestartCounter > restartCount)
- throw new IllegalStateException("writing to
file after restart");
- if(readOnly)
- throw new IOException("File is read-only");
- }
-
- public void write(byte[] b) throws IOException {
- synchronized (FileBucket.this) {
- confirmWriteSynchronized();
- super.write(b);
- length += b.length;
- }
- }
-
- public void write(byte[] b, int off, int len) throws
IOException {
- synchronized (FileBucket.this) {
- confirmWriteSynchronized();
- super.write(b, off, len);
- length += len;
- }
- }
-
- public void write(int b) throws IOException {
- synchronized (FileBucket.this) {
- confirmWriteSynchronized();
- super.write(b);
- length++;
- }
- }
-
- public void close() throws IOException {
- synchronized(this) {
- if(closed) return;
- closed = true;
- }
- boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
- if(logMINOR)
- Logger.minor(this, "Closing "+FileBucket.this);
- try {
- super.close();
- } catch (IOException e) {
- if(logMINOR)
- Logger.minor(this, "Failed closing
"+FileBucket.this+" : "+e, e);
- if(createFileOnly) tempfile.delete();
- throw e;
- }
- if(createFileOnly) {
- if(file.exists()) {
- if(logMINOR)
- Logger.minor(this, "File exists
creating file for "+this);
- tempfile.delete();
- throw new FileExistsException(file);
- }
- if(!tempfile.renameTo(file)) {
- if(logMINOR)
- Logger.minor(this, "Cannot
rename file for "+this);
- if(file.exists()) throw new
FileExistsException(file);
- tempfile.delete();
- if(logMINOR)
- Logger.minor(this, "Deleted,
cannot rename file for "+this);
- throw new IOException("Cannot rename
file");
- }
- }
- }
- }
-
- class FileBucketInputStream extends FileInputStream {
- Exception e;
-
- public FileBucketInputStream(File f) throws IOException {
- super(f);
- if (Logger.shouldLog(Logger.DEBUG, this))
- e = new Exception("debug");
- }
- }
-
- public synchronized InputStream getInputStream() throws IOException {
- if(!file.exists()) {
- Logger.normal(this, "File does not exist: "+file+" for
"+this);
- return new NullInputStream();
- } else
- return new FileBucketInputStream(file);
- }
-
- /**
- * @return the name of the file.
- */
- public synchronized String getName() {
- return file.getName();
- }
-
- public synchronized long size() {
- return length;
- }
-
- /**
* Returns the file object this buckets data is kept in.
*/
public synchronized File getFile() {
return file;
}
- /**
- * Actually delete the underlying file. Called by finalizer, will not be
- * called twice. But length must still be valid when calling it.
- */
- protected synchronized void deleteFile() {
- file.delete();
- }
-
- public void finalize() {
- if(deleteOnFinalize)
- free(deleteOnFinalize);
- }
-
- /**
- * Return directory used for temp files.
- */
- public final synchronized static String getTempDir() {
- return tempDir; // **FIXME**/TODO: locking on tempDir needs to
be checked by a Java guru for consistency
- }
-
- /**
- * Set temp file directory.
- * <p>
- * The directory must exist.
- */
- public final synchronized static void setTempDir(String dirName) {
- File dir = new File(dirName);
- if (!(dir.exists() && dir.isDirectory() && dir.canWrite())) {
- throw new IllegalArgumentException(
- "Bad Temp Directory: " + dir.getAbsolutePath());
- }
- tempDir = dirName; // **FIXME**/TODO: locking on tempDir needs
to be checked by a Java guru for consistency
- }
-
- // determine the temp directory in one of several ways
-
- static {
- // Try the Java property (1.2 and above)
- tempDir = System.getProperty("java.io.tmpdir");
-
- // Deprecated calls removed.
-
- // Try TEMP and TMP
- // if (tempDir == null) {
- // tempDir = System.getenv("TEMP");
- // }
-
- // if (tempDir == null) {
- // tempDir = System.getenv("TMP");
- // }
-
- // make some semi-educated guesses based on OS.
-
- if (tempDir == null) {
- String os = System.getProperty("os.name");
- if (os != null) {
-
- String[] candidates = null;
-
- // XXX: Add more possible OSes here.
- if (os.equalsIgnoreCase("Linux")
- || os.equalsIgnoreCase("FreeBSD")) {
- String[] linuxCandidates = { "/tmp",
"/var/tmp" };
- candidates = linuxCandidates;
- } else if (os.equalsIgnoreCase("Windows")) {
- String[] windowsCandidates =
- { "C:\\TEMP",
"C:\\WINDOWS\\TEMP" };
- candidates = windowsCandidates;
- }
-
- if (candidates != null) {
- for (int i = 0; i < candidates.length;
i++) {
- File path = new
File(candidates[i]);
- if (path.exists()
- && path.isDirectory()
- && path.canWrite()) {
- tempDir = candidates[i];
- break;
- }
- }
- }
- }
- }
-
- // last resort -- use current working directory
-
- if (tempDir == null) {
- // This can be null -- but that's OK, null => cwd for
File
- // constructor, anyways.
- tempDir = System.getProperty("user.dir");
- }
- }
-
public synchronized boolean isReadOnly() {
return readOnly;
}
@@ -394,46 +84,19 @@
deleteOnFinalize = false;
}
- public synchronized Bucket[] split(int splitSize) {
- if(length > ((long)Integer.MAX_VALUE) * splitSize)
- throw new IllegalArgumentException("Way too big!:
"+length+" for "+splitSize);
- int bucketCount = (int) (length / splitSize);
- if(length % splitSize > 0) bucketCount++;
- Bucket[] buckets = new Bucket[bucketCount];
- for(int i=0;i<buckets.length;i++) {
- long startAt = i * splitSize * 1L;
- long endAt = Math.min(startAt + splitSize * 1L, length);
- long len = endAt - startAt;
- buckets[i] = new ReadOnlyFileSliceBucket(file, startAt,
len);
- }
- return buckets;
+ protected boolean createFileOnly() {
+ return createFileOnly;
}
- public void free() {
- free(false);
+ protected boolean deleteOnExit() {
+ return deleteOnExit;
}
-
- public synchronized 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());
- }
+
+ protected boolean deleteOnFinalize() {
+ return deleteOnFinalize;
}
-
- public synchronized String toString() {
- return super.toString()+ ':' +file.getPath();
- }
- public synchronized SimpleFieldSet toFieldSet() {
- if(deleteOnFinalize) return null;
- SimpleFieldSet fs = new SimpleFieldSet(false);
- fs.putSingle("Type", "FileBucket");
- fs.putSingle("Filename", file.toString());
- fs.put("Length", length);
- return fs;
+ protected boolean deleteOnFree() {
+ return deleteOnFree;
}
}
Modified: trunk/freenet/src/freenet/support/io/FilenameGenerator.java
===================================================================
--- trunk/freenet/src/freenet/support/io/FilenameGenerator.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/FilenameGenerator.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -6,7 +6,6 @@
import org.tanukisoftware.wrapper.WrapperManager;
import freenet.crypt.RandomSource;
-import freenet.support.HexUtil;
import freenet.support.Logger;
import freenet.support.TimeUtil;
@@ -27,15 +26,14 @@
this.random = random;
this.prefix = prefix;
if (dir == null)
- tmpDir = new File(System.getProperty("java.io.tmpdir"));
+ tmpDir = FileUtil.getCanonicalFile(new
File(System.getProperty("java.io.tmpdir")));
else
- tmpDir = dir;
+ tmpDir = FileUtil.getCanonicalFile(dir);
if(!tmpDir.exists()) {
tmpDir.mkdir();
}
if(!(tmpDir.isDirectory() && tmpDir.canRead() &&
tmpDir.canWrite()))
throw new IOException("Not a directory or cannot
read/write: "+tmpDir);
-
if(wipeFiles) {
long wipedFiles = 0;
long wipeableFiles = 0;
@@ -64,18 +62,38 @@
}
}
- public File makeRandomFilename() {
- byte[] randomFilename = new byte[8]; // should be plenty
+ public long makeRandomFilename() {
+ long randomFilename; // should be plenty
while(true) {
- random.nextBytes(randomFilename);
- String filename = prefix +
HexUtil.bytesToHex(randomFilename);
+ randomFilename = random.nextLong();
+ if(randomFilename == -1) continue; // Disallowed as
used for error reporting
+ String filename = prefix +
Long.toHexString(randomFilename);
File ret = new File(tmpDir, filename);
if(!ret.exists()) {
if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Made random
filename: "+ret, new Exception("debug"));
- return ret;
+ return randomFilename;
}
}
}
+ public File getFilename(long id) {
+ return new File(tmpDir, prefix + Long.toHexString(id));
+ }
+
+ public boolean matches(File file) {
+ return getID(file) != -1;
+ }
+
+ public long getID(File file) {
+
if(!(FileUtil.getCanonicalFile(file.getParentFile()).equals(tmpDir))) return -1;
+ String name = file.getName();
+ if(!name.startsWith(prefix)) return -1;
+ try {
+ return Long.parseLong(name.substring(prefix.length()),
16);
+ } catch (NumberFormatException e) {
+ return -1;
+ }
+ }
+
}
Modified: trunk/freenet/src/freenet/support/io/NullPersistentFileTracker.java
===================================================================
--- trunk/freenet/src/freenet/support/io/NullPersistentFileTracker.java
2007-07-21 00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/NullPersistentFileTracker.java
2007-07-21 01:42:16 UTC (rev 14222)
@@ -22,4 +22,16 @@
return new File(".");
}
+ public boolean matches(File file) {
+ return false;
+ }
+
+ public FilenameGenerator getGenerator() {
+ return null;
+ }
+
+ public long getID(File file) {
+ return 0;
+ }
+
}
Modified: trunk/freenet/src/freenet/support/io/PersistentFileTracker.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentFileTracker.java
2007-07-21 00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/PersistentFileTracker.java
2007-07-21 01:42:16 UTC (rev 14222)
@@ -21,5 +21,14 @@
* Get the persistent temp files directory.
*/
public File getDir();
+
+ /**
+ * Is the file in question one of our persistent temp files?
+ */
+ public boolean matches(File file);
+
+ public FilenameGenerator getGenerator();
+
+ public long getID(File file);
}
Modified: trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2007-07-21 00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/PersistentTempBucketFactory.java
2007-07-21 01:42:16 UTC (rev 14222)
@@ -96,7 +96,7 @@
}
private Bucket makeRawBucket(long size) throws IOException {
- return new FileBucket(fg.makeRandomFilename(), false, true,
false, false, true);
+ return new PersistentTempFileBucket(fg.makeRandomFilename(),
fg);
}
public Bucket makeBucket(long size) throws IOException {
@@ -130,4 +130,16 @@
return dir;
}
+ public FilenameGenerator getGenerator() {
+ return fg;
+ }
+
+ public boolean matches(File file) {
+ return fg.matches(file);
+ }
+
+ public long getID(File file) {
+ return fg.getID(file);
+ }
+
}
Added: trunk/freenet/src/freenet/support/io/PersistentTempFileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/PersistentTempFileBucket.java
(rev 0)
+++ trunk/freenet/src/freenet/support/io/PersistentTempFileBucket.java
2007-07-21 01:42:16 UTC (rev 14222)
@@ -0,0 +1,40 @@
+package freenet.support.io;
+
+import java.io.File;
+
+import freenet.support.SimpleFieldSet;
+import freenet.support.api.Bucket;
+
+public class PersistentTempFileBucket extends TempFileBucket {
+
+ protected PersistentTempFileBucket(long id, FilenameGenerator
generator) {
+ super(id, generator);
+ }
+
+ protected boolean deleteOnFinalize() {
+ // Do not delete on finalize
+ return false;
+ }
+
+ public static Bucket create(SimpleFieldSet fs, PersistentFileTracker f)
throws CannotCreateFromFieldSetException {
+ String tmp = fs.get("Filename");
+ if(tmp == null) throw new CannotCreateFromFieldSetException("No
filename");
+ File file = FileUtil.getCanonicalFile(new File(tmp));
+ long id = f.getID(file);
+ tmp = fs.get("Length");
+ if(tmp == null) throw new CannotCreateFromFieldSetException("No
length");
+ long length;
+ try {
+ length = Long.parseLong(tmp);
+ if(length != file.length())
+ throw new
CannotCreateFromFieldSetException("Invalid length: should be "+length+"
actually "+file.length()+" on "+file);
+ } catch (NumberFormatException e) {
+ throw new CannotCreateFromFieldSetException("Corrupt
length "+tmp, e);
+ }
+ Bucket bucket = new PersistentTempFileBucket(id,
f.getGenerator());
+ if(file.exists()) // no point otherwise!
+ f.register(file);
+ return bucket;
+ }
+
+}
Modified:
trunk/freenet/src/freenet/support/io/SerializableToFieldSetBucketUtil.java
===================================================================
--- trunk/freenet/src/freenet/support/io/SerializableToFieldSetBucketUtil.java
2007-07-21 00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/SerializableToFieldSetBucketUtil.java
2007-07-21 01:42:16 UTC (rev 14222)
@@ -56,7 +56,7 @@
throw new CannotCreateFromFieldSetException("No type");
} else if(type.equals("FileBucket")) {
- return new FileBucket(fs, f);
+ return BaseFileBucket.create(fs, f);
} else if(type.equals("PaddedEphemerallyEncryptedBucket")) {
return new PaddedEphemerallyEncryptedBucket(fs, random,
f);
} else if(type.equals("NullBucket")) {
Deleted: trunk/freenet/src/freenet/support/io/SpyInputStream.java
===================================================================
--- trunk/freenet/src/freenet/support/io/SpyInputStream.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/SpyInputStream.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -1,148 +0,0 @@
-package freenet.support.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/*
- * This code is part of FProxy, an HTTP proxy server for Freenet. It is
- * distributed under the GNU Public Licence (GPL) version 2. See
- * http://www.gnu.org/ for further details of the GPL.
- */
-
-/**
- * The purpose of all of this gobbledeygook is to keep rude FCPClient
- * implementations from writing to temp files after the requests that own them
- * have been canceled.
- *
- * <p>
- * These could be removed once FCPClient implementation deficiencies have been
- * corrected but sanity checks are always useful.
- * </p>
- *
- * @author ian
- * @see freenet.support.SpyOutputStream
- */
-class SpyInputStream extends java.io.FilterInputStream {
-
- private String prefix = "";
- private TempFileBucket tfb = null;
-
- private final void println(String text) {
- }
-
- private final void checkValid() throws IOException {
- synchronized (tfb) {
- if (tfb.isReleased()) {
- throw new IOException(
- "Attempt to use a released
TempFileBucket: " + prefix);
- }
- }
- }
-
- /**
- * Constructor for the SpyInputStream object
- *
- * @param tfb
- * @param prefix
- * @exception IOException
- */
- public SpyInputStream(TempFileBucket tfb, String prefix)
- throws IOException {
- super(null);
- InputStream tmpIn = null;
- try {
- this.prefix = prefix;
- this.tfb = tfb;
- checkValid();
- tmpIn = tfb.getRealInputStream();
- in = tmpIn;
- } catch (IOException ioe) {
- try {
- if (tmpIn != null) {
- tmpIn.close();
- }
- } catch (Exception e) {
- // NOP
- }
- throw ioe;
- }
- println("Created new InputStream");
- }
-
- public int read() throws java.io.IOException {
- synchronized (tfb) {
- println(".read()");
- checkValid();
- return in.read();
- }
- }
-
- public int read(byte[] bytes) throws java.io.IOException {
- synchronized (tfb) {
- println(".read(byte[])");
- checkValid();
- return in.read(bytes);
- }
- }
-
- public int read(byte[] bytes, int a, int b) throws java.io.IOException {
- synchronized (tfb) {
- println(".read(byte[], int, int)");
- checkValid();
- // FIXME remove debugging
- if((a+b > bytes.length) || (a < 0) || (b < 0))
- throw new
ArrayIndexOutOfBoundsException("a="+a+", b="+b+", length "+bytes.length);
- return in.read(bytes, a, b);
- }
- }
-
- public long skip(long a) throws java.io.IOException {
- synchronized (tfb) {
- println(".skip(long)");
- checkValid();
- return in.skip(a);
- }
- }
-
- public int available() throws java.io.IOException {
- synchronized (tfb) {
- println(".available()");
- checkValid();
- return in.available();
- }
- }
-
- public void close() throws java.io.IOException {
- synchronized (tfb) {
- println(".close()");
- checkValid();
- in.close();
- if (tfb.streams.contains(in)) {
- tfb.streams.removeElement(in);
- }
- }
- }
-
-
- public void mark(int a) {
- synchronized (tfb) {
- println(".mark(int)");
- in.mark(a);
- }
- }
-
- public void reset() throws java.io.IOException {
- synchronized (tfb) {
- println(".reset()");
- checkValid();
- in.reset();
- }
- }
-
- public boolean markSupported() {
- synchronized (tfb) {
- println(".markSupported()");
- return in.markSupported();
- }
- }
-}
Deleted: trunk/freenet/src/freenet/support/io/SpyOutputStream.java
===================================================================
--- trunk/freenet/src/freenet/support/io/SpyOutputStream.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/SpyOutputStream.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -1,116 +0,0 @@
-package freenet.support.io;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import freenet.support.Logger;
-
-/*
- * This code is part of FProxy, an HTTP proxy server for Freenet. It is
- * distributed under the GNU Public Licence (GPL) version 2. See
- * http://www.gnu.org/ for further details of the GPL.
- */
-
-/**
- * @author ian
- * @see freenet.support.SpyInputStream
- */
-public class SpyOutputStream extends FilterOutputStream {
-
- private String prefix = "";
- private TempFileBucket tfb = null;
-
- private void debugPrintLn(String text) {
- if (Logger.shouldLog(Logger.DEBUG,this))
- Logger.debug(this, text);
- }
-
- private final void checkValid() throws IOException {
- synchronized (tfb) {
- if (tfb.isReleased()) {
- throw new IOException(
- "Attempt to use a released
TempFileBucket: " + prefix);
- }
- }
- }
-
- /**
- * Constructor for the SpyOutputStream object
- *
- * @param tfb
- * @param pref
- * @exception IOException
- */
- public SpyOutputStream(TempFileBucket tfb, String pref)
- throws IOException {
- super(null);
- OutputStream tmpOut = null;
- try {
- this.prefix = pref;
- this.tfb = tfb;
- checkValid();
- tmpOut = tfb.getRealOutputStream();
- out = tmpOut;
- } catch (IOException ioe) {
- //ioe.printStackTrace();
- debugPrintLn("SpyOutputStream ctr failed!: " +
ioe.toString());
- try {
- if (tmpOut != null) {
- tmpOut.close();
- }
- } catch (Exception e0) {
- // NOP
- }
- debugPrintLn("SpyOutputStream ctr failed!: " +
ioe.toString());
- throw ioe;
- }
- debugPrintLn("Created new OutputStream");
- }
-
- ////////////////////////////////////////////////////////////
- // FilterOutputStream implementation
-
- public void write(int b) throws IOException {
- synchronized (tfb) {
- // println(".write(b)");
- checkValid();
- out.write(b);
- }
- }
-
- public void write(byte[] buf) throws IOException {
- synchronized (tfb) {
- // println(".write(buf)");
- checkValid();
- out.write(buf);
- }
- }
-
- public void write(byte[] buf, int off, int len) throws IOException {
- synchronized (tfb) {
- // println(".write(buf,off,len)");
- checkValid();
- out.write(buf, off, len);
- }
- }
-
- public void flush() throws IOException {
- synchronized (tfb) {
- debugPrintLn(".flush()");
- checkValid();
- out.flush();
- }
- }
-
- public void close() throws IOException {
- synchronized (tfb) {
- debugPrintLn(".close()");
- checkValid();
- out.close();
- if (tfb.streams.contains(out)) {
- tfb.streams.removeElement(out);
- }
- }
- }
-}
Modified: trunk/freenet/src/freenet/support/io/TempBucketFactory.java
===================================================================
--- trunk/freenet/src/freenet/support/io/TempBucketFactory.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/TempBucketFactory.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -1,6 +1,5 @@
package freenet.support.io;
-import java.io.File;
import java.io.IOException;
import freenet.support.Logger;
@@ -20,24 +19,13 @@
*/
public class TempBucketFactory implements BucketFactory {
- private static class NOPHook implements TempBucketHook {
- public void enlargeFile(long curLength, long finalLength) {
- }
- public void shrinkFile(long curLength, long finalLength) {
- }
- public void deleteFile(long curLength) {
- }
- public void createFile(long curLength) {
- }
- }
-
- private final static TempBucketHook DONT_HOOK = new NOPHook();
- private static TempBucketHook hook = DONT_HOOK;
private static boolean logDebug=true;
private final FilenameGenerator filenameGenerator;
public static long defaultIncrement = 4096;
+
+ public static float DEFAULT_FACTOR = 1.25F;
// Storage accounting disabled by default.
public TempBucketFactory(FilenameGenerator filenameGenerator) {
@@ -46,7 +34,7 @@
}
public Bucket makeBucket(long size) throws IOException {
- return makeBucket(size, 1.25F, defaultIncrement);
+ return makeBucket(size, DEFAULT_FACTOR, defaultIncrement);
}
public Bucket makeBucket(long size, float factor) throws IOException {
@@ -68,10 +56,9 @@
public TempFileBucket makeBucket(long size, float factor, long
increment)
throws IOException {
logDebug = Logger.shouldLog(Logger.DEBUG,this);
- File f = filenameGenerator.makeRandomFilename();
- if(f == null) throw new NullPointerException();
+ long id = filenameGenerator.makeRandomFilename();
- return new TempFileBucket(f, hook, size, increment, factor);
+ return new TempFileBucket(id, filenameGenerator);
}
/**
@@ -97,31 +84,4 @@
}
}
}
-
- /**
- * Sets the storage accounting hook.
- *
- * @param t
- * The hook object to use to keep track of the amount of
storage
- * used. It is legal for t to be null. In this case storage
- * accounting is disabled.
- */
- public static void setHook(TempBucketHook t) {
- if (logDebug)
- Logger.debug(
- TempBucketFactory.class,
- "Set TempBucketHook to " + t);
- hook = t;
- if (hook == null) {
- // Allow hooks to be disabled w/o sprinkling
- // if (hook != null) {/*blah blah */} calls
- // throughout the code.
- hook = DONT_HOOK;
- if (logDebug) {
- Logger.debug(
- TempBucketHook.class,
- "TempBucketHook file usage management
was disabled.");
- }
- }
- }
}
Deleted: trunk/freenet/src/freenet/support/io/TempBucketHook.java
===================================================================
--- trunk/freenet/src/freenet/support/io/TempBucketHook.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/TempBucketHook.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -1,34 +0,0 @@
-/* This code is part of Freenet. It is distributed under the GNU General
- * Public License, version 2 (or at your option any later version). See
- * http://www.gnu.org/ for further details of the GPL. */
-package freenet.support.io;
-
-import java.io.IOException;
-
-public interface TempBucketHook {
-
- /** Allocate space for a write making the file larger
- * Call this before writing a file, make sure you call shrinkFile if the
write fails
- * @param curLength the length of the file before the write
- * @param finalLength the length of the file after the write
- * @throws IOException if insufficient space
- */
- void enlargeFile(long curLength, long finalLength) throws IOException;
-
- /** Deallocate space after a write enlarging the file fails
- * Call this if enlargeFile was called but the write failed.
- * Also call it if you want to truncate a file
- * @param curLength original length before write
- * @param finalLength length the file would have been if the write had
succeeded
- */
- void shrinkFile(long curLength, long finalLength);
-
- /** Deallocate space for a temp file, AFTER successful delete completed
- */
- void deleteFile(long curLength);
-
- /** Allocate space for a temp file, before actually creating it
- */
- void createFile(long curLength) throws IOException;
-
-}
Modified: trunk/freenet/src/freenet/support/io/TempFileBucket.java
===================================================================
--- trunk/freenet/src/freenet/support/io/TempFileBucket.java 2007-07-21
00:23:34 UTC (rev 14221)
+++ trunk/freenet/src/freenet/support/io/TempFileBucket.java 2007-07-21
01:42:16 UTC (rev 14222)
@@ -8,6 +8,7 @@
import freenet.support.Logger;
import freenet.support.SimpleFieldSet;
+import freenet.support.api.Bucket;
/*
* This code is part of FProxy, an HTTP proxy server for Freenet.
@@ -19,138 +20,49 @@
*
* @author giannij
*/
-public class TempFileBucket extends FileBucket {
- TempBucketHook hook = null;
- // How much we have asked the Hook to allocate for us
- long fakeLength = 0;
- long minAlloc;
- float factor;
+public class TempFileBucket extends BaseFileBucket implements Bucket,
SerializableToFieldSetBucket {
+ long filenameID;
+ final FilenameGenerator generator;
private static boolean logDebug = true;
+ private boolean readOnly;
/**
* Constructor for the TempFileBucket object
*
* @param f File
*/
- protected TempFileBucket(
- File f,
- TempBucketHook hook,
- long startLength,
- long minAlloc,
- float factor)
- throws IOException {
- super(f, false, false, true, true, true);
+ public TempFileBucket(
+ long id,
+ FilenameGenerator generator) {
+ super(generator.getFilename(id));
+ this.filenameID = id;
+ this.generator = generator;
synchronized(this) {
logDebug = Logger.shouldLog(Logger.DEBUG, this);
}
- if (minAlloc > 0)
- this.minAlloc = minAlloc;
- else
- this.minAlloc = 1024;
- this.factor = factor;
- if (factor < 1.0)
- throw new IllegalArgumentException("factor must be >=
1.0");
- // Make sure finalize wacks temp file
- // if it is not explictly freed.
- deleteOnFinalize = true;
-
//System.err.println("FProxyServlet.TempFileBucket -- created:
" +
// f.getAbsolutePath());
- this.hook = hook;
- long x = startLength <= 0 ? minAlloc : startLength;
- hook.createFile(x);
- this.fakeLength = x;
synchronized(this) {
if (logDebug)
Logger.debug(
this,
- "Initializing TempFileBucket(" + f +
',' + hook + ')');
+ "Initializing TempFileBucket(" +
getFile());
}
}
- /**
- * Gets the realInputStream attribute of the TempFileBucket object
- *
- * @return The realInputStream value
- * @exception IOException Description of the Exception
- */
- synchronized InputStream getRealInputStream() throws IOException {
- if (released || closing)
- throw new IllegalStateException(
- "Trying to getRealInputStream on released
TempFileBucket "+this+" !");
- if (logDebug)
- Logger.debug(
- this,
- "getRealInputStream() for " + file,
- new Exception("debug"));
- if (!file.exists())
- return new NullInputStream();
- else
- return new HookedFileBucketInputStream(file);
+ protected boolean deleteOnFinalize() {
+ // Make sure finalize wacks temp file
+ // if it is not explictly freed.
+ return true;
}
-
+
/**
- * Gets the realOutputStream attribute of the TempFileBucket object
- *
- * @return The realOutputStream value
- * @exception IOException Description of the Exception
- */
- OutputStream getRealOutputStream() throws IOException {
- if (released || closing)
- throw new IllegalStateException(
- "Trying to getRealOutputStream on released
TempFileBucket "+this+" !");
- synchronized(this) {
- if (logDebug)
- Logger.debug(
- this,
- "getRealOutputStream() for " + file,
- new Exception("debug"));
- }
- return super.getOutputStream();
- }
-
- // Wrap non-const members so we can tell
- // when code touches the Bucket after it
- // has been released.
- /**
- * Gets the inputStream attribute of the TempFileBucket object
- *
- * @return The inputStream value
- * @exception IOException Description of the Exception
- */
- public synchronized InputStream getInputStream() throws IOException {
- if (released || closing)
- throw new IllegalStateException(
- "Trying to getInputStream on released
TempFileBucket "+this+" !");
- logDebug = Logger.shouldLog(Logger.DEBUG, this);
- if (logDebug)
- Logger.debug(this, "getInputStream for " + file);
- InputStream newIn = new SpyInputStream(this,
file.getAbsolutePath());
- return newIn;
- }
-
- /**
- * Gets the outputStream attribute of the TempFileBucket object
- *
- * @return The outputStream value
- * @exception IOException Description of the Exception
- */
- public synchronized OutputStream getOutputStream() throws IOException {
- if (released || closing)
- throw new IllegalStateException(
- "Trying to getOutputStream on released
TempFileBucket "+this+" !");
- logDebug = Logger.shouldLog(Logger.DEBUG, this);
- if (logDebug)
- Logger.debug(this, "getOutputStream for " + file);
- return new SpyOutputStream(this, file.getAbsolutePath());
- }
-
- /**
* Release
*
* @return Success
*/
public synchronized boolean release() {
+ File file = getFile();
if(Logger.shouldLog(Logger.MINOR, this))
Logger.minor(this, "Releasing bucket: "+file, new
Exception("debug"));
//System.err.println("FProxyServlet.TempFileBucket -- release:
" + // file.getAbsolutePath());
@@ -235,13 +147,7 @@
new Exception());
// Nonrecoverable; even though the user can't
fix it it's still very serious
return false;
- } else {
- if (hook != null)
- hook.deleteFile(fakeLength);
}
- } else {
- if (hook != null)
- hook.deleteFile(fakeLength);
}
if (logDebug)
Logger.debug(
@@ -274,179 +180,55 @@
private boolean released;
private boolean closing;
- protected synchronized FileBucketOutputStream newFileBucketOutputStream(
- String s,
- boolean append,
- long restartCount)
- throws IOException {
- if (logDebug)
- Logger.debug(this,
- "Creating new HookedFileBucketOutputStream for
" + file);
- if (hook != null)
- return new HookedFileBucketOutputStream(s,
restartCount);
- else
- return super.newFileBucketOutputStream(new File(s), s,
restartCount);
- }
-
protected synchronized void deleteFile() {
if (logDebug)
- Logger.debug(this, "Deleting " + file);
- file.delete();
- if (hook != null)
- hook.deleteFile(fakeLength);
+ Logger.debug(this, "Deleting " + getFile());
+ getFile().delete();
}
protected synchronized void resetLength() {
if (logDebug)
- Logger.debug(this, "Resetting length for " + file);
- if (length != 0) {
- if (hook != null) {
- hook.shrinkFile(0, fakeLength);
- fakeLength = 0;
- }
- super.resetLength();
- }
+ Logger.debug(this, "Resetting length for " + getFile());
}
protected final synchronized void getLengthSynchronized(long len)
throws IOException {
// Core.logger.log(this, "getLengthSynchronized("+len+
// "); fakeLength = "+fakeLength,
Logger.DEBUG);
- long l = fakeLength;
- long ol = l;
- while (len > l) {
- l = (long) (l * factor);
- if (minAlloc > 0)
- l = l + minAlloc - (l % minAlloc);
- if (l <= fakeLength)
- throw new IllegalStateException("Bucket
extension error!");
- // Core.logger.log(this, "l now "+l,
Logger.DEBUG);
- if (ol == l)
- throw new IllegalStateException("infinite
loop");
- ol = l;
- }
- if (fakeLength != l) {
- if (Logger.shouldLog(Logger.DEBUG, this))
- Logger.debug(
- this,
- "getLengthSynchronized("
- + len
- + "): increasing "
- + fakeLength
- + " to: "
- + l
- + " (real length: "
- + length
- + ')');
- hook.enlargeFile(fakeLength, l);
- }
- fakeLength = l;
+ if(len <= 0) return;
+ length += len;
}
public synchronized String toString(){
- return "TempFileBucket (File:
'"+getFile().getAbsolutePath()+"', streams: "+streams.size()+", hook: "+hook+
')';
+ return "TempFileBucket (File:
'"+getFile().getAbsolutePath()+"', streams: "+streams.size();
}
- class HookedFileBucketInputStream extends FileBucketInputStream {
- HookedFileBucketInputStream(File f) throws IOException {
- super(f);
- streams.addElement(this);
- }
+ public SimpleFieldSet toFieldSet() {
+ SimpleFieldSet fs = super.toFieldSet();
+ fs.putSingle("Type", "TempFileBucket");
+ return fs;
+ }
- public void close() throws IOException {
- super.close();
- while (streams.remove(this));
- }
+ protected boolean createFileOnly() {
+ return false;
}
- class HookedFileBucketOutputStream extends FileBucketOutputStream {
+ protected boolean deleteOnFree() {
+ return true;
+ }
- protected HookedFileBucketOutputStream(
- String s,
- long restartCount)
- throws IOException {
- super(new File(s), s, restartCount);
- streams.addElement(this);
- if (Logger.shouldLog(Logger.DEBUG, this))
- Logger.debug(
- this,
- "Created HookedFileBucketOutputStream("
- + s
- + ','
- + restartCount
- + ')');
- }
+ public File getFile() {
+ return generator.getFilename(filenameID);
+ }
- public void close() throws IOException {
- super.close();
- while (streams.remove(this));
- }
+ public boolean isReadOnly() {
+ return readOnly;
+ }
- public void write(byte[] b) throws IOException {
- // Core.logger.log(this,
"HookedFileBucketOutputStream.write(byte[] len "+
- // b.length+") for "+file,
Logger.DEBUG);
- synchronized (TempFileBucket.this) {
- // Core.logger.log(this,
"Synchronized on TempFileBucket",
- // Logger.DEBUG);
- super.confirmWriteSynchronized();
- // Core.logger.log(this,
"confirmWriteSynchronized()", Logger.DEBUG);
- long finalLength = length + b.length;
- // Core.logger.log(this,
"length="+length+", finalLength="+finalLength,
- // Logger.DEBUG);
- long realStartLen = fakeLength;
- getLengthSynchronized(finalLength);
- // Core.logger.log(this, "Called
hook.enlargeFile()", Logger.DEBUG);
- try {
- super.write(b);
- // Core.logger.log(this,
"Written", Logger.DEBUG);
- } catch (IOException e) {
- // Core.logger.log(this,
"Write failed", Logger.DEBUG);
- hook.shrinkFile(realStartLen,
fakeLength);
- fakeLength = realStartLen;
- // Core.logger.log(this,
"Shrank file", Logger.DEBUG);
- throw e;
- }
- }
- }
-
- public void write(byte[] b, int off, int len) throws
IOException {
- // Core.logger.log(this,
"HookedFileBucketOutputStream.write(byte[], "+off+
- // ","+len+") for "+file,
Logger.DEBUG);
- synchronized (TempFileBucket.this) {
- long finalLength = length + len;
- long realStartLen = fakeLength;
- getLengthSynchronized(finalLength);
- try {
- super.write(b, off, len);
- } catch (IOException e) {
- hook.shrinkFile(realStartLen,
fakeLength);
- fakeLength = realStartLen;
- throw e;
- }
- }
- }
-
- public void write(int b) throws IOException {
- // Core.logger.log(this,
"HookedFileBucketOutputStream.write(int) for "+file,
- // Logger.DEBUG);
- synchronized (TempFileBucket.this) {
- long finalLength = length + 1;
- long realStartLen = fakeLength;
- getLengthSynchronized(finalLength);
- try {
- super.write(b);
- } catch (IOException e) {
- hook.shrinkFile(realStartLen,
fakeLength);
- fakeLength = realStartLen;
- throw e;
- }
- }
- }
-
+ public void setReadOnly() {
+ readOnly = true;
}
- public SimpleFieldSet toFieldSet() {
- SimpleFieldSet fs = super.toFieldSet();
- fs.putSingle("Type", "TempFileBucket");
- return fs;
+ protected boolean deleteOnExit() {
+ return true;
}
}