19 package org.sleuthkit.autopsy.casemodule;
 
   21 import java.util.ArrayList;
 
   22 import java.util.List;
 
   23 import java.util.logging.Level;
 
   24 import javax.annotation.concurrent.GuardedBy;
 
   25 import org.apache.commons.lang3.StringUtils;
 
   26 import org.openide.util.NbBundle;
 
   42 class AddImageTask 
implements Runnable {
 
   44     private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
 
   45     private final String deviceId;
 
   46     private final String imagePath;
 
   47     private final int sectorSize;
 
   48     private final String timeZone;
 
   49     private final ImageWriterSettings imageWriterSettings;
 
   50     private final boolean ignoreFatOrphanFiles;
 
   51     private final String md5;
 
   52     private final String sha1;
 
   53     private final String sha256;
 
   54     private final DataSourceProcessorProgressMonitor progressMonitor;
 
   55     private final DataSourceProcessorCallback callback;
 
   56     private boolean criticalErrorOccurred;
 
   69     private final Object tskAddImageProcessLock;
 
   70     @GuardedBy(
"tskAddImageProcessLock")
 
   71     private 
boolean tskAddImageProcessStopped;
 
   72     private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
 
   98     AddImageTask(String deviceId, String imagePath, 
int sectorSize, String timeZone, 
boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings,
 
   99             DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
 
  100         this.deviceId = deviceId;
 
  101         this.imagePath = imagePath;
 
  102         this.sectorSize = sectorSize;
 
  103         this.timeZone = timeZone;
 
  104         this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
 
  107         this.sha256 = sha256;
 
  108         this.imageWriterSettings = imageWriterSettings;
 
  109         this.callback = callback;
 
  110         this.progressMonitor = progressMonitor;
 
  111         tskAddImageProcessLock = 
new Object();
 
  121             currentCase = Case.getCurrentCaseThrows();
 
  122         } 
catch (NoCurrentCaseException ex) {
 
  123             logger.log(Level.SEVERE, String.format(
"Failed to add image data source at %s, no current case", imagePath), ex);
 
  126         progressMonitor.setIndeterminate(
true);
 
  127         progressMonitor.setProgress(0);
 
  128         String imageWriterPath = 
"";
 
  129         if (imageWriterSettings != null) {
 
  130             imageWriterPath = imageWriterSettings.getPath();
 
  132         List<String> errorMessages = 
new ArrayList<>();
 
  133         List<Content> newDataSources = 
new ArrayList<>();
 
  135             currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
 
  136             synchronized (tskAddImageProcessLock) {
 
  137                 if (!tskAddImageProcessStopped) {
 
  138                     tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, 
true, ignoreFatOrphanFiles, imageWriterPath);
 
  143             Thread progressUpdateThread = 
new Thread(
new ProgressUpdater(progressMonitor, tskAddImageProcess));
 
  144             progressUpdateThread.start();
 
  145             runAddImageProcess(errorMessages);
 
  146             progressUpdateThread.interrupt();
 
  147             commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources);
 
  148             progressMonitor.setProgress(100);
 
  150             currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
 
  151             DataSourceProcessorCallback.DataSourceProcessorResult result;
 
  152             if (criticalErrorOccurred) {
 
  153                 result = DataSourceProcessorResult.CRITICAL_ERRORS;
 
  154             } 
else if (!errorMessages.isEmpty()) {
 
  155                 result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
 
  157                 result = DataSourceProcessorResult.NO_ERRORS;
 
  159             callback.done(result, errorMessages, newDataSources);
 
  166     public void cancelTask() {
 
  167         synchronized (tskAddImageProcessLock) {
 
  168             tskAddImageProcessStopped = 
true;
 
  169             if (null != tskAddImageProcess) {
 
  179                     tskAddImageProcess.stop();
 
  181                 } 
catch (TskCoreException ex) {
 
  182                     logger.log(Level.SEVERE, String.format(
"Error cancelling adding image %s to the case database", imagePath), ex); 
 
  194     private void runAddImageProcess(List<String> errorMessages) {
 
  196             tskAddImageProcess.run(deviceId, 
new String[]{imagePath}, sectorSize);
 
  197         } 
catch (TskCoreException ex) {
 
  198             logger.log(Level.SEVERE, String.format(
"Critical error occurred adding image %s", imagePath), ex); 
 
  199             criticalErrorOccurred = 
true;
 
  200             errorMessages.add(ex.getMessage());
 
  201         } 
catch (TskDataException ex) {
 
  202             logger.log(Level.WARNING, String.format(
"Non-critical error occurred adding image %s", imagePath), ex); 
 
  203             errorMessages.add(ex.getMessage());
 
  221     private void commitOrRevertAddImageProcess(Case currentCase, List<String> errorMessages, List<Content> newDataSources) {
 
  222         synchronized (tskAddImageProcessLock) {
 
  223             if (tskAddImageProcessStopped || criticalErrorOccurred) {
 
  225                     tskAddImageProcess.revert();
 
  226                 } 
catch (TskCoreException ex) {
 
  227                     logger.log(Level.SEVERE, String.format(
"Error reverting after adding image %s to the case database", imagePath), ex); 
 
  228                     errorMessages.add(ex.getMessage());
 
  229                     criticalErrorOccurred = 
true;
 
  233                     long imageId = tskAddImageProcess.commit();
 
  235                         Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
 
  236                         String verificationError = newImage.verifyImageSize();
 
  237                         if (!verificationError.isEmpty()) {
 
  238                             errorMessages.add(verificationError);
 
  240                         if (imageWriterSettings != null) {
 
  241                             ImageWriterService.createImageWriter(imageId, imageWriterSettings);
 
  243                         newDataSources.add(newImage);
 
  244                         if (!StringUtils.isBlank(md5)) {
 
  246                                 newImage.setMD5(md5);
 
  247                             } 
catch (TskCoreException ex) {
 
  248                                 logger.log(Level.SEVERE, String.format(
"Failed to add MD5 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  249                                 errorMessages.add(ex.getMessage());
 
  250                                 criticalErrorOccurred = 
true;
 
  251                             } 
catch (TskDataException ignored) {
 
  259                         if (!StringUtils.isBlank(sha1)) {
 
  261                                 newImage.setSha1(sha1);
 
  262                             } 
catch (TskCoreException ex) {
 
  263                                 logger.log(Level.SEVERE, String.format(
"Failed to add SHA1 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  264                                 errorMessages.add(ex.getMessage());
 
  265                                 criticalErrorOccurred = 
true;
 
  266                             } 
catch (TskDataException ignored) {
 
  274                         if (!StringUtils.isBlank(sha256)) {
 
  276                                 newImage.setSha256(sha256);
 
  277                             } 
catch (TskCoreException ex) {
 
  278                                 logger.log(Level.SEVERE, String.format(
"Failed to add SHA256 for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  279                                 errorMessages.add(ex.getMessage());
 
  280                                 criticalErrorOccurred = 
true;
 
  281                             } 
catch (TskDataException ignored) {
 
  290                         String errorMessage = String.format(
"Error commiting after adding image %s to the case database, no object id returned", imagePath); 
 
  291                         logger.log(Level.SEVERE, errorMessage);
 
  292                         errorMessages.add(errorMessage);
 
  293                         criticalErrorOccurred = 
true;
 
  295                 } 
catch (TskCoreException ex) {
 
  296                     logger.log(Level.SEVERE, String.format(
"Error committing adding image %s to the case database", imagePath), ex); 
 
  297                     errorMessages.add(ex.getMessage());
 
  298                     criticalErrorOccurred = 
true;
 
  332                 while (!Thread.currentThread().isInterrupted()) {
 
  334                     if (currDir != null) {
 
  335                         if (!currDir.isEmpty()) {
 
  337                                     NbBundle.getMessage(
this.getClass(), 
"AddImageTask.run.progress.adding",
 
  352             } 
catch (InterruptedException expected) {
 
void setProgressText(String text)
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
final DataSourceProcessorProgressMonitor progressMonitor