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;
 
   96             LOGGER.log(Level.WARNING, 
"Unable to close the case while shutting down command line ingest manager", ex); 
 
  100         LifecycleManager.getDefault().exit();
 
  108             ingestLock = 
new Object();
 
  111                 LOGGER.log(Level.INFO, 
"Set running with desktop GUI runtime property to false");
 
  113                 LOGGER.log(Level.SEVERE, 
"Failed to set running with desktop GUI runtime property to false", ex);
 
  123             LOGGER.log(Level.INFO, 
"Job processing task started");
 
  127                 LOGGER.log(Level.INFO, 
"Autopsy is running from command line"); 
 
  128                 List<CommandLineCommand> commands = null;
 
  131                 Collection<? extends OptionProcessor> optionProcessors = Lookup.getDefault().lookupAll(OptionProcessor.class);
 
  132                 Iterator<? extends OptionProcessor> optionsIterator = optionProcessors.iterator();
 
  133                 while (optionsIterator.hasNext()) {
 
  135                     OptionProcessor processor = optionsIterator.next();
 
  138                         commands = ((CommandLineOptionProcessor) processor).getCommands();
 
  142                 if (commands == null || commands.isEmpty()) {
 
  143                     LOGGER.log(Level.SEVERE, 
"No command line commands specified");
 
  144                     System.out.println(
"No command line commands specified");
 
  150                     for (CommandLineCommand command : commands) {
 
  151                         CommandLineCommand.CommandType type = command.getType();
 
  155                                     LOGGER.log(Level.INFO, 
"Processing 'Create Case' command");
 
  156                                     System.out.println(
"Processing 'Create Case' command");
 
  157                                     Map<String, String> inputs = command.getInputs();
 
  158                                     String baseCaseName = inputs.get(CommandLineCommand.InputType.CASE_NAME.name());
 
  159                                     String rootOutputDirectory = inputs.get(CommandLineCommand.InputType.CASES_BASE_DIR_PATH.name());
 
  161                                     String caseTypeString = inputs.get(CommandLineCommand.InputType.CASE_TYPE.name());
 
  165                                     openCase(baseCaseName, rootOutputDirectory, caseType);
 
  168                                         OutputGenerator.saveCreateCaseOutput(caseForJob, outputDirPath, baseCaseName);
 
  170                                     String baseCaseName = command.getInputs().get(CommandLineCommand.InputType.CASE_NAME.name());
 
  171                                     LOGGER.log(Level.SEVERE, 
"Error creating or opening case " + baseCaseName, ex);
 
  172                                     System.out.println(
"Error creating or opening case " + baseCaseName);
 
  177                             case ADD_DATA_SOURCE:
 
  179                                     LOGGER.log(Level.INFO, 
"Processing 'Add Data Source' command");
 
  180                                     System.out.println(
"Processing 'Add Data Source' command");
 
  181                                     Map<String, String> inputs = command.getInputs();
 
  184                                     if (caseForJob == null) {
 
  185                                         String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  189                                     String dataSourcePath = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  194                                     OutputGenerator.saveAddDataSourceOutput(caseForJob, dataSource, outputDirPath);
 
  196                                     String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  197                                     LOGGER.log(Level.SEVERE, 
"Error adding data source " + dataSourcePath, ex);
 
  198                                     System.out.println(
"Error adding data source " + dataSourcePath);
 
  205                                     LOGGER.log(Level.INFO, 
"Processing 'Run Ingest' command");
 
  206                                     System.out.println(
"Processing 'Run Ingest' command");
 
  207                                     Map<String, String> inputs = command.getInputs();
 
  210                                     if (caseForJob == null) {
 
  211                                         String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  216                                     if (dataSource == null) {
 
  218                                         String dataSourceId = inputs.get(CommandLineCommand.InputType.DATA_SOURCE_ID.name());
 
  219                                         Long dataSourceObjId = Long.valueOf(dataSourceId);
 
  222                                         Content content = null;
 
  225                                         } 
catch (TskCoreException ex) {
 
  226                                             LOGGER.log(Level.SEVERE, 
"Exception while trying to find data source with object ID " + dataSourceId, ex);
 
  227                                             System.out.println(
"Exception while trying to find data source with object ID " + dataSourceId);
 
  232                                         if (content == null) {
 
  233                                             LOGGER.log(Level.SEVERE, 
"Unable to find data source with object ID {0}", dataSourceId);
 
  234                                             System.out.println(
"Unable to find data source with object ID " + dataSourceId);
 
  241                                         List<Content> contentList = Arrays.asList(
new Content[]{content});
 
  242                                         List<String> errorList = 
new ArrayList<>();
 
  247                                     String ingestProfile = inputs.get(CommandLineCommand.InputType.INGEST_PROFILE_NAME.name());
 
  248                                     analyze(dataSource, ingestProfile);
 
  250                                     String dataSourcePath = command.getInputs().get(CommandLineCommand.InputType.DATA_SOURCE_PATH.name());
 
  251                                     LOGGER.log(Level.SEVERE, 
"Error running ingest on data source " + dataSourcePath, ex);
 
  252                                     System.out.println(
"Error running ingest on data source " + dataSourcePath);
 
  258                             case LIST_ALL_DATA_SOURCES:
 
  260                                     LOGGER.log(Level.INFO, 
"Processing 'List All Data Sources' command");
 
  261                                     System.out.println(
"Processing 'List All Data Sources' command");
 
  262                                     Map<String, String> inputs = command.getInputs();
 
  265                                     if (caseForJob == null) {
 
  266                                         String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  271                                     OutputGenerator.listAllDataSources(caseForJob, outputDirPath);
 
  273                                     String caseDirPath = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  274                                     LOGGER.log(Level.SEVERE, 
"Error opening case in case directory: " + caseDirPath, ex);
 
  275                                     System.out.println(
"Error opening case in case directory: " + caseDirPath);
 
  281                             case GENERATE_REPORTS:
 
  283                                     LOGGER.log(Level.INFO, 
"Processing 'Generate Reports' command");
 
  284                                     System.out.println(
"Processing 'Generate Reports' command");
 
  285                                     Map<String, String> inputs = command.getInputs();
 
  288                                     if (caseForJob == null) {
 
  289                                         String caseDirPath = inputs.get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  293                                     String reportName = inputs.get(CommandLineCommand.InputType.REPORT_PROFILE_NAME.name());
 
  294                                     if (reportName == null) {
 
  303                                     String caseDirPath = command.getInputs().get(CommandLineCommand.InputType.CASE_FOLDER_PATH.name());
 
  304                                     LOGGER.log(Level.SEVERE, 
"Error opening case in case directory: " + caseDirPath, ex);
 
  305                                     System.out.println(
"Error opening case in case directory: " + caseDirPath);
 
  314                 } 
catch (Throwable ex) {
 
  322                     LOGGER.log(Level.SEVERE, 
"Unexpected error", ex);
 
  323                     System.out.println(
"Unexpected error. Exiting...");
 
  329                         LOGGER.log(Level.WARNING, 
"Exception while closing case", ex);
 
  330                         System.out.println(
"Exception while closing case");
 
  335                 LOGGER.log(Level.INFO, 
"Job processing task finished");
 
  336                 System.out.println(
"Job processing task finished");
 
  356             LOGGER.log(Level.INFO, 
"Opening case {0} in directory {1}", 
new Object[]{baseCaseName, rootOutputDirectory});
 
  357             Path caseDirectoryPath = 
findCaseDirectory(Paths.get(rootOutputDirectory), baseCaseName);
 
  358             if (null != caseDirectoryPath) {
 
  360                 LOGGER.log(Level.SEVERE, 
"Case {0} already exists. Case name must be unique. Exiting", baseCaseName);
 
  361                 throw new CaseActionException(
"Case " + baseCaseName + 
" already exists. Case name must be unique. Exiting");
 
  373             LOGGER.log(Level.INFO, 
"Opened case {0}", caseForJob.
getName());
 
  391             LOGGER.log(Level.INFO, 
"Adding data source {0} ", dataSource.
getPath().toString());
 
  394             List<AutoIngestDataSourceProcessor> validDataSourceProcessors;
 
  398                 LOGGER.log(Level.SEVERE, 
"Exception while determining best data source processor for {0}", dataSource.
getPath());
 
  404             if (validDataSourceProcessors.isEmpty()) {
 
  406                 LOGGER.log(Level.SEVERE, 
"Unsupported data source {0}", dataSource.
getPath());  
 
  414                     UUID taskId = UUID.randomUUID();
 
  418                     LOGGER.log(Level.INFO, 
"Identified data source type for {0} as {1}", 
new Object[]{dataSource.getPath(), selectedProcessor.getDataSourceType()});
 
  419                     selectedProcessor.process(dataSource.
getDeviceId(), dataSource.
getPath(), progressMonitor, callBack);
 
  435                 LOGGER.log(Level.SEVERE, 
"All data source processors failed to process {0}", dataSource.
getPath());
 
  450             if (null != resultCode) {
 
  451                 switch (resultCode) {
 
  453                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  455                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  459                     case NONCRITICAL_ERRORS:
 
  461                             LOGGER.log(Level.WARNING, 
"Non-critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  463                         LOGGER.log(Level.INFO, 
"Added data source to case");
 
  465                             LOGGER.log(Level.SEVERE, 
"Data source failed to produce content");
 
  469                     case CRITICAL_ERRORS:
 
  471                             LOGGER.log(Level.SEVERE, 
"Critical error running data source processor for {0}: {1}", 
new Object[]{dataSource.getPath(), errorMessage});
 
  473                         LOGGER.log(Level.SEVERE, 
"Failed to add data source to case");
 
  477                 LOGGER.log(Level.WARNING, 
"No result code for data source processor for {0}", dataSource.
getPath());
 
  500             LOGGER.log(Level.INFO, 
"Starting ingest modules analysis for {0} ", dataSource.
getPath());
 
  505             if (!ingestProfileName.isEmpty()) {
 
  507                 if (selectedProfile == null) {
 
  509                     LOGGER.log(Level.SEVERE, 
"Unable to find ingest profile: {0}. Ingest cancelled!", ingestProfileName);
 
  510                     System.out.println(
"Unable to find ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  516                 if (selectedFileSet == null) {
 
  518                     LOGGER.log(Level.SEVERE, 
"Unable to find file filter {0} for ingest profile: {1}. Ingest cancelled!", 
new Object[]{selectedProfile.getFileIngestFilter(), ingestProfileName});
 
  519                     System.out.println(
"Unable to find file filter " + selectedProfile.getFileIngestFilter() + 
" for ingest profile: " + ingestProfileName + 
". Ingest cancelled!");
 
  529                     if (selectedProfile == null || selectedFileSet == null) {
 
  538                     List<String> settingsWarnings = ingestJobSettings.
getWarnings();
 
  539                     if (settingsWarnings.isEmpty()) {
 
  542                         if (null != ingestJob) {
 
  549                             LOGGER.log(Level.INFO, 
"Finished ingest modules analysis for {0} ", dataSource.
getPath());
 
  552                                 if (!snapshot.isCancelled()) {
 
  553                                     List<String> cancelledModules = snapshot.getCancelledDataSourceIngestModules();
 
  554                                     if (!cancelledModules.isEmpty()) {
 
  555                                         LOGGER.log(Level.WARNING, String.format(
"Ingest module(s) cancelled for %s", dataSource.
getPath()));
 
  556                                         for (String module : snapshot.getCancelledDataSourceIngestModules()) {
 
  557                                             LOGGER.log(Level.WARNING, String.format(
"%s ingest module cancelled for %s", module, dataSource.
getPath()));
 
  560                                     LOGGER.log(Level.INFO, 
"Analysis of data source completed");
 
  562                                     LOGGER.log(Level.WARNING, 
"Analysis of data source cancelled");
 
  565                                         throw new AnalysisStartupException(String.format(
"Analysis cancelled due to %s for %s", cancellationReason.getDisplayName(), dataSource.
getPath()));
 
  571                                 LOGGER.log(Level.SEVERE, String.format(
"%s ingest module startup error for %s", error.getModuleDisplayName(), dataSource.
getPath()), error.getThrowable());
 
  573                             LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to ingest job startup error");
 
  574                             throw new AnalysisStartupException(String.format(
"Error(s) during ingest module startup for %s", dataSource.
getPath()));
 
  576                             LOGGER.log(Level.SEVERE, String.format(
"Ingest manager ingest job start error for %s", dataSource.
getPath()), ingestJobStartResult.
getStartupException());
 
  577                             throw new AnalysisStartupException(
"Ingest manager error starting job", ingestJobStartResult.
getStartupException());
 
  580                         for (String warning : settingsWarnings) {
 
  581                             LOGGER.log(Level.SEVERE, 
"Ingest job settings error for {0}: {1}", 
new Object[]{dataSource.getPath(), warning});
 
  583                         LOGGER.log(Level.SEVERE, 
"Failed to analyze data source due to settings errors");
 
  584                         throw new AnalysisStartupException(
"Error(s) in ingest job settings");
 
  605                 if (profile.toString().equalsIgnoreCase(ingestProfileName)) {
 
  607                     selectedProfile = profile;
 
  611             return selectedProfile;
 
  627                     fileIngestFilters.put(fSet.getName(), fSet);
 
  629                 return fileIngestFilters.get(filterName);
 
  631                 LOGGER.log(Level.SEVERE, 
"Failed to get file ingest filter: " + filterName, ex); 
 
  647             return Paths.get(caseFoldersPath.toString(), folderName);
 
  661             File searchFolder = 
new File(folderToSearch.toString());
 
  662             if (!searchFolder.isDirectory()) {
 
  665             Path caseFolderPath = null;
 
  666             String[] candidateFolders = searchFolder.list(
new CaseFolderFilter(caseName));
 
  667             long mostRecentModified = 0;
 
  668             for (String candidateFolder : candidateFolders) {
 
  669                 File file = 
new File(candidateFolder);
 
  670                 if (file.lastModified() >= mostRecentModified) {
 
  671                     mostRecentModified = file.lastModified();
 
  672                     caseFolderPath = Paths.get(folderToSearch.toString(), file.getPath());
 
  675             return caseFolderPath;
 
  710                     String eventType = 
event.getPropertyName();
 
  760         private final class AnalysisStartupException 
extends Exception {
 
  769                 super(message, cause);
 
  784         public boolean accept(File folder, String fileName) {
 
  785             File file = 
new File(folder, fileName);
 
  788                     if (null != caseName) {
 
  790                         if (fileNamePrefix.equals(caseName)) {
 
  810             for (File file : folder.listFiles()) {
 
  811                 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()