From 138c90f501f256629e46b3400b7e8fa981cb072a Mon Sep 17 00:00:00 2001 From: dhurd Date: Thu, 16 Aug 2012 14:03:21 -0400 Subject: [PATCH] File search by MD5 hash now runs in a SwingWorker thread. --- .../hashdatabase/HashDbSearchAction.java | 21 +--- .../hashdatabase/HashDbSearchPanel.form | 14 +-- .../hashdatabase/HashDbSearchPanel.java | 10 +- .../hashdatabase/HashDbSearchThread.java | 111 ++++++++++++++++++ .../autopsy/hashdatabase/HashDbSearcher.java | 24 ++++ 5 files changed, 147 insertions(+), 33 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchThread.java diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java index 5e97cd5e94..a739a1259a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchAction.java @@ -18,9 +18,6 @@ */ package org.sleuthkit.autopsy.hashdatabase; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; import javax.swing.JOptionPane; import org.openide.nodes.Node; import org.openide.util.HelpCtx; @@ -108,22 +105,8 @@ public class HashDbSearchAction extends CallableSystemAction implements HashSear } private void doSearch() { - // Get the map of hashes to FsContent and send it to the manager - List files = HashDbSearcher.findFilesByMd5(fsContent.getMd5Hash()); - for(int i=0; i> map = new LinkedHashMap>(); - map.put(fsContent.getMd5Hash(), files); - HashDbSearchManager man = new HashDbSearchManager(map); - man.execute(); - } else { - JOptionPane.showMessageDialog(null, "No other files with the same MD5 hash were found."); - } + HashDbSearchThread hashThread = new HashDbSearchThread(fsContent); + hashThread.execute(); } @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form index f7d0004eca..76fa27089f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.form @@ -37,16 +37,16 @@ + + + + + + + - - - - - - - diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java index 480510dd28..26e20f8a21 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchPanel.java @@ -24,15 +24,12 @@ import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; -import java.util.List; -import java.util.Map; import java.util.logging.Logger; import javax.swing.JOptionPane; import javax.swing.table.DefaultTableModel; import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; -import org.sleuthkit.datamodel.FsContent; /** * Searches for files by md5 hash, based off the hash given in this panel. @@ -328,10 +325,9 @@ public class HashDbSearchPanel extends javax.swing.JPanel implements ActionListe for(int i=0; i> map = HashDbSearcher.findFilesBymd5(hashes); - HashDbSearchManager man = new HashDbSearchManager(map); - man.execute(); + // Start a new thread and find the hashes + HashDbSearchThread hashThread = new HashDbSearchThread(hashes); + hashThread.execute(); return true; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchThread.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchThread.java new file mode 100644 index 0000000000..8e3a02a1ff --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearchThread.java @@ -0,0 +1,111 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.hashdatabase; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.util.Cancellable; +import org.sleuthkit.datamodel.FsContent; + +class HashDbSearchThread extends SwingWorker { + private Logger logger = Logger.getLogger(HashDbSearchThread.class.getName()); + private ProgressHandle progress; + Map> map; + ArrayList hashes = new ArrayList(); + FsContent fsContent; + + HashDbSearchThread(FsContent fsContent) { + this.hashes.add(fsContent.getMd5Hash()); + this.fsContent = fsContent; + } + HashDbSearchThread(ArrayList hashes) { + this.hashes = hashes; + } + + @Override + protected Object doInBackground() throws Exception { + logger.log(Level.INFO, "Starting background processing for file search by MD5 hash."); + + // Setup progress bar + final String displayName = "Searching"; + progress = ProgressHandleFactory.createHandle(displayName, new Cancellable() { + @Override + public boolean cancel() { + if (progress != null) + progress.setDisplayName(displayName + " (Cancelling...)"); + return HashDbSearchThread.this.cancel(true); + } + }); + // Start the progress bar as indeterminate + progress.start(); + progress.switchToIndeterminate(); + + // Do the querying + map = HashDbSearcher.findFilesBymd5(hashes, progress, this); + logger.log(Level.INFO, "Done background processing"); + + return null; + } + + @Override + protected void done() { + try { + super.get(); //block and get all exceptions thrown while doInBackground() + } catch (CancellationException ex) { + logger.log(Level.INFO, "File search by MD5 hash was canceled."); + } catch (InterruptedException ex) { + logger.log(Level.INFO, "File search by MD5 hash was interrupted."); + } catch (Exception ex) { + logger.log(Level.SEVERE, "Fatal error during file search by MD5 hash.", ex); + } finally { + progress.finish(); + if (!this.isCancelled()) { + logger.log(Level.INFO, "File search by MD5 hash completed without cancellation."); + // If its a right click action, we are given an FsContent which + // is the file right clicked, so we can remove that from the search + if(fsContent!=null) { + boolean quit = true; + for(List files: map.values()) { + files.remove(fsContent); + if(!files.isEmpty()) { + quit = false; + } + } + if(quit) { + JOptionPane.showMessageDialog(null, "No other files with the same MD5 hash were found."); + return; + } + } + HashDbSearchManager man = new HashDbSearchManager(map); + man.execute(); + } else { + logger.log(Level.INFO, "File search by MD5 hash was canceled."); + } + } + } + +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java index a7c6d185c5..d4c10f231a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSearcher.java @@ -22,6 +22,8 @@ import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.datamodel.FsContent; import org.sleuthkit.datamodel.SleuthkitCase; @@ -59,6 +61,28 @@ public class HashDbSearcher { } return map; } + // Same as above, but with a given ProgressHandle to accumulate and StringWorker to check if cancelled + static Map> findFilesBymd5(List md5Hash, ProgressHandle progress, SwingWorker worker) { + Map> map = new LinkedHashMap>(); + if(!worker.isCancelled()) { + progress.switchToDeterminate(md5Hash.size()); + int size = 0; + for(String md5 : md5Hash) { + if(worker.isCancelled()) { + break; + } + List files = findFilesByMd5(md5); + if(!files.isEmpty()) { + map.put(md5, files); + } + size++; + if(!worker.isCancelled()) { + progress.progress(size); + } + } + } + return map; + } /** * Given a file, returns a list of all files with the same