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;
 
   43 class AddImageTask 
implements Runnable {
 
   45     private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
 
   46     private final ImageDetails imageDetails;
 
   47     private final DataSourceProcessorProgressMonitor progressMonitor;
 
   48     private final AddDataSourceCallbacks addDataSourceCallbacks;
 
   49     private final AddImageTaskCallback addImageTaskCallback;
 
   50     private boolean criticalErrorOccurred;
 
   63     private final Object tskAddImageProcessLock;
 
   64     @GuardedBy(
"tskAddImageProcessLock")
 
   65     private 
boolean tskAddImageProcessStopped;
 
   66     private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
 
   77     AddImageTask(ImageDetails imageDetails, DataSourceProcessorProgressMonitor progressMonitor, AddDataSourceCallbacks addDataSourceCallbacks,  
 
   78             AddImageTaskCallback addImageTaskCallback) {
 
   79         this.imageDetails = imageDetails;
 
   80         this.addDataSourceCallbacks = addDataSourceCallbacks;
 
   81         this.addImageTaskCallback = addImageTaskCallback;
 
   82         this.progressMonitor = progressMonitor;
 
   83         tskAddImageProcessLock = 
new Object();
 
   93             currentCase = Case.getCurrentCaseThrows();
 
   94         } 
catch (NoCurrentCaseException ex) {
 
   95             logger.log(Level.SEVERE, String.format(
"Failed to start AddImageTask for %s, no current case", imageDetails.getImagePath()), ex);
 
   98         progressMonitor.setIndeterminate(
true);
 
   99         progressMonitor.setProgress(0);
 
  100         String imageWriterPath = 
"";
 
  101         if (imageDetails.imageWriterSettings != null) {
 
  102             imageWriterPath = imageDetails.imageWriterSettings.getPath();
 
  104         List<String> errorMessages = 
new ArrayList<>();
 
  105         List<Content> newDataSources = 
new ArrayList<>();
 
  107             synchronized (tskAddImageProcessLock) {
 
  108                 if (!tskAddImageProcessStopped) {
 
  109                     tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(imageDetails.timeZone, 
true, imageDetails.ignoreFatOrphanFiles, imageWriterPath);
 
  114             Thread progressUpdateThread = 
new Thread(
new ProgressUpdater(progressMonitor, tskAddImageProcess));
 
  115             progressUpdateThread.start();
 
  116             runAddImageProcess(errorMessages);
 
  117             progressUpdateThread.interrupt();
 
  118             finishAddImageProcess(errorMessages, newDataSources);
 
  119             progressMonitor.setProgress(100);
 
  121             DataSourceProcessorCallback.DataSourceProcessorResult result;
 
  122             if (criticalErrorOccurred) {
 
  123                 result = DataSourceProcessorResult.CRITICAL_ERRORS;
 
  124             } 
else if (!errorMessages.isEmpty()) {
 
  125                 result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
 
  127                 result = DataSourceProcessorResult.NO_ERRORS;
 
  129             addImageTaskCallback.onCompleted(result, errorMessages, newDataSources);
 
  136     public void cancelTask() {
 
  137         synchronized (tskAddImageProcessLock) {
 
  138             tskAddImageProcessStopped = 
true;
 
  139             if (null != tskAddImageProcess) {
 
  149                     tskAddImageProcess.stop();
 
  151                 } 
catch (TskCoreException ex) {
 
  152                     logger.log(Level.SEVERE, String.format(
"Error cancelling adding image %s to the case database", imageDetails.getImagePath()), ex); 
 
  164     private void runAddImageProcess(List<String> errorMessages) {
 
  166             tskAddImageProcess.run(imageDetails.deviceId, imageDetails.image, imageDetails.sectorSize, 
this.addDataSourceCallbacks);
 
  167         } 
catch (TskCoreException ex) {
 
  168             logger.log(Level.SEVERE, String.format(
"Critical error occurred adding image %s", imageDetails.getImagePath()), ex); 
 
  169             criticalErrorOccurred = 
true;
 
  170             errorMessages.add(ex.getMessage());
 
  171         } 
catch (TskDataException ex) {
 
  172             logger.log(Level.WARNING, String.format(
"Non-critical error occurred adding image %s", imageDetails.getImagePath()), ex); 
 
  173             errorMessages.add(ex.getMessage());
 
  190     private void finishAddImageProcess(List<String> errorMessages, List<Content> newDataSources) {
 
  191         synchronized (tskAddImageProcessLock) {
 
  192             Image newImage = imageDetails.image;
 
  193             String verificationError = newImage.verifyImageSize();
 
  194             if (!verificationError.isEmpty()) {
 
  195                 errorMessages.add(verificationError);
 
  197             if (imageDetails.imageWriterSettings != null) {
 
  198                 ImageWriterService.createImageWriter(newImage.getId(), imageDetails.imageWriterSettings);
 
  200             newDataSources.add(newImage);
 
  203             if (tskAddImageProcessStopped) {
 
  207             if (!StringUtils.isBlank(imageDetails.md5)) {
 
  209                     newImage.setMD5(imageDetails.md5);
 
  210                 } 
catch (TskCoreException ex) {
 
  211                     logger.log(Level.SEVERE, String.format(
"Failed to add MD5 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  212                     errorMessages.add(ex.getMessage());
 
  213                     criticalErrorOccurred = 
true;
 
  214                 } 
catch (TskDataException ignored) {
 
  222             if (!StringUtils.isBlank(imageDetails.sha1)) {
 
  224                     newImage.setSha1(imageDetails.sha1);
 
  225                 } 
catch (TskCoreException ex) {
 
  226                     logger.log(Level.SEVERE, String.format(
"Failed to add SHA1 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  227                     errorMessages.add(ex.getMessage());
 
  228                     criticalErrorOccurred = 
true;
 
  229                 } 
catch (TskDataException ignored) {
 
  237             if (!StringUtils.isBlank(imageDetails.sha256)) {
 
  239                     newImage.setSha256(imageDetails.sha256);
 
  240                 } 
catch (TskCoreException ex) {
 
  241                     logger.log(Level.SEVERE, String.format(
"Failed to add SHA256 for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
 
  242                     errorMessages.add(ex.getMessage());
 
  243                     criticalErrorOccurred = 
true;
 
  244                 } 
catch (TskDataException ignored) {
 
  283                 while (!Thread.currentThread().isInterrupted()) {
 
  285                     if (currDir != null) {
 
  286                         if (!currDir.isEmpty()) {
 
  288                                     NbBundle.getMessage(
this.getClass(), 
"AddImageTask.run.progress.adding",
 
  303             } 
catch (InterruptedException expected) {
 
  311     static class ImageDetails {
 
  316         boolean ignoreFatOrphanFiles;
 
  322         ImageDetails(String deviceId, Image image, 
int sectorSize, String timeZone, 
boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, 
ImageWriterSettings imageWriterSettings) {
 
  323             this.deviceId = deviceId;
 
  325             this.sectorSize = sectorSize;
 
  326             this.timeZone = timeZone;
 
  327             this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
 
  330             this.sha256 = sha256; 
 
  331             this.imageWriterSettings = imageWriterSettings;
 
  334         String getImagePath() {
 
  335             if (image.getPaths().length > 0) {
 
  336                 return image.getPaths()[0];
 
  338             return "Unknown data source path";
 
void setProgressText(String text)
 
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
 
final DataSourceProcessorProgressMonitor progressMonitor