Skip to content
Snippets Groups Projects
Commit 74d2123d authored by Greg DiCristofaro's avatar Greg DiCristofaro
Browse files

fixes to use soft references and auto close for content stream

parent be9a85ff
Branches
Tags
No related merge requests found
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.lang.ref.SoftReference;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.text.MessageFormat; import java.text.MessageFormat;
...@@ -118,8 +119,9 @@ public abstract class AbstractFile extends AbstractContent { ...@@ -118,8 +119,9 @@ public abstract class AbstractFile extends AbstractContent {
private volatile String uniquePath; private volatile String uniquePath;
private volatile FileSystem parentFileSystem; private volatile FileSystem parentFileSystem;
private ContentStream contentStream;
private boolean tryContentStream; private boolean tryContentStream;
private Object contentStreamLock = new Object();
private SoftReference<ContentStream> contentStreamRef = null;
/** /**
* Initializes common fields used by AbstactFile implementations (objects in * Initializes common fields used by AbstactFile implementations (objects in
...@@ -1070,44 +1072,54 @@ short getMetaFlagsAsInt() { ...@@ -1070,44 +1072,54 @@ short getMetaFlagsAsInt() {
return TSK_FS_META_FLAG_ENUM.toInt(metaFlags); return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
} }
/**
* Attempts to load the content stream for this file. If none exists, returns false.
* @return False if no content stream exists for this file. private boolean hasContentStream() {
* @throws TskCoreException ContentStream contentStream = null;
*/ try {
private boolean loadContentStream() throws TskCoreException { contentStream = getContentStream();
if (contentStream != null) { } catch (TskCoreException ex) {
return true; LOGGER.log(Level.WARNING, "An error occurred while loading content stream for file with id: " + getId(), ex);
} else if (tryContentStream) {
// only attempt to load if the flag indicates it should be tried
contentStream = getSleuthkitCase().getContentProvider().getContentStream(this).orElse(null);
if (contentStream == null) {
// if no content stream could be loaded, mark tryContentStream as false so load
// isn't attempted again
tryContentStream = false;
return false;
} else {
return true;
}
} else {
return false;
} }
return contentStream != null;
} }
/** /**
* @return True if the custom content provider for the case should be used to fetch content bytes. * Attempts to load the content stream for this file. If none exists, returns null.
* @return The content stream for this file or null if none exists.
* @throws TskCoreException
*/ */
private boolean useContentProvider() { private ContentStream getContentStream() throws TskCoreException {
return this.getCollected() == CollectedStatus.YES_REPO && getSleuthkitCase().getContentProvider() != null; ContentStream contentStream = null;
if (tryContentStream) {
try {
synchronized (contentStreamLock) {
// try to get soft reference content stream
contentStream = contentStreamRef == null ? null : contentStreamRef.get();
// load if not cached and then cache if present
if (contentStream == null) {
contentStream = getSleuthkitCase().getContentProvider().getContentStream(this).orElse(null);
if (contentStream != null) {
this.contentStreamRef = new SoftReference<>(contentStream);
}
}
}
} finally {
if (contentStream == null) {
// don't try to load the content stream again if it fails to load (either through exception or not existing)
tryContentStream = false;
}
}
}
return contentStream;
} }
@Override @Override
public final int read(byte[] buf, long offset, long len) throws TskCoreException { public final int read(byte[] buf, long offset, long len) throws TskCoreException {
//template method // try to use content stream if present
if (useContentProvider() && loadContentStream()) { ContentStream contentStream = getContentStream();
return this.contentStream.read(buf, offset, len); if (contentStream != null) {
return contentStream.read(buf, offset, len);
} }
//if localPath is set, use local, otherwise, use readCustom() supplied by derived class //if localPath is set, use local, otherwise, use readCustom() supplied by derived class
...@@ -1283,13 +1295,8 @@ final void setEncodingType(TskData.EncodingType encodingType) { ...@@ -1283,13 +1295,8 @@ final void setEncodingType(TskData.EncodingType encodingType) {
* @return true if the file exists, false otherwise * @return true if the file exists, false otherwise
*/ */
public boolean exists() { public boolean exists() {
if (useContentProvider()) { if (hasContentStream()) {
try { return true;
return loadContentStream();
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
return false;
}
} }
if (!localPathSet) { if (!localPathSet) {
...@@ -1313,13 +1320,8 @@ public boolean exists() { ...@@ -1313,13 +1320,8 @@ public boolean exists() {
* @return true if the file is readable * @return true if the file is readable
*/ */
public boolean canRead() { public boolean canRead() {
if (useContentProvider()) { if (hasContentStream()) {
try { return true;
return loadContentStream();
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, ex.getMessage());
return false;
}
} }
if (!localPathSet) { if (!localPathSet) {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
/** /**
* Custom provider for content bytes. * Custom provider for content bytes.
*/ */
public interface ContentStream { public interface ContentStream extends AutoCloseable {
/** /**
* Reads data that this content object is associated with (file contents, * Reads data that this content object is associated with (file contents,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment