From fe0e1b4cf188fd08e1df7d0694a87c785d998df1 Mon Sep 17 00:00:00 2001 From: Joe Ho Date: Tue, 13 Aug 2019 10:14:59 -0400 Subject: [PATCH] allow adding directories as Logical File Set --- .../autopsy/casemodule/AddLocalFilesTask.java | 10 +-- .../dsp/AddLogicalImageTask.java | 17 +---- .../dsp/Bundle.properties-MERGED | 2 + .../dsp/LogicalImagerDSProcessor.java | 66 +++++++++++++++---- .../logicalimager/dsp/LogicalImagerPanel.java | 16 ++++- 5 files changed, 74 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java index feae1ddb6b..775fc51d8c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java @@ -22,12 +22,12 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.autopsy.casemodule.services.FileManager; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.LocalFilesDataSource; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; @@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskDataException; * case database, grouped under a virtual directory that serves as the data * source. */ -class AddLocalFilesTask implements Runnable { +public class AddLocalFilesTask implements Runnable { private static final Logger LOGGER = Logger.getLogger(AddLocalFilesTask.class.getName()); private final String deviceId; @@ -68,7 +68,7 @@ class AddLocalFilesTask implements Runnable { * during processing. * @param callback Callback to call when processing is done. */ - AddLocalFilesTask(String deviceId, String rootVirtualDirectoryName, List localFilePaths, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + public AddLocalFilesTask(String deviceId, String rootVirtualDirectoryName, List localFilePaths, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { this.deviceId = deviceId; this.rootVirtualDirectoryName = rootVirtualDirectoryName; this.localFilePaths = localFilePaths; @@ -88,7 +88,7 @@ class AddLocalFilesTask implements Runnable { try { progress.setIndeterminate(true); FileManager fileManager = Case.getCurrentCaseThrows().getServices().getFileManager(); - LocalFilesDataSource newDataSource = fileManager.addLocalFilesDataSource(deviceId, rootVirtualDirectoryName, "", localFilePaths, new ProgressUpdater()); + LocalFilesDataSource newDataSource = fileManager.addLocalFilesDataSource(deviceId, "", "", localFilePaths, new ProgressUpdater()); newDataSources.add(newDataSource); } catch (TskDataException | TskCoreException | NoCurrentCaseException ex) { errors.add(ex.getMessage()); diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java index 9070dfc197..cac1ea4345 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/AddLogicalImageTask.java @@ -19,13 +19,11 @@ package org.sleuthkit.autopsy.logicalimager.dsp; import java.io.File; -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.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -80,20 +78,7 @@ final class AddLogicalImageTask extends AddMultipleImageTask { List errorList = new ArrayList<>(); List emptyDataSources = new ArrayList<>(); - 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); - logger.log(Level.SEVERE, String.format("Failed to copy directory %s to %s", src.toString(), dest.toString()), ex); - callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources); - return; - } - - // Add the alert.txt and users.txt to the case report + // 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) { 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 32bd3c7868..2551162ab2 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/Bundle.properties-MERGED @@ -39,6 +39,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 diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java index da9d5f7aa6..ae0f3d533f 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerDSProcessor.java @@ -19,6 +19,7 @@ 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; @@ -27,9 +28,11 @@ 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; @@ -131,7 +134,10 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { "# {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",}) + "LogicalImagerDSProcessor.noCurrentCase=No current case", + "# {0} - sparseImageDirectory", "LogicalImagerDSProcessor.directoryDoesNotContainSparseImage=Directory {0} does not contain any images", + + }) @Override public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { configPanel.storeSettings(); @@ -170,9 +176,21 @@ 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()); + 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 : src.listFiles()) { + for (File f : dest.listFiles()) { if (f.getName().endsWith(".vhd")) { try { imagePaths.add(f.getCanonicalPath()); @@ -184,17 +202,39 @@ public final class LogicalImagerDSProcessor implements DataSourceProcessor { } } } - try { - String deviceId = UUID.randomUUID().toString(); - 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); - 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); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java index 06722722d6..d491c77778 100644 --- a/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java +++ b/Core/src/org/sleuthkit/autopsy/logicalimager/dsp/LogicalImagerPanel.java @@ -333,9 +333,19 @@ final class LogicalImagerPanel extends JPanel implements DocumentListener { } }); if (vhdFiles.length == 0) { - setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path)); - firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); - return; + // No VHD files, try directories for individual files + String[] directories = dir.list(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return Paths.get(dir.toString(), name).toFile().isDirectory(); + } + }); + if (directories.length == 0) { + // No directories, bail + setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path)); + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false); + return; + } } manualImageDirPath = Paths.get(path); setNormalMessage(path);