Autopsy  4.6.0
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  */
19 package org.sleuthkit.autopsy.casemodule;
20 
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.openide.util.NbBundle;
32 import org.sleuthkit.datamodel.Content;
33 import org.sleuthkit.datamodel.Image;
34 import org.sleuthkit.datamodel.SleuthkitJNI;
35 import org.sleuthkit.datamodel.TskCoreException;
36 import org.sleuthkit.datamodel.TskDataException;
37 
38 /*
39  * A runnable that adds an image data source to the case database.
40  */
41 class AddImageTask implements Runnable {
42 
43  private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
44  private final String deviceId;
45  private final String imagePath;
46  private final int sectorSize;
47  private final String timeZone;
48  private final ImageWriterSettings imageWriterSettings;
49  private final boolean ignoreFatOrphanFiles;
50  private final DataSourceProcessorProgressMonitor progressMonitor;
51  private final DataSourceProcessorCallback callback;
52  private boolean criticalErrorOccurred;
53 
54  /*
55  * The cancellation requested flag and SleuthKit add image process are
56  * guarded by a monitor (called a lock here to avoid confusion with the
57  * progress monitor) to synchronize cancelling the process (setting the flag
58  * and calling its stop method) and calling either its commit or revert
59  * method. The built-in monitor of the add image process can't be used for
60  * this because it is already used to synchronize its run (init part),
61  * commit, revert, and currentDirectory methods.
62  *
63  * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
64  */
65  private final Object tskAddImageProcessLock;
66 
67  @GuardedBy("tskAddImageProcessLock")
68  private boolean tskAddImageProcessStopped;
69  private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
70 
92  AddImageTask(String deviceId, String imagePath, int sectorSize, String timeZone, boolean ignoreFatOrphanFiles, ImageWriterSettings imageWriterSettings,
93  DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
94  this.deviceId = deviceId;
95  this.imagePath = imagePath;
96  this.sectorSize = sectorSize;
97  this.timeZone = timeZone;
98  this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
99  this.imageWriterSettings = imageWriterSettings;
100  this.callback = callback;
101  this.progressMonitor = progressMonitor;
102  tskAddImageProcessLock = new Object();
103  }
104 
108  @Override
109  public void run() {
110  Case currentCase;
111  try {
112  currentCase = Case.getOpenCase();
113  } catch (NoCurrentCaseException ex) {
114  logger.log(Level.SEVERE, "Exception while getting open case.", ex);
115  return;
116  }
117  progressMonitor.setIndeterminate(true);
118  progressMonitor.setProgress(0);
119  String imageWriterPath = "";
120  if (imageWriterSettings != null) {
121  imageWriterPath = imageWriterSettings.getPath();
122  }
123  List<String> errorMessages = new ArrayList<>();
124  List<Content> newDataSources = new ArrayList<>();
125  try {
126  currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
127  synchronized (tskAddImageProcessLock) {
128  if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess
129  tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true,
130  ignoreFatOrphanFiles, imageWriterPath);
131  } else {
132  return; //we have already cancelled so we do not want to add the image, returning will execute the finally block
133  }
134  }
135  Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
136  progressUpdateThread.start();
137  runAddImageProcess(errorMessages);
138  progressUpdateThread.interrupt();
139  commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources);
140  progressMonitor.setProgress(100);
141  } finally {
142  currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
143  DataSourceProcessorCallback.DataSourceProcessorResult result;
144  if (criticalErrorOccurred) {
145  result = DataSourceProcessorResult.CRITICAL_ERRORS;
146  } else if (!errorMessages.isEmpty()) {
147  result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
148  } else {
149  result = DataSourceProcessorResult.NO_ERRORS;
150  }
151  callback.done(result, errorMessages, newDataSources);
152  }
153  }
154 
155  /*
156  * Attempts to cancel adding the image to the case database.
157  */
158  public void cancelTask() {
159  synchronized (tskAddImageProcessLock) {
160  tskAddImageProcessStopped = true;
161  if (null != tskAddImageProcess) {
162  try {
163  /*
164  * All this does is set a flag that will make the TSK add
165  * image process exit when the flag is checked between
166  * processing steps. The state of the flag is not
167  * accessible, so record it here so that it is known that
168  * the revert method of the process object needs to be
169  * called.
170  */
171  tskAddImageProcess.stop();
172 
173  } catch (TskCoreException ex) {
174  logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS
175  }
176  }
177  }
178  }
179 
186  private void runAddImageProcess(List<String> errorMessages) {
187  try {
188  tskAddImageProcess.run(deviceId, new String[]{imagePath}, sectorSize);
189  } catch (TskCoreException ex) {
190  logger.log(Level.SEVERE, String.format("Critical error occurred adding image %s", imagePath), ex); //NON-NLS
191  criticalErrorOccurred = true;
192  errorMessages.add(ex.getMessage());
193  } catch (TskDataException ex) {
194  logger.log(Level.WARNING, String.format("Non-critical error occurred adding image %s", imagePath), ex); //NON-NLS
195  errorMessages.add(ex.getMessage());
196  }
197  }
198 
213  private void commitOrRevertAddImageProcess(Case currentCase, List<String> errorMessages, List<Content> newDataSources) {
214  synchronized (tskAddImageProcessLock) {
215  if (tskAddImageProcessStopped || criticalErrorOccurred) {
216  try {
217  tskAddImageProcess.revert();
218  } catch (TskCoreException ex) {
219  logger.log(Level.SEVERE, String.format("Error reverting adding image %s to the case database", imagePath), ex); //NON-NLS
220  errorMessages.add(ex.getMessage());
221  criticalErrorOccurred = true;
222  }
223  } else {
224  try {
225  long imageId = tskAddImageProcess.commit();
226  if (imageId != 0) {
227  Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
228  String verificationError = newImage.verifyImageSize();
229  if (!verificationError.isEmpty()) {
230  errorMessages.add(verificationError);
231  }
232  if (imageWriterSettings != null) {
233  ImageWriterService.createImageWriter(imageId, imageWriterSettings);
234  }
235  newDataSources.add(newImage);
236  } else {
237  String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
238  logger.log(Level.SEVERE, errorMessage);
239  errorMessages.add(errorMessage);
240  criticalErrorOccurred = true;
241  }
242  } catch (TskCoreException ex) {
243  logger.log(Level.SEVERE, String.format("Error committing adding image %s to the case database", imagePath), ex); //NON-NLS
244  errorMessages.add(ex.getMessage());
245  criticalErrorOccurred = true;
246  }
247  }
248  }
249  }
250 
255  private class ProgressUpdater implements Runnable {
256 
258  private final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
259 
267  ProgressUpdater(DataSourceProcessorProgressMonitor progressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess) {
268  this.progressMonitor = progressMonitor;
270  }
271 
276  @Override
277  public void run() {
278  try {
279  while (!Thread.currentThread().isInterrupted()) {
280  String currDir = tskAddImageProcess.currentDirectory();
281  if (currDir != null) {
282  if (!currDir.isEmpty()) {
283  progressMonitor.setProgressText(
284  NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
285  currDir));
286  }
287  }
288  /*
289  * The sleep here throttles the UI updates and provides a
290  * non-standard mechanism for completing this task by
291  * interrupting the thread in which it is running.
292  *
293  * TODO (AUT-1870): Replace this with giving the task to a
294  * java.util.concurrent.ScheduledThreadPoolExecutor that is
295  * shut down when the main task completes.
296  */
297  Thread.sleep(500);
298  }
299  } catch (InterruptedException expected) {
300  }
301  }
302  }
303 
304 }
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
final DataSourceProcessorProgressMonitor progressMonitor

Copyright © 2012-2016 Basis Technology. Generated on: Mon May 7 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.