19 package org.sleuthkit.autopsy.commandlineingest;
21 import java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
24 import java.io.FilenameFilter;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.List;
28 import java.util.UUID;
29 import java.util.Collection;
30 import java.util.Iterator;
31 import java.util.logging.Level;
32 import org.netbeans.spi.sendopts.OptionProcessor;
33 import org.openide.LifecycleManager;
34 import org.openide.util.Lookup;
82 LOGGER.log(Level.WARNING,
"Unable to close the case while shutting down command line ingest manager", ex);
86 LifecycleManager.getDefault().exit();
94 ingestLock =
new Object();
97 LOGGER.log(Level.INFO,
"Set running with desktop GUI runtime property to false");
99 LOGGER.log(Level.SEVERE,
"Failed to set running with desktop GUI runtime property to false", ex);
104 LOGGER.log(Level.INFO,
"Job processing task started");
108 LOGGER.log(Level.INFO,
"Autopsy is running from command line");
109 String dataSourcePath =
"";
110 String baseCaseName =
"";
113 Collection<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
114 Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
115 while (optionsIterator.hasNext()) {
117 OptionProcessor processor = optionsIterator.next();
120 dataSourcePath = ((CommandLineOptionProcessor) processor).getPathToDataSource();
121 baseCaseName = ((CommandLineOptionProcessor) processor).getBaseCaseName();
125 LOGGER.log(Level.INFO,
"Data source path = {0}", dataSourcePath);
126 LOGGER.log(Level.INFO,
"Case name = {0}", baseCaseName);
127 System.out.println(
"Data source path = " + dataSourcePath);
128 System.out.println(
"Case name = " + baseCaseName);
131 if (dataSourcePath.isEmpty()) {
132 LOGGER.log(Level.SEVERE,
"Data source path not specified");
133 System.out.println(
"Data source path not specified");
137 if (baseCaseName.isEmpty()) {
138 LOGGER.log(Level.SEVERE,
"Case name not specified");
139 System.out.println(
"Case name not specified");
143 if (!(
new File(dataSourcePath).exists())) {
144 LOGGER.log(Level.SEVERE,
"Data source file not found {0}", dataSourcePath);
145 System.out.println(
"Data source file not found " + dataSourcePath);
151 LOGGER.log(Level.INFO,
"Output directory = {0}", rootOutputDir);
152 System.out.println(
"Output directory = " + rootOutputDir);
154 if (rootOutputDir.isEmpty()) {
155 LOGGER.log(Level.SEVERE,
"Output directory not specified, please configure Command Line Options Panel (in Tools -> Options)");
156 System.out.println(
"Output directory not specified, please configure Command Line Options Panel (in Tools -> Options)");
160 if (!(
new File(rootOutputDir).exists())) {
161 LOGGER.log(Level.SEVERE,
"The output directory doesn't exist {0}", rootOutputDir);
162 System.out.println(
"The output directory doesn't exist " + rootOutputDir);
165 rootOutputDirectory = Paths.get(rootOutputDir);
170 caseForJob =
openCase(baseCaseName);
172 LOGGER.log(Level.SEVERE,
"Error creating or opening case " + baseCaseName, ex);
173 System.out.println(
"Error creating or opening case " + baseCaseName);
177 if (caseForJob == null) {
178 LOGGER.log(Level.SEVERE,
"Error creating or opening case {0}", baseCaseName);
179 System.out.println(
"Error creating or opening case " + baseCaseName);
197 LOGGER.log(Level.SEVERE,
"Unable to ingest data source " + dataSourcePath +
". Exiting...", ex);
198 System.out.println(
"Unable to ingest data source " + dataSourcePath +
". Exiting...");
199 }
catch (Throwable ex) {
206 LOGGER.log(Level.SEVERE,
"Unexpected error while ingesting data source " + dataSourcePath, ex);
207 System.out.println(
"Unexpected error while ingesting data source " + dataSourcePath +
". Exiting...");
213 LOGGER.log(Level.WARNING,
"Exception while closing case", ex);
214 System.out.println(
"Exception while closing case");
219 LOGGER.log(Level.INFO,
"Job processing task finished");
220 System.out.println(
"Job processing task finished");
235 Content content = dataSource.
getContent().get(0);
236 return content.getId();
241 LOGGER.log(Level.INFO,
"Opening case {0}", baseCaseName);
243 Path caseDirectoryPath = findCaseDirectory(rootOutputDirectory, baseCaseName);
244 if (null != caseDirectoryPath) {
246 LOGGER.log(Level.SEVERE,
"Case {0} already exists. Case name must be unique. Exiting", baseCaseName);
247 throw new CaseActionException(
"Case " + baseCaseName +
" already exists. Case name must be unique. Exiting");
249 caseDirectoryPath = createCaseFolderPath(rootOutputDirectory, baseCaseName);
259 LOGGER.log(Level.INFO,
"Opened case {0}", caseForJob.
getName());
280 LOGGER.log(Level.INFO,
"Adding data source {0} ", dataSource.getPath().toString());
283 List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
287 LOGGER.log(Level.SEVERE,
"Exception while determining best data source processor for {0}", dataSource.getPath());
293 if (validDataSourceProcessors.isEmpty()) {
295 LOGGER.log(Level.SEVERE,
"Unsupported data source {0}", dataSource.getPath());
303 UUID taskId = UUID.randomUUID();
304 caseForJob.notifyAddingDataSource(taskId);
306 caseForJob.notifyAddingDataSource(taskId);
307 LOGGER.log(Level.INFO,
"Identified data source type for {0} as {1}",
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
308 selectedProcessor.process(dataSource.getDeviceId(), dataSource.getPath(), progressMonitor, callBack);
313 if ((dataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
314 || dataSource.getContent().isEmpty()) {
324 LOGGER.log(Level.SEVERE,
"All data source processors failed to process {0}", dataSource.getPath());
339 if (null != resultCode) {
340 switch (resultCode) {
342 LOGGER.log(Level.INFO,
"Added data source to case");
344 LOGGER.log(Level.SEVERE,
"Data source failed to produce content");
348 case NONCRITICAL_ERRORS:
350 LOGGER.log(Level.WARNING,
"Non-critical error running data source processor for {0}: {1}",
new Object[]{dataSource.getPath(), errorMessage});
352 LOGGER.log(Level.INFO,
"Added data source to case");
354 LOGGER.log(Level.SEVERE,
"Data source failed to produce content");
358 case CRITICAL_ERRORS:
360 LOGGER.log(Level.SEVERE,
"Critical error running data source processor for {0}: {1}",
new Object[]{dataSource.getPath(), errorMessage});
362 LOGGER.log(Level.SEVERE,
"Failed to add data source to case");
366 LOGGER.log(Level.WARNING,
"No result code for data source processor for {0}", dataSource.
getPath());
385 LOGGER.log(Level.INFO,
"Starting ingest modules analysis for {0} ", dataSource.getPath());
391 List<String> settingsWarnings = ingestJobSettings.
getWarnings();
392 if (settingsWarnings.isEmpty()) {
395 if (null != ingestJob) {
402 LOGGER.log(Level.INFO,
"Finished ingest modules analysis for {0} ", dataSource.getPath());
405 if (!snapshot.isCancelled()) {
406 List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
407 if (!cancelledModules.isEmpty()) {
408 LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.getPath()));
409 for (String module : snapshot.getCancelledDataSourceIngestModules()) {
410 LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.getPath()));
413 LOGGER.log(Level.INFO,
"Analysis of data source completed");
415 LOGGER.log(Level.WARNING,
"Analysis of data source cancelled");
418 throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.getPath()));
424 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.getPath()), error.getThrowable());
426 LOGGER.log(Level.SEVERE,
"Failed to analyze data source due to ingest job startup error");
427 throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.getPath()));
429 LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.getPath()), ingestJobStartResult.
getStartupException());
430 throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
433 for (String warning : settingsWarnings) {
434 LOGGER.log(Level.SEVERE,
"Ingest job settings error for {0}: {1}",
new Object[]{dataSource.getPath(), warning});
436 LOGGER.log(Level.SEVERE,
"Failed to analyze data source due to settings errors");
437 throw new AnalysisStartupException(
"Error(s) in ingest job settings");
454 Path createCaseFolderPath(Path caseFoldersPath, String caseName) {
456 return Paths.get(caseFoldersPath.toString(), folderName);
469 Path findCaseDirectory(Path folderToSearch, String caseName) {
470 File searchFolder =
new File(folderToSearch.toString());
471 if (!searchFolder.isDirectory()) {
474 Path caseFolderPath = null;
475 String[] candidateFolders = searchFolder.list(
new CaseFolderFilter(caseName));
476 long mostRecentModified = 0;
477 for (String candidateFolder : candidateFolders) {
478 File file =
new File(candidateFolder);
479 if (file.lastModified() >= mostRecentModified) {
480 mostRecentModified = file.lastModified();
481 caseFolderPath = Paths.get(folderToSearch.toString(), file.getPath());
484 return caseFolderPath;
508 String eventType =
event.getPropertyName();
558 private final class AnalysisStartupException
extends Exception {
567 super(message, cause);
582 public boolean accept(File folder, String fileName) {
583 File file =
new File(folder, fileName);
586 if (null != caseName) {
588 if (fileNamePrefix.equals(caseName)) {
608 for (File file : folder.listFiles()) {
609 if (file.getName().toLowerCase().endsWith(CASE_METADATA_EXT) && file.isFile()) {
synchronized List< String > getDataSourceProcessorErrorMessages()
static List< AutoIngestDataSourceProcessor > getOrderedListOfDataSourceProcessors(Path dataSourcePath)
void logDataSourceProcessorResult(AutoIngestDataSource dataSource)
static synchronized IngestManager getInstance()
static void closeCurrentCase()
void analyze(AutoIngestDataSource dataSource)
static String getReportFileName()
static void createCaseDirectory(String caseDirPath, CaseType caseType)
static final String CASE_METADATA_EXT
IngestJobStartResult beginIngestJob(Collection< Content > dataSources, IngestJobSettings settings)
AnalysisStartupException(String message)
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode()
CommandLineIngestManager()
String getReportDirectory()
void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource)
void propertyChange(PropertyChangeEvent event)
static boolean endsWithTimeStamp(String inputString)
static String createTimeStamp()
void removeIngestJobEventListener(final PropertyChangeListener listener)
static String getCommandLineModeResultsFolder()
List< IngestModuleError > getModuleErrors()
static final Logger LOGGER
static final long serialVersionUID
void addIngestJobEventListener(final PropertyChangeListener listener)
ProgressSnapshot getSnapshot()
void setProgressText(final String text)
AnalysisStartupException(String message, Throwable cause)
boolean accept(File folder, String fileName)
static int getTimeStampLength()
static synchronized void setRunningWithGUI(boolean runningWithGUI)
Case openCase(String baseCaseName)
List< String > getWarnings()
synchronized List< Content > getContent()
static boolean hasCaseMetadataFile(File folder)
static Case getCurrentCase()
synchronized static Logger getLogger(String name)
void setIndeterminate(final boolean indeterminate)
static String getCommandLineModeIngestModuleContextString()
void setProgress(final int progress)
static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
IngestManager.IngestManagerException getStartupException()
Long getDataSourceId(AutoIngestDataSource dataSource)