mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-13 08:26:15 +00:00
Merge pull request #4899 from jkho/5165-Logical-Imager-DSP-to-support-multiple-drives
5165 logical imager dsp to support multiple drives
This commit is contained in:
commit
7fd4a9ae9d
@ -30,7 +30,6 @@ import org.openide.util.NbBundle.Messages;
|
|||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
* - add alert.txt and users.txt files to report
|
* - add alert.txt and users.txt files to report
|
||||||
* - add an image data source to the case database.
|
* - add an image data source to the case database.
|
||||||
*/
|
*/
|
||||||
public class AddLogicalImageTask extends AddImageTask {
|
public class AddLogicalImageTask extends AddMultipleImageTask {
|
||||||
|
|
||||||
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 ALERT_TXT = "alert.txt"; //NON-NLS
|
||||||
@ -50,16 +49,14 @@ public class AddLogicalImageTask extends AddImageTask {
|
|||||||
private final DataSourceProcessorCallback callback;
|
private final DataSourceProcessorCallback callback;
|
||||||
private final DataSourceProcessorProgressMonitor progressMonitor;
|
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||||
|
|
||||||
public AddLogicalImageTask(String deviceId, String imagePath, int sectorSize,
|
public AddLogicalImageTask(String deviceId,
|
||||||
String timeZone, boolean ignoreFatOrphanFiles,
|
List<String> imagePaths,
|
||||||
String md5, String sha1, String sha256,
|
String timeZone,
|
||||||
ImageWriterSettings imageWriterSettings,
|
|
||||||
File src, File dest,
|
File src, File dest,
|
||||||
DataSourceProcessorProgressMonitor progressMonitor,
|
DataSourceProcessorProgressMonitor progressMonitor,
|
||||||
DataSourceProcessorCallback callback
|
DataSourceProcessorCallback callback
|
||||||
) {
|
) throws NoCurrentCaseException {
|
||||||
super(deviceId, imagePath, sectorSize, timeZone, ignoreFatOrphanFiles,
|
super(deviceId, imagePaths, timeZone, progressMonitor, callback);
|
||||||
md5, sha1, sha256, imageWriterSettings, progressMonitor, callback);
|
|
||||||
this.src = src;
|
this.src = src;
|
||||||
this.dest = dest;
|
this.dest = dest;
|
||||||
this.progressMonitor = progressMonitor;
|
this.progressMonitor = progressMonitor;
|
||||||
|
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013-2019 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> 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.casemodule;
|
||||||
|
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.util.NbBundle.Messages;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||||
|
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.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.Image;
|
||||||
|
import org.sleuthkit.datamodel.LocalFilesDataSource;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitJNI;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskDataException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* A runnable that adds multiple images to the case database
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type"
|
||||||
|
})
|
||||||
|
class AddMultipleImageTask implements Runnable {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(AddMultipleImageTask.class.getName());
|
||||||
|
public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImageTask_fsTypeUnknownErr();
|
||||||
|
private final String deviceId;
|
||||||
|
private final List<String> imageFilePaths;
|
||||||
|
private final String timeZone;
|
||||||
|
private final DataSourceProcessorProgressMonitor progressMonitor;
|
||||||
|
private final DataSourceProcessorCallback callback;
|
||||||
|
private final Case currentCase;
|
||||||
|
private boolean criticalErrorOccurred;
|
||||||
|
private volatile boolean cancelled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a runnable that adds multiple image files
|
||||||
|
* to a case database. If Sleuth Kit fails to find a filesystem
|
||||||
|
* in any of input image files, the file is added to the case as a
|
||||||
|
* local/logical file instead.
|
||||||
|
*
|
||||||
|
* @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 imageFilePaths The paths of the multiple output files.
|
||||||
|
* @param timeZone The time zone to use when processing dates and
|
||||||
|
* times for the image, obtained from
|
||||||
|
* java.util.TimeZone.getID.
|
||||||
|
* @param progressMonitor Progress monitor for reporting progress during
|
||||||
|
* processing.
|
||||||
|
* @param callback Callback to call when processing is done.
|
||||||
|
* @throws NoCurrentCaseException The exception if there is no open case.
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"# {0} - file", "AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as logical file",
|
||||||
|
"# {0} - deviceId", "# {1} - exceptionMessage",
|
||||||
|
"AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s",
|
||||||
|
})
|
||||||
|
AddMultipleImageTask(String deviceId, List<String> imageFilePaths, String timeZone,
|
||||||
|
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) throws NoCurrentCaseException {
|
||||||
|
this.deviceId = deviceId;
|
||||||
|
this.imageFilePaths = imageFilePaths;
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
this.callback = callback;
|
||||||
|
this.progressMonitor = progressMonitor;
|
||||||
|
currentCase = Case.getCurrentCaseThrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
/*
|
||||||
|
* Try to add the input image files as images.
|
||||||
|
*/
|
||||||
|
List<Content> newDataSources = new ArrayList<>();
|
||||||
|
List<String> localFileDataSourcePaths = new ArrayList<>();
|
||||||
|
List<String> errorMessages = new ArrayList<>();
|
||||||
|
currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
|
||||||
|
try {
|
||||||
|
progressMonitor.setIndeterminate(true);
|
||||||
|
for (String imageFilePath : imageFilePaths) {
|
||||||
|
if (!cancelled) {
|
||||||
|
addImageToCase(imageFilePath, newDataSources, localFileDataSourcePaths, errorMessages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to add any input image files that did not have file systems as a
|
||||||
|
* single local/logical files set with the device id as the root virtual
|
||||||
|
* directory name.
|
||||||
|
*/
|
||||||
|
if (!cancelled && !localFileDataSourcePaths.isEmpty()) {
|
||||||
|
FileManager fileManager = currentCase.getServices().getFileManager();
|
||||||
|
FileManager.FileAddProgressUpdater progressUpdater = (final AbstractFile newFile) -> {
|
||||||
|
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_addingFileAsLogicalFile(Paths.get(newFile.getParentPath(), newFile.getName())));
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
LocalFilesDataSource localFilesDataSource = fileManager.addLocalFilesDataSource(deviceId, "", timeZone, localFileDataSourcePaths, progressUpdater);
|
||||||
|
newDataSources.add(localFilesDataSource);
|
||||||
|
} catch (TskCoreException | TskDataException ex) {
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This appears to be the best that can be done to indicate completion
|
||||||
|
* with the DataSourceProcessorProgressMonitor in its current form.
|
||||||
|
*/
|
||||||
|
progressMonitor.setProgress(0);
|
||||||
|
progressMonitor.setProgress(100);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pass the results back via the callback.
|
||||||
|
*/
|
||||||
|
DataSourceProcessorResult result;
|
||||||
|
if (criticalErrorOccurred) {
|
||||||
|
result = DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||||
|
} else if (!errorMessages.isEmpty()) {
|
||||||
|
result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
|
||||||
|
} else {
|
||||||
|
result = DataSourceProcessorResult.NO_ERRORS;
|
||||||
|
}
|
||||||
|
callback.done(result, errorMessages, newDataSources);
|
||||||
|
criticalErrorOccurred = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to cancel the processing of the input image files. May result in
|
||||||
|
* partial processing of the input.
|
||||||
|
*/
|
||||||
|
public void cancelTask() {
|
||||||
|
LOGGER.log(Level.WARNING, "AddMultipleImageTask cancelled, processing may be incomplete"); // NON-NLS
|
||||||
|
cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to add an input image to the case.
|
||||||
|
*
|
||||||
|
* @param imageFilePath The image file path.
|
||||||
|
* @param newDataSources If the image is added, a data source is
|
||||||
|
* added to this list for eventual return to
|
||||||
|
* the caller via the callback.
|
||||||
|
* @param localFileDataSourcePaths If the image cannot be added because
|
||||||
|
* Sleuth Kit cannot detect a filesystem, the
|
||||||
|
* image file path is added to this list for
|
||||||
|
* later addition as a part of a
|
||||||
|
* local/logical files data source.
|
||||||
|
* @param errorMessages If there are any error messages, the
|
||||||
|
* error messages are added to this list for
|
||||||
|
* eventual return to the caller via the
|
||||||
|
* callback.
|
||||||
|
*/
|
||||||
|
@Messages({
|
||||||
|
"# {0} - imageFilePath", "AddMultipleImageTask.adding=Adding: {0}",
|
||||||
|
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
|
||||||
|
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
|
||||||
|
"# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",
|
||||||
|
})
|
||||||
|
private void addImageToCase(String imageFilePath, List<Content> newDataSources, List<String> localFileDataSourcePaths, List<String> errorMessages) {
|
||||||
|
/*
|
||||||
|
* Try to add the image to the case database as a data source.
|
||||||
|
*/
|
||||||
|
progressMonitor.setProgressText(Bundle.AddMultipleImageTask_adding(imageFilePath));
|
||||||
|
SleuthkitCase caseDatabase = currentCase.getSleuthkitCase();
|
||||||
|
SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = caseDatabase.makeAddImageProcess(timeZone, false, false, "");
|
||||||
|
try {
|
||||||
|
addImageProcess.run(deviceId, new String[]{imageFilePath});
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
if (ex.getMessage().contains(TSK_FS_TYPE_UNKNOWN_ERR_MSG)) {
|
||||||
|
/*
|
||||||
|
* If Sleuth Kit failed to add the image because it did not find
|
||||||
|
* a file system, save the image path so it can be added to the
|
||||||
|
* case as part of a local/logical files data source. All other
|
||||||
|
* errors are critical.
|
||||||
|
*/
|
||||||
|
localFileDataSourcePaths.add(imageFilePath);
|
||||||
|
} else {
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Either way, the add image process needs to be reverted.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
addImageProcess.revert();
|
||||||
|
} catch (TskCoreException e) {
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorReverting(imageFilePath, deviceId, e.getLocalizedMessage()));
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (TskDataException ex) {
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to commit the results of the add image process, retrieve the new
|
||||||
|
* image from the case database, and add it to the list of new data
|
||||||
|
* sources to be returned via the callback.
|
||||||
|
*/
|
||||||
|
try {
|
||||||
|
long imageId = addImageProcess.commit();
|
||||||
|
Image dataSource = caseDatabase.getImageById(imageId);
|
||||||
|
newDataSources.add(dataSource);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Verify the size of the new image. Note that it may not be what is
|
||||||
|
* expected, but at least part of it was added to the case.
|
||||||
|
*/
|
||||||
|
String verificationError = dataSource.verifyImageSize();
|
||||||
|
if (!verificationError.isEmpty()) {
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
/*
|
||||||
|
* The add image process commit failed or querying the case database
|
||||||
|
* for the newly added image failed. Either way, this is a critical
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
errorMessages.add(Bundle.AddMultipleImageTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
|
||||||
|
criticalErrorOccurred = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -14,6 +14,26 @@ AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}
|
|||||||
# {0} - src
|
# {0} - src
|
||||||
# {1} - dest
|
# {1} - dest
|
||||||
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
|
AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}
|
||||||
|
# {0} - imageFilePath
|
||||||
|
AddMultipleImageTask.adding=Adding: {0}
|
||||||
|
# {0} - file
|
||||||
|
AddMultipleImageTask.addingFileAsLogicalFile=Adding: {0} as logical file
|
||||||
|
# {0} - imageFilePath
|
||||||
|
# {1} - deviceId
|
||||||
|
# {2} - exceptionMessage
|
||||||
|
AddMultipleImageTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}
|
||||||
|
# {0} - imageFilePath
|
||||||
|
# {1} - deviceId
|
||||||
|
# {2} - exceptionMessage
|
||||||
|
AddMultipleImageTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}
|
||||||
|
# {0} - deviceId
|
||||||
|
# {1} - exceptionMessage
|
||||||
|
AddMultipleImageTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device %s: %s
|
||||||
|
AddMultipleImageTask.fsTypeUnknownErr=Cannot determine file system type
|
||||||
|
# {0} - imageFilePath
|
||||||
|
# {1} - deviceId
|
||||||
|
# {2} - exceptionMessage
|
||||||
|
AddMultipleImageTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}
|
||||||
# {0} - exception message
|
# {0} - exception message
|
||||||
Case.closeException.couldNotCloseCase=Error closing case: {0}
|
Case.closeException.couldNotCloseCase=Error closing case: {0}
|
||||||
Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory
|
Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory
|
||||||
@ -187,19 +207,21 @@ LogicalImagerDSProcessor.dataSourceType=Autopsy Imager
|
|||||||
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists
|
||||||
# {0} - directory
|
# {0} - directory
|
||||||
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}
|
||||||
|
# {0} - file
|
||||||
|
LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}
|
||||||
# {0} - imageDirPath
|
# {0} - imageDirPath
|
||||||
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.
|
||||||
|
LogicalImagerDSProcessor.noCurrentCase=No current case
|
||||||
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
|
LogicalImagerPanel.imageTable.columnModel.title0=Hostname
|
||||||
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
|
LogicalImagerPanel.imageTable.columnModel.title1=Extracted Date
|
||||||
# {0} - sparseImageDirectory
|
# {0} - sparseImageDirectory
|
||||||
# {1} - image
|
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain any images
|
||||||
LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}
|
|
||||||
# {0} - invalidFormatDirectory
|
# {0} - invalidFormatDirectory
|
||||||
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
||||||
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
|
LogicalImagerPanel.messageLabel.driveHasNoImages=Drive has no images
|
||||||
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
|
LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found
|
||||||
LogicalImagerPanel.messageLabel.noImageSelected=No image selected
|
LogicalImagerPanel.messageLabel.noImageSelected=No image selected
|
||||||
LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...
|
LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for images ...
|
||||||
LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive
|
LogicalImagerPanel.selectAcquisitionFromDriveLabel.text=Select acquisition from Drive
|
||||||
Menu/Case/OpenRecentCase=Open Recent Case
|
Menu/Case/OpenRecentCase=Open Recent Case
|
||||||
CTL_CaseDeleteAction=Delete Case
|
CTL_CaseDeleteAction=Delete Case
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.casemodule;
|
package org.sleuthkit.autopsy.casemodule;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -46,7 +47,6 @@ import org.sleuthkit.datamodel.Content;
|
|||||||
public class LogicalImagerDSProcessor implements DataSourceProcessor {
|
public class LogicalImagerDSProcessor implements DataSourceProcessor {
|
||||||
|
|
||||||
private static final String LOGICAL_IMAGER_DIR = "LogicalImager"; //NON-NLS
|
private static final String LOGICAL_IMAGER_DIR = "LogicalImager"; //NON-NLS
|
||||||
private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS
|
|
||||||
private final LogicalImagerPanel configPanel;
|
private final LogicalImagerPanel configPanel;
|
||||||
private AddLogicalImageTask addLogicalImageTask;
|
private AddLogicalImageTask addLogicalImageTask;
|
||||||
|
|
||||||
@ -128,6 +128,8 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
"# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.",
|
"# {0} - imageDirPath", "LogicalImagerDSProcessor.imageDirPathNotFound={0} not found.\nUSB drive has been ejected.",
|
||||||
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
|
"# {0} - directory", "LogicalImagerDSProcessor.failToCreateDirectory=Failed to create directory {0}",
|
||||||
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
|
"# {0} - directory", "LogicalImagerDSProcessor.directoryAlreadyExists=Directory {0} already exists",
|
||||||
|
"# {0} - file", "LogicalImagerDSProcessor.failToGetCanonicalPath=Fail to get canonical path for {0}",
|
||||||
|
"LogicalImagerDSProcessor.noCurrentCase=No current case",
|
||||||
})
|
})
|
||||||
@Override
|
@Override
|
||||||
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
|
||||||
@ -170,9 +172,31 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
String deviceId = UUID.randomUUID().toString();
|
String deviceId = UUID.randomUUID().toString();
|
||||||
String timeZone = Calendar.getInstance().getTimeZone().getID();
|
String timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||||
boolean ignoreFatOrphanFiles = false;
|
boolean ignoreFatOrphanFiles = false;
|
||||||
run(deviceId, Paths.get(src.toString(), SPARSE_IMAGE_VHD).toString(), 0,
|
|
||||||
timeZone, ignoreFatOrphanFiles, null, null, null, src, dest,
|
// Get all VHD files in the src directory
|
||||||
|
List<String> imagePaths = new ArrayList<>();
|
||||||
|
for (File f : src.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
run(deviceId, imagePaths,
|
||||||
|
timeZone, src, dest,
|
||||||
progressMonitor, callback);
|
progressMonitor, callback);
|
||||||
|
} catch (NoCurrentCaseException ex) {
|
||||||
|
String msg = Bundle.LogicalImagerDSProcessor_noCurrentCase();
|
||||||
|
errorList.add(msg);
|
||||||
|
callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -186,29 +210,21 @@ public class LogicalImagerDSProcessor implements DataSourceProcessor {
|
|||||||
* associated with the data source that is
|
* associated with the data source that is
|
||||||
* intended to be unique across multiple cases
|
* intended to be unique across multiple cases
|
||||||
* (e.g., a UUID).
|
* (e.g., a UUID).
|
||||||
* @param imagePath Path to the image file.
|
* @param imagePaths Paths to the image files.
|
||||||
* @param sectorSize The sector size (use '0' for autodetect).
|
|
||||||
* @param timeZone The time zone to use when processing dates
|
* @param timeZone The time zone to use when processing dates
|
||||||
* and times for the image, obtained from
|
* and times for the image, obtained from
|
||||||
* java.util.TimeZone.getID.
|
* java.util.TimeZone.getID.
|
||||||
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
|
|
||||||
* FAT filesystem.
|
|
||||||
* @param md5 The MD5 hash of the image, may be null.
|
|
||||||
* @param sha1 The SHA-1 hash of the image, may be null.
|
|
||||||
* @param sha256 The SHA-256 hash of the image, may be null.
|
|
||||||
* @param src The source directory of image.
|
* @param src The source directory of image.
|
||||||
* @param dest The destination directory to copy the source.
|
* @param dest The destination directory to copy the source.
|
||||||
* @param progressMonitor Progress monitor for reporting progress
|
* @param progressMonitor Progress monitor for reporting progress
|
||||||
* during processing.
|
* during processing.
|
||||||
* @param callback Callback to call when processing is done.
|
* @param callback Callback to call when processing is done.
|
||||||
*/
|
*/
|
||||||
private void run(String deviceId, String imagePath, int sectorSize, String timeZone,
|
private void run(String deviceId, List<String> imagePaths, String timeZone,
|
||||||
boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256,
|
|
||||||
File src, File dest,
|
File src, File dest,
|
||||||
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
|
DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback
|
||||||
) {
|
) throws NoCurrentCaseException {
|
||||||
addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePath, sectorSize,
|
addLogicalImageTask = new AddLogicalImageTask(deviceId, imagePaths, timeZone, src, dest,
|
||||||
timeZone, ignoreFatOrphanFiles, md5, sha1, sha256, null, src, dest,
|
|
||||||
progressMonitor, callback);
|
progressMonitor, callback);
|
||||||
new Thread(addLogicalImageTask).start();
|
new Thread(addLogicalImageTask).start();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileStore;
|
import java.nio.file.FileStore;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@ -54,7 +55,6 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
|||||||
public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final String SPARSE_IMAGE_VHD = "sparse_image.vhd"; //NON-NLS
|
|
||||||
private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected();
|
private static final String NO_IMAGE_SELECTED = Bundle.LogicalImagerPanel_messageLabel_noImageSelected();
|
||||||
private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages();
|
private static final String DRIVE_HAS_NO_IMAGES = Bundle.LogicalImagerPanel_messageLabel_driveHasNoImages();
|
||||||
private static final String[] EMPTY_LIST_DATA = {};
|
private static final String[] EMPTY_LIST_DATA = {};
|
||||||
@ -302,8 +302,7 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
|
|
||||||
@Messages({
|
@Messages({
|
||||||
"# {0} - sparseImageDirectory",
|
"# {0} - sparseImageDirectory",
|
||||||
"# {1} - image",
|
"LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain any images",
|
||||||
"LogicalImagerPanel.messageLabel.directoryDoesNotContainSparseImage=Directory {0} does not contain {1}",
|
|
||||||
"# {0} - invalidFormatDirectory",
|
"# {0} - invalidFormatDirectory",
|
||||||
"LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS"
|
"LogicalImagerPanel.messageLabel.directoryFormatInvalid=Directory {0} does not match format Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS"
|
||||||
})
|
})
|
||||||
@ -317,9 +316,15 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
String path = fileChooser.getSelectedFile().getPath();
|
String path = fileChooser.getSelectedFile().getPath();
|
||||||
Matcher m = regex.matcher(path);
|
Matcher m = regex.matcher(path);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
Path vhdPath = Paths.get(path, SPARSE_IMAGE_VHD);
|
File dir = Paths.get(path).toFile();
|
||||||
if (!vhdPath.toFile().exists()) {
|
String[] vhdFiles = dir.list(new FilenameFilter() {
|
||||||
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path, SPARSE_IMAGE_VHD));
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
return name.endsWith(".vhd");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (vhdFiles.length == 0) {
|
||||||
|
setErrorMessage(Bundle.LogicalImagerPanel_messageLabel_directoryDoesNotContainSparseImage(path));
|
||||||
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
|
firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), true, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -348,6 +353,16 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean dirHasVhdFiles(File dir) {
|
||||||
|
File[] fList = dir.listFiles(new FilenameFilter() {
|
||||||
|
@Override
|
||||||
|
public boolean accept(File dir, String name) {
|
||||||
|
return name.endsWith(".vhd");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return (fList != null && fList.length != 0);
|
||||||
|
}
|
||||||
|
|
||||||
private void driveListSelect() {
|
private void driveListSelect() {
|
||||||
String selectedStr = driveList.getSelectedValue();
|
String selectedStr = driveList.getSelectedValue();
|
||||||
if (selectedStr == null) {
|
if (selectedStr == null) {
|
||||||
@ -361,10 +376,9 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
imageTableModel = new ImageTableModel();
|
imageTableModel = new ImageTableModel();
|
||||||
int row = 0;
|
int row = 0;
|
||||||
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
// Find all directories with name like Logical_Imager_HOSTNAME_yyyymmdd_HH_MM_SS
|
||||||
// and has a sparse_image.vhd file in it
|
// and has vhd files in it
|
||||||
for (File file : fList) {
|
for (File file : fList) {
|
||||||
if (file.isDirectory()
|
if (file.isDirectory() && dirHasVhdFiles(file)) {
|
||||||
&& Paths.get(driveLetter, file.getName(), SPARSE_IMAGE_VHD).toFile().exists()) {
|
|
||||||
String dir = file.getName();
|
String dir = file.getName();
|
||||||
Matcher m = regex.matcher(dir);
|
Matcher m = regex.matcher(dir);
|
||||||
if (m.find()) {
|
if (m.find()) {
|
||||||
@ -464,11 +478,11 @@ public class LogicalImagerPanel extends JPanel implements DocumentListener {
|
|||||||
}//GEN-LAST:event_importRadioButtonActionPerformed
|
}//GEN-LAST:event_importRadioButtonActionPerformed
|
||||||
|
|
||||||
@Messages({
|
@Messages({
|
||||||
"LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for sparse_image.vhd ...",
|
"LogicalImagerPanel.messageLabel.scanningExternalDrives=Scanning external drives for images ...",
|
||||||
"LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found"
|
"LogicalImagerPanel.messageLabel.noExternalDriveFound=No drive found"
|
||||||
})
|
})
|
||||||
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
|
||||||
// Scan external drives for sparse_image.vhd
|
// Scan external drives for vhd images
|
||||||
clearImageTable();
|
clearImageTable();
|
||||||
setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives());
|
setNormalMessage(Bundle.LogicalImagerPanel_messageLabel_scanningExternalDrives());
|
||||||
List<String> listData = new ArrayList<>();
|
List<String> listData = new ArrayList<>();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user