diff --git a/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java b/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java index 8daf6c2266a7032e01934d1dbdbc836668889a39..82776adccab51e5c539d65e76af0a2a9954654d4 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/AbstractFile.java @@ -43,7 +43,6 @@ * to the case. */ public abstract class AbstractFile extends AbstractContent { - protected final TskData.TSK_DB_FILES_TYPE_ENUM fileType; protected final TSK_FS_NAME_TYPE_ENUM dirType; protected final TSK_FS_META_TYPE_ENUM metaType; @@ -61,6 +60,7 @@ public abstract class AbstractFile extends AbstractContent { private String localPath; ///< local path as stored in db tsk_files_path, is relative to the db, private String localAbsPath; ///< absolute path representation of the local path private volatile RandomAccessFile localFileHandle; + private volatile boolean errorLoadingFromFileRepo = false; private volatile java.io.File localFile; private TskData.EncodingType encodingType; //range support @@ -86,6 +86,7 @@ public abstract class AbstractFile extends AbstractContent { private boolean sha256HashDirty = false; private String mimeType; private boolean mimeTypeDirty = false; + protected TskData.FileLocation location; private static final Logger LOGGER = Logger.getLogger(AbstractFile.class.getName()); private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle"); private long dataSourceObjectId; @@ -124,6 +125,7 @@ public abstract class AbstractFile extends AbstractContent { * @param knownState knownState status of the file, or null if * unknown (default) * @param parentPath + * @param location * @param mimeType The MIME type of the file, can be null. * @param extension The extension part of the file name (not * including the '.'), can be null. @@ -143,6 +145,7 @@ public abstract class AbstractFile extends AbstractContent { int uid, int gid, String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, + TskData.FileLocation location, String mimeType, String extension) { super(db, objId, name); @@ -173,6 +176,7 @@ public abstract class AbstractFile extends AbstractContent { this.knownState = knownState; } this.parentPath = parentPath; + this.location = location; this.mimeType = mimeType; this.extension = extension == null ? "" : extension; this.encodingType = TskData.EncodingType.NONE; @@ -777,6 +781,13 @@ public boolean isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM flag) { public String getDirFlagAsString() { return dirFlag.toString(); } + + /** + * @return The directory flag value. + */ + public TSK_FS_NAME_FLAG_ENUM getDirFlag() { + return dirFlag; + } /** * @return a string representation of the meta flags @@ -791,6 +802,13 @@ public String getMetaFlagsAsString() { return str; } + /** + * @return The meta flags as stored in the database. + */ + public short getMetaFlagsAsInt() { + return TSK_FS_META_FLAG_ENUM.toInt(metaFlags); + } + /** * @param metaFlag the TSK_FS_META_FLAG_ENUM to check * @@ -804,7 +822,7 @@ public boolean isMetaFlagSet(TSK_FS_META_FLAG_ENUM metaFlag) { public final int read(byte[] buf, long offset, long len) throws TskCoreException { //template method //if localPath is set, use local, otherwise, use readCustom() supplied by derived class - if (localPathSet) { + if ((location == TskData.FileLocation.REPOSITORY) || localPathSet) { return readLocal(buf, offset, len); } else { return readInt(buf, offset, len); @@ -839,7 +857,7 @@ protected int readInt(byte[] buf, long offset, long len) throws TskCoreException * @throws TskCoreException exception thrown when file could not be read */ protected final int readLocal(byte[] buf, long offset, long len) throws TskCoreException { - if (!localPathSet) { + if ((location == TskData.FileLocation.LOCAL) && !localPathSet) { throw new TskCoreException( BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text")); } @@ -959,6 +977,15 @@ public String getLocalPath() { return localPath; } + /** + * Get the location of the file data + * + * @return file location + */ + public TskData.FileLocation getFileLocation() { + return location; + } + /** * Get local absolute path of the file, if localPath has been set * @@ -1024,21 +1051,36 @@ public boolean canRead() { * @throws org.sleuthkit.datamodel.TskCoreException If the local path is not * set. */ - private void loadLocalFile() throws TskCoreException { - if (!localPathSet) { - throw new TskCoreException( - BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text")); - } - + private synchronized void loadLocalFile() throws TskCoreException { + // already been set if (localFile != null) { return; } + + if (location.equals(TskData.FileLocation.LOCAL)) { + if (!localPathSet) { + throw new TskCoreException( + BUNDLE.getString("AbstractFile.readLocal.exception.msg1.text")); + } - synchronized (this) { if (localFile == null) { localFile = new java.io.File(localAbsPath); } + } else { + if (errorLoadingFromFileRepo == true) { + // Don't try to download it again + throw new TskCoreException("Previously failed to load file with object ID " + getId() + " from file repository."); + } + + // Copy the file from the server + try { + localFile = FileRepository.downloadFromFileRepository(this); + } catch (TskCoreException ex) { + // If we've failed to download from the file repository, don't try again for this session. + errorLoadingFromFileRepo = true; + throw ex; + } } } @@ -1087,6 +1129,7 @@ public String toString(boolean preserveState) { + "\t" + "parentPath " + parentPath + "\t" + "size " + size //NON-NLS + "\t" + "knownState " + knownState + "\t" + "md5Hash " + md5Hash + "\t" + "sha256Hash " + sha256Hash //NON-NLS + "\t" + "localPathSet " + localPathSet + "\t" + "localPath " + localPath //NON-NLS + + "\t" + "location " + location // NON-NLS + "\t" + "localAbsPath " + localAbsPath + "\t" + "localFile " + localFile //NON-NLS + "]\t"; } @@ -1222,7 +1265,7 @@ protected AbstractFile(SleuthkitCase db, long objId, TskData.TSK_FS_ATTR_TYPE_EN TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); + this(db, objId, db.getDataSourceObjectId(objId), attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, null, null); } /** @@ -1267,7 +1310,7 @@ protected AbstractFile(SleuthkitCase db, long objId, TskData.TSK_FS_ATTR_TYPE_EN String name, TskData.TSK_DB_FILES_TYPE_ENUM fileType, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); + this(db, objId, dataSourceObjectId, attrType, (int) attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, null, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties index c3da2ea73394283627e42d91e29f5c069ecb2841..74eeb7f4a9e9cc75adb712f49373d558e8eeb9e3 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties +++ b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties @@ -259,6 +259,7 @@ TskData.fileKnown.known=known TskData.fileKnown.knownBad=notable TskData.fileKnown.exception.msg1.text=No FileKnown of value\: {0} TskData.encodingType.exception.msg1.text=No EncodingType of value\: {0} +TskData.fileLocation.exception.msg1.text=No FileLocation of value\: {0} TskData.tskDbFilesTypeEnum.exception.msg1.text=No TSK_FILE_TYPE_ENUM of value\: {0} TskData.objectTypeEnum.exception.msg1.text=No ObjectType of value\: {0} TskData.tskImgTypeEnum.exception.msg1.text=No TSK_IMG_TYPE_ENUM of value\: {0} @@ -352,4 +353,7 @@ IntersectionFilter.displayName.text=Intersection tagsFilter.displayName.text=Must be tagged TextFilter.displayName.text=Must include text: TypeFilter.displayName.text=Limit event types to -FileTypesFilter.displayName.text=Limit file types to \ No newline at end of file +FileTypesFilter.displayName.text=Limit file types to +FileRepository.downloadError.title.text=Error downloading from file repository +FileRepository.downloadError.msg.text=Failed to download file with object ID {0} and SHA-256 hash {1} +FileRepository.notEnabled.msg.text=File repository is not enabled diff --git a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties-MERGED b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties-MERGED index c3da2ea73394283627e42d91e29f5c069ecb2841..74eeb7f4a9e9cc75adb712f49373d558e8eeb9e3 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties-MERGED +++ b/bindings/java/src/org/sleuthkit/datamodel/Bundle.properties-MERGED @@ -259,6 +259,7 @@ TskData.fileKnown.known=known TskData.fileKnown.knownBad=notable TskData.fileKnown.exception.msg1.text=No FileKnown of value\: {0} TskData.encodingType.exception.msg1.text=No EncodingType of value\: {0} +TskData.fileLocation.exception.msg1.text=No FileLocation of value\: {0} TskData.tskDbFilesTypeEnum.exception.msg1.text=No TSK_FILE_TYPE_ENUM of value\: {0} TskData.objectTypeEnum.exception.msg1.text=No ObjectType of value\: {0} TskData.tskImgTypeEnum.exception.msg1.text=No TSK_IMG_TYPE_ENUM of value\: {0} @@ -352,4 +353,7 @@ IntersectionFilter.displayName.text=Intersection tagsFilter.displayName.text=Must be tagged TextFilter.displayName.text=Must include text: TypeFilter.displayName.text=Limit event types to -FileTypesFilter.displayName.text=Limit file types to \ No newline at end of file +FileTypesFilter.displayName.text=Limit file types to +FileRepository.downloadError.title.text=Error downloading from file repository +FileRepository.downloadError.msg.text=Failed to download file with object ID {0} and SHA-256 hash {1} +FileRepository.notEnabled.msg.text=File repository is not enabled diff --git a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java index eca9630950c463208eac5a2b6e5c4367ecebbc3f..4d7b38f01ed786a9c161b109162c44e5a6015bbf 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CaseDatabaseFactory.java @@ -204,7 +204,7 @@ private void createFileTables(Statement stmt) throws SQLException { + "crtime " + dbQueryHelper.getBigIntType() + ", atime " + dbQueryHelper.getBigIntType() + ", " + "mtime " + dbQueryHelper.getBigIntType() + ", mode INTEGER, uid INTEGER, gid INTEGER, md5 TEXT, sha256 TEXT, " + "known INTEGER, " - + "parent_path TEXT, mime_type TEXT, extension TEXT, " + + "parent_path TEXT, location INTEGER NOT NULL, mime_type TEXT, extension TEXT, " + "FOREIGN KEY(obj_id) REFERENCES tsk_objects(obj_id) ON DELETE CASCADE, " + "FOREIGN KEY(fs_obj_id) REFERENCES tsk_fs_info(obj_id) ON DELETE CASCADE, " + "FOREIGN KEY(data_source_obj_id) REFERENCES data_source_info(obj_id) ON DELETE CASCADE)"); diff --git a/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java b/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java index ef147fb10c980eb874594e42931342e0ba336dd2..0e676e4ee6313e92d0ea0cfa82c0834281453d5d 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/DerivedFile.java @@ -71,11 +71,14 @@ public class DerivedFile extends AbstractFile { * @param mtime The modified time of the file. * @param md5Hash The MD5 hash of the file, null if not yet * calculated. + * @param sha256Hash The SHA-256 hash of the file, null if not yet + * calculated. * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. * @param localPath The absolute path of the file in secondary * storage. + * @param location The location of the file. * @param parentId The object id of parent of the file. * @param mimeType The MIME type of the file, null if it has not * yet been determined. @@ -94,6 +97,7 @@ public class DerivedFile extends AbstractFile { String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String localPath, + TskData.FileLocation location, long parentId, String mimeType, TskData.EncodingType encodingType, @@ -102,7 +106,7 @@ public class DerivedFile extends AbstractFile { // through the class hierarchy contructors. super(db, objId, dataSourceObjectId, TskData.TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TSK_DB_FILES_TYPE_ENUM.LOCAL, 0L, 0, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); + metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, extension); setLocalFilePath(localPath); setEncodingType(encodingType); } @@ -306,7 +310,7 @@ protected DerivedFile(SleuthkitCase db, this(db, objId, db.getDataSourceObjectId(objId), name, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, md5Hash, null, knownState, - parentPath, localPath, parentId, null, TskData.EncodingType.NONE, null); + parentPath, localPath, TskData.FileLocation.LOCAL, parentId, null, TskData.EncodingType.NONE, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/Directory.java b/bindings/java/src/org/sleuthkit/datamodel/Directory.java index 39b0c62188ef261354eedeb1596ba6f6f2fd0e6f..49e690cd1701ec2965200317773538c1c3dbf799 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/Directory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/Directory.java @@ -69,9 +69,12 @@ public class Directory extends FsContent { * @param gid The GID for the file. * @param md5Hash The MD5 hash of the file, null if not yet * calculated. + * @param sha256Hash The SHA-256 hash of the file, null if not yet + * calculated. * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. + * @param location The location of the file. */ Directory(SleuthkitCase db, long objId, @@ -85,8 +88,8 @@ public class Directory extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, String sha256Hash, FileKnown knownState, String parentPath) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, null, null); + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, TskData.FileLocation location) { + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, location, null, null); } /** @@ -247,6 +250,6 @@ protected Directory(SleuthkitCase db, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/File.java b/bindings/java/src/org/sleuthkit/datamodel/File.java index c6758c0ff88657acb513b55810acbc445b518df3..a0178482fb04a2eb17df9a20445a51daeb42d7fb 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/File.java +++ b/bindings/java/src/org/sleuthkit/datamodel/File.java @@ -72,6 +72,7 @@ public class File extends FsContent { * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. + * @param location The location of the file data. * @param mimeType The MIME type of the file, null if it has not * yet been determined. * @param extension The extension part of the file name (not @@ -89,9 +90,9 @@ public class File extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, TskData.FileLocation location, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, extension); } /** @@ -245,6 +246,6 @@ protected File(SleuthkitCase db, String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, mimeType, null); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, mimeType, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/FileRepository.java b/bindings/java/src/org/sleuthkit/datamodel/FileRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..6c4b456b4acc1f195adbeda028df9c0efa0a5b7a --- /dev/null +++ b/bindings/java/src/org/sleuthkit/datamodel/FileRepository.java @@ -0,0 +1,315 @@ +/* + * SleuthKit Java Bindings + * + * Copyright 2020 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.io.File; +import java.io.IOException; +import java.nio.file.Paths; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.ResourceBundle; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Class to represent a file repository. + */ +public class FileRepository { + private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("org.sleuthkit.datamodel.Bundle"); + private static final Logger logger = Logger.getLogger(FileRepository.class.getName()); + private static FileRepositoryErrorHandler errorHandler; + + private final static String FILE_PATH = "v1/files/"; + private final FileRepositorySettings settings; + private final File fileDownloadFolder; + + private static FileRepository instance; + + /** + * Create the file repository. + * + * @param settings The file repository settings + * @param fileDownloadPath The temporary folder to download files to from the repository + */ + private FileRepository(FileRepositorySettings settings, File fileDownloadPath) { + this.settings = settings; + this.fileDownloadFolder = fileDownloadPath; + } + + /** + * Initializes the file repository. + * + * @param settings The file repository settings + * @param fileDownloadPath The temporary folder to download files to from the repository + */ + public static synchronized void initialize(FileRepositorySettings settings, File fileDownloadPath) { + // If the download path is changing, delete any files in the old one + if ((instance != null) && (instance.fileDownloadFolder != null) + && ( ! instance.fileDownloadFolder.equals(fileDownloadPath))) { + deleteDownloadFolder(instance.fileDownloadFolder); + } + instance = new FileRepository(settings, fileDownloadPath); + } + + /** + * De-initializes the file repository. + */ + public static synchronized void deinitialize() { + if (instance != null) { + // Delete the temp folder + deleteDownloadFolder(instance.fileDownloadFolder); + } + + instance = null; + } + + /** + * Check if the file repository is enabled. + * + * @return true if enabled, false otherwise. + */ + public static boolean isEnabled() { + return instance != null; + } + + /** + * Set the error handling callback. + * + * @param handler The error handler. + */ + public static synchronized void setErrorHandler(FileRepositoryErrorHandler handler) { + errorHandler = handler; + } + + /** + * Report an error to the user. + * The idea is to use this for cases where it's a user error that may be able + * to be corrected through changing the repository settings. + * + * @param errorTitle The title for the error display. + * @param errorStr The error message. + */ + private static synchronized void reportError(String errorTitle, String errorStr) { + if (errorHandler != null) { + errorHandler.displayErrorToUser(errorTitle, errorStr); + } + } + + /** + * Delete the folder of downloaded files. + */ + private static synchronized void deleteDownloadFolder(File dirPath) { + if (dirPath.isDirectory() == false || dirPath.exists() == false) { + return; + } + + File[] files = dirPath.listFiles(); + if (files != null) { + for (File file : files) { + if (file.isDirectory()) { + deleteDownloadFolder(file); + } else { + if (file.delete() == false) { + logger.log(Level.WARNING, "Failed to delete file {0}", file.getPath()); //NON-NLS + } + } + } + } + if (dirPath.delete() == false) { + logger.log(Level.WARNING, "Failed to delete the empty directory at {0}", dirPath.getPath()); //NON-NLS + } + } + + /** + * Download a file from the file repository. + * The caller must ensure that this is not called on the same file multiple times concurrently. + * + * @param abstractFile The file being downloaded. + * + * @return The downloaded file. + * + * @throws TskCoreException + */ + public static synchronized File downloadFromFileRepository(AbstractFile abstractFile) throws TskCoreException { + + if (instance == null) { + String title = BUNDLE.getString("FileRepository.downloadError.title.text"); + String msg = BUNDLE.getString("FileRepository.notEnabled.msg.text"); + reportError(title, msg); + throw new TskCoreException("File repository is not enabled"); + } + + if (! abstractFile.getFileLocation().equals(TskData.FileLocation.REPOSITORY)) { + throw new TskCoreException("File with object ID " + abstractFile.getId() + " is not stored in the file repository"); + } + + if (abstractFile.getSha256Hash() == null || abstractFile.getSha256Hash().isEmpty()) { + throw new TskCoreException("File with object ID " + abstractFile.getId() + " has no SHA-256 hash and can not be downloaded"); + } + + // Download the file if it's not already there. + String targetPath = Paths.get(instance.fileDownloadFolder.getAbsolutePath(), abstractFile.getSha256Hash()).toString(); + if ( ! new File(targetPath).exists()) { + instance.downloadFile(abstractFile, targetPath); + } + + // Check that we got the file. + File tempFile = new File(targetPath); + if (tempFile.exists()) { + return tempFile; + } else { + String title = BUNDLE.getString("FileRepository.downloadError.title.text"); + String msg = MessageFormat.format(BUNDLE.getString("FileRepository.downloadError.msg.text"), abstractFile.getId(), abstractFile.getSha256Hash()); + reportError(title, msg); + throw new TskCoreException("Failed to download file with object ID " + abstractFile.getId() + + " and SHA-256 hash " + abstractFile.getSha256Hash() + " from file repository"); + } + } + + /** + * Download the file. + * + * @param abstractFile The file being downloaded. + * @param targetPath The location to save the file to. + * + * @throws TskCoreException + */ + private void downloadFile(AbstractFile abstractFile, String targetPath) throws TskCoreException { + + String url = "http://" + settings.getAddress() + ":" + settings.getPort() + "/" + FILE_PATH + abstractFile.getSha256Hash(); + + List<String> command = new ArrayList<>(); + command.add("curl"); + command.add("-X"); + command.add("GET"); + command.add(url); + command.add("-H"); + command.add("accept: */*"); + command.add("--output"); + command.add(targetPath); + + ProcessBuilder processBuilder = new ProcessBuilder(command).inheritIO(); + try { + Process process = processBuilder.start(); + process.waitFor(); + } catch (IOException ex) { + String title = BUNDLE.getString("FileRepository.downloadError.title.text"); + String msg = MessageFormat.format(BUNDLE.getString("FileRepository.downloadError.msg.text"), abstractFile.getId(), abstractFile.getSha256Hash()); + reportError(title, msg); + throw new TskCoreException("Error downloading file with SHA-256 hash " + abstractFile.getSha256Hash() + " from file repository", ex); + } catch (InterruptedException ex) { + throw new TskCoreException("Interrupted while downloading file with SHA-256 hash " + abstractFile.getSha256Hash() + " from file repository", ex); + } + } + + /** + * Upload a given file to the file repository. + * + * @param filePath The path on disk to the file being uploaded. + * + * @throws TskCoreException + */ + public static synchronized void uploadToFileRepository(String filePath) throws TskCoreException { + + if (instance == null) { + throw new TskCoreException("File repository is not enabled"); + } + + File file = new File(filePath); + if (! file.exists()) { + throw new TskCoreException("Error uploading file " + filePath + " to file repository - file does not exist"); + } + + // Upload the file. + instance.uploadFile(file); + } + + /** + * Upload the file. + * + * @param file The file being uploaded. + * + * @throws TskCoreException + */ + private void uploadFile(File file) throws TskCoreException { + String url = "http://" + settings.getAddress() + ":" + settings.getPort() + "/" + FILE_PATH; + + // Example: curl -X POST "http://localhost:8080/api/files" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=@Report.xml" + List<String> command = new ArrayList<>(); + command.add("curl"); + command.add("-X"); + command.add("POST"); + command.add(url); + command.add("-H"); + command.add("accept: application/json"); + command.add("-H"); + command.add("Content-Type: multipart/form-data"); + command.add("-F"); + command.add("file=@" + file.getAbsolutePath()); + + ProcessBuilder processBuilder = new ProcessBuilder(command).inheritIO(); + try { + Process process = processBuilder.start(); + process.waitFor(); + } catch (IOException | InterruptedException ex) { + throw new TskCoreException("Error saving file at " + file.getAbsolutePath() + " to file repository", ex); + } + } + + /** + * Utility class to hold the file repository server settings. + */ + static public class FileRepositorySettings { + private final String address; + private final String port; + + /** + * Create a FileRepositorySettings instance for the server. + * + * @param address The IP address/hostname of the server. + * @param port The port. + */ + public FileRepositorySettings(String address, String port) { + this.address = address; + this.port = port; + } + + String getAddress() { + return address; + } + + String getPort() { + return port; + } + } + + /** + * Callback class to use for error reporting. + */ + public interface FileRepositoryErrorHandler { + /** + * Handles displaying an error message to the user (if appropriate). + * + * @param title The title for the error display. + * @param error The more detailed error message to display. + */ + void displayErrorToUser(String title, String error); + } +} diff --git a/bindings/java/src/org/sleuthkit/datamodel/FsContent.java b/bindings/java/src/org/sleuthkit/datamodel/FsContent.java index aa4bb739d06a0bad71b343ab9766c75f5f38511a..29f5158d1e29a9272d7cc0881d28f9eaf1e66fa9 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/FsContent.java +++ b/bindings/java/src/org/sleuthkit/datamodel/FsContent.java @@ -101,6 +101,7 @@ public abstract class FsContent extends AbstractFile { * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. + * @param location The location of the file data. * @param mimeType The MIME type of the file, null if it has not * yet been determined. * @param extension The extension part of the file name (not @@ -122,9 +123,10 @@ public abstract class FsContent extends AbstractFile { short modes, int uid, int gid, String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, + TskData.FileLocation location, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, extension); this.fsObjId = fsObjId; } @@ -383,7 +385,7 @@ public String toString(boolean preserveState) { String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, null, null); + this(db, objId, db.getDataSourceObjectId(objId), fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, null, null); } /** @@ -442,6 +444,6 @@ public String toString(boolean preserveState) { String name, long metaAddr, int metaSeq, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, String md5Hash, FileKnown knownState, String parentPath, String mimeType) { - this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, mimeType, null); + this(db, objId, dataSourceObjectId, fsObjId, attrType, (int) attrId, name, TSK_DB_FILES_TYPE_ENUM.FS, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, mimeType, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java b/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java index ab98c64e75a8ffc50219df350fbe2c63b2a539f6..9f8a0a8e4ed495fe9a12a7c565ec611e2df82a60 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LayoutFile.java @@ -79,6 +79,7 @@ public class LayoutFile extends AbstractFile { * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. + * @param location The location of the file. * @param mimeType The MIME type of the file, null if it has not * yet been determined. */ @@ -92,8 +93,8 @@ public class LayoutFile extends AbstractFile { long size, long ctime, long crtime, long atime, long mtime, String md5Hash, String sha256Hash, FileKnown knownState, - String parentPath, String mimeType) { - super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, SleuthkitCase.extractExtension(name)); + String parentPath, TskData.FileLocation location, String mimeType) { + super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, SleuthkitCase.extractExtension(name)); } /** @@ -280,6 +281,6 @@ protected LayoutFile(SleuthkitCase db, long objId, String name, TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, String md5Hash, FileKnown knownState, String parentPath) { - this(db, objId, db.getDataSourceObjectId(objId), name, fileType, dirType, metaType, dirFlag, metaFlags, size, 0L, 0L, 0L, 0L, md5Hash, null, knownState, parentPath, null); + this(db, objId, db.getDataSourceObjectId(objId), name, fileType, dirType, metaType, dirFlag, metaFlags, size, 0L, 0L, 0L, 0L, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL, null); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java index 8eafbefdbf6f4ea45cd4677d9107701fbf6ef4a3..92418608e1052f03025e213c35100d548947d726 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalDirectory.java @@ -55,6 +55,7 @@ public class LocalDirectory extends SpecialDirectory { * @param md5Hash The MD5 hash for the local directory. * @param knownState The known state for the local directory * @param parentPath The parent path for the local directory + * @param location The location of the directory. */ LocalDirectory(SleuthkitCase db, long objId, @@ -63,10 +64,10 @@ public class LocalDirectory extends SpecialDirectory { TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String md5Hash, String sha256Hash, FileKnown knownState, - String parentPath) { + String parentPath, TskData.FileLocation location) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR, 0L, 0, dirType, metaType, dirFlag, - metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, null); + metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, location, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java b/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java index 99abf74e70cd7f77cbaa062e0fa1316072064611..f3ed981b0a0ae21abec95ec027be73ecda37d798 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalFile.java @@ -68,6 +68,7 @@ public class LocalFile extends AbstractFile { * database lookup, null if not yet looked up. * @param parentId The object id of parent of the file. * @param parentPath The path of the parent of the file. + * @param location The location of the file. * @param dataSourceObjectId The object id of the data source for the file. * @param localPath The absolute path of the file in secondary * storage. @@ -84,14 +85,15 @@ public class LocalFile extends AbstractFile { long size, long ctime, long crtime, long atime, long mtime, String mimeType, String md5Hash, String sha256Hash, FileKnown knownState, - long parentId, String parentPath, + long parentId, String parentPath, TskData.FileLocation location, long dataSourceObjectId, String localPath, TskData.EncodingType encodingType, String extension) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, fileType, 0L, 0, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); + metaFlags, size, ctime, crtime, atime, mtime, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, + location, mimeType, extension); // TODO (AUT-1904): The parent id should be passed to AbstractContent // through the class hierarchy contructors, using // AbstractContent.UNKNOWN_ID as needed. @@ -219,7 +221,7 @@ protected LocalFile(SleuthkitCase db, size, ctime, crtime, atime, mtime, null, md5Hash, null, knownState, - AbstractContent.UNKNOWN_ID, parentPath, + AbstractContent.UNKNOWN_ID, parentPath, TskData.FileLocation.LOCAL, db.getDataSourceObjectId(objId), localPath, TskData.EncodingType.NONE, null); diff --git a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java index 0572291890859ea7ecaa7a61236cde43b1c102e5..f34e58785d26ec198c105bf94f354498efa332dd 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java +++ b/bindings/java/src/org/sleuthkit/datamodel/LocalFilesDataSource.java @@ -66,9 +66,12 @@ public class LocalFilesDataSource extends VirtualDirectory implements DataSource * @param parentPath The parent path for the virtual directory, * should be "/" if the virtual directory is a * data source. + * @param location The location of the file */ - public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, String md5Hash, String sha256Hash, TskData.FileKnown knownState, String parentPath) { - super(db, objId, dataSourceObjectId, name, dirType, metaType, dirFlag, metaFlags, md5Hash, sha256Hash, knownState, parentPath); + public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, + TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, + String md5Hash, String sha256Hash, TskData.FileKnown knownState, String parentPath, TskData.FileLocation location) { + super(db, objId, dataSourceObjectId, name, dirType, metaType, dirFlag, metaFlags, md5Hash, sha256Hash, knownState, parentPath, location); this.objectId = objId; this.deviceId = deviceId; this.timezone = timezone; @@ -263,6 +266,6 @@ private static void closeStatement(Statement statement) { */ @Deprecated public LocalFilesDataSource(SleuthkitCase db, long objId, long dataSourceObjectId, String deviceId, String name, TskData.TSK_FS_NAME_TYPE_ENUM dirType, TskData.TSK_FS_META_TYPE_ENUM metaType, TskData.TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String timezone, String md5Hash, TskData.FileKnown knownState, String parentPath) { - this(db, objId, dataSourceObjectId, deviceId, name, dirType, metaType, dirFlag, metaFlags, timezone, md5Hash, null, knownState, parentPath); + this(db, objId, dataSourceObjectId, deviceId, name, dirType, metaType, dirFlag, metaFlags, timezone, md5Hash, null, knownState, parentPath, TskData.FileLocation.LOCAL); } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java b/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java index df038e6021013a8f0a5b706e27721a721b2856d5..00ab42f5b5f4a9417a8349d569585b3c7765512f 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SlackFile.java @@ -72,6 +72,7 @@ public class SlackFile extends FsContent { * @param knownState The known state of the file from a hash * database lookup, null if not yet looked up. * @param parentPath The path of the parent of the file. + * @param location The location of the file, * @param mimeType The MIME type of the file, null if it has not * yet been determined. * @param extension The extension part of the file name (not @@ -89,9 +90,9 @@ public class SlackFile extends FsContent { long size, long ctime, long crtime, long atime, long mtime, short modes, int uid, int gid, - String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, String mimeType, + String md5Hash, String sha256Hash, FileKnown knownState, String parentPath, TskData.FileLocation location, String mimeType, String extension) { - super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.SLACK, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, extension); + super(db, objId, dataSourceObjectId, fsObjId, attrType, attrId, name, TskData.TSK_DB_FILES_TYPE_ENUM.SLACK, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, extension); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index f380bc88aedeeeaa47004a371a6fd833317bb446..3c171a0648b04bab432d5a4845fd07b35548a82a 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -2205,6 +2205,7 @@ private CaseDbSchemaVersionNumber updateFromSchema8dot5toSchema8dot6(CaseDbSchem acquireSingleUserCaseWriteLock(); try { statement.execute("ALTER TABLE tsk_files ADD COLUMN sha256 TEXT"); + statement.execute("ALTER TABLE tsk_files ADD COLUMN location INTEGER NOT NULL DEFAULT " + TskData.FileLocation.LOCAL.getValue()); return new CaseDbSchemaVersionNumber(8, 6); @@ -2852,7 +2853,7 @@ public List<DataSource> getDataSources() throws TskCoreException { final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue()); String parentPath = "/"; //NON-NLS - dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath); + dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath, TskData.FileLocation.LOCAL); } else { /* * Data found in 'tsk_image_info', so we build an Image. @@ -2951,7 +2952,7 @@ public DataSource getDataSource(long objectId) throws TskDataException, TskCoreE final short metaFlags = (short) (TSK_FS_META_FLAG_ENUM.ALLOC.getValue() | TSK_FS_META_FLAG_ENUM.USED.getValue()); String parentPath = "/"; //NON-NLS - dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath); + dataSource = new LocalFilesDataSource(this, objectId, objectId, deviceId, dsName, dirType, metaType, dirFlag, metaFlags, timezone, null, null, FileKnown.UNKNOWN, parentPath, TskData.FileLocation.LOCAL); } else { /* * Data found in 'tsk_image_info', so we build an Image. @@ -5618,8 +5619,8 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, // Insert a row for the virtual directory into the tsk_files table. // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, - // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id,extension) - // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) + // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, parent_path, location, data_source_obj_id,extension) + // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); statement.clearParameters(); statement.setLong(1, newObjId); @@ -5673,6 +5674,8 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, // parent path statement.setString(19, parentPath); + statement.setLong(20, TskData.FileLocation.LOCAL.getValue()); + // data source object id (same as object id if this is a data source) long dataSourceObjectId; if (0 == parentId) { @@ -5680,15 +5683,15 @@ public VirtualDirectory addVirtualDirectory(long parentId, String directoryName, } else { dataSourceObjectId = getDataSourceObjectId(connection, parentId); } - statement.setLong(20, dataSourceObjectId); + statement.setLong(21, dataSourceObjectId); //extension, since this is not really file we just set it to null - statement.setString(21, null); + statement.setString(22, null); connection.executeUpdate(statement); return new VirtualDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType, metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN, - parentPath); + parentPath, TskData.FileLocation.LOCAL); } catch (SQLException e) { throw new TskCoreException("Error creating virtual directory '" + directoryName + "'", e); } finally { @@ -5763,8 +5766,8 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas // Insert a row for the local directory into the tsk_files table. // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, - // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, data_source_obj_id) - // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, location, data_source_obj_id) + // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); statement.clearParameters(); statement.setLong(1, newObjId); @@ -5808,19 +5811,21 @@ public LocalDirectory addLocalDirectory(long parentId, String directoryName, Cas // parent path statement.setString(19, parentPath); + + statement.setLong(20, TskData.FileLocation.LOCAL.getValue()); // data source object id long dataSourceObjectId = getDataSourceObjectId(connection, parentId); - statement.setLong(20, dataSourceObjectId); + statement.setLong(21, dataSourceObjectId); //extension, since this is a directory we just set it to null - statement.setString(21, null); + statement.setString(22, null); connection.executeUpdate(statement); return new LocalDirectory(this, newObjId, dataSourceObjectId, directoryName, dirType, metaType, dirFlag, metaFlags, null, null, FileKnown.UNKNOWN, - parentPath); + parentPath, TskData.FileLocation.LOCAL); } catch (SQLException e) { throw new TskCoreException("Error creating local directory '" + directoryName + "'", e); } finally { @@ -5867,8 +5872,8 @@ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String root // its own object id. // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, // dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, - // atime, mtime, md5, known, mime_type, parent_path, data_source_obj_id, extension) - // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) + // atime, mtime, md5, sha256, known, mime_type, parent_path, location, data_source_obj_id, extension) + // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); preparedStatement.clearParameters(); preparedStatement.setLong(1, newObjId); @@ -5896,11 +5901,12 @@ public LocalFilesDataSource addLocalFilesDataSource(String deviceId, String root preparedStatement.setNull(18, java.sql.Types.VARCHAR); // MIME type String parentPath = "/"; //NON-NLS preparedStatement.setString(19, parentPath); - preparedStatement.setLong(20, newObjId); - preparedStatement.setString(21, null); //extension, just set it to null + preparedStatement.setLong(20, TskData.FileLocation.LOCAL.getValue()); + preparedStatement.setLong(21, newObjId); + preparedStatement.setString(22, null); //extension, just set it to null connection.executeUpdate(preparedStatement); - return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, FileKnown.UNKNOWN, parentPath); + return new LocalFilesDataSource(this, newObjId, newObjId, deviceId, rootDirectoryName, dirType, metaType, dirFlag, metaFlags, timeZone, null, null, FileKnown.UNKNOWN, parentPath, TskData.FileLocation.LOCAL); } catch (SQLException ex) { throw new TskCoreException(String.format("Error creating local files data source with device id %s and directory name %s", deviceId, rootDirectoryName), ex); @@ -6186,6 +6192,122 @@ public FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS releaseSingleUserCaseWriteLock(); } } + + /** + * Add a file system file to the database by supplying all fields to copy into the + * tsk_files entry. This should generally only be used when the location + * field is not set to LOCAL since it does not create any additional database + * entries for reading the file data (such as rows in tsk_files_path for local files, + * rows in tsk_file_layout for layout files, etc). + * + * @param fsObjId The fs object ID or null + * @param fileName The name of the file. + * @param fileType The type of file + * @param metaAddr The meta address of the file. + * @param metaSeq The meta address sequence of the file. + * @param attrType The attributed type of the file. + * @param attrId The attribute id + * @param dirFlag The allocated status from the name structure + * @param metaFlags The meta flags. + * @param size The size of the file in bytes. + * @param ctime The changed time of the file. + * @param crtime The creation time of the file. + * @param atime The accessed time of the file + * @param mtime The modified time of the file. + * @param md5 The MD5 hash of the file (may be null). + * @param sha256 The SHA-256 hash of the file (may be null). + * @param known The FileKnown value of the file. + * @param mimeType The MIME type of the file (may be null). + * @param isFile True, unless the file is a directory. + * @param location The location the file is stored. + * @param parent The parent of the file (e.g., a virtual directory) + * @param transaction The current transaction + * + * @return Newly created file + * + * @throws TskCoreException + */ + public AbstractFile addFileSystemFile(long fsObjId, + String fileName, + TskData.TSK_DB_FILES_TYPE_ENUM fileType, + long metaAddr, long metaSeq, + TSK_FS_ATTR_TYPE_ENUM attrType, int attrId, + TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, long size, + long ctime, long crtime, long atime, long mtime, + String md5, String sha256, FileKnown known, String mimeType, + boolean isFile, TskData.FileLocation location, Content parent, + CaseDbTransaction transaction) throws TskCoreException { + + TimelineManager timelineManager = getTimelineManager(); + Statement queryStatement = null; + try { + CaseDbConnection connection = transaction.getConnection(); + + // Insert a row for the local/logical file into the tsk_objects table. + // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?) + long objectId = addObject(parent.getId(), TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection); + + String parentPath; + long dataSourceObjId; + + if (parent instanceof AbstractFile) { + AbstractFile parentFile = (AbstractFile) parent; + if (isRootDirectory(parentFile, transaction)) { + parentPath = "/"; + } else { + parentPath = parentFile.getParentPath() + parent.getName() + "/"; //NON-NLS + } + dataSourceObjId = parentFile.getDataSourceObjectId(); + } else { + parentPath = "/"; + dataSourceObjId = getDataSourceObjectId(connection, parent.getId()); + } + + PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE_SYSTEM_FILE); + statement.clearParameters(); + statement.setLong(1, objectId); // obj_is + statement.setLong(2, fsObjId); // fs_obj_id + statement.setLong(3, dataSourceObjId); // data_source_obj_id + statement.setShort(4, (short) attrType.getValue()); // attr_type + statement.setInt(5, attrId); // attr_id + statement.setString(6, fileName); // name + statement.setLong(7, metaAddr); // meta_addr + statement.setInt(8, (int)metaSeq); // meta_addr + statement.setShort(9, fileType.getFileType()); //type + statement.setShort(10, (short) 1); // has_path + TSK_FS_NAME_TYPE_ENUM dirType = isFile ? TSK_FS_NAME_TYPE_ENUM.REG : TSK_FS_NAME_TYPE_ENUM.DIR; + statement.setShort(11, dirType.getValue()); // dir_type + TSK_FS_META_TYPE_ENUM metaType = isFile ? TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG : TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR; + statement.setShort(12, metaType.getValue()); // meta_type + statement.setShort(13, dirFlag.getValue()); // dir_flags + statement.setShort(14, metaFlags); // meta_flags + statement.setLong(15, size < 0 ? 0 : size); + statement.setLong(16, ctime); + statement.setLong(17, crtime); + statement.setLong(18, atime); + statement.setLong(19, mtime); + statement.setString(20, md5); // MD5 + statement.setString(21, sha256); // SHA-256 + statement.setByte(22, known.getFileKnownValue()); // Known + statement.setString(23, mimeType); // MIME type + statement.setString(24, parentPath); + statement.setLong(25, location.getValue()); + final String extension = extractExtension(fileName); + statement.setString(26, extension); + + connection.executeUpdate(statement); + + DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags, + size, ctime, crtime, atime, mtime, md5, sha256, known, parentPath, mimeType, TskData.FileLocation.LOCAL, parent.getId(), null, null, extension); + timelineManager.addEventsForNewFile(derivedFile, connection); + + return getAbstractFileById(objectId, connection); + } catch (SQLException ex) { + throw new TskCoreException("Failed to add file system file", ex); + } finally { + closeStatement(queryStatement); + } + } /** * Add a file system file. @@ -6267,15 +6389,19 @@ public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, statement.setLong(17, crtime); statement.setLong(18, atime); statement.setLong(19, mtime); - statement.setString(20, parentPath); + statement.setNull(20, java.sql.Types.VARCHAR); // MD5 + statement.setNull(21, java.sql.Types.VARCHAR); // SHA-256 + statement.setByte(22, FileKnown.UNKNOWN.getFileKnownValue()); // Known + statement.setNull(23, java.sql.Types.VARCHAR); // MIME type + statement.setString(24, parentPath); + statement.setLong(25, TskData.FileLocation.LOCAL.getValue()); final String extension = extractExtension(fileName); - statement.setString(21, extension); + statement.setString(26, extension); connection.executeUpdate(statement); DerivedFile derivedFile = new DerivedFile(this, objectId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags, - size, ctime, crtime, atime, mtime, null, null, null, parentPath, null, parent.getId(), null, null, extension); - + size, ctime, crtime, atime, mtime, null, null, null, parentPath, null, TskData.FileLocation.LOCAL, parent.getId(), null, null, extension); timelineManager.addEventsForNewFile(derivedFile, connection); transaction.commit(); @@ -6285,7 +6411,7 @@ public FsContent addFileSystemFile(long dataSourceObjId, long fsObjId, attrType, attrId, fileName, metaAddr, metaSeq, dirType, metaType, dirFlag, metaFlags, size, ctime, crtime, atime, mtime, - (short) 0, 0, 0, null, null, null, parentPath, null, + (short) 0, 0, 0, null, null, null, parentPath, TskData.FileLocation.LOCAL, null, extension); } catch (SQLException ex) { @@ -6382,8 +6508,8 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, * has_path, dir_type, meta_type, dir_flags, meta_flags, size, * ctime, crtime, atime, mtime, md5, known, mime_type, - * parent_path, data_source_obj_id,extension) VALUES (?, ?, ?, - * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) + * parent_path, location, data_source_obj_id,extension) VALUES (?, ?, ?, + * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) */ PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); prepStmt.clearParameters(); @@ -6406,10 +6532,11 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type prepStmt.setNull(19, java.sql.Types.VARCHAR); // parent path - prepStmt.setLong(20, parent.getId()); // data_source_obj_id + prepStmt.setLong(20, TskData.FileLocation.LOCAL.getValue()); // location + prepStmt.setLong(21, parent.getId()); // data_source_obj_id //extension, since this is not a FS file we just set it to null - prepStmt.setString(21, null); + prepStmt.setString(22, null); connection.executeUpdate(prepStmt); /* @@ -6441,7 +6568,7 @@ public final List<LayoutFile> addLayoutFiles(Content parent, List<TskFileRange> 0L, 0L, 0L, 0L, null, null, FileKnown.UNKNOWN, - parent.getUniquePath(), + parent.getUniquePath(), TskData.FileLocation.LOCAL, null)); } @@ -6563,8 +6690,8 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws * INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, * has_path, dir_type, meta_type, dir_flags, meta_flags, size, * ctime, crtime, atime, mtime, md5, known, mime_type, - * parent_path, data_source_obj_id,extenion) VALUES (?, ?, ?, ?, - * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) + * parent_path, location, data_source_obj_id,extenion) VALUES (?, ?, ?, ?, + * ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) */ PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); prepStmt.clearParameters(); @@ -6591,8 +6718,9 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type prepStmt.setString(19, parentPath); // parent path - prepStmt.setLong(20, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id - prepStmt.setString(21, extractExtension(carvedFile.getName())); //extension + prepStmt.setLong(20, TskData.FileLocation.LOCAL.getValue()); + prepStmt.setLong(21, carvedFilesDir.getDataSourceObjectId()); // data_source_obj_id + prepStmt.setString(22, extractExtension(carvedFile.getName())); //extension connection.executeUpdate(prepStmt); /* @@ -6626,7 +6754,7 @@ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws 0L, 0L, 0L, 0L, null, null, FileKnown.UNKNOWN, - parentPath, + parentPath, TskData.FileLocation.LOCAL, null)); } @@ -6762,13 +6890,15 @@ public DerivedFile addDerivedFile(String fileName, String localPath, //parent path statement.setString(19, parentPath); + + statement.setLong(20, TskData.FileLocation.LOCAL.getValue()); // root data source object id long dataSourceObjId = getDataSourceObjectId(connection, parentId); - statement.setLong(20, dataSourceObjId); + statement.setLong(21, dataSourceObjId); final String extension = extractExtension(fileName); //extension - statement.setString(21, extension); + statement.setString(22, extension); connection.executeUpdate(statement); @@ -6776,7 +6906,7 @@ public DerivedFile addDerivedFile(String fileName, String localPath, addFilePath(connection, newObjId, localPath, encodingType); DerivedFile derivedFile = new DerivedFile(this, newObjId, dataSourceObjId, fileName, dirType, metaType, dirFlag, metaFlags, - savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension); + savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, TskData.FileLocation.LOCAL, parentId, null, encodingType, extension); timelineManager.addEventsForNewFile(derivedFile, connection); transaction.commit(); @@ -6886,7 +7016,7 @@ public DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long dataSourceObjId = getDataSourceObjectId(connection, parentId); final String extension = extractExtension(derivedFile.getName()); return new DerivedFile(this, derivedFile.getId(), dataSourceObjId, derivedFile.getName(), dirType, metaType, dirFlag, metaFlags, - savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, parentId, null, encodingType, extension); + savedSize, ctime, crtime, atime, mtime, null, null, null, parentPath, localPath, TskData.FileLocation.LOCAL, parentId, null, encodingType, extension); } catch (SQLException ex) { connection.rollbackTransaction(); throw new TskCoreException("Failed to add derived file to case database", ex); @@ -6987,9 +7117,11 @@ public LocalFile addLocalFile(String fileName, String localPath, * @param crtime The creation time of the file. * @param atime The accessed time of the file * @param mtime The modified time of the file. - * @param md5 The MD5 hash of the file + * @param md5 The MD5 hash of the file. + * @param sha256 The SHA256 hash of the file. * @param known The known status of the file (can be null) * @param mimeType The MIME type of the file + * @param location The location of the file * @param isFile True, unless the file is a directory. * @param encodingType Type of encoding used on the file * @param parent The parent of the file (e.g., a virtual directory) @@ -7003,9 +7135,11 @@ public LocalFile addLocalFile(String fileName, String localPath, */ public LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, - String md5, String sha256, FileKnown known, String mimeType, + String md5, String sha256, FileKnown known, String mimeType, + TskData.FileLocation location, boolean isFile, TskData.EncodingType encodingType, Content parent, CaseDbTransaction transaction) throws TskCoreException { + CaseDbConnection connection = transaction.getConnection(); Statement queryStatement = null; try { @@ -7017,8 +7151,8 @@ public LocalFile addLocalFile(String fileName, String localPath, // Insert a row for the local/logical file into the tsk_files table. // INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, // dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, known, mime_type, - // parent_path, data_source_obj_id,extension) - // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) + // parent_path, location, data_source_obj_id,extension) + // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?) PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); statement.clearParameters(); statement.setLong(1, objectId); @@ -7065,9 +7199,10 @@ public LocalFile addLocalFile(String fileName, String localPath, dataSourceObjId = getDataSourceObjectId(connection, parent.getId()); } statement.setString(19, parentPath); - statement.setLong(20, dataSourceObjId); + statement.setLong(20, location.getValue()); + statement.setLong(21, dataSourceObjId); final String extension = extractExtension(fileName); - statement.setString(21, extension); + statement.setString(22, extension); connection.executeUpdate(statement); addFilePath(connection, objectId, localPath, encodingType); @@ -7082,7 +7217,7 @@ public LocalFile addLocalFile(String fileName, String localPath, savedSize, ctime, crtime, atime, mtime, mimeType, md5, sha256, known, - parent.getId(), parentPath, + parent.getId(), parentPath, location, dataSourceObjId, localPath, encodingType, extension); @@ -7196,8 +7331,8 @@ public LayoutFile addLayoutFile(String fileName, * Insert a row for the file into the tsk_files table: INSERT INTO * tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, * meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, - * mtime, md5, known, mime_type, parent_path, - * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, + * mtime, md5, known, mime_type, parent_path, location, + * data_source_obj_id,extenion) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, * ?, ?, ?, ?, ?, ?, ?,?) */ PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); @@ -7234,9 +7369,10 @@ public LayoutFile addLayoutFile(String fileName, prepStmt.setByte(17, FileKnown.UNKNOWN.getFileKnownValue()); // Known prepStmt.setNull(18, java.sql.Types.VARCHAR); // MIME type prepStmt.setString(19, parentPath); // parent path - prepStmt.setLong(20, parent.getDataSource().getId()); // data_source_obj_id + prepStmt.setLong(20, TskData.FileLocation.LOCAL.getValue()); // location + prepStmt.setLong(21, parent.getDataSource().getId()); // data_source_obj_id - prepStmt.setString(21, extractExtension(fileName)); //extension + prepStmt.setString(22, extractExtension(fileName)); //extension connection.executeUpdate(prepStmt); /* @@ -7270,7 +7406,7 @@ public LayoutFile addLayoutFile(String fileName, ctime, crtime, atime, mtime, null, null, FileKnown.UNKNOWN, - parentPath, + parentPath, TskData.FileLocation.LOCAL, null); transaction.commit(); @@ -8570,7 +8706,8 @@ private List<AbstractFile> resultSetToAbstractFiles(ResultSet rs, CaseDbConnecti TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), rs.getShort("meta_flags"), //NON-NLS rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS - rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); //NON-NLS + rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), parentPath, //NON-NLS + TskData.FileLocation.valueOf(rs.getByte("location")), rs.getString("mime_type")); //NON-NLS results.add(lf); } else if (type == TSK_DB_FILES_TYPE_ENUM.DERIVED.getFileType()) { final DerivedFile df; @@ -8616,7 +8753,8 @@ org.sleuthkit.datamodel.File file(ResultSet rs, FileSystem fs) throws SQLExcepti rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS - rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS + rs.getString("parent_path"), TskData.FileLocation.valueOf(rs.getByte("location")), //NON-NLS + rs.getString("mime_type"), rs.getString("extension")); //NON-NLS f.setFileSystem(fs); return f; } @@ -8643,7 +8781,7 @@ Directory directory(ResultSet rs, FileSystem fs) throws SQLException { rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS rs.getShort("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS - rs.getString("parent_path")); //NON-NLS + rs.getString("parent_path"), TskData.FileLocation.valueOf(rs.getByte("location"))); //NON-NLS dir.setFileSystem(fs); return dir; } @@ -8701,7 +8839,8 @@ VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) thr rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), - parentPath); + parentPath, + TskData.FileLocation.valueOf(rs.getByte("location"))); } else { final VirtualDirectory vd = new VirtualDirectory(this, objId, dsObjId, @@ -8710,7 +8849,8 @@ VirtualDirectory virtualDirectory(ResultSet rs, CaseDbConnection connection) thr TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS - FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS + FileKnown.valueOf(rs.getByte("known")), parentPath, //NON-NLS + TskData.FileLocation.valueOf(rs.getByte("location"))); //NON-NLS return vd; } } @@ -8735,7 +8875,7 @@ LocalDirectory localDirectory(ResultSet rs) throws SQLException { TSK_FS_META_TYPE_ENUM.valueOf(rs.getShort("meta_type")), //NON-NLS TSK_FS_NAME_FLAG_ENUM.valueOf(rs.getShort("dir_flags")), //NON-NLS rs.getShort("meta_flags"), rs.getString("md5"), rs.getString("sha256"), //NON-NLS - FileKnown.valueOf(rs.getByte("known")), parentPath); //NON-NLS + FileKnown.valueOf(rs.getByte("known")), parentPath, TskData.FileLocation.valueOf(rs.getByte("location"))); //NON-NLS return ld; } @@ -8788,7 +8928,7 @@ private DerivedFile derivedFile(ResultSet rs, CaseDbConnection connection, long rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS - parentPath, localPath, parentId, rs.getString("mime_type"), + parentPath, localPath, TskData.FileLocation.valueOf(rs.getByte("location")), parentId, rs.getString("mime_type"), encodingType, rs.getString("extension")); return df; } @@ -8841,7 +8981,7 @@ private LocalFile localFile(ResultSet rs, CaseDbConnection connection, long pare rs.getLong("size"), //NON-NLS rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS rs.getString("mime_type"), rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS - parentId, parentPath, rs.getLong("data_source_obj_id"), + parentId, parentPath, TskData.FileLocation.valueOf(rs.getByte("location")), rs.getLong("data_source_obj_id"), localPath, encodingType, rs.getString("extension")); return file; } @@ -8869,7 +9009,8 @@ org.sleuthkit.datamodel.SlackFile slackFile(ResultSet rs, FileSystem fs) throws rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), //NON-NLS (short) rs.getInt("mode"), rs.getInt("uid"), rs.getInt("gid"), //NON-NLS rs.getString("md5"), rs.getString("sha256"), FileKnown.valueOf(rs.getByte("known")), //NON-NLS - rs.getString("parent_path"), rs.getString("mime_type"), rs.getString("extension")); //NON-NLS + rs.getString("parent_path"), TskData.FileLocation.valueOf(rs.getByte("location")), //NON-NLS + rs.getString("mime_type"), rs.getString("extension")); //NON-NLS f.setFileSystem(fs); return f; } @@ -8931,7 +9072,8 @@ List<Content> fileChildren(ResultSet rs, CaseDbConnection connection, long paren rs.getLong("size"), rs.getLong("ctime"), rs.getLong("crtime"), rs.getLong("atime"), rs.getLong("mtime"), rs.getString("md5"), rs.getString("sha256"), - FileKnown.valueOf(rs.getByte("known")), parentPath, rs.getString("mime_type")); + FileKnown.valueOf(rs.getByte("known")), parentPath, + TskData.FileLocation.valueOf(rs.getByte("location")), rs.getString("mime_type")); children.add(lf); break; } @@ -11111,6 +11253,30 @@ private List<IngestModuleInfo> getIngestModules(int ingestJobId, CaseDbConnectio } } + + /** + * Check whether any files in the case are stored in the repository. + * + * @return true if any files have the location field set to "REPOSITORY", false otherwise. + * + * @throws TskCoreException + */ + public boolean caseUsesFileRepository() throws TskCoreException { + acquireSingleUserCaseReadLock(); + try (CaseDbConnection connection = getConnection(); + Statement statement = connection.createStatement(); + ResultSet rs = connection.executeQuery(statement, "SELECT COUNT(*) as count FROM tsk_files WHERE location=" + TskData.FileLocation.REPOSITORY.getValue());) { + int count = 0; + if (rs.next()) { + count = rs.getInt("count"); + } + return count > 0; + } catch (SQLException ex) { + throw new TskCoreException("Error querying case database for files stored in repository", ex); + } finally { + releaseSingleUserCaseReadLock(); + } + } /** * Stores a pair of object ID and its type @@ -11203,10 +11369,10 @@ private enum PREPARED_STATEMENT { SELECT_FILE_DERIVATION_METHOD("SELECT tool_name, tool_version, other FROM tsk_files_derived_method WHERE derived_id = ?"), //NON-NLS SELECT_MAX_OBJECT_ID("SELECT MAX(obj_id) AS max_obj_id FROM tsk_objects"), //NON-NLS INSERT_OBJECT("INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?)"), //NON-NLS - INSERT_FILE("INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, data_source_obj_id,extension) " //NON-NLS - + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS - INSERT_FILE_SYSTEM_FILE("INSERT INTO tsk_files(obj_id, fs_obj_id, data_source_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, parent_path, extension)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS + INSERT_FILE("INSERT INTO tsk_files (obj_id, fs_obj_id, name, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, location, data_source_obj_id,extension) " //NON-NLS + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), //NON-NLS + INSERT_FILE_SYSTEM_FILE("INSERT INTO tsk_files(obj_id, fs_obj_id, data_source_obj_id, attr_type, attr_id, name, meta_addr, meta_seq, type, has_path, dir_type, meta_type, dir_flags, meta_flags, size, ctime, crtime, atime, mtime, md5, sha256, known, mime_type, parent_path, location, extension)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), // NON-NLS UPDATE_DERIVED_FILE("UPDATE tsk_files SET type = ?, dir_type = ?, meta_type = ?, dir_flags = ?, meta_flags = ?, size= ?, ctime= ?, crtime= ?, atime= ?, mtime= ?, mime_type = ? " + "WHERE obj_id = ?"), //NON-NLS INSERT_LAYOUT_FILE("INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) " //NON-NLS @@ -12653,7 +12819,7 @@ public LocalFile addLocalFile(String fileName, String localPath, Content parent, CaseDbTransaction transaction) throws TskCoreException { return addLocalFile(fileName, localPath, size, ctime, crtime, atime, mtime, - md5, null, known, mimeType, isFile, encodingType, + md5, null, known, mimeType, TskData.FileLocation.LOCAL, isFile, encodingType, parent, transaction); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java index 5db5888d5b34d8a0ebbd926d18b1fa52559c2512..573ec25d756605f6fb6d5d064de308897af553ba 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SpecialDirectory.java @@ -44,11 +44,11 @@ public abstract class SpecialDirectory extends AbstractFile { short modes, int uid, int gid, String md5Hash, String sha256Hash, FileKnown knownState, - String parentPath, + String parentPath, TskData.FileLocation location, String mimeType) { super(db, objId, dataSourceObjectId, attrType, attrId, name, fileType, metaAddr, metaSeq, dirType, metaType, dirFlag, - metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, mimeType, null); + metaFlags, size, ctime, crtime, atime, mtime, modes, uid, gid, md5Hash, sha256Hash, knownState, parentPath, location, mimeType, null); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java index c66755ac36cabafe5c6a2ba38df60417ecc73adc..d91aea2ed1cba28c862ef19b84fb9bcaf76b428a 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TskCaseDbBridge.java @@ -789,8 +789,8 @@ private long addFileToDb(long parentObjId, // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?) long objectId = caseDb.addObject(parentObjId, TskData.ObjectType.ABSTRACTFILE.getObjectType(), connection); - String fileInsert = "INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path, extension, has_layout)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; // NON-NLS + String fileInsert = "INSERT INTO tsk_files (fs_obj_id, obj_id, data_source_obj_id, type, attr_type, attr_id, name, meta_addr, meta_seq, dir_type, meta_type, dir_flags, meta_flags, size, crtime, ctime, atime, mtime, mode, gid, uid, md5, known, parent_path, location, extension, has_layout)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; // NON-NLS PreparedStatement preparedStatement = connection.getPreparedStatement(fileInsert, Statement.NO_GENERATED_KEYS); preparedStatement.clearParameters(); @@ -866,11 +866,12 @@ private long addFileToDb(long parentObjId, preparedStatement.setString(22, md5); // md5 preparedStatement.setInt(23, known.getFileKnownValue());// known preparedStatement.setString(24, escaped_path); // parent_path - preparedStatement.setString(25, extension); // extension + preparedStatement.setLong(25, TskData.FileLocation.LOCAL.getValue()); // location + preparedStatement.setString(26, extension); // extension if (hasLayout) { - preparedStatement.setInt(26, 1); // has_layout + preparedStatement.setInt(27, 1); // has_layout } else { - preparedStatement.setNull(26, java.sql.Types.INTEGER); + preparedStatement.setNull(27, java.sql.Types.INTEGER); } connection.executeUpdate(preparedStatement); @@ -884,7 +885,7 @@ private long addFileToDb(long parentObjId, TskData.TSK_FS_META_TYPE_ENUM.valueOf((short) metaType), TskData.TSK_FS_NAME_FLAG_ENUM.valueOf(dirFlags), (short) metaFlags, - size, ctime, crtime, atime, mtime, null, null, null, escaped_path, null, parentObjId, null, null, extension); + size, ctime, crtime, atime, mtime, null, null, null, escaped_path, null, TskData.FileLocation.LOCAL, parentObjId, null, null, extension); timelineManager.addEventsForNewFileQuiet(derivedFile, connection); } diff --git a/bindings/java/src/org/sleuthkit/datamodel/TskData.java b/bindings/java/src/org/sleuthkit/datamodel/TskData.java index 6ff21a0a03cb007cc49d3d6fe5fa3579307ce8c2..ca07b7b650ae46ec5abfbb16fe082809cec3e406 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/TskData.java +++ b/bindings/java/src/org/sleuthkit/datamodel/TskData.java @@ -878,4 +878,31 @@ public static EncodingType valueOf(int type) { MessageFormat.format(bundle.getString("TskData.encodingType.exception.msg1.text"), type)); } } + + /** + * Location of the data for an AbstractFile. + */ + public enum FileLocation{ + LOCAL(0), + REPOSITORY(1); + + private final int value; + + private FileLocation(int value){ + this.value = value; + } + + public int getValue(){ + return value; + } + + public static FileLocation valueOf(int value) { + for (FileLocation v : FileLocation.values()) { + if (v.value == value) { + return v; + } + } + throw new IllegalArgumentException(MessageFormat.format(bundle.getString("TskData.fileLocation.exception.msg1.text"), value)); + } + } } diff --git a/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java b/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java index 729707128e93f097312caca5a16222c30927943b..7fac11eb5a923ed83c305ce53f9752f9fa2ccb6c 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java +++ b/bindings/java/src/org/sleuthkit/datamodel/VirtualDirectory.java @@ -63,10 +63,12 @@ public class VirtualDirectory extends SpecialDirectory { * directory. * @param metaFlags The meta flags for the virtual directory. * @param md5Hash The MD5 hash for the virtual directory. + * @param sha256Hash The SHA-256 hash for the virtual directory. * @param knownState The known state for the virtual directory * @param parentPath The parent path for the virtual directory, * should be "/" if the virtual directory is a * data source. + * @param location The location of the file. */ VirtualDirectory(SleuthkitCase db, long objId, @@ -75,10 +77,10 @@ public class VirtualDirectory extends SpecialDirectory { TSK_FS_NAME_TYPE_ENUM dirType, TSK_FS_META_TYPE_ENUM metaType, TSK_FS_NAME_FLAG_ENUM dirFlag, short metaFlags, String md5Hash, String sha256Hash, FileKnown knownState, - String parentPath) { + String parentPath, TskData.FileLocation location) { super(db, objId, dataSourceObjectId, TSK_FS_ATTR_TYPE_ENUM.TSK_FS_ATTR_TYPE_DEFAULT, 0, name, TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR, 0L, 0, dirType, metaType, dirFlag, - metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, null); + metaFlags, 0L, 0L, 0L, 0L, 0L, (short) 0, 0, 0, md5Hash, sha256Hash, knownState, parentPath, location, null); } /**