From 8d198a5156519ae1454d2930f7ebc5c2c14412b7 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 30 Jun 2017 14:47:31 -0400 Subject: [PATCH 01/31] 2800 Column Headers for By Extension nodes adjusted to remove term filter --- .../sleuthkit/autopsy/datamodel/Bundle.properties | 12 ++++++------ .../sleuthkit/autopsy/datamodel/Bundle_ja.properties | 6 ------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index d582413648..755062d28d 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -87,8 +87,8 @@ DeletedContent.deletedContentsNode.name=Deleted Files DeletedContent.createSheet.name.name=Name DeletedContent.createSheet.name.displayName=Name DeletedContent.createSheet.name.desc=no description -DeletedContent.createSheet.filterType.name=Filter Type -DeletedContent.createSheet.filterType.displayName=Filter Type +DeletedContent.createSheet.filterType.name=Type +DeletedContent.createSheet.filterType.displayName=Type DeletedContent.createSheet.filterType.desc=no description DeletedContent.createKeys.maxObjects.msg=There are more Deleted Files than can be displayed. Only the first {0} Deleted Files will be shown. DeletedContent.createNodeForKey.typeNotSupported.msg=Not supported for this type of Displayable Item\: {0} @@ -112,13 +112,13 @@ FileSize.fileSizeRootNode.name=File Size FileSize.createSheet.name.name=Name FileSize.createSheet.name.displayName=Name FileSize.createSheet.name.desc=no description -FileSize.createSheet.filterType.name=Filter Type -FileSize.createSheet.filterType.displayName=Filter Type +FileSize.createSheet.filterType.name=Size Range +FileSize.createSheet.filterType.displayName=Size Range FileSize.createSheet.filterType.desc=no description FileSize.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} FileTypeChildren.exception.notSupported.msg=Not supported for this type of Displayable Item\: {0} -FileTypesByExtNode.createSheet.filterType.name=Filter Type -FileTypesByExtNode.createSheet.filterType.displayName=Filter Type +FileTypesByExtNode.createSheet.filterType.name=File Type +FileTypesByExtNode.createSheet.filterType.displayName=File Type FileTypesByExtNode.createSheet.filterType.desc=no description FileTypesByExtNode.createSheet.fileExt.name=File Extensions FileTypesByExtNode.createSheet.fileExt.displayName=File Extensions diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties index 56c4dd7bd5..e9eeb6ab06 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties @@ -64,8 +64,6 @@ DataSourcesNode.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b DeletedContent.fsDelFilter.text=\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0 DeletedContent.allDelFilter.text=\u3059\u3079\u3066 DeletedContent.deletedContentsNode.name=\u524a\u9664\u3055\u308c\u305f\u30d5\u30a1\u30a4\u30eb -DeletedContent.createSheet.name.name=\u540d\u524d -DeletedContent.createSheet.name.displayName=\u540d\u524d DeletedContent.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093 DeletedContent.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 DeletedContent.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 @@ -92,8 +90,6 @@ FileNode.getActions.viewInNewWin.text=\u65b0\u898f\u30a6\u30a3\u30f3\u30c9\u30a6 FileNode.getActions.openInExtViewer.text=\u5916\u90e8\u30d3\u30e5\u30fc\u30a2\u3067\u958b\u304f FileNode.getActions.searchFilesSameMD5.text=\u540c\u3058MD5\u30cf\u30c3\u30b7\u30e5\u3092\u6301\u3064\u30d5\u30a1\u30a4\u30eb\u3092\u691c\u7d22 FileSize.fileSizeRootNode.name=\u30d5\u30a1\u30a4\u30eb\u30b5\u30a4\u30ba -FileSize.createSheet.name.name=\u540d\u524d -FileSize.createSheet.name.displayName=\u540d\u524d FileSize.createSheet.name.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093 FileSize.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 FileSize.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 @@ -111,8 +107,6 @@ FileTypeExtensionFilters.autDocOfficeFilter.text=\u30aa\u30d5\u30a3\u30b9 FileTypeExtensionFilters.autoDocPdfFilter.text=PDF FileTypeExtensionFilters.autDocTxtFilter.text=\u30d7\u30ec\u30fc\u30f3\u30c6\u30ad\u30b9\u30c8 FileTypeExtensionFilters.autDocRtfFilter.text=\u30ea\u30c3\u30c1\u30c6\u30ad\u30b9\u30c8 -FileTypesByExtNode.createSheet.filterType.name=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 -FileTypesByExtNode.createSheet.filterType.displayName=\u30d5\u30a3\u30eb\u30bf\u30fc\u30bf\u30a4\u30d7 FileTypesByExtNode.createSheet.filterType.desc=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093 FileTypesByExtNode.createSheet.fileExt.name=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50 FileTypesByExtNode.createSheet.fileExt.displayName=\u30d5\u30a1\u30a4\u30eb\u62e1\u5f35\u5b50 From b487037ccc9f30ae3c13ab78cb8b3e93b3de53a6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 30 Jun 2017 15:45:02 -0400 Subject: [PATCH 02/31] 2800 fix merge conflict --- .../datamodel/FileTypesByExtension.java | 12 +++--- .../datamodel/FileTypesByMimeType.java | 42 ++++++++++++++++--- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 8da58193bc..c2f610aab8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -153,7 +153,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * something to provide a sub-node. */ FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) { - super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, null), true), Lookups.singleton(filter == null ? FNAME : filter.getDisplayName())); this.filter = filter; init(); } @@ -166,7 +166,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { * provides updates on events */ private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) { - super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getName())); + super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true), Lookups.singleton(filter == null ? FNAME : filter.getDisplayName())); this.filter = filter; init(); } @@ -178,7 +178,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { super.setDisplayName(FNAME); } // sub-node in file tree (i.e. documents, exec, etc.) else { - super.setName(filter.getName()); + super.setName(filter.getDisplayName()); super.setDisplayName(filter.getDisplayName()); } this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS @@ -202,7 +202,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { ss = Sheet.createPropertiesSet(); s.put(ss); } - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getName())); + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getDisplayName())); return s; } @@ -301,7 +301,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { } private void init() { - super.setName(filter.getName()); + super.setName(filter.getDisplayName()); updateDisplayName(); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS } @@ -521,7 +521,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"), Arrays.asList(".htm", ".html")), //NON-NLS - AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS + AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"), Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 2ab11bca97..12bc521706 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -34,7 +34,9 @@ import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; +import org.openide.nodes.Sheet; import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; @@ -222,11 +224,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi */ class ByMimeTypeNode extends DisplayableItemNode { - @NbBundle.Messages("FileTypesByMimeType.name.text=By MIME Type") + @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"}) + final String NAME = Bundle.FileTypesByMimeType_name_text(); ByMimeTypeNode() { - super(Children.create(new ByMimeTypeNodeChildren(), true)); + super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text())); super.setName(NAME); super.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); @@ -290,8 +293,12 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi */ class MediaTypeNode extends DisplayableItemNode { + @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type", + "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type", + "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"}) + MediaTypeNode(String name) { - super(Children.create(new MediaTypeNodeChildren(name), true)); + super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name.substring(0, 1).toUpperCase() + name.substring(1))); //Capitalized first letter of text to be more consistant setName(name); setDisplayName(name); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); @@ -307,6 +314,18 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi return v.visit(this); } + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.desc"), getDisplayName())); + return s; + } + @Override public String getItemType() { return getClass().getName(); @@ -352,9 +371,11 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi * media subtype is the portion of the MIME type following the /. */ class MediaSubTypeNode extends DisplayableItemNode implements Observer { - + @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype", + "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype", + "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"}) private MediaSubTypeNode(String mimeType) { - super(Children.create(new MediaSubTypeNodeChildren(mimeType), true)); + super(Children.create(new MediaSubTypeNodeChildren(mimeType), true),Lookups.singleton(mimeType)); addObserver(this); init(mimeType); } @@ -393,6 +414,17 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); } + @Override + protected Sheet createSheet() { + Sheet s = super.createSheet(); + Sheet.Set ss = s.get(Sheet.PROPERTIES); + if (ss == null) { + ss = Sheet.createPropertiesSet(); + s.put(ss); + } + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc"), getDisplayName())); + return s; + } @Override public String getItemType() { From 0055ebd2351c8f1bf05d81597517ba21a8b8c464 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 30 Jun 2017 17:00:39 -0400 Subject: [PATCH 03/31] 2800 removed name column from By Extensions table added extensions to docs and execs --- .../datamodel/FileTypesByExtension.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index c2f610aab8..819db21e5e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -202,7 +202,16 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { ss = Sheet.createPropertiesSet(); s.put(ss); } - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getDisplayName())); + if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) { + String extensions = ""; + for (String ext : filter.getFilter()) { + extensions += "'" + ext + "', "; + } + extensions = extensions.substring(0, extensions.lastIndexOf(',')); + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"), extensions)); + } else { + ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getDisplayName())); + } return s; } @@ -472,10 +481,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { FileTypeExtensions.getArchiveExtensions()), TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"), - Arrays.asList(".doc", ".docx", ".pdf", ".xls", ".rtf", ".txt")), //NON-NLS + Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"), - Arrays.asList(".exe", ".dll", ".bat", ".cmd", ".com")); //NON-NLS + FileTypeExtensions.getExecutableExtensions()); //NON-NLS private final int id; private final String name; @@ -521,7 +530,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"), Arrays.asList(".htm", ".html")), //NON-NLS - AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS + AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"), Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS From 27df14d98c0c6bcc26515ab6a0ddb5c3030d1781 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 30 Jun 2017 17:17:27 -0400 Subject: [PATCH 04/31] 2800 removed capitalization of media type in path --- .../org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 12bc521706..d7c777fa98 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -298,7 +298,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"}) MediaTypeNode(String name) { - super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name.substring(0, 1).toUpperCase() + name.substring(1))); //Capitalized first letter of text to be more consistant + super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name)); setName(name); setDisplayName(name); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); From e07de120822e4d8fdff916c17aed481216a89f54 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 7 Jul 2017 15:01:14 -0400 Subject: [PATCH 05/31] 2545 Added support for exporting/importing/deleting multiple keyword lists at one time --- .../keywordsearch/GlobalEditListPanel.java | 38 ++++++++--------- .../GlobalListSettingsPanel.java | 11 ++--- .../GlobalListsManagementPanel.java | 42 ++++++++++++------- 3 files changed, 48 insertions(+), 43 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java index cb8f55f1aa..043af08692 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalEditListPanel.java @@ -101,7 +101,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis } }); } - + /** * Enables and disables buttons on this panel based on the current state. */ @@ -125,12 +125,12 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis } } - @NbBundle.Messages("GlobalEditListPanel.editKeyword.title=Edit Keyword") + @NbBundle.Messages("GlobalEditListPanel.editKeyword.title=Edit Keyword") /** - * Adds keywords to a keyword list, returns true if at least one keyword was successfully added and no - * duplicates were found. - * - * @return - true or false + * Adds keywords to a keyword list, returns true if at least one keyword was + * successfully added and no duplicates were found. + * + * @return - true or false */ private boolean addKeywordsAction(String existingKeywords, boolean isLiteral, boolean isWholeWord) { String keywordsToRedisplay = existingKeywords; @@ -140,7 +140,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis int dupeCount = 0; int badCount = 1; // Default to 1 so we enter the loop the first time - if (!existingKeywords.isEmpty()){ //if there is an existing keyword then this action was called by the edit button + if (!existingKeywords.isEmpty()) { //if there is an existing keyword then this action was called by the edit button dialog.setTitle(NbBundle.getMessage(GlobalEditListPanel.class, "GlobalEditListPanel.editKeyword.title")); } while (badCount > 0) { @@ -162,7 +162,7 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis final Keyword keyword = new Keyword(newWord, !dialog.isKeywordRegex(), dialog.isKeywordExact(), currentKeywordList.getName(), newWord); if (currentKeywordList.hasKeyword(keyword)) { dupeCount++; - continue; + continue; } //check if valid @@ -231,8 +231,9 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis /** * Remove one or more keywords from a keyword list. - * - * @param selectedKeywords the indices of the keywords you would like to delete + * + * @param selectedKeywords the indices of the keywords you would like to + * delete */ private void deleteKeywordAction(int[] selectedKeywords) { tableModel.deleteSelected(selectedKeywords); @@ -411,20 +412,15 @@ class GlobalEditListPanel extends javax.swing.JPanel implements ListSelectionLis public void valueChanged(ListSelectionEvent e) { //respond to list selection changes in KeywordSearchListManagementPanel ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); + currentKeywordList = null; if (!listSelectionModel.isSelectionEmpty()) { - int index = listSelectionModel.getMinSelectionIndex(); - - listSelectionModel.setSelectionInterval(index, index); XmlKeywordSearchList loader = XmlKeywordSearchList.getCurrent(); - - currentKeywordList = loader.getListsL(false).get(index); - tableModel.resync(); - setButtonStates(); - } else { - currentKeywordList = null; - tableModel.resync(); - setButtonStates(); + if (listSelectionModel.getMinSelectionIndex() == listSelectionModel.getMaxSelectionIndex()) { + currentKeywordList = loader.getListsL(false).get(listSelectionModel.getMinSelectionIndex()); + } } + tableModel.resync(); + setButtonStates(); } @Override diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java index f0c8162d8f..cb7aac9018 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java @@ -46,8 +46,7 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option @Override public void actionPerformed(ActionEvent e) { if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) { - String toDelete = editListPanel.getCurrentKeywordList().getName(); - deleteAction(toDelete); + deleteAction(); listsManagementPanel.resync(); } } @@ -56,9 +55,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option listsManagementPanel.addRenameButtonActionPerformed(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - String toDelete = editListPanel.getCurrentKeywordList().getName(); if (copyAction()) { - deleteAction(toDelete); + deleteAction(); listsManagementPanel.resync(); } } @@ -83,9 +81,8 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option * * @param toDelete - the list to delete */ - private void deleteAction(String toDelete) { - XmlKeywordSearchList deleter = XmlKeywordSearchList.getCurrent(); - deleter.deleteList(toDelete); + private void deleteAction() { + listsManagementPanel.deleteSelected(); editListPanel.setCurrentKeywordList(null); editListPanel.setButtonStates(); listsManagementPanel.setButtonStates(); diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java index f7aa622d62..7735b6d142 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListsManagementPanel.java @@ -102,12 +102,12 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa } /** - * Opens the dialogue for creating a new keyword list and adds it to the table. + * Opens the dialogue for creating a new keyword list and adds it to the + * table. */ private void newKeywordListAction() { XmlKeywordSearchList writer = XmlKeywordSearchList.getCurrent(); String listName = ""; - listName = (String) JOptionPane.showInputDialog(null, NbBundle.getMessage(this.getClass(), "KeywordSearch.newKwListTitle"), NbBundle.getMessage(this.getClass(), "KeywordSearch.newKeywordListMsg"), JOptionPane.PLAIN_MESSAGE, null, null, listName); @@ -158,15 +158,19 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa boolean isIngestRunning = IngestManager.getInstance().isIngestRunning(); boolean isListSelected = !listsTable.getSelectionModel().isSelectionEmpty(); boolean canEditList = isListSelected && !isIngestRunning; + boolean multiSelection = false; //can't rename or copy when multiple lists selected + if (isListSelected) { + multiSelection = (listsTable.getSelectionModel().getMaxSelectionIndex() != listsTable.getSelectionModel().getMinSelectionIndex()); + } // items that only need ingest to not be running importButton.setEnabled(!isIngestRunning); - - // items that need an unlocked list w/out ingest running + // items that need an unlocked list w/out ingest running deleteListButton.setEnabled(canEditList); renameListButton.setEnabled(canEditList); - + renameListButton.setEnabled(canEditList && !multiSelection); // items that only need a selected list copyListButton.setEnabled(isListSelected); + copyListButton.setEnabled(isListSelected && !multiSelection); exportButton.setEnabled(isListSelected); } @@ -435,13 +439,9 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); }//GEN-LAST:event_importButtonActionPerformed private void listsTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_listsTableKeyPressed - if (evt.getKeyCode() == KeyEvent.VK_DELETE) { - int[] selected = listsTable.getSelectedRows(); - if (selected.length == 0) { - return; - } else if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) { - String listName = (String) listsTable.getModel().getValueAt(selected[0], 0); - XmlKeywordSearchList.getCurrent().deleteList(listName); + if (evt.getKeyCode() == KeyEvent.VK_DELETE && !IngestManager.getInstance().isIngestRunning() && !listsTable.getSelectionModel().isSelectionEmpty()) { + if (KeywordSearchUtil.displayConfirmDialog(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.title"), NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel1.customizeComponents.body"), KeywordSearchUtil.DIALOG_MESSAGE_TYPE.WARN)) { + deleteSelected(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } else { return; @@ -492,7 +492,11 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa XmlKeywordSearchList reader = XmlKeywordSearchList.getCurrent(); List toWrite = new ArrayList<>(); - toWrite.add(reader.getList(listName)); + + for (int index : listsTable.getSelectedRows()) { + toWrite.add(reader.getList(listsTable.getValueAt(index, 0).toString())); + } + final XmlKeywordSearchList exporter = new XmlKeywordSearchList(fileAbs); boolean written = exporter.saveLists(toWrite); if (written) { @@ -541,6 +545,14 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa tableModel.resync(); } + void deleteSelected() { + int[] selected = listsTable.getSelectedRows(); + if (selected.length == 0) { + return; + } + tableModel.deleteSelected(selected); + } + private class KeywordListTableModel extends AbstractTableModel { private static final long serialVersionUID = 1L; @@ -586,8 +598,8 @@ class GlobalListsManagementPanel extends javax.swing.JPanel implements OptionsPa //delete selected from handle, events are fired from the handle void deleteSelected(int[] selected) { List toDel = new ArrayList<>(); - for (int i = 0; i < selected.length; i++) { - toDel.add((String) getValueAt(0, selected[i])); + for (int i : selected) { + toDel.add(getValueAt(i, 0).toString()); } for (String del : toDel) { listsHandle.deleteList(del); From fba8b5b307a566e88b573d218b56475eed919f69 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 7 Jul 2017 15:29:30 -0400 Subject: [PATCH 06/31] 2760 fixed warning about image folder to not show when examiner mode selected --- .../experimental/configuration/AutoIngestSettingsPanel.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 17a1c9847a..7a8b4f214f 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -326,12 +326,15 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } break; case REVIEW: + jLabelInvalidImageFolder.setVisible(false); if (!validateResultsPath()) { isValidNodePanel = false; } break; case STANDALONE: + jLabelInvalidImageFolder.setVisible(false); + jLabelInvalidResultsFolder.setVisible(false); break; default: break; From 44f35c3d73eca3fc516c35efd29525d4c6f2e6d9 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 7 Jul 2017 17:08:45 -0400 Subject: [PATCH 07/31] 2760 made buttons and warnings on Auto Ingest Options enable/disable more consistantly --- .../AutoIngestSettingsPanel.java | 41 +++++++++---------- .../configuration/Bundle.properties | 2 - 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index 7a8b4f214f..a14671dac4 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -306,10 +306,13 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { */ boolean valid() { - if (!cbJoinAutoIngestCluster.isSelected()) { + if (!cbJoinAutoIngestCluster.isSelected()) { //hide the invalid field warnings when in stand alone mode + jLabelInvalidImageFolder.setVisible(false); + jLabelInvalidResultsFolder.setVisible(false); + sharedSettingsErrorTextField.setVisible(false); + configButtonErrorTextField.setText(""); return true; } - boolean isValidNodePanel = true; switch (getModeFromRadioButtons()) { @@ -333,8 +336,6 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { break; case STANDALONE: - jLabelInvalidImageFolder.setVisible(false); - jLabelInvalidResultsFolder.setVisible(false); break; default: break; @@ -599,23 +600,24 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { private void enableOptionsBasedOnMode(OptionsUiMode mode) { if (mode != OptionsUiMode.DOWNLOADING_CONFIGURATION) { - jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected()); - jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected()); + boolean nonMasterSharedConfig = !masterNodeCheckBox.isSelected() && sharedConfigCheckbox.isSelected(); + jRadioButtonAutomated.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected()); + jRadioButtonReview.setEnabled(cbJoinAutoIngestCluster.isSelected() && !sharedConfigCheckbox.isSelected()); - jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM); - inputPathTextField.setEnabled(mode == OptionsUiMode.AIM); - browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM); + jLabelSelectInputFolder.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + inputPathTextField.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + browseInputFolderButton.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); - jLabelSelectOutputFolder.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); - outputPathTextField.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); - browseOutputFolderButton.setEnabled(mode == OptionsUiMode.AIM || mode == OptionsUiMode.REVIEW); + jLabelSelectOutputFolder.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + outputPathTextField.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); + browseOutputFolderButton.setEnabled((mode == OptionsUiMode.AIM && !nonMasterSharedConfig) || mode == OptionsUiMode.REVIEW); jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); - jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM); - bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM); - bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM); - bnLogging.setEnabled(mode == OptionsUiMode.AIM); + jPanelIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + bnEditIngestSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + bnAdvancedSettings.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); + bnLogging.setEnabled(mode == OptionsUiMode.AIM && !nonMasterSharedConfig); jPanelSharedConfig.setEnabled(mode == OptionsUiMode.AIM); sharedConfigCheckbox.setEnabled(mode == OptionsUiMode.AIM); masterNodeCheckBox.setEnabled(mode == OptionsUiMode.AIM && sharedConfigCheckbox.isSelected()); @@ -1392,12 +1394,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { void setEnabledStateForSharedConfiguration() { if (jRadioButtonAutomated.isSelected() && cbJoinAutoIngestCluster.isSelected()) { - if (sharedConfigCheckbox.isEnabled() && sharedConfigCheckbox.isSelected()) { - setEnabledState(masterNodeCheckBox.isSelected()); - } else { - // If we are in AIM mode and shared config is not enabled, allow this - setEnabledState(true); - } + enableOptionsBasedOnMode(OptionsUiMode.AIM); } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties index efc97f2909..21da10e84d 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/Bundle.properties @@ -12,7 +12,6 @@ AdvancedAutoIngestSettingsPanel.lbSecondsBetweenJobs.toolTipText=A wait time use AdvancedAutoIngestSettingsPanel.tbWarning.text=WARNING: Ensure you know what you are doing before modifying these values. Informed use can improve system performance. Misuse can cause system performance degradation and data loss. Please consult the user guide for details. AdvancedAutoIngestSettingsPanel.threadCountLabel.text=For this computer, a maximum of {0} file ingest threads should be used. AIMIngestSettingsPanel.browseGlobalSettingsButton.text=Browse -AIMIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder: AIMIngestSettingsPanel.globalSettingsErrorTextField.text= AIMIngestSettingsPanel.globalSettingsTextField.text= AIMIngestSettingsPanel.jButton1.text=Download shared settings @@ -33,7 +32,6 @@ AutoIngestSettingsPanel.downloadButton.text=Download Config AutoIngestSettingsPanel.EmptySettingsDirectory=Enter path to settings directory AutoIngestSettingsPanel.ErrorSettingDefaultFolder=Error creating default folder AutoIngestSettingsPanel.FileExportRules.text=File Export Rules -AutoIngestSettingsPanel.globalSettingsCheckbox.text=Use shared configuration in folder: AutoIngestSettingsPanel.globalSettingsErrorTextField.text= AutoIngestSettingsPanel.globalSettingsTextField.text= AutoIngestSettingsPanel.ImageDirectoryUnspecified=Shared images folder must be set From 94690abf90ea350b43fb0c87cc6e1c28a3e08823 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 12 Jul 2017 13:01:27 -0400 Subject: [PATCH 08/31] 2763 changed lambda expression as arguement to super contrstructor to anon class --- .../corecomponents/ThumbnailViewChildren.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java index bc16b97c35..50e15c8116 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewChildren.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -104,11 +105,11 @@ class ThumbnailViewChildren extends Children.Keys { * children nodes (which might not be preloaded at this point). */ // get list of supported children sorted by persisted criteria - final List suppContent = - Stream.of(parent.getChildren().getNodes()) - .filter(ThumbnailViewChildren::isSupported) - .sorted(getComparator()) - .collect(Collectors.toList()); + final List suppContent + = Stream.of(parent.getChildren().getNodes()) + .filter(ThumbnailViewChildren::isSupported) + .sorted(getComparator()) + .collect(Collectors.toList()); if (suppContent.isEmpty()) { //if there are no images, there is nothing more to do @@ -314,7 +315,12 @@ class ThumbnailViewChildren extends Children.Keys { private boolean cancelled = false; ThumbnailLoadTask() { - super(() -> ImageUtils.getThumbnail(content, thumbSize)); + super(new Callable() { //Does not work as lambda expression in dependent projects in IDE + public Image call() { + return ImageUtils.getThumbnail(content, thumbSize); + } + }); + //super(() -> ImageUtils.getThumbnail(content, thumbSize)); progressText = Bundle.ThumbnailViewNode_progressHandle_text(content.getName()); progressHandle = ProgressHandleFactory.createSystemHandle(progressText); From 7e3c7241e11fb4301690fedeb0394a8cbd8fd87b Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 12 Jul 2017 16:29:16 -0400 Subject: [PATCH 09/31] 2760 re-opening auto ingest options after cancel restores correct settings --- .../experimental/configuration/AutoIngestSettingsPanel.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java index a14671dac4..be6e8e006b 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestSettingsPanel.java @@ -174,6 +174,7 @@ public class AutoIngestSettingsPanel extends javax.swing.JPanel { } validateSettings(); + enableOptionsBasedOnMode(getModeFromRadioButtons()); } /** From 9c66e6aac6f19228d8c3a4a6f3108219c103a77a Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 12 Jul 2017 17:58:38 -0400 Subject: [PATCH 10/31] 1930 made reset method of Metadata Content viewer reset it to being empty --- Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java index 26fc09d19f..df1db76507 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Metadata.java @@ -220,6 +220,7 @@ public class Metadata extends javax.swing.JPanel implements DataContentViewer { @Override public void resetComponent() { + setText(""); return; } From 61fa9c036728357ff853c104f3072c2fab1abd18 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 13 Jul 2017 13:20:11 +0200 Subject: [PATCH 11/31] clean up FileTypesByMimeType --- .../datamodel/FileTypesByMimeType.java | 109 +++++++----------- 1 file changed, 40 insertions(+), 69 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 7f3de1cd21..b84508c882 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -36,10 +36,10 @@ import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.core.UserPreferences; +import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; +import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -55,6 +55,7 @@ import org.sleuthkit.datamodel.TskData; public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName()); + private final SleuthkitCase skCase; /** * The nodes of this tree will be determined dynamically by the mimetypes @@ -62,36 +63,53 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi * type as the key and a Map, from media subtype to count, as the value. */ private final HashMap> existingMimeTypeCounts = new HashMap<>(); - private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName()); + /** + * Root of the File Types tree. Used to provide single answer to question: + * Should the child counts be shown next to the nodes? + */ private final FileTypes typesRoot; - private void removeListeners() { - deleteObservers(); - IngestManager.getInstance().removeIngestJobEventListener(pcl); - Case.removePropertyChangeListener(pcl); - } - /* + /** * The pcl is in the class because it has the easiest mechanisms to add and * remove itself during its life cycles. */ private final PropertyChangeListener pcl; /** - * Performs the query on the database to get all distinct MIME types of - * files in it, and populate the hashmap with those results. + * Create the base expression used as the where clause in the queries for + * files by mime type. Filters out certain kinds of files and directories, + * and known/slack files based on user preferences. + * + * @return The base expression to be used in the where clause of queries for + * files by mime type. */ - private void populateHashMap() { - String query = "SELECT mime_type,count(*) as count from tsk_files " - + " where mime_type IS NOT null " - + " AND dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + static private String createBaseWhereExpr() { + return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + " AND (type IN (" + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + "," + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal() - + ((UserPreferences.hideSlackFilesInViewsTree()) ? "" - : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) - + "))" + " GROUP BY mime_type"; + + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal())) + + "))" + + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : ""); + } + + private void removeListeners() { + deleteObservers(); + IngestManager.getInstance().removeIngestJobEventListener(pcl); + Case.removePropertyChangeListener(pcl); + } + + /** + * Performs the query on the database to get all distinct MIME types of + * files in it, and populate the hashmap with those results. + */ + private void populateHashMap() { + String query = "SELECT mime_type, count(*) AS count FROM tsk_files " + + " WHERE mime_type IS NOT null " + + " AND " + createBaseWhereExpr() + + " GROUP BY mime_type"; synchronized (existingMimeTypeCounts) { existingMimeTypeCounts.clear(); @@ -114,7 +132,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi } } } catch (TskCoreException | SQLException ex) { - LOGGER.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS + logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS } } @@ -369,33 +387,6 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi } } - /** - * Create the portion of the query following WHERE for a query of the - * database for each file which matches the complete MIME type represented - * by this node. Matches against the mime_type column in tsk_files. - * - * @param mimeType - the complete mimetype of the file mediatype/subtype - * - * @return query.toString - portion of SQL query which will follow a WHERE - * clause. - */ - static private String createQuery(String mimeType) { - StringBuilder query = new StringBuilder(); - query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS - query.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(","); - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(","); - if (!UserPreferences.hideSlackFilesInViewsTree()) { - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()).append(","); - } - query.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))"); - if (UserPreferences.hideKnownFilesInViewsTree()) { - query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS - } - query.append(" AND mime_type = '").append(mimeType).append("'"); //NON-NLS - return query.toString(); - } - /** * Factory for populating the contents of the Media Sub Type Node with the * files that match MimeType which is represented by this position in the @@ -411,23 +402,13 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi this.mimeType = mimeType; } - /** - * Uses the createQuery method to complete the query, Select * from - * tsk_files WHERE. The results from the database will contain the files - * which match this mime type and their information. - * - * @param list - will contain all files and their attributes from the - * tsk_files table where mime_type matches the one specified - * - * @return true - */ @Override protected boolean createKeys(List list) { try { - List files = skCase.findAllFilesWhere(createQuery(mimeType)); - list.addAll(files); + list.addAll(skCase.findAllFilesWhere( + createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")); //NON-NLS } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS + logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS } return true; } @@ -437,19 +418,9 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi refresh(true); } - /** - * Creates the content to populate the Directory Listing Table view for - * each file - * - * @param key - * - * @return - */ @Override protected Node createNodeForKey(Content key) { return key.accept(new FileTypes.FileNodeCreationVisitor()); } - } - } From c74855c98ec77ef2898042f1719b53a44d55a38e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 10 Jul 2017 18:08:39 -0400 Subject: [PATCH 12/31] 2811 - Warning not to use SQLite databases for multi-user purposes added --- .../centralrepository/optionspanel/EamDbSettingsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java index 47d565cce5..a8395be399 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java @@ -861,7 +861,7 @@ public class EamDbSettingsDialog extends JDialog { * * @return true */ - @Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema.", + @Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema. SQLite should only be used for single user cases.", "EamDbSettingsDialog.validation.failedConnection=The connection to the database failed. Update the settings and try the Test again."}) private boolean enableTestButton(boolean isValidInput) { if (selectedPlatform != EamDbPlatformEnum.DISABLED && isValidInput) { From a7ad8c0e35f736821b4b0c0dcf666d1f06ee9245 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Fri, 14 Jul 2017 10:49:57 -0400 Subject: [PATCH 13/31] 2810 Modified warning to reflect single examiner instead of single user case --- .../centralrepository/optionspanel/EamDbSettingsDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java index a8395be399..b3c282b607 100644 --- a/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java +++ b/CentralRepository/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java @@ -861,7 +861,7 @@ public class EamDbSettingsDialog extends JDialog { * * @return true */ - @Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema. SQLite should only be used for single user cases.", + @Messages({"EamDbSettingsDialog.validation.mustTest=Once you are statisfied with the database settings, click the Test button to test the database connection, settings, and schema. SQLite should only be used by one examiner at a time.", "EamDbSettingsDialog.validation.failedConnection=The connection to the database failed. Update the settings and try the Test again."}) private boolean enableTestButton(boolean isValidInput) { if (selectedPlatform != EamDbPlatformEnum.DISABLED && isValidInput) { From 21f920ae7644b54e918a198602816040b07525a2 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Sat, 15 Jul 2017 13:31:51 +0200 Subject: [PATCH 14/31] first pass at content cache --- .../datamodel/BlackboardArtifactNode.java | 44 ++++++++++--------- .../autopsy/datamodel/Bundle.properties | 1 - .../autopsy/datamodel/Bundle_ja.properties | 1 - 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7c44f8fbe7..aaba845702 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.datamodel; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.MessageFormat; @@ -26,22 +28,23 @@ import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.stream.Collectors; import javax.swing.Action; -import org.apache.commons.lang3.StringUtils; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.BlackBoardArtifactTagDeletedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked; import org.sleuthkit.autopsy.timeline.actions.ViewArtifactInTimelineAction; import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction; @@ -60,10 +63,15 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class BlackboardArtifactNode extends DisplayableItemNode { + private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName()); + + private static Cache contentCache = CacheBuilder.newBuilder() + .expireAfterWrite(1, TimeUnit.MINUTES). + build(); + private final BlackboardArtifact artifact; private final Content associated; private List> customProperties; - private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName()); /* * Artifact types which should have the full unique path of the associated * content as a property. @@ -108,6 +116,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { if (evt.getNewValue() == null) { // case was closed. Remove listeners so that we don't get called with a stale case handle removeListeners(); + contentCache.invalidateAll(); } } } @@ -142,7 +151,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode { super(Children.LEAF, createLookup(artifact)); this.artifact = artifact; - //this.associated = getAssociatedContent(artifact); this.associated = this.getLookup().lookup(Content.class); this.setName(Long.toString(artifact.getArtifactID())); this.setDisplayName(); @@ -522,26 +530,20 @@ public class BlackboardArtifactNode extends DisplayableItemNode { * @return */ private static Lookup createLookup(BlackboardArtifact artifact) { - List forLookup = new ArrayList<>(); - forLookup.add(artifact); - // Add the content the artifact is associated with - Content content = getAssociatedContent(artifact); - if (content != null) { - forLookup.add(content); - } - return Lookups.fixed(forLookup.toArray(new Object[forLookup.size()])); - } - - private static Content getAssociatedContent(BlackboardArtifact artifact) { try { - return artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Getting file failed", ex); //NON-NLS + Content content = contentCache.get(artifact.getObjectID(), () -> artifact.getSleuthkitCase().getContentById(artifact.getObjectID())); + if (content == null) { + return Lookups.fixed(artifact); + } else { + return Lookups.fixed(artifact, content); + } + } catch (ExecutionException ex) { + //JMTODO: Clean this up. Either swallow it with appropriate logging/notification, or propogate it, not both. + LOGGER.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS + throw new IllegalArgumentException("Could not get associated content from database", ex); } - throw new IllegalArgumentException( - NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.getAssocCont.exception.msg")); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index d582413648..6ab68ce162 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -42,7 +42,6 @@ BlackboardArtifactNode.createSheet.filePath.name=File Path BlackboardArtifactNode.createSheet.filePath.displayName=File Path BlackboardArtifactNode.createSheet.dataSrc.name=Data Source BlackboardArtifactNode.createSheet.dataSrc.displayName=Data Source -BlackboardArtifactNode.getAssocCont.exception.msg=Could not get file from database BlackboardArtifactTagNode.createSheet.srcFile.text=Source File BlackboardArtifactTagNode.createSheet.unavail.text=Unavailable BlackboardArtifactTagNode.createSheet.srcFilePath.text=Source File Path diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties index 56c4dd7bd5..533ead21ce 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle_ja.properties @@ -32,7 +32,6 @@ BlackboardArtifactNode.createSheet.filePath.name=\u30d5\u30a1\u30a4\u30eb\u30d1\ BlackboardArtifactNode.createSheet.filePath.displayName=\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 BlackboardArtifactNode.createSheet.dataSrc.name=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 BlackboardArtifactNode.createSheet.dataSrc.displayName=\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9 -BlackboardArtifactNode.getAssocCont.exception.msg=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304b\u3089\u30d5\u30a1\u30a4\u30eb\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f BlackboardArtifactTagNode.createSheet.srcFile.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb BlackboardArtifactTagNode.createSheet.unavail.text=\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 BlackboardArtifactTagNode.createSheet.srcFilePath.text=\u30bd\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 From c3a074e582533b4d554b4133814036ac1f713b7b Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 17 Jul 2017 17:19:10 -0400 Subject: [PATCH 15/31] Introduced specialized PostgreSQL query for file types by extension queries. --- .../datamodel/FileTypesByExtension.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index a447b9bad9..571a3876a9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.logging.Level; +import org.apache.commons.lang.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; @@ -330,24 +331,39 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { } } - private static String createQuery(FileTypesByExtension.SearchFilterInterface filter) { - StringBuilder query = new StringBuilder(); - query.append("(dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()).append(")"); //NON-NLS - if (UserPreferences.hideKnownFilesInViewsTree()) { - query.append(" AND (known IS NULL OR known != ").append(TskData.FileKnown.KNOWN.getFileKnownValue()).append(")"); //NON-NLS + private String createQuery(FileTypesByExtension.SearchFilterInterface filter) { + if (filter.getFilter().isEmpty()) { + return ""; } - query.append(" AND (NULL"); //NON-NLS - for (String s : filter.getFilter()) { - query.append(" OR LOWER(name) LIKE LOWER('%").append(s).append("')"); //NON-NLS + + String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" + + (UserPreferences.hideKnownFilesInViewsTree() ? " AND (known IS NULL OR known != " + + TskData.FileKnown.KNOWN.getFileKnownValue() + ")" : " ") + + " AND (NULL "; //NON-NLS + + if (skCase.getDatabaseType().equals(TskData.DbType.POSTGRESQL)) { + // For PostgreSQL we get a more efficient query by using builtin + // regular expression support and or'ing all extensions. We also + // escape the dot at the beginning of the extension. + // We will end up with a query that looks something like this: + // OR LOWER(name) ~ '(\.zip|\.rar|\.7zip|\.cab|\.jar|\.cpio|\.ar|\.gz|\.tgz|\.bz2)$') + query += "OR LOWER(name) ~ '(\\"; + query += StringUtils.join(filter.getFilter(), "|\\"); + query += ")$'"; + } else { + for (String s : filter.getFilter()) { + query += "OR LOWER(name) LIKE '%" + s.toLowerCase() + "'"; // NON-NLS + } } - query.append(')'); - return query.toString(); + + query += ')'; + return query; } /** * Child node factory for a specific file type - does the database query. */ - private static class FileExtensionNodeChildren extends ChildFactory.Detachable implements Observer { + private class FileExtensionNodeChildren extends ChildFactory.Detachable implements Observer { private final SleuthkitCase skCase; private final FileTypesByExtension.SearchFilterInterface filter; From 887616a9e2f071b35ebc975d21e5461ae9b604f2 Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 18 Jul 2017 10:57:11 -0400 Subject: [PATCH 16/31] Addressed review comments. --- .../autopsy/datamodel/FileTypesByExtension.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 8f6f292110..46bdf674f7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Observable; import java.util.Observer; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -343,7 +344,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { private String createQuery(FileTypesByExtension.SearchFilterInterface filter) { if (filter.getFilter().isEmpty()) { - return ""; + // We should never be given a search filter without extensions + // but if we are it is clearly a programming error so we throw + // an IllegalArgumentException. + throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS } String query = "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")" @@ -358,7 +362,8 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { // We will end up with a query that looks something like this: // OR LOWER(name) ~ '(\.zip|\.rar|\.7zip|\.cab|\.jar|\.cpio|\.ar|\.gz|\.tgz|\.bz2)$') query += "OR LOWER(name) ~ '(\\"; - query += StringUtils.join(filter.getFilter(), "|\\"); + query += StringUtils.join(filter.getFilter().stream() + .map(String::toLowerCase).collect(Collectors.toList()), "|\\"); query += ")$'"; } else { for (String s : filter.getFilter()) { From 583d848f0837eb630348961a8bdf3e95746e2e8b Mon Sep 17 00:00:00 2001 From: esaunders Date: Tue, 18 Jul 2017 13:39:38 -0400 Subject: [PATCH 17/31] Base file node icons on extension only. --- Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index eb4125ad3a..5190d59a87 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -30,7 +30,6 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; -import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -62,8 +61,7 @@ public class FileNode extends AbstractFsContentNode { } else { ext = "." + ext; } - if (ImageUtils.isImageThumbnailSupported(file) - || FileTypeExtensions.getImageExtensions().contains(ext)) { + if (FileTypeExtensions.getImageExtensions().contains(ext)) { return "org/sleuthkit/autopsy/images/image-file.png"; //NON-NLS } if (FileTypeExtensions.getVideoExtensions().contains(ext)) { From f730a9012a69e4781823049576404bfdeeda68d6 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 19 Jul 2017 11:29:58 -0400 Subject: [PATCH 18/31] Support slack files in File Size area of tree. --- Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index b31d2e4fd4..19fd4659e8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -45,6 +45,7 @@ import org.sleuthkit.datamodel.File; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; @@ -483,6 +484,11 @@ public class FileSize implements AutopsyVisitableItem { return new FileNode(f, false); } + @Override + public FileNode visit(SlackFile f) { + return new FileNode(f, false); + } + @Override protected AbstractNode defaultVisit(Content di) { throw new UnsupportedOperationException( From 2d2ea329f23b4972d78e58625b09ab4ea097823a Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 20 Jul 2017 16:29:12 +0200 Subject: [PATCH 19/31] don't make the nodes at the same time as the keys, use addAll rather than adding each key to list. --- .../autopsy/datamodel/KeywordHits.java | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 9214652223..477ca2fa7b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -33,6 +33,7 @@ import java.util.Observable; import java.util.Observer; import java.util.Set; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -95,6 +96,10 @@ public class KeywordHits implements AutopsyVisitableItem { + " OR attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()//NON-NLS + ")"; //NON-NLS + static private boolean isOnlyDefaultInstance(List instances) { + return (instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME)); + } + public KeywordHits(SleuthkitCase skCase) { this.skCase = skCase; keywordResults = new KeywordResults(); @@ -265,7 +270,6 @@ public class KeywordHits implements AutopsyVisitableItem { addRegExpToList(listMap, reg, word, id); } } else {//single term - if ("1".equals(kwType) || reg == null) { //literal, substring or exact /* * Substring, treated same as exact match. "1" is @@ -626,9 +630,8 @@ public class KeywordHits implements AutopsyVisitableItem { @Override public boolean isLeafTypeNode() { - List instances = keywordResults.getKeywordInstances(setName, keyword); // is this an exact/substring match (i.e. did we use the DEFAULT name)? - return instances.size() == 1 && instances.get(0).equals(DEFAULT_INSTANCE_NAME); + return isOnlyDefaultInstance(keywordResults.getKeywordInstances(setName, keyword)); } @Override @@ -661,7 +664,6 @@ public class KeywordHits implements AutopsyVisitableItem { return s; } - } /** @@ -720,26 +722,21 @@ public class KeywordHits implements AutopsyVisitableItem { // The keys are different depending on what we are displaying. // regexp get another layer to show instances. // Exact/substring matches don't. - if ((instances.size() == 1) && (instances.get(0).equals(DEFAULT_INSTANCE_NAME))) { - for (Long id : keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME)) { - RegExpInstanceKey key = new RegExpInstanceKey(id); - nodesMap.computeIfAbsent(key, k -> createNode(k)); - list.add(key); - } + if (isOnlyDefaultInstance(instances)) { + list.addAll(keywordResults.getArtifactIds(setName, keyword, DEFAULT_INSTANCE_NAME).stream() + .map(RegExpInstanceKey::new) + .collect(Collectors.toList())); } else { - for (String instance : instances) { - RegExpInstanceKey key = new RegExpInstanceKey(instance); - nodesMap.computeIfAbsent(key, k -> createNode(k)); - list.add(key); - } - + list.addAll(instances.stream() + .map(RegExpInstanceKey::new) + .collect(Collectors.toList())); } return true; } @Override protected Node createNodeForKey(RegExpInstanceKey key) { - return nodesMap.get(key); + return nodesMap.computeIfAbsent(key, this::createNode); } private DisplayableItemNode createNode(RegExpInstanceKey key) { @@ -895,16 +892,13 @@ public class KeywordHits implements AutopsyVisitableItem { @Override protected boolean createKeys(List list) { - for (Long id : keywordResults.getArtifactIds(setName, keyword, instance)) { - nodesMap.computeIfAbsent(id, i -> createBlackboardArtifactNode(i)); - list.add(id); - } + list.addAll(keywordResults.getArtifactIds(setName, keyword, instance)); return true; } @Override protected Node createNodeForKey(Long artifactId) { - return nodesMap.get(artifactId); + return nodesMap.computeIfAbsent(artifactId, KeywordHits.this::createBlackboardArtifactNode); } } } From 2216b78a7d2e6f5f66196dbc03d06887a9abad0c Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 20 Jul 2017 17:37:53 +0200 Subject: [PATCH 20/31] remove unused maps, inline method only used in one place --- .../org/sleuthkit/autopsy/datamodel/KeywordHits.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index 477ca2fa7b..343074ddc9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -24,7 +24,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -708,7 +707,6 @@ public class KeywordHits implements AutopsyVisitableItem { private final String keyword; private final String setName; - private final Map nodesMap = new HashMap<>(); private RegExpInstancesFactory(String setName, String keyword) { super(); @@ -736,10 +734,6 @@ public class KeywordHits implements AutopsyVisitableItem { @Override protected Node createNodeForKey(RegExpInstanceKey key) { - return nodesMap.computeIfAbsent(key, this::createNode); - } - - private DisplayableItemNode createNode(RegExpInstanceKey key) { if (key.isRegExp()) { return new RegExpInstanceNode(setName, keyword, key.getRegExpKey()); } else { @@ -747,6 +741,7 @@ public class KeywordHits implements AutopsyVisitableItem { return createBlackboardArtifactNode(key.getIdKey()); } } + } /** @@ -881,7 +876,6 @@ public class KeywordHits implements AutopsyVisitableItem { private final String keyword; private final String setName; private final String instance; - private final Map nodesMap = new HashMap<>(); private HitsFactory(String setName, String keyword, String instance) { super(); @@ -898,7 +892,7 @@ public class KeywordHits implements AutopsyVisitableItem { @Override protected Node createNodeForKey(Long artifactId) { - return nodesMap.computeIfAbsent(artifactId, KeywordHits.this::createBlackboardArtifactNode); + return createBlackboardArtifactNode(artifactId); } } } From dde7d77f0da4904b762be218d751a9643ac3f0a3 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 20 Jul 2017 16:12:33 -0400 Subject: [PATCH 21/31] Add support for new TSK_FS_META_TYPE_VIRT_DIR --- .../autopsy/directorytree/ExtractUnallocAction.java | 4 +++- .../org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java | 1 + .../autopsy/modules/interestingitems/FilesSet.java | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java index 9f566760e4..07aa0855f8 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExtractUnallocAction.java @@ -417,7 +417,9 @@ final class ExtractUnallocAction extends AbstractAction { try { List lflst = new ArrayList<>(); for (Content layout : vd.getChildren()) { - lflst.add((LayoutFile) layout); + if(layout instanceof LayoutFile){ + lflst.add((LayoutFile) layout); + } } return lflst; } catch (TskCoreException tce) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java index 707777525c..df9eeacbff 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/GetFilesCountVisitor.java @@ -51,6 +51,7 @@ final class GetFilesCountVisitor extends ContentVisitor.Default { queryB.append(") )"); queryB.append(" AND ( (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG.getValue()); //NON-NLS queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR.getValue()); //NON-NLS + queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR.getValue()); //NON-NLS queryB.append(") OR (meta_type = ").append(TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT.getValue()); //NON-NLS queryB.append(" AND (name != '.') AND (name != '..')"); //NON-NLS queryB.append(") )"); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java index 43bb5a4a79..38d7285fc1 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSet.java @@ -537,10 +537,12 @@ public final class FilesSet implements Serializable { case FILES: return file.isFile(); case DIRECTORIES: - return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR; + return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR + || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR; case FILES_AND_DIRECTORIES: return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG - || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR; + || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR + || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR; case ALL: return true; //Effectively ignores the metatype condition when All is selected. default: From 0826d405abc32991fb28edafe4d5f5900f3b3119 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 20 Jul 2017 17:40:16 -0400 Subject: [PATCH 22/31] 2672: Nightly will check more failed keywords and also check antlog.txt. --- test/script/regression.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/script/regression.py b/test/script/regression.py index 40cfe38a10..538a307d94 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -1386,11 +1386,18 @@ class Logs(object): try: for line in log: line = line.replace(rep_path, "test_data") - if line.startswith("SEVERE"): + line_ignoreCase = line.lower() + if line.startswith("SEVERE") or line.startswith("BUILD FAILED") or "fatal error" in line_ignoreCase or "crashed" in line_ignoreCase: common_log.write(file +": " + line) except UnicodeDecodeError as e: pass log.close() + # some build errors are stored in antlog.txt not the autopsy logs + antlog = 'antlog.txt' + for ant_line in codecs.open(os.path.join(logs_path, os.pardir, antlog)): + ant_ignoreCase = ant_line.lower() + if ant_line.startswith("SEVERE") or ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: + common_log.write(antlog +": " + ant_line) common_log.write("\n") common_log.close() srtcmdlst = ["sort", test_data.common_log_path, "-o", test_data.common_log_path] From 7aa7d05b188961c2d258b7bd1d7a752151f61fe0 Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 24 Jul 2017 12:42:10 -0400 Subject: [PATCH 23/31] Use alternative to Content for File Types key to avoid database queries to get child count. --- .../autopsy/datamodel/FileTypes.java | 186 +++++++++++++++++- .../datamodel/FileTypesByExtension.java | 12 +- .../datamodel/FileTypesByMimeType.java | 12 +- 3 files changed, 200 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index 0878a5a451..119889fe3b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -18,9 +18,12 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Observable; import java.util.Observer; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.SwingWorker; @@ -31,6 +34,8 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -40,6 +45,7 @@ import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LocalFile; import org.sleuthkit.datamodel.SlackFile; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.SleuthkitItemVisitor; import org.sleuthkit.datamodel.TskCoreException; /** @@ -215,7 +221,7 @@ public final class FileTypes implements AutopsyVisitableItem { * Updates the display name of the mediaSubTypeNode to include the count * of files which it represents. */ - @NbBundle.Messages("FileTypes.bgCounting.placeholder=(counting...)") + @NbBundle.Messages("FileTypes.bgCounting.placeholder= (counting...)") void updateDisplayName() { if (typesRoot.shouldShowCounts()) { //only show "(counting...)" the first time, otherwise it is distracting. @@ -243,4 +249,182 @@ public final class FileTypes implements AutopsyVisitableItem { } } } + + /** + * Class that is used as a key by NetBeans for creating result nodes. This + * is a wrapper around a Content object and is being put in place as an + * optimization to avoid the Content.hashCode() implementation which issues + * a database query to get the number of children when determining whether 2 + * Content objects represent the same thing. TODO: This is a temporary + * solution that can hopefully be removed once we address the issue of + * determining how many children a Content has. + */ + static class FileTypesKey implements Content { + + private final Content content; + + public FileTypesKey(Content content) { + this.content = content; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final FileTypesKey other = (FileTypesKey) obj; + + return this.content.getId() == other.content.getId(); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 101 * hash + (int)(this.content.getId() ^ (this.content.getId() >>> 32)); + return hash; + } + + @Override + public T accept(SleuthkitItemVisitor v) { + return content.accept(v); + } + + @Override + public int read(byte[] buf, long offset, long len) throws TskCoreException { + return content.read(buf, offset, len); + } + + @Override + public void close() { + content.close(); + } + + @Override + public long getSize() { + return content.getSize(); + } + + @Override + public T accept(ContentVisitor v) { + return content.accept(v); + } + + @Override + public String getName() { + return content.getName(); + } + + @Override + public String getUniquePath() throws TskCoreException { + return content.getUniquePath(); + } + + @Override + public long getId() { + return content.getId(); + } + + @Override + public Content getDataSource() throws TskCoreException { + return content.getDataSource(); + } + + @Override + public List getChildren() throws TskCoreException { + return content.getChildren(); + } + + @Override + public boolean hasChildren() throws TskCoreException { + return content.hasChildren(); + } + + @Override + public int getChildrenCount() throws TskCoreException { + return content.getChildrenCount(); + } + + @Override + public Content getParent() throws TskCoreException { + return content.getParent(); + } + + @Override + public List getChildrenIds() throws TskCoreException { + return content.getChildrenIds(); + } + + @Override + public BlackboardArtifact newArtifact(int artifactTypeID) throws TskCoreException { + return content.newArtifact(artifactTypeID); + } + + @Override + public BlackboardArtifact newArtifact(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException { + return content.newArtifact(type); + } + + @Override + public ArrayList getArtifacts(String artifactTypeName) throws TskCoreException { + return content.getArtifacts(artifactTypeName); + } + + @Override + public BlackboardArtifact getGenInfoArtifact() throws TskCoreException { + return content.getGenInfoArtifact(); + } + + @Override + public BlackboardArtifact getGenInfoArtifact(boolean create) throws TskCoreException { + return content.getGenInfoArtifact(create); + } + + @Override + public ArrayList getGenInfoAttributes(BlackboardAttribute.ATTRIBUTE_TYPE attr_type) throws TskCoreException { + return content.getGenInfoAttributes(attr_type); + } + + @Override + public ArrayList getArtifacts(int artifactTypeID) throws TskCoreException { + return content.getArtifacts(artifactTypeID); + } + + @Override + public ArrayList getArtifacts(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException { + return content.getArtifacts(type); + } + + @Override + public ArrayList getAllArtifacts() throws TskCoreException { + return content.getAllArtifacts(); + } + + @Override + public Set getHashSetNames() throws TskCoreException { + return content.getHashSetNames(); + } + + @Override + public long getArtifactsCount(String artifactTypeName) throws TskCoreException { + return content.getArtifactsCount(artifactTypeName); + } + + @Override + public long getArtifactsCount(int artifactTypeID) throws TskCoreException { + return content.getArtifactsCount(artifactTypeID); + } + + @Override + public long getArtifactsCount(BlackboardArtifact.ARTIFACT_TYPE type) throws TskCoreException { + return content.getArtifactsCount(type); + } + + @Override + public long getAllArtifactsCount() throws TskCoreException { + return content.getAllArtifactsCount(); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 46bdf674f7..5f8a29e9a6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.List; import java.util.Observable; import java.util.Observer; +import java.util.function.Function; import java.util.logging.Level; import java.util.stream.Collectors; import org.apache.commons.lang.StringUtils; @@ -36,7 +37,9 @@ import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -378,7 +381,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { /** * Child node factory for a specific file type - does the database query. */ - private class FileExtensionNodeChildren extends ChildFactory.Detachable implements Observer { + private class FileExtensionNodeChildren extends ChildFactory.Detachable implements Observer { private final SleuthkitCase skCase; private final FileTypesByExtension.SearchFilterInterface filter; @@ -418,9 +421,10 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { - list.addAll(skCase.findAllFilesWhere(createQuery(filter))); + list.addAll(skCase.findAllFilesWhere(createQuery(filter)) + .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS } @@ -428,7 +432,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { } @Override - protected Node createNodeForKey(Content key) { + protected Node createNodeForKey(FileTypesKey key) { return key.accept(new FileTypes.FileNodeCreationVisitor()); } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 7553b3d657..4bd91c6e2c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Observable; import java.util.Observer; import java.util.logging.Level; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; @@ -41,6 +42,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import static org.sleuthkit.autopsy.core.UserPreferences.hideKnownFilesInViewsTree; import static org.sleuthkit.autopsy.core.UserPreferences.hideSlackFilesInViewsTree; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.FileTypes.FileTypesKey; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; @@ -428,7 +430,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi * files that match MimeType which is represented by this position in the * tree. */ - private class MediaSubTypeNodeChildren extends ChildFactory.Detachable implements Observer { + private class MediaSubTypeNodeChildren extends ChildFactory.Detachable implements Observer { private final String mimeType; @@ -439,10 +441,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi } @Override - protected boolean createKeys(List list) { + protected boolean createKeys(List list) { try { - list.addAll(skCase.findAllFilesWhere( - createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")); //NON-NLS + list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'") + .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS } @@ -455,7 +457,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi } @Override - protected Node createNodeForKey(Content key) { + protected Node createNodeForKey(FileTypesKey key) { return key.accept(new FileTypes.FileNodeCreationVisitor()); } } From 1ea1d24d699d700d75ab5d26d611dfa4f5255cdc Mon Sep 17 00:00:00 2001 From: esaunders Date: Mon, 24 Jul 2017 16:39:14 -0400 Subject: [PATCH 24/31] Pass Content object through to ResultsTableArtifact to eliminate unnecessary database queries and File object creation. --- .../corecomponents/DataContentViewerArtifact.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java index 2c9fa00b0d..f80866ac9b 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/DataContentViewerArtifact.java @@ -491,18 +491,19 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private String[][] rowData = null; private final String artifactDisplayName; + private final Content content; - ResultsTableArtifact(BlackboardArtifact artifact) { + ResultsTableArtifact(BlackboardArtifact artifact, Content content) { artifactDisplayName = artifact.getDisplayName(); + this.content = content; addRows(artifact); - } ResultsTableArtifact(String errorMsg) { artifactDisplayName = errorMsg; rowData = new String[1][3]; rowData[0] = new String[]{"", errorMsg, ""}; - + content = null; } private String[][] getRows() { @@ -512,7 +513,6 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat private void addRows(BlackboardArtifact artifact) { List rowsToAdd = new ArrayList<>(); try { - Content content = artifact.getSleuthkitCase().getContentById(artifact.getObjectID()); /* * Add rows for each attribute. */ @@ -716,7 +716,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat // Build the new artifact contents cache. ArrayList artifactContents = new ArrayList<>(); for (BlackboardArtifact artifact : artifacts) { - artifactContents.add(new ResultsTableArtifact(artifact)); + artifactContents.add(new ResultsTableArtifact(artifact, content)); } // If the node has an underlying blackboard artifact, show it. If not, From dc34558edec7f4522a7a4fc2062cd7d612429c59 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Tue, 25 Jul 2017 09:55:59 +0200 Subject: [PATCH 25/31] resolve TODO --- .../datamodel/BlackboardArtifactNode.java | 70 +++++++++---------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index aaba845702..7317b5781f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -283,7 +283,7 @@ public class BlackboardArtifactNode extends DisplayableItemNode { // Do nothing since the display name will be set to the file name. } } - + for (Map.Entry entry : map.entrySet()) { ss.put(new NodeProperty<>(entry.getKey(), entry.getKey(), @@ -477,46 +477,46 @@ public class BlackboardArtifactNode extends DisplayableItemNode { LOGGER.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS } } - + /** - * Fill map with EmailMsg properties, not all attributes are filled - * - * @param map map with preserved ordering, where property names/values - * are put - * @param attribute attribute to check/fill as property - */ + * Fill map with EmailMsg properties, not all attributes are filled + * + * @param map map with preserved ordering, where property names/values + * are put + * @param attribute attribute to check/fill as property + */ private void addEmailMsgProperty(Map map, BlackboardAttribute attribute ) { - - final int attributeTypeID = attribute.getAttributeType().getTypeID(); - - // Skip certain Email msg attributes - if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID() - || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID() + + final int attributeTypeID = attribute.getAttributeType().getTypeID(); + + // Skip certain Email msg attributes + if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID() + || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID() + || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID() + || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID() + || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID() || attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID() ) { - - // do nothing + + // do nothing } else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) { - String value = attribute.getDisplayString(); - if (value.length() > 160) { - value = value.substring(0, 160) + "..."; - } - map.put(attribute.getAttributeType().getDisplayName(), value); + String value = attribute.getDisplayString(); + if (value.length() > 160) { + value = value.substring(0, 160) + "..."; + } + map.put(attribute.getAttributeType().getDisplayName(), value); } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) { - map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated)); + map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated)); } else { - map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString()); + map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString()); + } + } - - } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -525,24 +525,24 @@ public class BlackboardArtifactNode extends DisplayableItemNode { /** * Create a Lookup based on what is in the passed in artifact. * - * @param artifact + * @param artifact The artifact to make a look up for. * - * @return + * @return A lookup with the artifact and possibly any associated content in + * it. */ private static Lookup createLookup(BlackboardArtifact artifact) { // Add the content the artifact is associated with - + final long objectID = artifact.getObjectID(); try { - Content content = contentCache.get(artifact.getObjectID(), () -> artifact.getSleuthkitCase().getContentById(artifact.getObjectID())); + Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID)); if (content == null) { return Lookups.fixed(artifact); } else { return Lookups.fixed(artifact, content); } } catch (ExecutionException ex) { - //JMTODO: Clean this up. Either swallow it with appropriate logging/notification, or propogate it, not both. LOGGER.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS - throw new IllegalArgumentException("Could not get associated content from database", ex); + return Lookups.fixed(artifact); } } From 79086fb50552b86022a98262cc3d72df594729f6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Tue, 25 Jul 2017 10:54:04 -0400 Subject: [PATCH 26/31] 2672: Check 'SEVERE at autopsy logs and build failure at antlog --- test/script/regression.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/script/regression.py b/test/script/regression.py index 538a307d94..cf5cfa7998 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -1386,8 +1386,7 @@ class Logs(object): try: for line in log: line = line.replace(rep_path, "test_data") - line_ignoreCase = line.lower() - if line.startswith("SEVERE") or line.startswith("BUILD FAILED") or "fatal error" in line_ignoreCase or "crashed" in line_ignoreCase: + if line.startswith("SEVERE"): common_log.write(file +": " + line) except UnicodeDecodeError as e: pass @@ -1396,7 +1395,7 @@ class Logs(object): antlog = 'antlog.txt' for ant_line in codecs.open(os.path.join(logs_path, os.pardir, antlog)): ant_ignoreCase = ant_line.lower() - if ant_line.startswith("SEVERE") or ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: + if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: common_log.write(antlog +": " + ant_line) common_log.write("\n") common_log.close() From dc9e5676e1fc915858e61eb6238cb434fe394cc6 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Wed, 26 Jul 2017 11:22:57 +0200 Subject: [PATCH 27/31] raise the threshold to 1M files, some very minor cleanup --- .../autopsy/datamodel/FileTypes.java | 46 ++++++++++++------- .../datamodel/FileTypesByExtension.java | 2 +- .../datamodel/FileTypesByMimeType.java | 2 +- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index 0878a5a451..8296da0191 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -47,10 +47,24 @@ import org.sleuthkit.datamodel.TskCoreException; */ public final class FileTypes implements AutopsyVisitableItem { - private final static Logger logger = Logger.getLogger(FileTypes.class.getName()); + private static final Logger logger = Logger.getLogger(FileTypes.class.getName()); + @NbBundle.Messages("FileTypes.name.text=File Types") + private static final String NAME = Bundle.FileTypes_name_text(); + /** + * Threshold used to limit db queries for child node counts. When the + * tsk_files table has more than this number of rows, we don't query for the + * child node counts, and since we don't have an accurate number we don't + * show the counts. + */ + private static final int NODE_COUNT_FILE_TABLE_THRESHOLD = 1_000_000; + /** + * Used to keep track of whether we have hit + * NODE_COUNT_FILE_TABLE_THRESHOLD. If we have, we stop querying for the + * number of rows in tsk_files, since it is already too large. + */ + private boolean showCounts = true; private final SleuthkitCase skCase; - private boolean showCounts = true; FileTypes(SleuthkitCase skCase) { this.skCase = skCase; @@ -66,15 +80,16 @@ public final class FileTypes implements AutopsyVisitableItem { } /** - * Should the nodes show counts? - * - * - * @return True, unless the DB has more than 200k rows. + * Check the db to determine if the nodes should show child counts. */ - boolean shouldShowCounts() { + void updateShowCounts() { + /* + * once we have passed the threshold, we don't need to keep checking the + * number of rows in tsk_files + */ if (showCounts) { try { - if (skCase.countFilesWhere("1=1") > 200000) { //NON-NLS + if (skCase.countFilesWhere("1=1") > NODE_COUNT_FILE_TABLE_THRESHOLD) { //NON-NLS showCounts = false; } } catch (TskCoreException tskCoreException) { @@ -82,10 +97,7 @@ public final class FileTypes implements AutopsyVisitableItem { logger.log(Level.SEVERE, "Error counting files.", tskCoreException); //NON-NLS } } - return showCounts; } - @NbBundle.Messages("FileTypes.name.text=File Types") - static private final String NAME = Bundle.FileTypes_name_text(); /** * Node which will contain By Mime Type and By Extension nodes. @@ -97,8 +109,8 @@ public final class FileTypes implements AutopsyVisitableItem { new FileTypesByExtension(FileTypes.this), new FileTypesByMimeType(FileTypes.this))), Lookups.singleton(NAME)); - setName(NAME); - setDisplayName(NAME); + this.setName(NAME); + this.setDisplayName(NAME); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS } @@ -215,9 +227,9 @@ public final class FileTypes implements AutopsyVisitableItem { * Updates the display name of the mediaSubTypeNode to include the count * of files which it represents. */ - @NbBundle.Messages("FileTypes.bgCounting.placeholder=(counting...)") + @NbBundle.Messages("FileTypes.bgCounting.placeholder= (counting...)") void updateDisplayName() { - if (typesRoot.shouldShowCounts()) { + if (typesRoot.showCounts) { //only show "(counting...)" the first time, otherwise it is distracting. setDisplayName(getDisplayNameBase() + ((childCount < 0) ? Bundle.FileTypes_bgCounting_placeholder() : ("(" + childCount + ")"))); //NON-NLS @@ -239,7 +251,7 @@ public final class FileTypes implements AutopsyVisitableItem { } }.execute(); } else { - setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" : ("(" + childCount + "+)"))); //NON-NLS + setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" : (" (" + childCount + "+)"))); //NON-NLS } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java index 46bdf674f7..0cf9045300 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java @@ -89,7 +89,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem { */ try { Case.getCurrentCase(); - typesRoot.shouldShowCounts(); + typesRoot.updateShowCounts(); update(); } catch (IllegalStateException notUsed) { /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index 7553b3d657..0ecd3f0b51 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -158,7 +158,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi */ try { Case.getCurrentCase(); - typesRoot.shouldShowCounts(); + typesRoot.updateShowCounts(); populateHashMap(); } catch (IllegalStateException notUsed) { /** From abcc6b47bc79496e1bb9d4c808ce65e666967e10 Mon Sep 17 00:00:00 2001 From: esaunders Date: Wed, 26 Jul 2017 11:03:58 -0400 Subject: [PATCH 28/31] Added JIRA reference to comment. --- Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index 119889fe3b..a28cea3103 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -257,7 +257,7 @@ public final class FileTypes implements AutopsyVisitableItem { * a database query to get the number of children when determining whether 2 * Content objects represent the same thing. TODO: This is a temporary * solution that can hopefully be removed once we address the issue of - * determining how many children a Content has. + * determining how many children a Content has (JIRA-2823). */ static class FileTypesKey implements Content { From 2995585ea31a90d93f25fbf00fb96d9eef826304 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 26 Jul 2017 13:35:40 -0400 Subject: [PATCH 29/31] 2672: Check if there's any failure message in antolog.txt right after a test finish. --- test/script/regression.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/test/script/regression.py b/test/script/regression.py index cf5cfa7998..8bd7a64c5a 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -220,6 +220,14 @@ class TestRunner(object): if not file_exists(test_data.get_db_path(DBType.OUTPUT)): Errors.print_error("Autopsy did not run properly; No .db file was created") sys.exit(1) + # exit if any build errors are found in antlog.txt + antlog = 'antlog.txt' + logs_path = test_data.logs_dir + for ant_line in codecs.open(os.path.join(logs_path, os.pardir, antlog)): + ant_ignoreCase = ant_line.lower() + if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: + Errors.print_error("Autopsy test failed. Please check the build log antlog.txt for details.") + sys.exit(1) try: # Dump the database before we diff or use it for rebuild TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT), @@ -1391,12 +1399,6 @@ class Logs(object): except UnicodeDecodeError as e: pass log.close() - # some build errors are stored in antlog.txt not the autopsy logs - antlog = 'antlog.txt' - for ant_line in codecs.open(os.path.join(logs_path, os.pardir, antlog)): - ant_ignoreCase = ant_line.lower() - if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: - common_log.write(antlog +": " + ant_line) common_log.write("\n") common_log.close() srtcmdlst = ["sort", test_data.common_log_path, "-o", test_data.common_log_path] From 988d119e31d66f798ebeda89d9d1e31bc5d3c2be Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 26 Jul 2017 14:48:33 -0400 Subject: [PATCH 30/31] 2672: Check the build failure before checking if the database file exists. --- test/script/regression.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/script/regression.py b/test/script/regression.py index 8bd7a64c5a..056a0e9889 100755 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -216,10 +216,6 @@ class TestRunner(object): TestRunner._run_ant(test_data) time.sleep(2) # Give everything a second to process - # exit if .db was not created - if not file_exists(test_data.get_db_path(DBType.OUTPUT)): - Errors.print_error("Autopsy did not run properly; No .db file was created") - sys.exit(1) # exit if any build errors are found in antlog.txt antlog = 'antlog.txt' logs_path = test_data.logs_dir @@ -228,6 +224,10 @@ class TestRunner(object): if ant_line.startswith("BUILD FAILED") or "fatal error" in ant_ignoreCase or "crashed" in ant_ignoreCase: Errors.print_error("Autopsy test failed. Please check the build log antlog.txt for details.") sys.exit(1) + # exit if .db was not created + if not file_exists(test_data.get_db_path(DBType.OUTPUT)): + Errors.print_error("Autopsy did not run properly; No .db file was created") + sys.exit(1) try: # Dump the database before we diff or use it for rebuild TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT), From 692a61c8f5b0e977dfef8259ebaa10a1077c44cc Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 26 Jul 2017 18:39:16 -0400 Subject: [PATCH 31/31] 2858 minimized use of isFile and isDirectory when populating Examiner case list --- .../experimental/autoingest/PathUtils.java | 69 +++++++------------ 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java index 772dcf667e..18ce9709d5 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/PathUtils.java @@ -23,17 +23,13 @@ import java.io.FilenameFilter; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CaseMetadata; -import org.sleuthkit.autopsy.casemodule.GeneralFilter; final class PathUtils { - private static final List CASE_METADATA_FILE_EXTS = Arrays.asList(new String[]{CaseMetadata.getFileExtension()}); - private static final GeneralFilter caseMetadataFileFilter = new GeneralFilter(CASE_METADATA_FILE_EXTS, "Autopsy Case File"); + private final static String CASE_METADATA_EXT = CaseMetadata.getFileExtension(); /** * Searches a given folder for the most recently modified case folder for a @@ -83,34 +79,6 @@ final class PathUtils { return caseFolderPaths; } - /** - * Determines whether or not there is a case metadata file in a given - * folder. - * - * @param folderPath Path to the folder to search. - * - * @return True or false. - */ - static boolean hasCaseMetadataFile(Path folderPath) { - /** - * TODO: If need be, this can be rewritten without the FilenameFilter so - * that it does not necessarily visit every file in the folder. - */ - File folder = folderPath.toFile(); - if (!folder.isDirectory()) { - return false; - } - - String[] caseDataFiles = folder.list((File folder1, String fileName) -> { - File file = new File(folder1, fileName); - if (file.isFile()) { - return caseMetadataFileFilter.accept(file); - } - return false; - }); - return caseDataFiles.length != 0; - } - /** * Extracts the case name from a case folder path. * @@ -141,6 +109,12 @@ final class PathUtils { return Paths.get(caseFoldersPath.toString(), folderName); } + /** + * Supress creation of instances of this class. + */ + private PathUtils() { + } + private static class CaseFolderFilter implements FilenameFilter { private final String caseName; @@ -152,28 +126,37 @@ final class PathUtils { @Override public boolean accept(File folder, String fileName) { File file = new File(folder, fileName); - if (file.isDirectory() && fileName.length() > TimeStampUtils.getTimeStampLength()) { - Path filePath = Paths.get(file.getPath()); + if (fileName.length() > TimeStampUtils.getTimeStampLength() && file.isDirectory()) { if (TimeStampUtils.endsWithTimeStamp(fileName)) { if (null != caseName) { String fileNamePrefix = fileName.substring(0, fileName.length() - TimeStampUtils.getTimeStampLength()); if (fileNamePrefix.equals(caseName)) { - return hasCaseMetadataFile(filePath); + return hasCaseMetadataFile(file); } } else { - return hasCaseMetadataFile(filePath); + return hasCaseMetadataFile(file); } } } return false; } - } + /** + * Determines whether or not there is a case metadata file in a given + * folder. + * + * @param folder The file object representing the folder to search. + * + * @return True or false. + */ + private static boolean hasCaseMetadataFile(File folder) { + for (File file : folder.listFiles()) { + if (file.getName().toLowerCase().endsWith(CASE_METADATA_EXT) && file.isFile()) { + return true; + } + } + return false; + } - /** - * Supress creation of instances of this class. - */ - private PathUtils() { } - }