diff --git a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java index dc41ea72b33c4aaf1fe22008368ea450973d217b..0422de29a3774ebc864b896ea03dd692a6696941 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java +++ b/bindings/java/src/org/sleuthkit/datamodel/JniDbHelper.java @@ -22,8 +22,10 @@ import java.util.List; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.Map; import java.util.Objects; +import java.util.Queue; import java.util.logging.Level; import java.util.logging.Logger; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; @@ -33,6 +35,9 @@ * case database. All callbacks from the native code should come through this class. * Any changes to the method signatures in this class will require changes to the * native code. + * + * Note that this code should only be used for the add image process, and not + * to add additional files afterward. */ class JniDbHelper { @@ -47,8 +52,9 @@ class JniDbHelper { private final Map<ParentCacheKey, Long> parentDirCache = new HashMap<>(); private static final long BATCH_FILE_THRESHOLD = 500; - private final List<FileInfo> batchedFiles = new ArrayList<>(); - private final List<LayoutRangeInfo> batchedLayoutRanges = new ArrayList<>(); + private final Queue<FileInfo> batchedFiles = new LinkedList<>(); + private final Queue<LayoutRangeInfo> batchedLayoutRanges = new LinkedList<>(); + private final List<Long> layoutFileIds = new ArrayList<>(); JniDbHelper(SleuthkitCase caseDb, AddDataSourceCallbacks addDataSourceCallbacks) { this.caseDb = caseDb; @@ -95,6 +101,7 @@ private void revertTransaction() { void finish() { addBatchedFilesToDb(); addBatchedLayoutRangesToDb(); + processLayoutFiles(); } /** @@ -330,7 +337,8 @@ private long addBatchedFilesToDb() { List<Long> newObjIds = new ArrayList<>(); try { beginTransaction(); - for (FileInfo fileInfo : batchedFiles) { + FileInfo fileInfo; + while ((fileInfo = batchedFiles.poll()) != null) { long computedParentObjId = fileInfo.parentObjId; try { // If we weren't given the parent object ID, look it up @@ -370,9 +378,6 @@ private long addBatchedFilesToDb() { } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding file to the database - parent object ID: " + computedParentObjId + ", file system object ID: " + fileInfo.fsObjId + ", name: " + fileInfo.name, ex); - revertTransaction(); - batchedFiles.clear(); - return -1; } } commitTransaction(); @@ -385,10 +390,8 @@ private long addBatchedFilesToDb() { } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding batched files to database", ex); revertTransaction(); - batchedFiles.clear(); return -1; } - batchedFiles.clear(); return 0; } @@ -413,10 +416,11 @@ private long getParentObjId(FileInfo fileInfo) throws TskCoreException { if (parentDirCache.containsKey(key)) { return parentDirCache.get(key); } else { - // The parent wasn't found in the cache so do a database query - java.io.File parentAsFile = new java.io.File(parentPath); - return caseDb.findParentObjIdJNI(fileInfo.parMetaAddr, fileInfo.fsObjId, parentAsFile.getPath(), parentAsFile.getName(), trans); - } + // There's no reason to do a database query since every folder added is being + // stored in the cache. + throw new TskCoreException("Parent not found in cache (fsObjId: " +fileInfo.fsObjId + ", parMetaAddr: " + fileInfo.parMetaAddr + + ", parSeq: " + fileInfo.parSeq + ", parentPath: " + parentPath + ")"); + } } /** @@ -461,6 +465,10 @@ long addLayoutFile(long parentObjId, null, null, true, trans); commitTransaction(); + + // Store the layout file ID for later processing + layoutFileIds.add(objId); + return objId; } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding layout file to the database - parent object ID: " + parentObjId @@ -498,19 +506,16 @@ long addLayoutFileRange(long objId, long byteStart, long byteLen, long seq) { private long addBatchedLayoutRangesToDb() { try { beginTransaction(); - - for (LayoutRangeInfo range : batchedLayoutRanges) { + LayoutRangeInfo range; + while ((range = batchedLayoutRanges.poll()) != null) { try { caseDb.addLayoutFileRangeJNI(range.objId, range.byteStart, range.byteLen, range.seq, trans); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding layout file range to the database - layout file ID: " + range.objId + ", byte start: " + range.byteStart, ex); - revertTransaction(); - return -1; } } commitTransaction(); - batchedLayoutRanges.clear(); return 0; } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Error adding batched files to database", ex); @@ -518,6 +523,16 @@ private long addBatchedLayoutRangesToDb() { return -1; } } + + /** + * Send completed layout files on for further processing. + * Note that this must wait until we know all the ranges for each + * file have been added to the database. + */ + void processLayoutFiles() { + addDataSourceCallbacks.onFilesAdded(layoutFileIds); + layoutFileIds.clear(); + } /** * Add a virtual directory to hold unallocated file system blocks. diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 3f7ad417bcd6bc9908b30d81c26768222ce78565..3a26e343d1d92a00be16412b0adf2da130d98ef8 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -11065,44 +11065,6 @@ void addImageNameJNI(long objId, String name, long sequence, } } - /** - * Looks up a parent file object ID. The calling thread is expected to have - * a case read lock. For use with the JNI callbacks associated with the add - * image process. - * - * @param metaAddr The metadata address. - * @param fsObjId The file system object ID. - * @param path The file path. - * @param name The file name. - * @param transaction The open transaction. - * - * @return The object ID if found, -1 otherwise. - * - * @throws TskCoreException - */ - long findParentObjIdJNI(long metaAddr, long fsObjId, String path, String name, CaseDbTransaction transaction) throws TskCoreException { - ResultSet resultSet = null; - try { - CaseDbConnection connection = transaction.getConnection(); - PreparedStatement preparedStatement = connection.getPreparedStatement(PREPARED_STATEMENT.SELECT_OBJ_ID_BY_META_ADDR_AND_PATH); - preparedStatement.clearParameters(); - preparedStatement.setLong(1, metaAddr); - preparedStatement.setLong(2, fsObjId); - preparedStatement.setString(3, path); - preparedStatement.setString(4, name); - resultSet = connection.executeQuery(preparedStatement); - if (resultSet.next()) { - return resultSet.getLong("obj_id"); - } else { - throw new TskCoreException(String.format("Error looking up parent - meta addr: %d, path: %s, name: %s", metaAddr, path, name)); - } - } catch (SQLException ex) { - throw new TskCoreException(String.format("Error looking up parent - meta addr: %d, path: %s, name: %s", metaAddr, path, name), ex); - } finally { - closeResultSet(resultSet); - } - } - /** * Add a file system file to the database. For use with the JNI callbacks * associated with the add image process. @@ -11526,7 +11488,6 @@ private enum PREPARED_STATEMENT { INSERT_POOL_INFO("INSERT INTO tsk_pool_info (obj_id, pool_type) VALUES (?, ?)"), INSERT_FS_INFO("INSERT INTO tsk_fs_info (obj_id, data_source_obj_id, img_offset, fs_type, block_size, block_count, root_inum, first_inum, last_inum, display_name)" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"), - SELECT_OBJ_ID_BY_META_ADDR_AND_PATH("SELECT obj_id FROM tsk_files WHERE meta_addr = ? AND fs_obj_id = ? AND parent_path = ? AND name = ?"), SELECT_TAG_NAME_BY_ID("SELECT * FROM tag_names where tag_name_id = ?"); private final String sql;