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