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.ArrayList;
 
   28 import java.util.Arrays;
 
   29 import java.util.List;
 
   30 import java.util.UUID;
 
   31 import java.util.Collection;
 
   32 import java.util.EnumSet;
 
   33 import java.util.Iterator;
 
   36 import java.util.logging.Level;
 
   37 import org.netbeans.spi.sendopts.OptionProcessor;
 
   38 import org.openide.LifecycleManager;
 
   39 import org.openide.util.Lookup;
 
   95             LOGGER.log(Level.WARNING, 
"Unable to close the case while shutting down command line ingest manager", ex); 
 
   99         LifecycleManager.getDefault().exit();
 
  107             ingestLock = 
new Object();
 
  110                 LOGGER.log(Level.INFO, 
"Set running with desktop GUI runtime property to false");
 
  112                 LOGGER.log(Level.SEVERE, 
"Failed to set running with desktop GUI runtime property to false", ex);
 
  122             LOGGER.log(Level.INFO, 
"Job processing task started");
 
  126                 LOGGER.log(Level.INFO, 
"Autopsy is running from command line"); 
 
  127                 List<CommandLineCommand> commands = null;
 
  130                 Collection<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
 
  131                 Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
 
  132                 while (optionsIterator.hasNext()) {
 
  134                     OptionProcessor processor = optionsIterator.next();
 
  137                         commands = ((CommandLineOptionProcessor) processor).getCommands();
 
  141                 if (commands == null || commands.isEmpty()) {
 
  142                     LOGGER.log(Level.SEVERE, 
"No command line commands specified");
 
  143                     System.out.println(
"No command line commands specified");
 
  149                     for (CommandLineCommand command : commands) {
 
  150                         CommandLineCommand.CommandType type = command.getType();
 
  154                                 LOGGER.log(Level.INFO, 
"Processing 'Create Case' command");
 
  155                                 System.out.println(
"Processing 'Create Case' command");
 
  156                                 Map<String, String> inputs = command.getInputs();
 
  157                                 String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
 
  158                                 String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  160                                 String caseTypeString = inputs.get(CommandLineCommand.InputType.CASE_TYPE.name());
 
  164                                 openCase(baseCaseName, rootOutputDirectory, caseType);
 
  167                                 OutputGenerator.saveCreateCaseOutput(caseForJob, outputDirPath, baseCaseName);
 
  169                                 String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
 
  170                                 LOGGER.log(Level.SEVERE, 
"Error creating or opening case " + baseCaseName, ex);
 
  171                                 System.out.println(
"Error creating or opening case " + baseCaseName);
 
  176                             case ADD_DATA_SOURCE:
 
  178                                 LOGGER.log(Level.INFO, 
"Processing 'Add Data Source' command");
 
  179                                 System.out.println(
"Processing 'Add Data Source' command");
 
  180                                 Map<String, String> inputs = command.getInputs();
 
  183                                 if (caseForJob == null) {
 
  184                                     String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  188                                 String dataSourcePath = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  193                                 OutputGenerator.saveAddDataSourceOutput(caseForJob, dataSource, outputDirPath);
 
  195                                 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  196                                 LOGGER.log(Level.SEVERE, 
"Error adding data source " + dataSourcePath, ex);
 
  197                                 System.out.println(
"Error adding data source " + dataSourcePath);
 
  204                                 LOGGER.log(Level.INFO, 
"Processing 'Run Ingest' command");
 
  205                                 System.out.println(
"Processing 'Run Ingest' command");
 
  206                                 Map<String, String> inputs = command.getInputs();
 
  209                                 if (caseForJob == null) {
 
  210                                     String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  215                                 if (dataSource == null) {
 
  217                                     String dataSourceId = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_ID.name());
 
  218                                     Long dataSourceObjId = Long.valueOf(dataSourceId);
 
  221                                     Content content = null;
 
  224                                     } 
catch (TskCoreException ex) {
 
  225                                         LOGGER.log(Level.SEVERE, 
"Exception while trying to find data source with object ID " + dataSourceId, ex);
 
  226                                         System.out.println(
"Exception while trying to find data source with object ID " + dataSourceId);
 
  231                                     if (content == null) {
 
  232                                         LOGGER.log(Level.SEVERE, 
"Unable to find data source with object ID {0}", dataSourceId);
 
  233                                         System.out.println(
"Unable to find data source with object ID " + dataSourceId);
 
  240                                     List<Content> contentList = Arrays.asList(
new Content[]{content});
 
  241                                     List<String> errorList = 
new ArrayList<>();
 
  246                                 String ingestProfile = inputs.get(CommandLineCommand.InputType.INGEST_PROFILE_NAME.name());
 
  247                                 analyze(dataSource, ingestProfile);
 
  249                                 String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  250                                 LOGGER.log(Level.SEVERE, 
"Error running ingest on data source " + dataSourcePath, ex);
 
  251                                 System.out.println(
"Error running ingest on data source " + dataSourcePath);
 
  257                             case LIST_ALL_DATA_SOURCES:
 
  259                                 LOGGER.log(Level.INFO, 
"Processing 'List All Data Sources' command");
 
  260                                 System.out.println(
"Processing 'List All Data Sources' command");
 
  261                                 Map<String, String> inputs = command.getInputs();
 
  264                                 if (caseForJob == null) {
 
  265                                     String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  270                                 OutputGenerator.listAllDataSources(caseForJob, outputDirPath);
 
  272                                 String caseDirPath = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  273                                 LOGGER.log(Level.SEVERE, 
"Error opening case in case directory: " + caseDirPath, ex);
 
  274                                 System.out.println(
"Error opening case in case directory: " + caseDirPath);
 
  280                             case GENERATE_REPORTS:
 
  282                                 LOGGER.log(Level.INFO, 
"Processing 'Generate Reports' command");
 
  283                                 System.out.println(
"Processing 'Generate Reports' command");
 
  284                                 Map<String, String> inputs = command.getInputs();
 
  287                                 if (caseForJob == null) {
 
  288                                     String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  292                                 String reportName = inputs.get(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name());
 
  293                                 if (reportName == null) {
 
  302                                 String caseDirPath = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  303                                 LOGGER.log(Level.SEVERE, 
"Error opening case in case directory: " + caseDirPath, ex);
 
  304                                 System.out.println(
"Error opening case in case directory: " + caseDirPath);
 
  313                 } 
catch (Throwable ex) {
 
  321                     LOGGER.log(Level.SEVERE, 
"Unexpected error", ex);
 
  322                     System.out.println(
"Unexpected error. Exiting...");
 
  328                         LOGGER.log(Level.WARNING, 
"Exception while closing case", ex);
 
  329                         System.out.println(
"Exception while closing case");
 
  334                 LOGGER.log(Level.INFO, 
"Job processing task finished");
 
  335                 System.out.println(
"Job processing task finished");
 
  355             LOGGER.log(Level.INFO, 
"Opening case {0} in directory {1}", 
new Object[]{baseCaseName, rootOutputDirectory});
 
  356             Path caseDirectoryPath = 
findCaseDirectory(Paths.get(rootOutputDirectory), baseCaseName);
 
  357             if (null != caseDirectoryPath) {
 
  359                 LOGGER.log(Level.SEVERE, 
"Case {0} already exists. Case name must be unique. Exiting", baseCaseName);
 
  360                 throw new CaseActionException(
"Case " + baseCaseName + 
" already exists. Case name must be unique. Exiting");
 
  372             LOGGER.log(Level.INFO, 
"Opened case {0}", caseForJob.
getName());
 
  393             LOGGER.log(Level.INFO, 
"Adding data source {0} ", dataSource.
getPath().toString());
 
  396             List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
 
  400                 LOGGER.log(Level.SEVERE, 
"Exception while determining best data source processor for {0}", dataSource.
getPath());
 
  406             if (validDataSourceProcessors.isEmpty()) {
 
  408                 LOGGER.log(Level.SEVERE, 
"Unsupported data source {0}", dataSource.
getPath());  
 
  416                     UUID taskId = UUID.randomUUID();
 
  420                     LOGGER.log(Level.INFO, 
"Identified data source type for {0} as {1}", 
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
 
  421                     selectedProcessor.process(dataSource.
getDeviceId(), dataSource.
getPath(), progressMonitor, callBack);
 
  437                 LOGGER.log(Level.SEVERE, 
"All data source processors failed to process {0}", dataSource.
getPath());
 
  452             if (null != resultCode) {
 
  453                 switch (resultCode) {
 
  455                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  457                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  461                     case NONCRITICAL_ERRORS:
 
  463                             LOGGER.log(Level.WARNING, 
"Non-critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  465                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  467                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  471                     case CRITICAL_ERRORS:
 
  473                             LOGGER.log(Level.SEVERE, 
"Critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  475                         LOGGER.log(Level.SEVERE, 
"Failed to add data source to case");
 
  479                 LOGGER.log(Level.WARNING, 
"No result code for data source processor for {0}", dataSource.
getPath());
 
  502             LOGGER.log(Level.INFO, 
"Starting ingest modules analysis for {0} ", dataSource.
getPath());
 
  507             if (!ingestProfileName.isEmpty()) {
 
  509                 if (selectedProfile == null) {
 
  511                     LOGGER.log(Level.SEVERE, 
"Unable to find ingest profile: {0}. Ingest cancelled!", ingestProfileName);
 
  512                     System.out.println(
"Unable to find ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  518                 if (selectedFileSet == null) {
 
  520                     LOGGER.log(Level.SEVERE, 
"Unable to find file filter {0} for ingest profile: {1}. Ingest cancelled!", 
new Object[]{selectedProfile.getFileIngestFilter(), ingestProfileName});
 
  521                     System.out.println(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() + 
" for ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  531                     if (selectedProfile == null || selectedFileSet == null) {
 
  540                     List<String> settingsWarnings = ingestJobSettings.
getWarnings();
 
  541                     if (settingsWarnings.isEmpty()) {
 
  544                         if (null != ingestJob) {
 
  551                             LOGGER.log(Level.INFO, 
"Finished ingest modules analysis for {0} ", dataSource.
getPath());
 
  554                                 if (!snapshot.isCancelled()) {
 
  555                                     List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
 
  556                                     if (!cancelledModules.isEmpty()) {
 
  557                                         LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.
getPath()));
 
  558                                         for (String module : snapshot.getCancelledDataSourceIngestModules()) {
 
  559                                             LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.
getPath()));
 
  562                                     LOGGER.log(Level.INFO, 
"Analysis of data source completed");
 
  564                                     LOGGER.log(Level.WARNING, 
"Analysis of data source cancelled");
 
  567                                         throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.
getPath()));
 
  573                                 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.
getPath()), error.getThrowable());
 
  575                             LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to ingest job startup error");
 
  576                             throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.
getPath()));
 
  578                             LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.
getPath()), ingestJobStartResult.
getStartupException());
 
  579                             throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
 
  582                         for (String warning : settingsWarnings) {
 
  583                             LOGGER.log(Level.SEVERE, 
"Ingest job settings error for {0}: {1}", 
new Object[]{dataSource.getPath(), warning});
 
  585                         LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to settings errors");
 
  586                         throw new AnalysisStartupException(
"Error(s) in ingest job settings");
 
  607                 if (profile.toString().equalsIgnoreCase(ingestProfileName)) {
 
  609                     selectedProfile = profile;
 
  613             return selectedProfile;
 
  629                     fileIngestFilters.put(fSet.getName(), fSet);
 
  631                 return fileIngestFilters.get(filterName);
 
  633                 LOGGER.log(Level.SEVERE, 
"Failed to get file ingest filter: " + filterName, ex); 
 
  649             return Paths.get(caseFoldersPath.toString(), folderName);
 
  663             File searchFolder = 
new File(folderToSearch.toString());
 
  664             if (!searchFolder.isDirectory()) {
 
  667             Path caseFolderPath = null;
 
  668             String[] candidateFolders = searchFolder.list(
new CaseFolderFilter(caseName));
 
  669             long mostRecentModified = 0;
 
  670             for (String candidateFolder : candidateFolders) {
 
  671                 File file = 
new File(candidateFolder);
 
  672                 if (file.lastModified() >= mostRecentModified) {
 
  673                     mostRecentModified = file.lastModified();
 
  674                     caseFolderPath = Paths.get(folderToSearch.toString(), file.getPath());
 
  677             return caseFolderPath;
 
  712                     String eventType = 
event.getPropertyName();
 
  762         private final class AnalysisStartupException 
extends Exception {
 
  771                 super(message, cause);
 
  786         public boolean accept(File folder, String fileName) {
 
  787             File file = 
new File(folder, fileName);
 
  790                     if (null != caseName) {
 
  792                         if (fileNamePrefix.equals(caseName)) {
 
  812             for (File file : folder.listFiles()) {
 
  813                 if (file.getName().toLowerCase().endsWith(CASE_METADATA_EXT) && file.isFile()) {
 
synchronized List< String > getDataSourceProcessorErrorMessages()
 
static List< AutoIngestDataSourceProcessor > getOrderedListOfDataSourceProcessors(Path dataSourcePath)
 
void logDataSourceProcessorResult(AutoIngestDataSource dataSource)
 
void openCase(String baseCaseName, String rootOutputDirectory, CaseType caseType)
 
static synchronized IngestManager getInstance()
 
static List< FilesSet > getStandardFileIngestFilters()
 
static void closeCurrentCase()
 
static void createCaseDirectory(String caseDirPath, CaseType caseType)
 
String getCaseDirectory()
 
IngestProfiles.IngestProfile getSelectedProfile(String ingestProfileName)
 
static final String CASE_METADATA_EXT
 
IngestJobStartResult beginIngestJob(Collection< Content > dataSources, IngestJobSettings settings)
 
AutoIngestDataSource dataSource
 
AnalysisStartupException(String message)
 
synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode()
 
CommandLineIngestManager()
 
static synchronized FilesSetsManager getInstance()
 
Path findCaseDirectory(Path folderToSearch, String caseName)
 
Path createCaseFolderPath(Path caseFoldersPath, String caseName)
 
void runDataSourceProcessor(Case caseForJob, AutoIngestDataSource dataSource)
 
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
 
void propertyChange(PropertyChangeEvent event)
 
static boolean endsWithTimeStamp(String inputString)
 
static final String LOG_DIR_NAME
 
static String createTimeStamp()
 
void removeIngestJobEventListener(final PropertyChangeListener listener)
 
Map< String, FilesSet > getCustomFileIngestFilters()
 
List< IngestModuleError > getModuleErrors()
 
static final Logger LOGGER
 
static final long serialVersionUID
 
void addIngestJobEventListener(final PropertyChangeListener listener)
 
void setFileFilter(FilesSet fileIngestFilter)
 
ProgressSnapshot getSnapshot()
 
String getOutputDirPath(Case caseForJob)
 
void setProgressText(final String text)
 
static synchronized List< IngestProfile > getIngestProfiles()
 
AnalysisStartupException(String message, Throwable cause)
 
SleuthkitCase getSleuthkitCase()
 
FilesSet getSelectedFilter(String filterName)
 
boolean accept(File folder, String fileName)
 
void analyze(AutoIngestDataSource dataSource, String ingestProfileName)
 
static int getTimeStampLength()
 
static synchronized void setRunningWithGUI(boolean runningWithGUI)
 
List< String > getWarnings()
 
synchronized List< Content > getContent()
 
synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List< String > errorMessages, List< Content > content)
 
static boolean hasCaseMetadataFile(File folder)
 
static Case getCurrentCase()
 
synchronized static Logger getLogger(String name)
 
static Case getCurrentCaseThrows()
 
void setIndeterminate(final boolean indeterminate)
 
static String getCommandLineModeIngestModuleContextString()
 
void setProgress(final int progress)
 
void notifyAddingDataSource(UUID eventId)
 
static String getDefaultReportingConfigName()
 
static void createAsCurrentCase(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType)
 
IngestManager.IngestManagerException getStartupException()