mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Merge pull request #3577 from eugene7646/unalloc_image_add_3590
Ability to add image as unallocated space if other DSPs fail to process it (3590)
This commit is contained in:
@@ -278,7 +278,7 @@ public class ImageDSProcessor implements DataSourceProcessor, AutoIngestDataSour
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
this.deviceId = deviceId;
|
||||
this.imagePath = dataSourcePath.toString();
|
||||
this.sectorSize = 0;
|
||||
|
||||
@@ -18,20 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.casemodule;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Calendar;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
import org.sleuthkit.autopsy.coreutils.DriveUtils;
|
||||
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
|
||||
import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||
|
||||
/**
|
||||
* A local drive data source processor that implements the DataSourceProcessor
|
||||
@@ -39,11 +34,8 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||
* wizard. It also provides a run method overload to allow it to be used
|
||||
* independently of the wizard.
|
||||
*/
|
||||
@ServiceProviders(value = {
|
||||
@ServiceProvider(service = DataSourceProcessor.class),
|
||||
@ServiceProvider(service = AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
public class LocalDiskDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class LocalDiskDSProcessor implements DataSourceProcessor {
|
||||
|
||||
private static final String DATA_SOURCE_TYPE = NbBundle.getMessage(LocalDiskDSProcessor.class, "LocalDiskDSProcessor.dsType.text");
|
||||
private final LocalDiskPanel configPanel;
|
||||
@@ -230,38 +222,6 @@ public class LocalDiskDSProcessor implements DataSourceProcessor, AutoIngestData
|
||||
setDataSourceOptionsCalled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
|
||||
// verify that the data source is not a file or a directory
|
||||
File file = dataSourcePath.toFile();
|
||||
// ELTODO this needs to be tested more. should I keep isDirectory or just test for isFile?
|
||||
if (file.isFile() || file.isDirectory()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check whether data source is an existing disk or partition
|
||||
// ELTODO this needs to be tested more. do these methods actually work correctly?
|
||||
// or should I use PlatformUtil.getPhysicalDrives() and PlatformUtil.getPartitions() instead?
|
||||
String path = dataSourcePath.toString();
|
||||
if ((DriveUtils.isPhysicalDrive(path) || DriveUtils.isPartition(path)) && DriveUtils.driveExists(path)) {
|
||||
return 90;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
this.deviceId = deviceId;
|
||||
this.drivePath = dataSourcePath.toString();
|
||||
this.sectorSize = 0;
|
||||
this.timeZone = Calendar.getInstance().getTimeZone().getID();
|
||||
this.ignoreFatOrphanFiles = false;
|
||||
setDataSourceOptionsCalled = true;
|
||||
run(deviceId, drivePath, sectorSize, timeZone, ignoreFatOrphanFiles, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configuration of the data source processor without using the
|
||||
* configuration panel.
|
||||
|
||||
@@ -51,8 +51,7 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor;
|
||||
* method overload to allow it to be used independently of the wizard.
|
||||
*/
|
||||
@ServiceProviders(value = {
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
,
|
||||
@ServiceProvider(service = DataSourceProcessor.class),
|
||||
@ServiceProvider(service = AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
@Messages({
|
||||
@@ -369,7 +368,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
run(deviceId, deviceId, this.localFilePaths, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,9 +63,8 @@ public interface AutoIngestDataSourceProcessor extends DataSourceProcessor {
|
||||
* background task to report progress.
|
||||
* @param callBack Callback that will be used by the background task
|
||||
* to return results.
|
||||
* @throws org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException
|
||||
*/
|
||||
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException;
|
||||
void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack);
|
||||
|
||||
/**
|
||||
* A custom exception for the use of AutomatedIngestDataSourceProcessor.
|
||||
|
||||
@@ -18,10 +18,18 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datasourceprocessors;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.openide.util.lookup.ServiceProviders;
|
||||
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
@@ -32,12 +40,25 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||
* also provides a run method overload to allow it to be used independently of
|
||||
* the wizard.
|
||||
*/
|
||||
@ServiceProvider(service = DataSourceProcessor.class)
|
||||
public class RawDSProcessor implements DataSourceProcessor {
|
||||
@ServiceProviders(value={
|
||||
@ServiceProvider(service=DataSourceProcessor.class),
|
||||
@ServiceProvider(service=AutoIngestDataSourceProcessor.class)}
|
||||
)
|
||||
public class RawDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor {
|
||||
|
||||
private final RawDSInputPanel configPanel;
|
||||
private AddRawImageTask addImageTask;
|
||||
|
||||
private static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC);
|
||||
private static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC);
|
||||
private static final List<FileFilter> filtersList = new ArrayList<>();
|
||||
static {
|
||||
filtersList.add(rawFilter);
|
||||
filtersList.add(encaseFilter);
|
||||
}
|
||||
|
||||
// By default, split image into 2GB unallocated space chunks
|
||||
private static final long DEFAULT_CHUNK_SIZE = 2000000000L; // 2 GB
|
||||
|
||||
/*
|
||||
* Constructs a Raw data source processor that implements the
|
||||
* DataSourceProcessor service provider interface to allow integration with
|
||||
@@ -158,5 +179,29 @@ public class RawDSProcessor implements DataSourceProcessor {
|
||||
public void reset() {
|
||||
configPanel.reset();
|
||||
}
|
||||
|
||||
private static boolean isAcceptedByFiler(File file, List<FileFilter> filters) {
|
||||
for (FileFilter filter : filters) {
|
||||
if (filter.accept(file)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException {
|
||||
// check file extension for supported types
|
||||
if (!isAcceptedByFiler(dataSourcePath.toFile(), filtersList)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
run(deviceId, dataSourcePath.toString(), Calendar.getInstance().getTimeZone().getID(), DEFAULT_CHUNK_SIZE, progressMonitor, callBack);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -178,36 +178,30 @@ class AddArchiveTask implements Runnable {
|
||||
|
||||
logger.log(Level.INFO, "Using {0} to process extracted file {1} ", new Object[]{selectedProcessor.getDataSourceType(), file});
|
||||
synchronized (archiveDspLock) {
|
||||
try {
|
||||
UUID taskId = UUID.randomUUID();
|
||||
currentCase.notifyAddingDataSource(taskId);
|
||||
AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, newFilePath);
|
||||
DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock);
|
||||
selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack);
|
||||
archiveDspLock.wait();
|
||||
UUID taskId = UUID.randomUUID();
|
||||
currentCase.notifyAddingDataSource(taskId);
|
||||
AutoIngestDataSource internalDataSource = new AutoIngestDataSource(deviceId, newFilePath);
|
||||
DataSourceProcessorCallback internalArchiveDspCallBack = new AddDataSourceCallback(currentCase, internalDataSource, taskId, archiveDspLock);
|
||||
selectedProcessor.process(deviceId, newFilePath, progressMonitor, internalArchiveDspCallBack);
|
||||
archiveDspLock.wait();
|
||||
|
||||
// at this point we got the content object(s) from the current DSP.
|
||||
// check whether the data source was processed successfully
|
||||
if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
|
||||
|| internalDataSource.getContent().isEmpty()) {
|
||||
// move onto the the next DSP that can process this data source
|
||||
continue;
|
||||
// at this point we got the content object(s) from the current DSP.
|
||||
// check whether the data source was processed successfully
|
||||
if ((internalDataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
|
||||
|| internalDataSource.getContent().isEmpty()) {
|
||||
// move onto the the next DSP that can process this data source
|
||||
for (String errorMessage : internalDataSource.getDataSourceProcessorErrorMessages()) {
|
||||
logger.log(Level.SEVERE, "Data source processor {0} was unable to process {1}: {2}", new Object[]{selectedProcessor.getDataSourceType(), internalDataSource.getPath(), errorMessage});
|
||||
}
|
||||
|
||||
// if we are here it means the data source was addedd successfully
|
||||
success = true;
|
||||
newDataSources.addAll(internalDataSource.getContent());
|
||||
|
||||
// skip all other DSPs for this data source
|
||||
break;
|
||||
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
||||
// Log that the current DSP failed and set the error flag. We consider it an error
|
||||
// if a DSP fails even if a later one succeeds since we expected to be able to process
|
||||
// the data source which each DSP on the list.
|
||||
criticalErrorOccurred = true;
|
||||
errorMessages.add(ex.getMessage());
|
||||
logger.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{newFilePath.toString(), selectedProcessor.getDataSourceType()});
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we are here it means the data source was addedd successfully
|
||||
success = true;
|
||||
newDataSources.addAll(internalDataSource.getContent());
|
||||
|
||||
// skip all other DSPs for this data source
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +265,7 @@ class AddArchiveTask implements Runnable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of data source processors. LocalDisk, LocalFiles, and
|
||||
* Get a list of data source processors. LocalFiles, and
|
||||
* ArchiveDSP are removed from the list.
|
||||
*
|
||||
* @return List of data source processors
|
||||
@@ -285,10 +279,9 @@ class AddArchiveTask implements Runnable {
|
||||
for (Iterator<AutoIngestDataSourceProcessor> iterator = validDataSourceProcessors.iterator(); iterator.hasNext();) {
|
||||
AutoIngestDataSourceProcessor selectedProcessor = iterator.next();
|
||||
|
||||
// skip local files and local disk DSPs, only looking for "valid" data sources.
|
||||
// skip local files, only looking for "valid" data sources.
|
||||
// also skip nested archive files, those will be ingested as logical files and extracted during ingest
|
||||
if ((selectedProcessor instanceof LocalDiskDSProcessor)
|
||||
|| (selectedProcessor instanceof LocalFilesDSProcessor)
|
||||
if ((selectedProcessor instanceof LocalFilesDSProcessor)
|
||||
|| (selectedProcessor instanceof ArchiveExtractorDSProcessor)) {
|
||||
iterator.remove();
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public class ArchiveExtractorDSProcessor implements AutoIngestDataSourceProcesso
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException {
|
||||
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
|
||||
run(deviceId, dataSourcePath.toString(), progressMonitor, callBack);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ import org.sleuthkit.autopsy.core.ServicesMonitor.ServicesMonitorException;
|
||||
import org.sleuthkit.autopsy.core.UserPreferencesException;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
||||
import static org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
|
||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
|
||||
import org.sleuthkit.autopsy.events.AutopsyEvent;
|
||||
@@ -2486,29 +2487,32 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
caseForJob.notifyAddingDataSource(taskId);
|
||||
jobLogger.logDataSourceProcessorSelected(selectedProcessor.getDataSourceType());
|
||||
SYS_LOGGER.log(Level.INFO, "Identified data source type for {0} as {1}", new Object[]{manifestPath, selectedProcessor.getDataSourceType()});
|
||||
try {
|
||||
selectedProcessor.process(dataSource.getDeviceId(), dataSource.getPath(), progressMonitor, callBack);
|
||||
ingestLock.wait();
|
||||
return;
|
||||
} catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) {
|
||||
// Log that the current DSP failed and set the error flag. We consider it an error
|
||||
// if a DSP fails even if a later one succeeds since we expected to be able to process
|
||||
// the data source which each DSP on the list.
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
currentJob.setErrorsOccurred(true);
|
||||
selectedProcessor.process(dataSource.getDeviceId(), dataSource.getPath(), progressMonitor, callBack);
|
||||
ingestLock.wait();
|
||||
|
||||
// at this point we got the content object(s) from the current DSP.
|
||||
// check whether the data source was processed successfully
|
||||
if ((dataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
|
||||
|| dataSource.getContent().isEmpty()) {
|
||||
// move onto the the next DSP that can process this data source
|
||||
jobLogger.logDataSourceProcessorError(selectedProcessor.getDataSourceType());
|
||||
SYS_LOGGER.log(Level.SEVERE, "Exception while processing {0} with data source processor {1}", new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
|
||||
logDataSourceProcessorResult(dataSource);
|
||||
continue;
|
||||
}
|
||||
|
||||
logDataSourceProcessorResult(dataSource);
|
||||
return;
|
||||
}
|
||||
// If we get to this point, none of the processors were successful
|
||||
SYS_LOGGER.log(Level.SEVERE, "All data source processors failed to process {0}", dataSource.getPath());
|
||||
jobLogger.logFailedToAddDataSource();
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
currentJob.setErrorsOccurred(true);
|
||||
// Throw an exception. It will get caught & handled upstream and will result in AIM auto-pause.
|
||||
throw new AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException("Failed to process " + dataSource.getPath() + " with all data source processors");
|
||||
}
|
||||
} finally {
|
||||
currentJob.setDataSourceProcessor(null);
|
||||
logDataSourceProcessorResult(dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2537,8 +2541,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
case NO_ERRORS:
|
||||
jobLogger.logDataSourceAdded();
|
||||
if (dataSource.getContent().isEmpty()) {
|
||||
currentJob.setErrorsOccurred(true);
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
jobLogger.logNoDataSourceContent();
|
||||
}
|
||||
break;
|
||||
@@ -2549,8 +2551,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
}
|
||||
jobLogger.logDataSourceAdded();
|
||||
if (dataSource.getContent().isEmpty()) {
|
||||
currentJob.setErrorsOccurred(true);
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
jobLogger.logNoDataSourceContent();
|
||||
}
|
||||
break;
|
||||
@@ -2559,8 +2559,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
for (String errorMessage : dataSource.getDataSourceProcessorErrorMessages()) {
|
||||
SYS_LOGGER.log(Level.SEVERE, "Critical error running data source processor for {0}: {1}", new Object[]{manifestPath, errorMessage});
|
||||
}
|
||||
currentJob.setErrorsOccurred(true);
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
jobLogger.logFailedToAddDataSource();
|
||||
break;
|
||||
}
|
||||
@@ -2573,8 +2571,6 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
|
||||
* cancelCurrentJob.
|
||||
*/
|
||||
SYS_LOGGER.log(Level.WARNING, "Cancellation while waiting for data source processor for {0}", manifestPath);
|
||||
currentJob.setErrorsOccurred(true);
|
||||
setCaseNodeDataErrorsOccurred(caseDirectoryPath);
|
||||
jobLogger.logDataSourceProcessorCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user