Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
AddImageTask.java
Go to the documentation of this file.
1/*
2 * Autopsy Forensic Browser
3 *
4 * Copyright 2013-2018 Basis Technology Corp.
5 * Contact: carrier <at> sleuthkit <dot> org
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19package org.sleuthkit.autopsy.casemodule;
20
21import java.util.ArrayList;
22import java.util.List;
23import java.util.logging.Level;
24import javax.annotation.concurrent.GuardedBy;
25import org.apache.commons.lang3.StringUtils;
26import org.openide.util.NbBundle;
27import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
28import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
29import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
30import org.sleuthkit.autopsy.coreutils.Logger;
31import org.sleuthkit.autopsy.imagewriter.ImageWriterService;
32import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
33import org.sleuthkit.datamodel.AddDataSourceCallbacks;
34import org.sleuthkit.datamodel.Content;
35import org.sleuthkit.datamodel.Host;
36import org.sleuthkit.datamodel.Image;
37import org.sleuthkit.datamodel.SleuthkitJNI;
38import org.sleuthkit.datamodel.TskCoreException;
39import org.sleuthkit.datamodel.TskDataException;
40
41/*
42 * A runnable that adds an image data source to the case database.
43 */
44class AddImageTask implements Runnable {
45
46 private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
47 private final ImageDetails imageDetails;
48 private final DataSourceProcessorProgressMonitor progressMonitor;
49 private final AddDataSourceCallbacks addDataSourceCallbacks;
50 private final AddImageTaskCallback addImageTaskCallback;
51 private boolean criticalErrorOccurred;
52
53 /*
54 * The cancellation requested flag and SleuthKit add image process are
55 * guarded by a monitor (called a lock here to avoid confusion with the
56 * progress monitor) to synchronize cancelling the process (setting the flag
57 * and calling its stop method) and calling either its commit or revert
58 * method. The built-in monitor of the add image process can't be used for
59 * this because it is already used to synchronize its run (init part),
60 * commit, revert, and currentDirectory methods.
61 *
62 * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
63 */
64 private final Object tskAddImageProcessLock;
65 @GuardedBy("tskAddImageProcessLock")
66 private boolean tskAddImageProcessStopped;
67 private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
68
78 AddImageTask(ImageDetails imageDetails, DataSourceProcessorProgressMonitor progressMonitor, AddDataSourceCallbacks addDataSourceCallbacks,
79 AddImageTaskCallback addImageTaskCallback) {
80 this.imageDetails = imageDetails;
81 this.addDataSourceCallbacks = addDataSourceCallbacks;
82 this.addImageTaskCallback = addImageTaskCallback;
83 this.progressMonitor = progressMonitor;
84 tskAddImageProcessLock = new Object();
85 }
86
90 @Override
91 public void run() {
92 Case currentCase;
93 try {
94 currentCase = Case.getCurrentCaseThrows();
95 } catch (NoCurrentCaseException ex) {
96 logger.log(Level.SEVERE, String.format("Failed to start AddImageTask for %s, no current case", imageDetails.getImagePath()), ex);
97 return;
98 }
99 progressMonitor.setIndeterminate(true);
100 progressMonitor.setProgress(0);
101 String imageWriterPath = "";
102 if (imageDetails.imageWriterSettings != null) {
103 imageWriterPath = imageDetails.imageWriterSettings.getPath();
104 }
105 List<String> errorMessages = new ArrayList<>();
106 List<Content> newDataSources = new ArrayList<>();
107 try {
108 synchronized (tskAddImageProcessLock) {
109 if (!tskAddImageProcessStopped) {
110 tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(imageDetails.timeZone, true, imageDetails.ignoreFatOrphanFiles, imageWriterPath, imageDetails.password);
111 } else {
112 return;
113 }
114 }
115 Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
116 progressUpdateThread.start();
117 runAddImageProcess(errorMessages);
118 progressUpdateThread.interrupt();
119 finishAddImageProcess(errorMessages, newDataSources);
120 progressMonitor.setProgress(100);
121 } finally {
122 DataSourceProcessorCallback.DataSourceProcessorResult result;
123 if (criticalErrorOccurred) {
124 result = DataSourceProcessorResult.CRITICAL_ERRORS;
125 } else if (!errorMessages.isEmpty()) {
126 result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
127 } else {
128 result = DataSourceProcessorResult.NO_ERRORS;
129 }
130 addImageTaskCallback.onCompleted(result, errorMessages, newDataSources);
131 }
132 }
133
134 /*
135 * Attempts to cancel adding the image to the case database.
136 */
137 public void cancelTask() {
138 synchronized (tskAddImageProcessLock) {
139 tskAddImageProcessStopped = true;
140 if (null != tskAddImageProcess) {
141 try {
142 /*
143 * All this does is set a flag that will make the TSK add
144 * image process exit when the flag is checked between
145 * processing steps. The state of the flag is not
146 * accessible, so record it here so that it is known that
147 * the revert method of the process object needs to be
148 * called.
149 */
150 tskAddImageProcess.stop();
151
152 } catch (TskCoreException ex) {
153 logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imageDetails.getImagePath()), ex); //NON-NLS
154 }
155 }
156 }
157 }
158
165 private void runAddImageProcess(List<String> errorMessages) {
166 try {
167 tskAddImageProcess.run(imageDetails.deviceId, imageDetails.image, imageDetails.sectorSize, this.addDataSourceCallbacks);
168 } catch (TskCoreException ex) {
169 logger.log(Level.SEVERE, String.format("Critical error occurred adding image %s", imageDetails.getImagePath()), ex); //NON-NLS
170 criticalErrorOccurred = true;
171 errorMessages.add(ex.getMessage());
172 } catch (TskDataException ex) {
173 logger.log(Level.WARNING, String.format("Non-critical error occurred adding image %s", imageDetails.getImagePath()), ex); //NON-NLS
174 errorMessages.add(ex.getMessage());
175 }
176 }
177
191 private void finishAddImageProcess(List<String> errorMessages, List<Content> newDataSources) {
192 synchronized (tskAddImageProcessLock) {
193 Image newImage = imageDetails.image;
194 String verificationError = newImage.verifyImageSize();
195 if (!verificationError.isEmpty()) {
196 errorMessages.add(verificationError);
197 }
198 if (imageDetails.imageWriterSettings != null) {
199 ImageWriterService.createImageWriter(newImage.getId(), imageDetails.imageWriterSettings);
200 }
201 newDataSources.add(newImage);
202
203 // If the add image process was cancelled don't do any further processing here
204 if (tskAddImageProcessStopped) {
205 return;
206 }
207
208 if (!StringUtils.isBlank(imageDetails.md5)) {
209 try {
210 newImage.setMD5(imageDetails.md5);
211 } catch (TskCoreException ex) {
212 logger.log(Level.SEVERE, String.format("Failed to add MD5 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
213 errorMessages.add(ex.getMessage());
214 criticalErrorOccurred = true;
215 } catch (TskDataException ignored) {
216 /*
217 * The only reasonable way for this to happen at
218 * present is through C/C++ processing of an EWF
219 * image, which is not an error.
220 */
221 }
222 }
223 if (!StringUtils.isBlank(imageDetails.sha1)) {
224 try {
225 newImage.setSha1(imageDetails.sha1);
226 } catch (TskCoreException ex) {
227 logger.log(Level.SEVERE, String.format("Failed to add SHA1 hash for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
228 errorMessages.add(ex.getMessage());
229 criticalErrorOccurred = true;
230 } catch (TskDataException ignored) {
231 /*
232 * The only reasonable way for this to happen at
233 * present is through C/C++ processing of an EWF
234 * image, which is not an error.
235 */
236 }
237 }
238 if (!StringUtils.isBlank(imageDetails.sha256)) {
239 try {
240 newImage.setSha256(imageDetails.sha256);
241 } catch (TskCoreException ex) {
242 logger.log(Level.SEVERE, String.format("Failed to add SHA256 for image data source %s (objId=%d)", newImage.getName(), newImage.getId()), ex);
243 errorMessages.add(ex.getMessage());
244 criticalErrorOccurred = true;
245 } catch (TskDataException ignored) {
246 /*
247 * The only reasonable way for this to happen at
248 * present is through C/C++ processing of an EWF
249 * image, which is not an error.
250 */
251 }
252 }
253 }
254 }
255
260 private class ProgressUpdater implements Runnable {
261
263 private final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
264
272 ProgressUpdater(DataSourceProcessorProgressMonitor progressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess) {
273 this.progressMonitor = progressMonitor;
274 this.tskAddImageProcess = tskAddImageProcess;
275 }
276
281 @Override
282 public void run() {
283 try {
284 while (!Thread.currentThread().isInterrupted()) {
285 String currDir = tskAddImageProcess.currentDirectory();
286 if (currDir != null) {
287 if (!currDir.isEmpty()) {
288 progressMonitor.setProgressText(
289 NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
290 currDir));
291 }
292 }
293 /*
294 * The sleep here throttles the UI updates and provides a
295 * non-standard mechanism for completing this task by
296 * interrupting the thread in which it is running.
297 *
298 * TODO (AUT-1870): Replace this with giving the task to a
299 * java.util.concurrent.ScheduledThreadPoolExecutor that is
300 * shut down when the main task completes.
301 */
302 Thread.sleep(500);
303 }
304 } catch (InterruptedException expected) {
305 }
306 }
307 }
308
312 static class ImageDetails {
313 String deviceId;
314 Image image;
315 int sectorSize;
316 String timeZone;
317 boolean ignoreFatOrphanFiles;
318 String md5;
319 String sha1;
320 String sha256;
321 ImageWriterSettings imageWriterSettings;
322 String password;
323
324 ImageDetails(String deviceId, Image image, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, String md5, String sha1, String sha256, ImageWriterSettings imageWriterSettings, String password) {
325 this.deviceId = deviceId;
326 this.image = image;
327 this.sectorSize = sectorSize;
328 this.timeZone = timeZone;
329 this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
330 this.md5 = md5;
331 this.sha1 = sha1;
332 this.sha256 = sha256;
333 this.imageWriterSettings = imageWriterSettings;
334 this.password = password;
335 }
336
337 String getImagePath() {
338 if (image.getPaths().length > 0) {
339 return image.getPaths()[0];
340 }
341 return "Unknown data source path";
342 }
343 }
344}
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
final DataSourceProcessorProgressMonitor progressMonitor

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.