Merge remote-tracking branch 'upstream/release-4.4.1' into develop

This commit is contained in:
Richard Cordovano 2017-07-12 17:59:57 -04:00
commit a13c95e1b8
3 changed files with 59 additions and 83 deletions

View File

@ -74,12 +74,12 @@ public final class FileTypes implements AutopsyVisitableItem {
boolean shouldShowCounts() { boolean shouldShowCounts() {
if (showCounts) { if (showCounts) {
try { try {
if (skCase.countFilesWhere("1=1") > 200000) { if (skCase.countFilesWhere("1=1") > 200000) { //NON-NLS
showCounts = false; showCounts = false;
} }
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
showCounts = false; showCounts = false;
logger.log(Level.SEVERE, "Error counting files.", tskCoreException); logger.log(Level.SEVERE, "Error counting files.", tskCoreException); //NON-NLS
} }
} }
return showCounts; return showCounts;
@ -96,10 +96,10 @@ public final class FileTypes implements AutopsyVisitableItem {
super(new RootContentChildren(Arrays.asList( super(new RootContentChildren(Arrays.asList(
new FileTypesByExtension(FileTypes.this), new FileTypesByExtension(FileTypes.this),
new FileTypesByMimeType(FileTypes.this))), new FileTypesByMimeType(FileTypes.this))),
Lookups.singleton(NAME)); Lookups.singleton(NAME));
setName(NAME); setName(NAME);
setDisplayName(NAME); setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
} }
@Override @Override
@ -184,18 +184,15 @@ public final class FileTypes implements AutopsyVisitableItem {
static abstract class BGCountUpdatingNode extends DisplayableItemNode implements Observer { static abstract class BGCountUpdatingNode extends DisplayableItemNode implements Observer {
private long childCount = -1; private long childCount = -1;
private final SleuthkitCase skCase;
private FileTypes typesRoot; private FileTypes typesRoot;
BGCountUpdatingNode(FileTypes typesRoot, Children children) { BGCountUpdatingNode(FileTypes typesRoot, Children children) {
this(typesRoot, children, null); this(typesRoot, children, null);
} }
BGCountUpdatingNode(FileTypes typesRoot, Children children, Lookup lookup) { BGCountUpdatingNode(FileTypes typesRoot, Children children, Lookup lookup) {
super(children, lookup); super(children, lookup);
this.typesRoot = typesRoot; this.typesRoot = typesRoot;
this.skCase = typesRoot.getSleuthkitCase();
} }
@Override @Override
@ -205,37 +202,44 @@ public final class FileTypes implements AutopsyVisitableItem {
abstract String getDisplayNameBase(); abstract String getDisplayNameBase();
abstract String geQuery(); /**
* Calculate the number of children of this node, possibly by querying
* the DB.
*
* @return @throws TskCoreException if there was an error querying the
* DB to calculate the number of children.
*/
abstract long calculateChildCount() throws TskCoreException;
/** /**
* Updates the display name of the mediaSubTypeNode to include the count * Updates the display name of the mediaSubTypeNode to include the count
* of files which it represents. * of files which it represents.
*/ */
@NbBundle.Messages("FileTypes.bgCounting.placeholder=(counting...)")
void updateDisplayName() { void updateDisplayName() {
if (typesRoot.shouldShowCounts()) { if (typesRoot.shouldShowCounts()) {
//only show "(counting...)" the first time, otherwise it is distracting. //only show "(counting...)" the first time, otherwise it is distracting.
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "(counting...)" setDisplayName(getDisplayNameBase() + ((childCount < 0) ? Bundle.FileTypes_bgCounting_placeholder()
: ("(" + childCount + ")"))); : ("(" + childCount + ")"))); //NON-NLS
new SwingWorker<Long, Void>() { new SwingWorker<Long, Void>() {
@Override @Override
protected Long doInBackground() throws Exception { protected Long doInBackground() throws Exception {
return skCase.countFilesWhere(geQuery()); return calculateChildCount();
} }
@Override @Override
protected void done() { protected void done() {
try { try {
childCount = get(); childCount = get();
setDisplayName(getDisplayNameBase() + " (" + childCount + ")"); setDisplayName(getDisplayNameBase() + " (" + childCount + ")"); //NON-NLS
} catch (InterruptedException | ExecutionException ex) { } catch (InterruptedException | ExecutionException ex) {
setDisplayName(getDisplayNameBase()); setDisplayName(getDisplayNameBase());
logger.log(Level.WARNING, "Failed to get count of files for " + getDisplayNameBase(), ex); logger.log(Level.WARNING, "Failed to get count of files for " + getDisplayNameBase(), ex); //NON-NLS
} }
} }
}.execute(); }.execute();
} else { } else {
setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" setDisplayName(getDisplayNameBase() + ((childCount < 0) ? "" : ("(" + childCount + "+)"))); //NON-NLS
: ("(" + childCount + "+)")));
} }
} }
} }

View File

@ -325,10 +325,9 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
} }
@Override @Override
String geQuery() { long calculateChildCount() throws TskCoreException {
return createQuery(filter); return skCase.countFilesWhere(createQuery(filter));
} }
} }
private static String createQuery(FileTypesByExtension.SearchFilterInterface filter) { private static String createQuery(FileTypesByExtension.SearchFilterInterface filter) {

View File

@ -26,10 +26,10 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.logging.Level; import java.util.logging.Level;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
@ -50,7 +50,7 @@ import org.sleuthkit.datamodel.TskData;
* File Types view, shows all files with a mime type. Will initially be empty * File Types view, shows all files with a mime type. Will initially be empty
* until file type identification has been performed. Contains a Property Change * until file type identification has been performed. Contains a Property Change
* Listener which is checking for changes in IngestJobEvent Completed or * Listener which is checking for changes in IngestJobEvent Completed or
* Cancelled and IngestModuleEvent Content Changed. * Canceled and IngestModuleEvent Content Changed.
*/ */
public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem { public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
@ -59,9 +59,9 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
/** /**
* The nodes of this tree will be determined dynamically by the mimetypes * The nodes of this tree will be determined dynamically by the mimetypes
* which exist in the database. This hashmap will store them with the media * which exist in the database. This hashmap will store them with the media
* type as the key and a list of media subtypes as the value. * type as the key and a Map, from media subtype to count, as the value.
*/ */
private final HashMap<String, List<String>> existingMimeTypes = new HashMap<>(); private final HashMap<String, Map<String, Long>> existingMimeTypeCounts = new HashMap<>();
private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName()); private static final Logger LOGGER = Logger.getLogger(FileTypesByMimeType.class.getName());
private final FileTypes typesRoot; private final FileTypes typesRoot;
@ -76,54 +76,40 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
*/ */
private final PropertyChangeListener pcl; private final PropertyChangeListener pcl;
/**
* Retrieve the media types by retrieving the keyset from the hashmap.
*
* @return mediaTypes - a list of strings representing all distinct media
* types of files for this case
*/
private List<String> getMediaTypeList() {
synchronized (existingMimeTypes) {
List<String> mediaTypes = new ArrayList<>(existingMimeTypes.keySet());
Collections.sort(mediaTypes);
return mediaTypes;
}
}
/** /**
* Performs the query on the database to get all distinct MIME types of * Performs the query on the database to get all distinct MIME types of
* files in it, and populate the hashmap with those results. * files in it, and populate the hashmap with those results.
*/ */
private void populateHashMap() { private void populateHashMap() {
StringBuilder allDistinctMimeTypesQuery = new StringBuilder(); String query = "SELECT mime_type,count(*) as count from tsk_files "
allDistinctMimeTypesQuery.append("SELECT DISTINCT mime_type from tsk_files where mime_type IS NOT null"); //NON-NLS + " where mime_type IS NOT null "
allDistinctMimeTypesQuery.append(" AND dir_type = ").append(TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()); //NON-NLS + " AND dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue()
allDistinctMimeTypesQuery.append(" AND (type IN (").append(TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal()).append(","); //NON-NLS + " AND (type IN ("
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal()).append(","); + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal()).append(","); + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
if (!UserPreferences.hideSlackFilesInViewsTree()) { + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()).append(","); + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
} + ((UserPreferences.hideSlackFilesInViewsTree()) ? ""
allDistinctMimeTypesQuery.append(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()).append("))"); : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
synchronized (existingMimeTypes) { + "))" + " GROUP BY mime_type";
existingMimeTypes.clear(); synchronized (existingMimeTypeCounts) {
existingMimeTypeCounts.clear();
if (skCase == null) { if (skCase == null) {
return; return;
} }
try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(allDistinctMimeTypesQuery.toString())) { try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
ResultSet resultSet = dbQuery.getResultSet(); ResultSet resultSet = dbQuery.getResultSet();
while (resultSet.next()) { while (resultSet.next()) {
final String mime_type = resultSet.getString("mime_type"); //NON-NLS final String mime_type = resultSet.getString("mime_type"); //NON-NLS
if (!mime_type.isEmpty()) { if (!mime_type.isEmpty()) {
String mimeType[] = mime_type.split("/");
//if the mime_type contained multiple slashes then everything after the first slash will become the subtype //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
final String mimeMediaSubType = StringUtils.join(ArrayUtils.subarray(mimeType, 1, mimeType.length), "/"); final String mediaType = StringUtils.substringBefore(mime_type, "/");
if (mimeType.length > 1 && !mimeType[0].isEmpty() && !mimeMediaSubType.isEmpty()) { final String subType = StringUtils.removeStart(mime_type, mediaType + "/");
if (!existingMimeTypes.containsKey(mimeType[0])) { if (!mediaType.isEmpty() && !subType.isEmpty()) {
existingMimeTypes.put(mimeType[0], new ArrayList<>()); final long count = resultSet.getLong("count");
} existingMimeTypeCounts.computeIfAbsent(mediaType, t -> new HashMap<>())
existingMimeTypes.get(mimeType[0]).add(mimeMediaSubType); .put(subType, count);
} }
} }
} }
@ -133,11 +119,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
} }
setChanged(); setChanged();
notifyObservers(); notifyObservers();
} }
FileTypesByMimeType( FileTypes typesRoot) { FileTypesByMimeType(FileTypes typesRoot) {
this.skCase = typesRoot.getSleuthkitCase(); this.skCase = typesRoot.getSleuthkitCase();
this.typesRoot = typesRoot; this.typesRoot = typesRoot;
this.pcl = (PropertyChangeEvent evt) -> { this.pcl = (PropertyChangeEvent evt) -> {
@ -228,9 +213,10 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
} }
boolean isEmpty() { boolean isEmpty() {
return existingMimeTypes.isEmpty(); synchronized (existingMimeTypeCounts) {
return existingMimeTypeCounts.isEmpty();
}
} }
} }
/** /**
@ -246,9 +232,13 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
@Override @Override
protected boolean createKeys(List<String> mediaTypeNodes) { protected boolean createKeys(List<String> mediaTypeNodes) {
if (!existingMimeTypes.isEmpty()) { final List<String> keylist;
mediaTypeNodes.addAll(getMediaTypeList()); synchronized (existingMimeTypeCounts) {
keylist = new ArrayList<>(existingMimeTypeCounts.keySet());
} }
Collections.sort(keylist);
mediaTypeNodes.addAll(keylist);
return true; return true;
} }
@ -261,7 +251,6 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
public void update(Observable o, Object arg) { public void update(Observable o, Object arg) {
refresh(true); refresh(true);
} }
} }
/** /**
@ -310,7 +299,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
@Override @Override
protected boolean createKeys(List<String> mediaTypeNodes) { protected boolean createKeys(List<String> mediaTypeNodes) {
mediaTypeNodes.addAll(existingMimeTypes.get(mediaType)); mediaTypeNodes.addAll(existingMimeTypeCounts.get(mediaType).keySet());
return true; return true;
} }
@ -333,7 +322,7 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
private final String subType; private final String subType;
private MediaSubTypeNode(String mimeType) { private MediaSubTypeNode(String mimeType) {
super(typesRoot,Children.create(new MediaSubTypeNodeChildren(mimeType), true)); super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true));
this.mimeType = mimeType; this.mimeType = mimeType;
this.subType = StringUtils.substringAfter(mimeType, "/"); this.subType = StringUtils.substringAfter(mimeType, "/");
super.setName(mimeType); super.setName(mimeType);
@ -375,24 +364,8 @@ public final class FileTypesByMimeType extends Observable implements AutopsyVisi
} }
@Override @Override
String geQuery() { long calculateChildCount() {
return createQuery(mimeType); return existingMimeTypeCounts.get(StringUtils.substringBefore(mimeType, "/")).get(subType);
}
}
/**
* Get children count without actually loading all nodes
*
* @return count(*) - the number of items that will be shown in this items
* Directory Listing
*/
static private long calculateItems(SleuthkitCase sleuthkitCase, String mime_type) {
try {
return sleuthkitCase.countFilesWhere(createQuery(mime_type));
} catch (TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error getting file search view count", ex); //NON-NLS
return 0;
} }
} }