diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 533e299de2..5ad9a606a6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -26,7 +26,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datasourceprocessors.ImageWriterService; +import org.sleuthkit.autopsy.imagewriter.ImageWriterService; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Image; diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties index 079c93d832..4b55829ba6 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/Bundle.properties @@ -10,4 +10,7 @@ RawDSInputPanel.jBreakFileUpLabel.text=Break image up into: RawDSInputPanel.jNoBreakupRadioButton.text=Do not break up RawDSInputPanel.j2GBBreakupRadioButton.text=2GB chunks RawDSInputPanel.timeZoneLabel.text=Please select the input timezone: -ImageWriterService.serviceName=Image Writer \ No newline at end of file +ImageWriterService.serviceName=Image Writer +ImageWriterService.waitingForVHDs=Waiting for VHD(s) to complete +ImageWriterService.shouldWait=Wait for VHD(s) in progress to complete? +ImageWriterService.localDisk=Local disk image copy diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriter.java b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriter.java rename to Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java index 71e9c9f440..80f7fa8aa4 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriter.java +++ b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriter.java @@ -16,13 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourceprocessors; +package org.sleuthkit.autopsy.imagewriter; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.HashSet; -import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; @@ -65,10 +63,6 @@ class ImageWriter implements PropertyChangeListener{ private ScheduledThreadPoolExecutor periodicTasksExecutor = null; private final boolean doUI; - private static final ImageWriterService service = new ImageWriterService(); - - - /** * Create the Image Writer object. * After creation, startListeners() should be called. @@ -133,8 +127,6 @@ class ImageWriter implements PropertyChangeListener{ // the same image if more ingest modules are run later if(isStarted){ return; - } else { - isStarted = true; } Image image; @@ -143,8 +135,6 @@ class ImageWriter implements PropertyChangeListener{ imageHandle = image.getImageHandle(); } catch (TskCoreException ex){ logger.log(Level.SEVERE, "Error loading image", ex); - - // Stay subscribed to the events for now. Case close will clean everything up. imageHandle = null; return; } @@ -170,6 +160,9 @@ class ImageWriter implements PropertyChangeListener{ logger.log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS } }); + + // Setting this means that finishTask and all the UI updaters are initialized (if running UI) + isStarted = true; } // Wait for finishImageWriter to complete @@ -181,7 +174,6 @@ class ImageWriter implements PropertyChangeListener{ } synchronized(currentTasksLock){ - unsubscribeFromEvents(); if(doUI){ // Some of these may be called twice if the user closes the case progressUpdateTask.cancel(true); @@ -196,13 +188,14 @@ class ImageWriter implements PropertyChangeListener{ /** * If a task hasn't been started yet, set the cancel flag so it can no longer * start. + * This is intended to be used in case close so a job doesn't suddenly start + * up during cleanup. */ void cancelIfNotStarted(){ synchronized(currentTasksLock){ - if(finishTask == null){ + if(! isStarted){ isCancelled = true; } - unsubscribeFromEvents(); } } @@ -212,7 +205,9 @@ class ImageWriter implements PropertyChangeListener{ * never started */ boolean jobIsInProgress(){ - return((finishTask != null) && (! finishTask.isDone())); + synchronized(currentTasksLock){ + return((isStarted) && (! finishTask.isDone())); + } } /** @@ -223,9 +218,8 @@ class ImageWriter implements PropertyChangeListener{ synchronized(currentTasksLock){ // All of the following is redundant but safe to call on a complete job isCancelled = true; - unsubscribeFromEvents(); - if(imageHandle != null){ + if(isStarted){ SleuthkitJNI.cancelFinishImage(imageHandle); // Stop the progress bar update task. @@ -234,8 +228,10 @@ class ImageWriter implements PropertyChangeListener{ // when that happens. // Since we've stopped the update task, we'll stop the associated progress // bar now, too. - progressUpdateTask.cancel(true); - progressHandle.finish(); + if(doUI){ + progressUpdateTask.cancel(true); + progressHandle.finish(); + } } } } @@ -245,15 +241,19 @@ class ImageWriter implements PropertyChangeListener{ * Also makes sure the progressUpdateTask is canceled. */ void waitForJobToFinish(){ - // Wait for the finish task to end - if(finishTask != null){ - try{ - finishTask.get(); - } catch (InterruptedException | ExecutionException ex){ - Logger.getLogger(ImageWriter.class.getName()).log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS - } - progressUpdateTask.cancel(true); - } + synchronized(currentTasksLock){ + // Wait for the finish task to end + if(isStarted){ + try{ + finishTask.get(); + } catch (InterruptedException | ExecutionException ex){ + Logger.getLogger(ImageWriter.class.getName()).log(Level.SEVERE, "Error finishing VHD image", ex); //NON-NLS + } + if(doUI){ + progressUpdateTask.cancel(true); + } + } + } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriterService.java b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriterService.java similarity index 82% rename from Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriterService.java rename to Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriterService.java index e6211b748a..8f3791d53c 100644 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/ImageWriterService.java +++ b/Core/src/org/sleuthkit/autopsy/imagewriter/ImageWriterService.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.datasourceprocessors; +package org.sleuthkit.autopsy.imagewriter; import java.util.HashSet; import java.util.Set; @@ -30,6 +30,13 @@ import org.sleuthkit.autopsy.framework.AutopsyService; @ServiceProviders(value = {@ServiceProvider(service = AutopsyService.class)}) +/** + * Creates and handles closing of ImageWriter objects. + * Currently, ImageWriter is only enabled for local disks, and local disks can + * not be processed in multi user mode. If ImageWriter is ever enabled for multi user + * cases this code will need to be revised. + */ + public class ImageWriterService implements AutopsyService { private static final Set imageWriters = new HashSet<>(); // Contains all Image Writer objects @@ -58,8 +65,8 @@ public class ImageWriterService implements AutopsyService { @Override public void closeCaseResources(CaseContext context) throws AutopsyServiceException { - context.getProgressIndicator().progress("Waiting for VHD(s) to complete"); - + context.getProgressIndicator().progress(NbBundle.getMessage(this.getClass(), "ImageWriterService.waitingForVHDs")); + synchronized(imageWritersLock){ // If any of our ImageWriter objects haven't started the finish task, set the cancel flag // to make sure they don't start now. The reason they haven't started is that @@ -82,8 +89,8 @@ public class ImageWriterService implements AutopsyService { if(jobsAreInProgress){ // If jobs are in progress, ask the user if they want to wait for them to complete NotifyDescriptor descriptor = new NotifyDescriptor.Confirmation( - "Wait for Image Writer to finish?", - "Title", + NbBundle.getMessage(this.getClass(), "ImageWriterService.shouldWait"), + NbBundle.getMessage(this.getClass(), "ImageWriterService.localDisk"), NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); descriptor.setValue(NotifyDescriptor.NO_OPTION); @@ -103,6 +110,14 @@ public class ImageWriterService implements AutopsyService { } } + + // Stop listening for events + for(ImageWriter writer: imageWriters){ + writer.unsubscribeFromEvents(); + } + + // Clear out the list of Image Writers + imageWriters.clear(); } } }