diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/Bundle.properties-MERGED index d0c05b6ef4..cec2da7dfb 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/configuration/Bundle.properties-MERGED @@ -191,7 +191,6 @@ EditNonFullPathsRulePanel.fileNamesInfoLabel.text=File names are case insensitiv EditNonFullPathsRulePanel.extensionsInfoLabel.text=Extensions are case insensitive. ConfigVisualPanel2.promptBeforeExit.text=Prompt before exiting imager ConfigVisualPanel2.promptBeforeExit.actionCommand= -ConfigVisualPanel2.createVHDCheckBox.toolTipText= ConfigVisualPanel2.createVHDCheckBox.text=Create VHD NewRuleSetPanel.attributeRule.description=Search for files based on one or more attributes or metadata fields. NewRuleSetPanel.attributeRule.name=Attribute diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java index cac1ea4345..01ae872c45 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java @@ -19,12 +19,16 @@ package org.sleuthkit.autopsy.logicalimager.dsp; import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; +import org.apache.commons.io.FileUtils; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.casemodule.AddLocalFilesTask; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; @@ -38,24 +42,28 @@ import org.sleuthkit.datamodel.TskCoreException; * alert.txt and users.txt files to report - add an image data source to the * case database. */ -final class AddLogicalImageTask extends AddMultipleImageTask { +final class AddLogicalImageTask implements Runnable { - private final static Logger logger = Logger.getLogger(AddLogicalImageTask.class.getName()); + private final static Logger LOGGER = Logger.getLogger(AddLogicalImageTask.class.getName()); private final static String ALERT_TXT = "alert.txt"; //NON-NLS private final static String USERS_TXT = "users.txt"; //NON-NLS + private final String deviceId; + private final String timeZone; private final File src; private final File dest; private final DataSourceProcessorCallback callback; private final DataSourceProcessorProgressMonitor progressMonitor; + private volatile boolean cancelled; + AddLogicalImageTask(String deviceId, - List imagePaths, String timeZone, File src, File dest, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback ) throws NoCurrentCaseException { - super(deviceId, imagePaths, timeZone, progressMonitor, callback); + this.deviceId = deviceId; + this.timeZone = timeZone; this.src = src; this.dest = dest; this.progressMonitor = progressMonitor; @@ -71,14 +79,34 @@ final class AddLogicalImageTask extends AddMultipleImageTask { "AddLogicalImageTask.doneCopying=Done copying", "# {0} - src", "# {1} - dest", "AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}", "# {0} - file", "AddLogicalImageTask.addingToReport=Adding {0} to report", - "# {0} - file", "AddLogicalImageTask.doneAddingToReport=Done adding {0} to report" + "# {0} - file", "AddLogicalImageTask.doneAddingToReport=Done adding {0} to report", + "AddLogicalImageTask.ingestionCancelled=Ingestion cancelled", + "# {0} - file", "AddLogicalImageTask.failToGetCanonicalPath=Fail to get canonical path for {0}", + "# {0} - sparseImageDirectory", "AddLogicalImageTask.directoryDoesNotContainSparseImage=Directory {0} does not contain any images", + "AddLogicalImageTask.noCurrentCase=No current case", }) @Override public void run() { List errorList = new ArrayList<>(); List emptyDataSources = new ArrayList<>(); - // Add the alert.txt and users.txt to the case report + try { + progressMonitor.setProgressText(Bundle.AddLogicalImageTask_copyingImageFromTo(src.toString(), dest.toString())); + FileUtils.copyDirectory(src, dest); + progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneCopying()); + } catch (IOException ex) { + // Copy directory failed + String msg = Bundle.AddLogicalImageTask_failedToCopyDirectory(src.toString(), dest.toString()); + errorList.add(msg); + callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); + return; + } + + if (cancelled) { + return; + } + + // Add the alert.txt and users.txt to the case report progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(ALERT_TXT)); String status = addReport(Paths.get(dest.toString(), ALERT_TXT), ALERT_TXT + " " + src.getName()); if (status != null) { @@ -97,7 +125,50 @@ final class AddLogicalImageTask extends AddMultipleImageTask { } progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(USERS_TXT)); - super.run(); + // Get all VHD files in the dest directory + List imagePaths = new ArrayList<>(); + for (File f : dest.listFiles()) { + if (f.getName().endsWith(".vhd")) { + try { + imagePaths.add(f.getCanonicalPath()); + } catch (IOException ex) { + String msg = Bundle.AddLogicalImageTask_failToGetCanonicalPath(f.getName()); + errorList.add(msg); + callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); + return; + } + } + } + if (imagePaths.isEmpty()) { + // No VHD in src directory, try ingest directories using Logical File Set + String[] directories = dest.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return Paths.get(dir.toString(), name).toFile().isDirectory(); + } + }); + for (String dir : directories) { + imagePaths.add(Paths.get(dest.toString(), dir).toFile().getAbsolutePath()); + } + if (imagePaths.isEmpty()) { + String msg = Bundle.AddLogicalImageTask_directoryDoesNotContainSparseImage(dest); + errorList.add(msg); + callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); + return; + } + + // ingest the directories + new Thread(new AddLocalFilesTask(deviceId, null, imagePaths, progressMonitor, callback)).start(); + } else { + // ingest the VHDs + try { + new Thread(new AddMultipleImageTask(deviceId, imagePaths, timeZone , progressMonitor, callback)).start(); + } catch (NoCurrentCaseException ex) { + String msg = Bundle.AddLogicalImageTask_noCurrentCase(); + errorList.add(msg); + callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); + } + } } /** @@ -121,8 +192,17 @@ final class AddLogicalImageTask extends AddMultipleImageTask { return null; } catch (TskCoreException ex) { String msg = Bundle.AddLogicalImageTask_failedToAddReport(reportPath.toString(), ex.getMessage()); - logger.log(Level.SEVERE, String.format("Failed to add report %s. Reason= %s", reportPath.toString(), ex.getMessage()), ex); + LOGGER.log(Level.SEVERE, String.format("Failed to add report %s. Reason= %s", reportPath.toString(), ex.getMessage()), ex); return msg; } } + + /** + * Attempts to cancel the processing of the input image files. May result in + * partial processing of the input. + */ + void cancelTask() { + LOGGER.log(Level.WARNING, "AddLogicalImageTask cancelled, processing may be incomplete"); // NON-NLS + cancelled = true; + } } diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED index 2551162ab2..d9c56237be 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED @@ -7,6 +7,8 @@ AddLogicalImageTask.addingToReport=Adding {0} to report # {0} - src # {1} - dest AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1} +# {0} - sparseImageDirectory +AddLogicalImageTask.directoryDoesNotContainSparseImage=Directory {0} does not contain any images # {0} - file AddLogicalImageTask.doneAddingToReport=Done adding {0} to report AddLogicalImageTask.doneCopying=Done copying @@ -16,6 +18,10 @@ AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1} # {0} - src # {1} - dest AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1} +# {0} - file +AddLogicalImageTask.failToGetCanonicalPath=Fail to get canonical path for {0} +AddLogicalImageTask.ingestionCancelled=Ingestion cancelled +AddLogicalImageTask.noCurrentCase=No current case # {0} - imageFilePath AddMultipleImageTask.adding=Adding: {0} # {0} - file @@ -39,12 +45,8 @@ AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for de LogicalImagerDSProcessor.dataSourceType=Autopsy Logical Imager Results # {0} - directory LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists -# {0} - sparseImageDirectory -LogicalImagerDSProcessor.directoryDoesNotContainSparseImage=Directory {0} does not contain any images # {0} - directory LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0} -# {0} - file -LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0} # {0} - imageDirPath LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected. LogicalImagerDSProcessor.noCurrentCase=No current case diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java index ae0f3d533f..8a66270f55 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java @@ -19,8 +19,6 @@ package org.sleuthkit.autopsy.logicalimager.dsp; import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -28,11 +26,9 @@ import java.util.Calendar; import java.util.List; import java.util.UUID; import javax.swing.JPanel; -import org.apache.commons.io.FileUtils; import org.openide.util.NbBundle.Messages; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.casemodule.AddLocalFilesTask; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @@ -133,10 +129,7 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { "# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.", "# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}", "# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists", - "# {0} - file", "LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}", "LogicalImagerDSProcessor.noCurrentCase=No current case", - "# {0} - sparseImageDirectory", "LogicalImagerDSProcessor.directoryDoesNotContainSparseImage=Directory {0} does not contain any images", - }) @Override public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { @@ -177,64 +170,14 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { File src = imageDirPath.toFile(); try { - progressMonitor.setProgressText(Bundle.AddLogicalImageTask_copyingImageFromTo(src.toString(), dest.toString())); - FileUtils.copyDirectory(src, dest); - progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneCopying()); - } catch (IOException ex) { - // Copy directory failed - String msg = Bundle.AddLogicalImageTask_failedToCopyDirectory(src.toString(), dest.toString()); + String deviceId = UUID.randomUUID().toString(); + String timeZone = Calendar.getInstance().getTimeZone().getID(); + run(deviceId, timeZone, src, dest, + progressMonitor, callback); + } catch (NoCurrentCaseException ex) { + String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase(); errorList.add(msg); callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - return; - } - - // Get all VHD files in the src directory - List imagePaths = new ArrayList<>(); - for (File f : dest.listFiles()) { - if (f.getName().endsWith(".vhd")) { - try { - imagePaths.add(f.getCanonicalPath()); - } catch (IOException ex) { - String msg = Bundle.LogicalImagerDSProcessor_failToGetCanonicalPath(f.getName()); - errorList.add(msg); - callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - return; - } - } - } - String deviceId = UUID.randomUUID().toString(); - if (imagePaths.isEmpty()) { - // No VHD in src directory, try ingest directories using Logical File Set - String[] directories = dest.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return Paths.get(dir.toString(), name).toFile().isDirectory(); - } - }); - for (String dir : directories) { - imagePaths.add(Paths.get(dest.toString(), dir).toFile().getAbsolutePath()); - } - if (imagePaths.isEmpty()) { - String msg = Bundle.LogicalImagerDSProcessor_directoryDoesNotContainSparseImage(dest); - errorList.add(msg); - callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - return; - } - - // ingest the directories - new Thread(new AddLocalFilesTask(deviceId, null, imagePaths, progressMonitor, callback)).start(); - - } else { - try { - String timeZone = Calendar.getInstance().getTimeZone().getID(); - run(deviceId, imagePaths, - timeZone, src, dest, - progressMonitor, callback); - } catch (NoCurrentCaseException ex) { - String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase(); - errorList.add(msg); - callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - } } } @@ -248,7 +191,6 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { * @param deviceId An ASCII-printable identifier for the device * associated with the data source that is intended * to be unique across multiple cases (e.g., a UUID). - * @param imagePaths Paths to the image files. * @param timeZone The time zone to use when processing dates and * times for the image, obtained from * java.util.TimeZone.getID. @@ -258,11 +200,11 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { * processing. * @param callback Callback to call when processing is done. */ - private void run(String deviceId, List imagePaths, String timeZone, + private void run(String deviceId, String timeZone, File src, File dest, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback ) throws NoCurrentCaseException { - addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePaths, timeZone, src, dest, + addLogicalImageTask = new AddLogicalImageTask(deviceId, timeZone, src, dest, progressMonitor, callback); new Thread(addLogicalImageTask).start(); }