diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceBrowser.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceBrowser.java index 525168b84e..e05b2db86a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceBrowser.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceBrowser.java @@ -39,7 +39,6 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; - /** * Panel which allows viewing and selecting of Data Sources and some of their * related information. @@ -124,10 +123,11 @@ final class DataSourceBrowser extends javax.swing.JPanel implements ExplorerMana */ private List getDataSourceSummaryList(Map usageMap, Map fileCountsMap) { List summaryList = new ArrayList<>(); + + final Map artifactCountsMap = DataSourceInfoUtilities.getCountsOfArtifacts(); + final Map tagCountsMap = DataSourceInfoUtilities.getCountsOfTags(); try { SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - final Map artifactCountsMap = DataSourceInfoUtilities.getCountsOfArtifacts(skCase); - final Map tagCountsMap = DataSourceInfoUtilities.getCountsOfTags(skCase); for (DataSource dataSource : skCase.getDataSources()) { summaryList.add(new DataSourceSummary(dataSource, usageMap.get(dataSource.getId()), fileCountsMap.get(dataSource.getId()), artifactCountsMap.get(dataSource.getId()), tagCountsMap.get(dataSource.getId()))); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceInfoUtilities.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceInfoUtilities.java index 39325d4df3..203ed907ef 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceInfoUtilities.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceInfoUtilities.java @@ -49,8 +49,9 @@ class DataSourceInfoUtilities { * comma seperated list of values of data source usage types * expected to be in the datasource */ - static Map getDataSourceTypes(SleuthkitCase skCase) { + static Map getDataSourceTypes() { try { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); List listOfArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_DATA_SOURCE_USAGE); Map typeMap = new HashMap<>(); for (BlackboardArtifact typeArtifact : listOfArtifacts) { @@ -67,7 +68,7 @@ class DataSourceInfoUtilities { } } return typeMap; - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Unable to get types of files for all datasources, providing empty results", ex); return Collections.emptyMap(); } @@ -83,16 +84,14 @@ class DataSourceInfoUtilities { * files in the datasource, will only contain entries for * datasources which have at least 1 file */ - static Map getCountsOfFiles(SleuthkitCase skCase) { + static Map getCountsOfFiles() { try { - DataSourceCountsCallback callback = new DataSourceCountsCallback(); final String countFilesQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFilesQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException ex) { + return getCountsMap(countFilesQuery); + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); return Collections.emptyMap(); } @@ -108,15 +107,13 @@ class DataSourceInfoUtilities { * artifacts in the datasource, will only contain entries for * datasources which have at least 1 artifact */ - static Map getCountsOfArtifacts(SleuthkitCase skCase) { + static Map getCountsOfArtifacts() { try { - DataSourceCountsCallback callback = new DataSourceCountsCallback(); final String countArtifactsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifacts WHERE review_status_id !=" + BlackboardArtifact.ReviewStatus.REJECTED.getID() + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactsQuery, callback); - return callback.getMapOfCounts(); - } catch (TskCoreException ex) { + return getCountsMap(countArtifactsQuery); + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Unable to get counts of artifacts for all datasources, providing empty results", ex); return Collections.emptyMap(); } @@ -133,28 +130,25 @@ class DataSourceInfoUtilities { * tags which have been applied in the datasource, will only contain * entries for datasources which have at least 1 item tagged. */ - static Map getCountsOfTags(SleuthkitCase skCase) { + static Map getCountsOfTags() { try { - DataSourceCountsCallback fileCountcallback = new DataSourceCountsCallback(); final String countFileTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM content_tags as content_tags, tsk_files as tsk_files" + " WHERE content_tags.obj_id = tsk_files.obj_id" + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countFileTagsQuery, fileCountcallback); - Map tagCountMap = new HashMap<>(fileCountcallback.getMapOfCounts()); - DataSourceCountsCallback artifactCountcallback = new DataSourceCountsCallback(); + //new hashmap so it can be modifiable + Map tagCountMap = new HashMap<>(getCountsMap(countFileTagsQuery)); final String countArtifactTagsQuery = "data_source_obj_id, COUNT(*) AS count" + " FROM blackboard_artifact_tags as artifact_tags, blackboard_artifacts AS arts" + " WHERE artifact_tags.artifact_id = arts.artifact_id" + " GROUP BY data_source_obj_id"; //NON-NLS - skCase.getCaseDbAccessManager().select(countArtifactTagsQuery, artifactCountcallback); //combine the results from the count artifact tags query into the copy of the mapped results from the count file tags query - artifactCountcallback.getMapOfCounts().forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); + getCountsMap(countArtifactTagsQuery).forEach((key, value) -> tagCountMap.merge(key, value, (value1, value2) -> value1 + value2)); return tagCountMap; - } catch (TskCoreException ex) { + } catch (TskCoreException | NoCurrentCaseException ex) { logger.log(Level.WARNING, "Unable to get counts of tags for all datasources, providing empty results", ex); return Collections.emptyMap(); - } + } } /** @@ -199,7 +193,7 @@ class DataSourceInfoUtilities { * specified mime types in the current case for the specified data * source, null if no count was retrieved */ - static Long getCountOfFiles(DataSource currentDataSource, Set setOfMimeTypes) { + static Long getCountOfFilesForMimeTypes(DataSource currentDataSource, Set setOfMimeTypes) { if (currentDataSource != null) { try { String inClause = String.join("', '", setOfMimeTypes); @@ -217,6 +211,84 @@ class DataSourceInfoUtilities { return null; } + /** + * Get a map containing the number of files in each data source in the + * current case. + * + * @param skCase the current SluethkitCase + * + * @return Collection which maps datasource id to a count for the number of + * files in the datasource, will only contain entries for + * datasources which have at least 1 file + */ + static Map getCountsOfUnallocatedFiles() { + try { + final String countUnallocatedFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND dir_flags=" + TskData.TSK_FS_NAME_FLAG_ENUM.UNALLOC.getValue() + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS + return getCountsMap(countUnallocatedFilesQuery); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of files in each data source in the + * current case. + * + * @param skCase the current SluethkitCase + * + * @return Collection which maps datasource id to a count for the number of + * files in the datasource, will only contain entries for + * datasources which have at least 1 file + */ + static Map getCountsOfDirectories() { + try { + final String countDirectoriesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type<>" + TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND meta_type=" + TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue() + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS + return getCountsMap(countDirectoriesQuery); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); + return Collections.emptyMap(); + } + } + + /** + * Get a map containing the number of files in each data source in the + * current case. + * + * @param skCase the current SluethkitCase + * + * @return Collection which maps datasource id to a count for the number of + * files in the datasource, will only contain entries for + * datasources which have at least 1 file + */ + static Map getCountsOfSlackFiles() { + try { + final String countSlackFilesQuery = "data_source_obj_id, COUNT(*) AS count" + + " FROM tsk_files WHERE type=" + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.getFileType() + + " AND dir_type<>" + TskData.TSK_FS_NAME_TYPE_ENUM.VIRT_DIR.getValue() + + " AND name<>'' GROUP BY data_source_obj_id"; //NON-NLS + return getCountsMap(countSlackFilesQuery); + } catch (TskCoreException | NoCurrentCaseException ex) { + logger.log(Level.WARNING, "Unable to get counts of files for all datasources, providing empty results", ex); + return Collections.emptyMap(); + } + } + + private static Map getCountsMap(String query) throws TskCoreException, NoCurrentCaseException { + SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); + DataSourceSingleCountCallback callback = new DataSourceSingleCountCallback(); + skCase.getCaseDbAccessManager().select(query, callback); + return callback.getMapOfCounts(); + } + private DataSourceInfoUtilities() { } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceCountsCallback.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSingleCountCallback.java similarity index 94% rename from Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceCountsCallback.java rename to Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSingleCountCallback.java index 1f66a63358..cf74b39728 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceCountsCallback.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSingleCountCallback.java @@ -32,9 +32,9 @@ import org.sleuthkit.datamodel.CaseDbAccessManager; * selects data_source_obj_id and count(*) with a group by data_source_obj_id * clause. */ -class DataSourceCountsCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { +class DataSourceSingleCountCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback { - private static final Logger logger = Logger.getLogger(DataSourceCountsCallback.class.getName()); + private static final Logger logger = Logger.getLogger(DataSourceSingleCountCallback.class.getName()); private Map dataSourceObjIdCounts = new HashMap<>(); @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryDialog.java index e1f8477961..516ea8496d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryDialog.java @@ -19,18 +19,13 @@ package org.sleuthkit.autopsy.casemodule.datasourceSummary; import java.awt.Frame; -import java.util.HashMap; import java.util.Map; import java.util.Observable; import java.util.Observer; -import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.event.ListSelectionEvent; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.datamodel.DataSource; -import org.sleuthkit.datamodel.SleuthkitCase; /** * Dialog for displaying the Data Sources Summary information @@ -55,15 +50,8 @@ final class DataSourceSummaryDialog extends javax.swing.JDialog implements Obser }) DataSourceSummaryDialog(Frame owner) { super(owner, Bundle.DataSourceSummaryPanel_window_title(), true); - Map usageMap = new HashMap<>(); - Map fileCountsMap = new HashMap<>(); - try { - SleuthkitCase skCase = Case.getCurrentCaseThrows().getSleuthkitCase(); - usageMap = DataSourceInfoUtilities.getDataSourceTypes(skCase); - fileCountsMap = DataSourceInfoUtilities.getCountsOfFiles(skCase); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Unable to data source usage information", ex); - } + Map usageMap = DataSourceInfoUtilities.getDataSourceTypes(); + Map fileCountsMap = DataSourceInfoUtilities.getCountsOfFiles(); filesPanel = new DataSourceSummaryFilesPanel(fileCountsMap); detailsPanel = new DataSourceSummaryDetailsPanel(usageMap); dataSourcesPanel = new DataSourceBrowser(usageMap, fileCountsMap); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryFilesPanel.java index 233486edf5..1b94ecbf92 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/datasourceSummary/DataSourceSummaryFilesPanel.java @@ -37,12 +37,19 @@ public class DataSourceSummaryFilesPanel extends javax.swing.JPanel { private FilesByMimeTypeTableModel filesByMimeTypeTableModel = new FilesByMimeTypeTableModel(null); private FilesByCategoryTableModel filesByCategoryTableModel = new FilesByCategoryTableModel(null); private static final Logger logger = Logger.getLogger(DataSourceSummaryFilesPanel.class.getName()); - private final Map fileCountsMap; + private final Map allFilesCountsMap; + private final Map slackFilesCountsMap; + private final Map directoriesCountsMap; + private final Map unallocatedFilesCountsMap; + /** * Creates new form DataSourceSummaryFilesPanel */ public DataSourceSummaryFilesPanel(Map fileCountsMap) { - this.fileCountsMap = fileCountsMap; + this.allFilesCountsMap = fileCountsMap; + this.slackFilesCountsMap = DataSourceInfoUtilities.getCountsOfSlackFiles(); + this.directoriesCountsMap = DataSourceInfoUtilities.getCountsOfDirectories(); + this.unallocatedFilesCountsMap = DataSourceInfoUtilities.getCountsOfUnallocatedFiles(); initComponents(); fileCountsByMimeTypeTable.getTableHeader().setReorderingAllowed(false); } @@ -195,15 +202,15 @@ public class DataSourceSummaryFilesPanel extends javax.swing.JPanel { } else if (columnIndex == 1) { switch (rowIndex) { case 0: - return DataSourceInfoUtilities.getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); + return DataSourceInfoUtilities.getCountOfFilesForMimeTypes(currentDataSource, FileTypeUtils.FileTypeCategory.IMAGE.getMediaTypes()); case 1: - return DataSourceInfoUtilities.getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); + return DataSourceInfoUtilities.getCountOfFilesForMimeTypes(currentDataSource, FileTypeUtils.FileTypeCategory.VIDEO.getMediaTypes()); case 2: - return DataSourceInfoUtilities.getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); + return DataSourceInfoUtilities.getCountOfFilesForMimeTypes(currentDataSource, FileTypeUtils.FileTypeCategory.AUDIO.getMediaTypes()); case 3: - return DataSourceInfoUtilities.getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); + return DataSourceInfoUtilities.getCountOfFilesForMimeTypes(currentDataSource, FileTypeUtils.FileTypeCategory.DOCUMENTS.getMediaTypes()); case 4: - return DataSourceInfoUtilities.getCountOfFiles(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); + return DataSourceInfoUtilities.getCountOfFilesForMimeTypes(currentDataSource, FileTypeUtils.FileTypeCategory.EXECUTABLE.getMediaTypes()); default: break; } @@ -217,7 +224,7 @@ public class DataSourceSummaryFilesPanel extends javax.swing.JPanel { } } - + /** * Table model for the files table model to display counts of specific file * types found in the currently selected data source. @@ -259,7 +266,7 @@ public class DataSourceSummaryFilesPanel extends javax.swing.JPanel { "DataSourceSummaryFilesPanel.FilesByCategoryTableModel.unallocated.row=Unallocated", "DataSourceSummaryFilesPanel.FilesByCategoryTableModel.slack.row=Slack", "DataSourceSummaryFilesPanel.FilesByCategoryTableModel.directory.row=Directory" - + }) @Override public Object getValueAt(int rowIndex, int columnIndex) { @@ -281,15 +288,23 @@ public class DataSourceSummaryFilesPanel extends javax.swing.JPanel { } else if (columnIndex == 1) { switch (rowIndex) { case 0: - return fileCountsMap.get(currentDataSource.getId()) == null ? 0 : fileCountsMap.get(currentDataSource.getId()); + return allFilesCountsMap.get(currentDataSource.getId()) == null ? 0 : allFilesCountsMap.get(currentDataSource.getId()); case 1: - return 0; + Long unallocatedFilesCount = unallocatedFilesCountsMap.get(currentDataSource.getId()); + Long allFilesCount = allFilesCountsMap.get(currentDataSource.getId()); + if (allFilesCount == null) { + return 0; + } else if (unallocatedFilesCount == null) { + return allFilesCount; + } else { + return allFilesCount - unallocatedFilesCount; + } case 2: - return 0; + return unallocatedFilesCountsMap.get(currentDataSource.getId()) == null ? 0 : unallocatedFilesCountsMap.get(currentDataSource.getId()); case 3: - return 0; + return slackFilesCountsMap.get(currentDataSource.getId()) == null ? 0 : slackFilesCountsMap.get(currentDataSource.getId()); case 4: - return 0; + return directoriesCountsMap.get(currentDataSource.getId()) == null ? 0 : directoriesCountsMap.get(currentDataSource.getId()); default: break; }