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 directoryh = " + 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());
 
  279             LOGGER.log(Level.INFO, 
"Adding data source {0} ", dataSource.getPath().toString());
 
  282             List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
 
  286                 LOGGER.log(Level.SEVERE, 
"Exception while determining best data source processor for {0}", dataSource.getPath());
 
  292             if (validDataSourceProcessors.isEmpty()) {
 
  294                 LOGGER.log(Level.SEVERE, 
"Unsupported data source {0}", dataSource.getPath());  
 
  302                     UUID taskId = UUID.randomUUID();
 
  303                     caseForJob.notifyAddingDataSource(taskId);
 
  305                     caseForJob.notifyAddingDataSource(taskId);
 
  306                     LOGGER.log(Level.INFO, 
"Identified data source type for {0} as {1}", 
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
 
  307                     selectedProcessor.process(dataSource.getDeviceId(), dataSource.getPath(), progressMonitor, callBack);
 
  312                     if ((dataSource.getResultDataSourceProcessorResultCode() == CRITICAL_ERRORS)
 
  313                             || dataSource.getContent().isEmpty()) {
 
  323                 LOGGER.log(Level.SEVERE, 
"All data source processors failed to process {0}", dataSource.getPath());
 
  338             if (null != resultCode) {
 
  339                 switch (resultCode) {
 
  341                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  343                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  347                     case NONCRITICAL_ERRORS:
 
  349                             LOGGER.log(Level.WARNING, 
"Non-critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  351                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  353                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  357                     case CRITICAL_ERRORS:
 
  359                             LOGGER.log(Level.SEVERE, 
"Critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  361                         LOGGER.log(Level.SEVERE, 
"Failed to add data source to case");
 
  365                 LOGGER.log(Level.WARNING, 
"No result code for data source processor for {0}", dataSource.
getPath());
 
  384             LOGGER.log(Level.INFO, 
"Starting ingest modules analysis for {0} ", dataSource.getPath());
 
  390                     List<String> settingsWarnings = ingestJobSettings.
getWarnings();
 
  391                     if (settingsWarnings.isEmpty()) {
 
  394                         if (null != ingestJob) {
 
  401                             LOGGER.log(Level.INFO, 
"Finished ingest modules analysis for {0} ", dataSource.getPath());
 
  404                                 if (!snapshot.isCancelled()) {
 
  405                                     List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
 
  406                                     if (!cancelledModules.isEmpty()) {
 
  407                                         LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.getPath()));
 
  408                                         for (String module : snapshot.getCancelledDataSourceIngestModules()) {
 
  409                                             LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.getPath()));
 
  412                                     LOGGER.log(Level.INFO, 
"Analysis of data source completed");
 
  414                                     LOGGER.log(Level.WARNING, 
"Analysis of data source cancelled");
 
  417                                         throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.getPath()));
 
  423                                 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.getPath()), error.getThrowable());
 
  425                             LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to ingest job startup error");
 
  426                             throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.getPath()));
 
  428                             LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.getPath()), ingestJobStartResult.
getStartupException());
 
  429                             throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
 
  432                         for (String warning : settingsWarnings) {
 
  433                             LOGGER.log(Level.SEVERE, 
"Ingest job settings error for {0}: {1}", 
new Object[]{dataSource.getPath(), warning});
 
  435                         LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to settings errors");
 
  436                         throw new AnalysisStartupException(
"Error(s) in ingest job settings");
 
  453         Path createCaseFolderPath(Path caseFoldersPath, String caseName) {
 
  455             return Paths.get(caseFoldersPath.toString(), folderName);
 
  468         Path findCaseDirectory(Path folderToSearch, String caseName) {
 
  469             File searchFolder = 
new File(folderToSearch.toString());
 
  470             if (!searchFolder.isDirectory()) {
 
  473             Path caseFolderPath = null;
 
  474             String[] candidateFolders = searchFolder.list(
new CaseFolderFilter(caseName));
 
  475             long mostRecentModified = 0;
 
  476             for (String candidateFolder : candidateFolders) {
 
  477                 File file = 
new File(candidateFolder);
 
  478                 if (file.lastModified() >= mostRecentModified) {
 
  479                     mostRecentModified = file.lastModified();
 
  480                     caseFolderPath = Paths.get(folderToSearch.toString(), file.getPath());
 
  483             return caseFolderPath;
 
  507                     String eventType = 
event.getPropertyName();
 
  557         private final class AnalysisStartupException 
extends Exception {
 
  566                 super(message, cause);
 
  581         public boolean accept(File folder, String fileName) {
 
  582             File file = 
new File(folder, fileName);
 
  585                     if (null != caseName) {
 
  587                         if (fileNamePrefix.equals(caseName)) {
 
  607             for (File file : folder.listFiles()) {
 
  608                 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)