diff --git a/bindings/java/src/org/sleuthkit/datamodel/CarvingResult.java b/bindings/java/src/org/sleuthkit/datamodel/CarvingResult.java index 24708b6520d4361307a383ded28637b91f6375ff..b1fc7e5dd94e21d3e8e789ab9797beab867baae9 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/CarvingResult.java +++ b/bindings/java/src/org/sleuthkit/datamodel/CarvingResult.java @@ -21,65 +21,39 @@ import java.util.List; /** - * A carving result consisting of a set of carved files and the image, volume, - * or file system from which they were carved. + * A carving result consisting of a set of carved files and the parent content + * (e.g., an unallocated space file or an image data source) from which the + * files were carved. */ public final class CarvingResult { - private final Content carvedFilesParent; + private final Content parent; private final List<CarvedFile> carvedFiles; /** * Constructs a carving result consisting of a set of carved files and the - * image from which they were carved. + * parent content (e.g., an unallocated space file or an image data source) + * from which the files were carved. * - * - * @param carvedFilesParent An image that is the parent of a set of carved - * files. - * @param carvedFiles The carved files. - */ - public CarvingResult(Image carvedFilesParent, List<CarvedFile> carvedFiles) { - this.carvedFilesParent = carvedFilesParent; - this.carvedFiles = carvedFiles; - } - - /** - * Constructs a carving result consisting of a set of carved files and the - * volume from which they were carved. - * - * @param carvedFilesParent A volume that is the parent of a set of carved - * files. - * @param carvedFiles The carved files. - */ - public CarvingResult(FileSystem carvedFilesParent, List<CarvedFile> carvedFiles) { - this.carvedFilesParent = carvedFilesParent; - this.carvedFiles = carvedFiles; - } - - /** - * Constructs a carving result consisting of a set of carved files and file - * system from which they were carved. - * - * @param carvedFilesParent A file system that is the parent of a set of - * carved files. - * @param carvedFiles The carved files. + * @param parent The parent of a set of carved files. + * @param carvedFiles The carved files. */ - public CarvingResult(Volume carvedFilesParent, List<CarvedFile> carvedFiles) { - this.carvedFilesParent = carvedFilesParent; + public CarvingResult(Content parent, List<CarvedFile> carvedFiles) { + this.parent = parent; this.carvedFiles = carvedFiles; } /** - * Gets the parent of a set the carved files in a carving result. + * Gets the parent of the carved files in a carving result. * * @return The carved files parent. */ - final Content getCarvedFilesParent() { - return carvedFilesParent; + final Content getParent() { + return parent; } /** - * Gets the set of carved files in a carving result. + * Gets the carved files in a carving result. * * @return The carved files. */ @@ -88,7 +62,8 @@ final List<CarvedFile> getCarvedFiles() { } /** - * A file carved out of a parent image, volume, or file system. + * A file carved out of parent content (e.g., an unallocated space file or + * an image data source). */ public static class CarvedFile { @@ -97,8 +72,8 @@ public static class CarvedFile { private final List<TskFileRange> layoutInParent; /** - * Constructs a file carved out of a parent image, volume, or file - * system. + * Constructs a file carved out of parent content (e.g., an unallocated + * space file or an image data source). * * @param name The name of the file. * @param sizeInBytes The size of the file in bytes. @@ -111,7 +86,7 @@ public CarvedFile(String name, long sizeInBytes, List<TskFileRange> layoutInPare } /** - * Gets the name of a carved file. + * Gets the name of the carved file. * * @return The file name. */ @@ -120,7 +95,7 @@ final String getName() { } /** - * Gets the size of a carved file. + * Gets the size of the carved file. * * @return The size of the file in bytes. */ @@ -129,8 +104,7 @@ final long getSizeInBytes() { } /** - * Gets the layout of the carved file within its parent image, voluem, - * or file system. + * Gets the layout of the carved file within its parent. * * @return A list of TskRange objects representing the layoput of the * carved file within its parent. diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 67712807735a6d02b603daa9e7134f4b1e044cd4..bed958fcab04dc417017bc3e57b9d65593ea6d78 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -93,6 +93,7 @@ public class SleuthkitCase { private final ConnectionPool connections; private final ResultSetHelper rsHelper = new ResultSetHelper(this); private final Map<Long, Long> carvedFileContainersCache = new HashMap<Long, Long>(); // Caches the IDs of the root $CarvedFiles for each volume. + private final Map<Long, VirtualDirectory> rootIdsToCarvedFileDirs = new HashMap<Long, VirtualDirectory>(); private final Map<Long, FileSystem> fileSystemIdMap = new HashMap<Long, FileSystem>(); // Cache for file system files. private final ArrayList<ErrorObserver> sleuthkitCaseErrorObservers = new ArrayList<ErrorObserver>(); private final String dbPath; @@ -3447,190 +3448,144 @@ public List<VirtualDirectory> getVirtualDirectoryRoots() throws TskCoreException * operation. */ public final List<LayoutFile> addCarvedFiles(CarvingResult carvingResult) throws TskCoreException { - List<LayoutFile> addedFiles = new ArrayList<LayoutFile>(); - CaseDbTransaction localTrans = null; - Statement s = null; - ResultSet rs = null; + CaseDbTransaction transaction = null; + Statement statement = null; + ResultSet resultSet = null; acquireExclusiveLock(); try { - localTrans = beginTransaction(); - CaseDbConnection connection = localTrans.getConnection(); + transaction = beginTransaction(); + CaseDbConnection connection = transaction.getConnection(); - Content parent = carvingResult.getCarvedFilesParent(); + /* + * Find the root file system, volume, or image ancestor of the + * carved files parent. This is necessary because the carved files + * will be "re-parented" as children of the $CarvedFiles virtual + * directory of this ancestor. + */ + Content root = carvingResult.getParent(); + while ((root instanceof FileSystem == false) + && (root instanceof Volume == false) + && (root instanceof Image == false)) { + root = root.getParent(); + } - // first, check the cache - long carvedFilesDirId; - Long cachedCarvedFilesDirId = carvedFileContainersCache.get(parent.getId()); - if (null != cachedCarvedFilesDirId) { - carvedFilesDirId = cachedCarvedFilesDirId; - } else { - List<Content> children = Collections.<Content>emptyList(); - if (parent instanceof FileSystem) { - FileSystem fs = (FileSystem) parent; - children = fs.getRootDirectory().getChildren(); - } else if (parent instanceof Volume - || parent instanceof Image) { - children = parent.getChildren(); - } else { - throw new TskCoreException("The given ID (" + parent.getId() + ") was not an image, volume or file system."); + /* + * Get or create the cached $CarvedFiles virtual directory for the + * root ancestor. + */ + VirtualDirectory carvedFilesDir = rootIdsToCarvedFileDirs.get(root.getId()); + if (null == carvedFilesDir) { + List<Content> children = Collections.emptyList(); + if (root instanceof FileSystem) { + FileSystem fileSystem = (FileSystem) root; + children = fileSystem.getRootDirectory().getChildren(); + } else if (root instanceof Volume || root instanceof Image) { + children = root.getChildren(); } - - // see if any of the children are a '$CarvedFiles' directory - Content carvedFilesDir = null; for (Content child : children) { - if (child.getName().equals(VirtualDirectory.NAME_CARVED)) { - carvedFilesDir = child; + if (child instanceof VirtualDirectory && child.getName().equals(VirtualDirectory.NAME_CARVED)) { + carvedFilesDir = (VirtualDirectory) child; break; } } - - // if we found it, add it to the cache and grab its ID - if (carvedFilesDir != null) { - // add it to the cache - carvedFileContainersCache.put(parent.getId(), carvedFilesDir.getId()); - carvedFilesDirId = carvedFilesDir.getId(); - } else { - // a carved files directory does not exist; create one - VirtualDirectory vd = addVirtualDirectory(parent.getId(), VirtualDirectory.NAME_CARVED, localTrans); - carvedFilesDirId = vd.getId(); - // add it to the cache - carvedFileContainersCache.put(parent.getId(), carvedFilesDirId); + if (null == carvedFilesDir) { + carvedFilesDir = addVirtualDirectory(root.getId(), VirtualDirectory.NAME_CARVED, transaction); } + rootIdsToCarvedFileDirs.put(root.getId(), carvedFilesDir); } - // get the parent path for the $CarvedFiles directory - String parentPath = getFileParentPath(carvedFilesDirId, localTrans); - if (parentPath == null) { - parentPath = "/"; //NON-NLS - } - String parentName = getFileName(carvedFilesDirId, localTrans); - if (parentName != null) { - parentPath = parentPath + parentName + "/"; //NON-NLS - } - - // TODO (AUT-1903): We should cache this when we start adding - // lots of carved files... - boolean isContainerAFs = false; - s = connection.createStatement(); - rs = connection.executeQuery(s, "SELECT * FROM tsk_fs_info " //NON-NLS - + "WHERE obj_id = " + parent.getId()); //NON-NLS - if (rs.next()) { - isContainerAFs = true; - } - rs.close(); - rs = null; - - // TODO (AUT-1903): This result is another thing that should be - // cached. - long dataSourceObjectId = getDataSourceObjectId(connection, carvedFilesDirId); - - for (CarvingResult.CarvedFile itemToAdd : carvingResult.getCarvedFiles()) { - - // Insert a row for the carved file into the tsk_objects table. - // INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?) - PreparedStatement statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS); - statement.clearParameters(); - statement.setLong(1, carvedFilesDirId); - statement.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); - connection.executeUpdate(statement); - rs = statement.getGeneratedKeys(); - rs.next(); - long newObjId = rs.getLong(1); - - // Insert a row for the carved 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, parent_path, data_source_obj_id) - // VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); - statement.clearParameters(); - statement.setLong(1, newObjId); - - // only insert into the fs_obj_id column if container is a FS - if (isContainerAFs) { - statement.setLong(2, parent.getId()); + /* + * Add the carved files to the database as children of the + * $CarvedFile directory of the root ancestor. + */ + List<LayoutFile> carvedFiles = new ArrayList<LayoutFile>(); + for (CarvingResult.CarvedFile carvedFile : carvingResult.getCarvedFiles()) { + /* + * Insert a row for the carved file into the tsk_objects table: + * INSERT INTO tsk_objects (par_obj_id, type) VALUES (?, ?) + */ + PreparedStatement prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_OBJECT, Statement.RETURN_GENERATED_KEYS); + prepStmt.clearParameters(); + prepStmt.setLong(1, carvedFilesDir.getId()); + prepStmt.setLong(2, TskData.ObjectType.ABSTRACTFILE.getObjectType()); + connection.executeUpdate(prepStmt); + resultSet = prepStmt.getGeneratedKeys(); + resultSet.next(); + long carvedFileId = resultSet.getLong(1); + + /** + * Insert a row for the carved 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, parent_path, data_source_obj_id) + * VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + */ + prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_FILE); + prepStmt.clearParameters(); + prepStmt.setLong(1, carvedFileId); + if (root instanceof FileSystem) { + prepStmt.setLong(2, root.getId()); } else { - statement.setNull(2, java.sql.Types.BIGINT); + prepStmt.setNull(2, java.sql.Types.BIGINT); } - statement.setString(3, itemToAdd.getName()); - - // type - final TSK_DB_FILES_TYPE_ENUM type = TSK_DB_FILES_TYPE_ENUM.CARVED; - statement.setShort(4, type.getFileType()); - - // has_path - statement.setShort(5, (short) 1); - - // dirType - final TSK_FS_NAME_TYPE_ENUM dirType = TSK_FS_NAME_TYPE_ENUM.REG; - statement.setShort(6, dirType.getValue()); - - // metaType - final TSK_FS_META_TYPE_ENUM metaType = TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG; - statement.setShort(7, metaType.getValue()); - - // dirFlag - final TSK_FS_NAME_FLAG_ENUM dirFlag = TSK_FS_NAME_FLAG_ENUM.UNALLOC; - statement.setShort(8, dirFlag.getValue()); - - // metaFlags - final short metaFlags = TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(); - statement.setShort(9, metaFlags); - - // size - statement.setLong(10, itemToAdd.getSizeInBytes()); - - // nulls for params 11-14 - statement.setNull(11, java.sql.Types.BIGINT); - statement.setNull(12, java.sql.Types.BIGINT); - statement.setNull(13, java.sql.Types.BIGINT); - statement.setNull(14, java.sql.Types.BIGINT); - - // parent path - statement.setString(15, parentPath); - - // data source object id - statement.setLong(16, dataSourceObjectId); - - connection.executeUpdate(statement); + prepStmt.setString(3, carvedFile.getName()); + prepStmt.setShort(4, TSK_DB_FILES_TYPE_ENUM.CARVED.getFileType()); + prepStmt.setShort(5, (short) 1); // Has a path + prepStmt.setShort(6, TSK_FS_NAME_TYPE_ENUM.REG.getValue()); + prepStmt.setShort(7, TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); + prepStmt.setShort(8, TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue()); + prepStmt.setShort(9, TSK_FS_META_FLAG_ENUM.UNALLOC.getValue()); + prepStmt.setLong(10, carvedFile.getSizeInBytes()); + prepStmt.setNull(11, java.sql.Types.BIGINT); + prepStmt.setNull(12, java.sql.Types.BIGINT); + prepStmt.setNull(13, java.sql.Types.BIGINT); + prepStmt.setNull(14, java.sql.Types.BIGINT); + prepStmt.setString(15, carvedFilesDir.getUniquePath()); + prepStmt.setLong(16, carvedFilesDir.getDataSourceObjectId()); + connection.executeUpdate(prepStmt); // Add a row in the tsk_layout_file table for each TskFileRange. // INSERT INTO tsk_file_layout (obj_id, byte_start, byte_len, sequence) // VALUES (?, ?, ?, ?) - statement = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE); - for (TskFileRange tskFileRange : itemToAdd.getLayoutInParent()) { - statement.clearParameters(); - - // set the object ID - statement.setLong(1, newObjId); - - // set byte_start - statement.setLong(2, tskFileRange.getByteStart()); - - // set byte_len - statement.setLong(3, tskFileRange.getByteLen()); - - // set the sequence number - statement.setLong(4, tskFileRange.getSequence()); - - // execute it - connection.executeUpdate(statement); + prepStmt = connection.getPreparedStatement(PREPARED_STATEMENT.INSERT_LAYOUT_FILE); + for (TskFileRange tskFileRange : carvedFile.getLayoutInParent()) { + prepStmt.clearParameters(); + prepStmt.setLong(1, carvedFileId); + prepStmt.setLong(2, tskFileRange.getByteStart()); + prepStmt.setLong(3, tskFileRange.getByteLen()); + prepStmt.setLong(4, tskFileRange.getSequence()); + connection.executeUpdate(prepStmt); } - addedFiles.add(new LayoutFile(this, newObjId, dataSourceObjectId, itemToAdd.getName(), - type, dirType, metaType, dirFlag, metaFlags, - itemToAdd.getSizeInBytes(), null, FileKnown.UNKNOWN, parentPath, null)); - } - localTrans.commit(); - return addedFiles; + /* + * Construct a layout file representation of the carved file. + */ + carvedFiles.add(new LayoutFile(this, + carvedFileId, + carvedFilesDir.getDataSourceObjectId(), + carvedFile.getName(), + TSK_DB_FILES_TYPE_ENUM.CARVED, + TSK_FS_NAME_TYPE_ENUM.REG, + TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG, + TSK_FS_NAME_FLAG_ENUM.UNALLOC, + TSK_FS_META_FLAG_ENUM.UNALLOC.getValue(), + carvedFile.getSizeInBytes(), + null, + FileKnown.UNKNOWN, + carvedFilesDir.getUniquePath(), + null)); + } + transaction.commit(); + return carvedFiles; } catch (SQLException ex) { - if (null != localTrans) { - localTrans.rollback(); + if (null != transaction) { + transaction.rollback(); } throw new TskCoreException("Failed to add carved file to case database", ex); } finally { - closeResultSet(rs); - closeStatement(s); + closeResultSet(resultSet); + closeStatement(statement); releaseExclusiveLock(); } } @@ -7130,7 +7085,7 @@ public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) thr CarvingResult.CarvedFile carvedFile = new CarvingResult.CarvedFile(container.getName(), container.getSize(), container.getRanges()); carvedFiles.add(carvedFile); } - CarvingResult carvingResult; + CarvingResult carvingResult; Content parent = getContentById(filesToAdd.get(0).getId()); if (parent instanceof Image) { carvingResult = new CarvingResult((Image) parent, carvedFiles); @@ -7143,5 +7098,5 @@ public List<LayoutFile> addCarvedFiles(List<CarvedFileContainer> filesToAdd) thr } return addCarvedFiles(carvingResult); } - + }