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

Merge branch '7013-customCallback' of github.com:gdicristofaro/sleuthkit into 7121-openFiles

parents 915614fc a0f03ad9
Branches
Tags
No related merge requests found
...@@ -119,9 +119,9 @@ public abstract class AbstractFile extends AbstractContent { ...@@ -119,9 +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 boolean tryContentStream; private final boolean tryContentProviderStream;
private Object contentStreamLock = new Object(); private Object contentProviderStreamLock = new Object();
private SoftReference<ContentStream> contentStreamRef = null; private SoftReference<ContentProviderStream> contentProviderStreamRef = null;
/** /**
* Initializes common fields used by AbstactFile implementations (objects in * Initializes common fields used by AbstactFile implementations (objects in
...@@ -234,8 +234,8 @@ public abstract class AbstractFile extends AbstractContent { ...@@ -234,8 +234,8 @@ public abstract class AbstractFile extends AbstractContent {
this.osAccountObjId = osAccountObjectId; this.osAccountObjId = osAccountObjectId;
this.collected = collected; this.collected = collected;
// any item that is marked as YES_REPO and there is a custom content provider for the db will attempt to use the content provider to provide data // any item that is marked as YES_REPO and there is a custom content provider for the db will attempt to use the content provider to provide data
// this will be flipped to false if there is no content stream from the content provider for this file // this will be flipped to false if there is no content provider stream from the content provider for this file
this.tryContentStream = collected == CollectedStatus.YES_REPO && db.getContentProvider() != null; this.tryContentProviderStream = collected == CollectedStatus.YES_REPO && db.getContentProvider() != null;
if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) { if (Objects.nonNull(fileAttributes) && !fileAttributes.isEmpty()) {
this.fileAttributesCache.addAll(fileAttributes); this.fileAttributesCache.addAll(fileAttributes);
loadedAttributesCacheFromDb = true; loadedAttributesCacheFromDb = true;
...@@ -1072,58 +1072,47 @@ short getMetaFlagsAsInt() { ...@@ -1072,58 +1072,47 @@ short getMetaFlagsAsInt() {
return TSK_FS_META_FLAG_ENUM.toInt(metaFlags); return TSK_FS_META_FLAG_ENUM.toInt(metaFlags);
} }
private boolean hasContentStream() {
ContentStream contentStream = null;
try {
contentStream = getContentStream();
} catch (TskCoreException ex) {
LOGGER.log(Level.WARNING, "An error occurred while loading content stream for file with id: " + getId(), ex);
}
return contentStream != null;
}
/** /**
* Attempts to load the content stream for this file. If none exists, returns null. * Attempts to get cached or load the content provider stream for this file.
* @return The content stream for this file or null if none exists. * If none exists, returns null.
* @throws TskCoreException *
* NOTE: Does not check the value for tryContentProviderStream before
* attempting.
*
* @return The content stream for this file or null if none exists.
*
* @throws TskCoreException
*/ */
private ContentStream getContentStream() throws TskCoreException { private ContentProviderStream getContentProviderStream() throws TskCoreException {
ContentStream contentStream = null; synchronized (contentProviderStreamLock) {
if (tryContentStream) { // try to get soft reference content provider stream
try { ContentProviderStream contentProviderStream = contentProviderStreamRef == null ? null : contentProviderStreamRef.get();
synchronized (contentStreamLock) { // load if not cached and then cache if present
// try to get soft reference content stream if (contentProviderStream == null) {
contentStream = contentStreamRef == null ? null : contentStreamRef.get(); ContentStreamProvider provider = getSleuthkitCase().getContentProvider();
// load if not cached and then cache if present contentProviderStream = provider == null ? null : provider.getContentStream(this).orElse(null);
if (contentStream == null) {
contentStream = getSleuthkitCase().getContentProvider().getContentStream(this).orElse(null); if (contentProviderStream == null) {
if (contentStream != null) { throw new TskCoreException(MessageFormat.format("Could not get content provider string for file with obj id: {0}, path: {1}",
this.contentStreamRef = new SoftReference<>(contentStream); getId(),
} getUniquePath()));
}
} }
} finally {
if (contentStream == null) { this.contentProviderStreamRef = new SoftReference<>(contentProviderStream);
// don't try to load the content stream again if it fails to load (either through exception or not existing)
tryContentStream = false;
}
} }
return contentProviderStream;
} }
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 {
// try to use content stream if present // try to use content provider stream if should use
ContentStream contentStream = getContentStream(); if (tryContentProviderStream) {
if (contentStream != null) { ContentProviderStream contentProviderStream = getContentProviderStream();
return contentStream.read(buf, offset, len); return contentProviderStream.read(buf, offset, len);
} } else if (localPathSet) {
//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
if (localPathSet) {
return readLocal(buf, offset, len); return readLocal(buf, offset, len);
} else { } else {
return readInt(buf, offset, len); return readInt(buf, offset, len);
...@@ -1289,17 +1278,14 @@ final void setEncodingType(TskData.EncodingType encodingType) { ...@@ -1289,17 +1278,14 @@ final void setEncodingType(TskData.EncodingType encodingType) {
} }
/** /**
* Check if the file exists. If non-local always true, if local, checks if * Check if the file exists. If non-local or file is marked with YES_REPO
* actual local path exists * and there is a content provider always true, if local, checks if actual
* local path exists
* *
* @return true if the file exists, false otherwise * @return true if the file exists, false otherwise
*/ */
public boolean exists() { public boolean exists() {
if (hasContentStream()) { if (tryContentProviderStream || !localPathSet) {
return true;
}
if (!localPathSet) {
return true; return true;
} else { } else {
try { try {
...@@ -1314,17 +1300,13 @@ public boolean exists() { ...@@ -1314,17 +1300,13 @@ public boolean exists() {
/** /**
* Check if the file exists and is readable. If non-local (e.g. within an * Check if the file exists and is readable. If non-local (e.g. within an
* image), always true, if local, checks if actual local path exists and is * image) or file is marked with YES_REPO and there is a content provider,
* readable * always true, if local, checks if actual local path exists and is readable
* *
* @return true if the file is readable * @return true if the file is readable
*/ */
public boolean canRead() { public boolean canRead() {
if (hasContentStream()) { if (tryContentProviderStream || !localPathSet) {
return true;
}
if (!localPathSet) {
return true; return true;
} else { } else {
try { try {
......
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
*/ */
package org.sleuthkit.datamodel; package org.sleuthkit.datamodel;
import java.util.Optional;
/** /**
* Custom provider for content bytes. * Custom provider for content bytes.
*/ */
public interface ContentStream extends AutoCloseable { @SuppressWarnings("try")
public interface ContentProviderStream extends AutoCloseable {
/** /**
* Reads data that this content object is associated with (file contents, * Reads data that this content object is associated with (file contents,
...@@ -39,21 +38,4 @@ public interface ContentStream extends AutoCloseable { ...@@ -39,21 +38,4 @@ public interface ContentStream extends AutoCloseable {
* tsk core * tsk core
*/ */
public int read(byte[] buf, long offset, long len) throws TskCoreException; public int read(byte[] buf, long offset, long len) throws TskCoreException;
/**
* Custom provider for bytes of an abstract file.
*/
public interface ContentProvider {
/**
* Provides a content stream for a content object or empty if this
* provider has none to provide.
*
* @param content The content.
*
* @return The content stream or empty if no stream can be provided
* for this content.
*/
Optional<ContentStream> getContentStream(Content content) throws TskCoreException;
}
} }
/*
* SleuthKit Java Bindings
*
* Copyright 2023 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.datamodel;
import java.util.Optional;
/**
* Custom provider for bytes of an abstract file.
*/
public interface ContentStreamProvider {
/**
* Provides a content stream for a content object or empty if this provider
* has none to provide.
*
* @param content The content.
*
* @return The content stream or empty if no stream can be provided for this
* content.
*/
Optional<ContentProviderStream> getContentStream(Content content) throws TskCoreException;
}
...@@ -94,7 +94,6 @@ ...@@ -94,7 +94,6 @@
import org.sqlite.SQLiteConfig; import org.sqlite.SQLiteConfig;
import org.sqlite.SQLiteDataSource; import org.sqlite.SQLiteDataSource;
import org.sqlite.SQLiteJDBCLoader; import org.sqlite.SQLiteJDBCLoader;
import org.sleuthkit.datamodel.ContentStream.ContentProvider;
   
/** /**
* Represents the case database with methods that provide abstractions for * Represents the case database with methods that provide abstractions for
...@@ -205,7 +204,7 @@ public class SleuthkitCase { ...@@ -205,7 +204,7 @@ public class SleuthkitCase {
private final Cache<Long, Boolean> isRootDirectoryCache private final Cache<Long, Boolean> isRootDirectoryCache
= CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build(); = CacheBuilder.newBuilder().maximumSize(200000).expireAfterAccess(5, TimeUnit.MINUTES).build();
// custom provider for file bytes (can be null) // custom provider for file bytes (can be null)
private final ContentProvider contentProvider; private final ContentStreamProvider contentProvider;
/* /*
* First parameter is used to specify the SparseBitSet to use, as object IDs * First parameter is used to specify the SparseBitSet to use, as object IDs
...@@ -339,7 +338,7 @@ public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException ...@@ -339,7 +338,7 @@ public static void tryConnect(CaseDbConnectionInfo info) throws TskCoreException
* *
* @throws Exception * @throws Exception
*/ */
private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType, ContentProvider contentProvider) throws Exception { private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbType dbType, ContentStreamProvider contentProvider) throws Exception {
Class.forName("org.sqlite.JDBC"); Class.forName("org.sqlite.JDBC");
this.dbPath = dbPath; this.dbPath = dbPath;
this.dbType = dbType; this.dbType = dbType;
...@@ -372,7 +371,7 @@ private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbTyp ...@@ -372,7 +371,7 @@ private SleuthkitCase(String dbPath, SleuthkitJNI.CaseDbHandle caseHandle, DbTyp
* *
* @throws Exception * @throws Exception
*/ */
private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType, ContentProvider contentProvider) throws Exception { private SleuthkitCase(String host, int port, String dbName, String userName, String password, SleuthkitJNI.CaseDbHandle caseHandle, String caseDirPath, DbType dbType, ContentStreamProvider contentProvider) throws Exception {
this.dbPath = ""; this.dbPath = "";
this.databaseName = dbName; this.databaseName = dbName;
this.dbType = dbType; this.dbType = dbType;
...@@ -421,7 +420,7 @@ private void init() throws Exception { ...@@ -421,7 +420,7 @@ private void init() throws Exception {
* @return The custom content provider for this case if one exists. * @return The custom content provider for this case if one exists.
* Otherwise, returns null. * Otherwise, returns null.
*/ */
ContentProvider getContentProvider() { ContentStreamProvider getContentProvider() {
return this.contentProvider; return this.contentProvider;
} }
   
...@@ -3002,7 +3001,7 @@ public static SleuthkitCase openCase(String dbPath) throws TskCoreException { ...@@ -3002,7 +3001,7 @@ public static SleuthkitCase openCase(String dbPath) throws TskCoreException {
* @throws org.sleuthkit.datamodel.TskCoreException * @throws org.sleuthkit.datamodel.TskCoreException
*/ */
@Beta @Beta
public static SleuthkitCase openCase(String dbPath, ContentProvider provider) throws TskCoreException { public static SleuthkitCase openCase(String dbPath, ContentStreamProvider provider) throws TskCoreException {
try { try {
final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath); final SleuthkitJNI.CaseDbHandle caseHandle = SleuthkitJNI.openCaseDb(dbPath);
return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, provider); return new SleuthkitCase(dbPath, caseHandle, DbType.SQLITE, provider);
...@@ -3042,7 +3041,7 @@ public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo i ...@@ -3042,7 +3041,7 @@ public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo i
* @throws TskCoreException If there is a problem opening the database. * @throws TskCoreException If there is a problem opening the database.
*/ */
@Beta @Beta
public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentProvider contentProvider) throws TskCoreException { public static SleuthkitCase openCase(String databaseName, CaseDbConnectionInfo info, String caseDir, ContentStreamProvider contentProvider) throws TskCoreException {
try { try {
/* /*
* The flow of this method involves trying to open case and if * The flow of this method involves trying to open case and if
...@@ -3094,7 +3093,7 @@ public static SleuthkitCase newCase(String dbPath) throws TskCoreException { ...@@ -3094,7 +3093,7 @@ public static SleuthkitCase newCase(String dbPath) throws TskCoreException {
* @throws org.sleuthkit.datamodel.TskCoreException * @throws org.sleuthkit.datamodel.TskCoreException
*/ */
@Beta @Beta
public static SleuthkitCase newCase(String dbPath, ContentProvider contentProvider) throws TskCoreException { public static SleuthkitCase newCase(String dbPath, ContentStreamProvider contentProvider) throws TskCoreException {
try { try {
CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath); CaseDatabaseFactory factory = new CaseDatabaseFactory(dbPath);
factory.createCaseDatabase(); factory.createCaseDatabase();
...@@ -3143,7 +3142,7 @@ public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, ...@@ -3143,7 +3142,7 @@ public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info,
* @throws org.sleuthkit.datamodel.TskCoreException * @throws org.sleuthkit.datamodel.TskCoreException
*/ */
@Beta @Beta
public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentProvider contentProvider) throws TskCoreException { public static SleuthkitCase newCase(String caseName, CaseDbConnectionInfo info, String caseDirPath, ContentStreamProvider contentProvider) throws TskCoreException {
String databaseName = createCaseDataBaseName(caseName); String databaseName = createCaseDataBaseName(caseName);
try { try {
/** /**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment