Autopsy  3.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-2014 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 
20 package org.sleuthkit.autopsy.casemodule;
21 
22 
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.logging.Level;
27 
28 import org.openide.util.NbBundle;
40 
41 /*
42  * A background task that adds the given image to
43  * database using the Sleuthkit JNI interface.
44  *
45  * It updates the given ProgressMonitor as it works through adding the image,
46  * and et the end, calls the specified Callback.
47  */
48  class AddImageTask implements Runnable {
49 
50  private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
51 
52  private final Case currentCase;
53 
54  // true if the process was requested to cancel
55  private final Object lock = new Object(); // synchronization object for cancelRequested
56  private volatile boolean cancelRequested = false;
57 
58  //true if revert has been invoked.
59  private boolean reverted = false;
60 
61  // true if there was a critical error in adding the data source
62  private boolean hasCritError = false;
63 
64  private final List<String> errorList = new ArrayList<>();
65 
66  private final DataSourceProcessorProgressMonitor progressMonitor;
67  private final DataSourceProcessorCallback callbackObj;
68 
69  private final List<Content> newContents = Collections.synchronizedList(new ArrayList<Content>());
70 
71  private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess;
72  private Thread dirFetcher;
73 
74  private final String imagePath;
75  String timeZone;
76  boolean noFatOrphans;
77 
78  /*
79  * A thread that updates the progressMonitor with the name of the
80  * directory currently being processed by the AddImageTask
81  */
82  private class CurrentDirectoryFetcher implements Runnable {
83 
84  DataSourceProcessorProgressMonitor progressMonitor;
86 
88  this.progressMonitor = aProgressMonitor;
89  this.process = proc;
90  }
91 
95  @Override
96  public void run() {
97  try {
98  while (!Thread.currentThread().isInterrupted()) {
99  String currDir = process.currentDirectory();
100  if (currDir != null) {
101  if (!currDir.isEmpty() ) {
102  progressMonitor.setProgressText(
103  NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
104  currDir));
105  }
106  }
107  // this sleep here prevents the UI from locking up
108  // due to too frequent updates to the progressMonitor above
109  Thread.sleep(500);
110  }
111  } catch (InterruptedException ie) {
112  // nothing to do, thread was interrupted externally
113  // signaling the end of AddImageProcess
114  }
115  }
116  }
117 
118  public AddImageTask(String imgPath, String tz, boolean noOrphans, DataSourceProcessorProgressMonitor aProgressMonitor, DataSourceProcessorCallback cbObj ) {
119 
120  currentCase = Case.getCurrentCase();
121 
122  this.imagePath = imgPath;
123  this.timeZone = tz;
124  this.noFatOrphans = noOrphans;
125 
126  this.callbackObj = cbObj;
127  this.progressMonitor = aProgressMonitor;
128  }
129 
137  @Override
138  public void run() {
139  errorList.clear();
140  try {
141  currentCase.getSleuthkitCase().acquireExclusiveLock();
142  addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans);
143  dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess));
144  try {
145  progressMonitor.setIndeterminate(true);
146  progressMonitor.setProgress(0);
147  dirFetcher.start();
148  addImageProcess.run(new String[]{this.imagePath});
149  } catch (TskCoreException ex) {
150  logger.log(Level.SEVERE, "Core errors occurred while running add image. ", ex); //NON-NLS
151  hasCritError = true;
152  errorList.add(ex.getMessage());
153  } catch (TskDataException ex) {
154  logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); //NON-NLS
155  errorList.add(ex.getMessage());
156  }
157  postProcess();
158  } finally {
159  currentCase.getSleuthkitCase().releaseExclusiveLock();
160  }
161  }
162 
169  private void commitImage() throws Exception {
170 
171  long imageId = 0;
172  try {
173  imageId = addImageProcess.commit();
174  } catch (TskCoreException e) {
175  logger.log(Level.WARNING, "Errors occured while committing the image", e); //NON-NLS
176  errorList.add(e.getMessage());
177  } finally {
178  if (imageId != 0) {
179  // get the newly added Image so we can return to caller
180  Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
181 
182  //while we have the image, verify the size of its contents
183  String verificationErrors = newImage.verifyImageSize();
184  if (verificationErrors.equals("") == false) {
185  //data error (non-critical)
186  errorList.add(verificationErrors);
187  }
188 
189  // Add the image to the list of new content
190  newContents.add(newImage);
191  }
192 
193  logger.log(Level.INFO, "Image committed, imageId: {0}", imageId); //NON-NLS
194  logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
195  }
196  }
197 
202  private void postProcess() {
203 
204  // cancel the directory fetcher
205  dirFetcher.interrupt();
206 
207  if (cancelRequested() || hasCritError) {
208  logger.log(Level.WARNING, "Critical errors or interruption in add image process. Image will not be committed."); //NON-NLS
209  revert();
210  }
211 
212  if (!errorList.isEmpty()) {
213  logger.log(Level.INFO, "There were errors that occured in add image process"); //NON-NLS
214  }
215 
216  // When everything happens without an error:
217  if (!(cancelRequested() || hasCritError)) {
218  try {
219  if (addImageProcess != null) {
220  // commit image
221  try {
222  commitImage();
223  } catch (Exception ex) {
224  errorList.add(ex.getMessage());
225  // Log error/display warning
226  logger.log(Level.SEVERE, "Error adding image to case.", ex); //NON-NLS
227  }
228  } else {
229  logger.log(Level.SEVERE, "Missing image process object"); //NON-NLS
230  }
231 
232  // Tell the progress monitor we're done
233  progressMonitor.setProgress(100);
234  } catch (Exception ex) {
235  //handle unchecked exceptions post image add
236  errorList.add(ex.getMessage());
237 
238  logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); //NON-NLS
239  logger.log(Level.SEVERE, "Error adding image to case", ex); //NON-NLS
240  }
241  }
242 
243  // invoke the callBack, unless the caller cancelled
244  if (!cancelRequested()) {
245  doCallBack();
246  }
247  }
248 
249  /*
250  * Call the callback with results, new content, and errors, if any
251  */
252  private void doCallBack()
253  {
254  DataSourceProcessorCallback.DataSourceProcessorResult result;
255 
256  if (hasCritError) {
257  result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS;
258  }
259  else if (!errorList.isEmpty()) {
260  result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS;
261  }
262  else {
263  result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS;
264  }
265 
266  // invoke the callback, passing it the result, list of new contents, and list of errors
267  callbackObj.done(result, errorList, newContents);
268  }
269 
270  /*
271  * cancel the image addition, if possible
272  */
273  public void cancelTask() {
274 
275  synchronized (lock) {
276  cancelRequested = true;
277  try {
278  interrupt();
279  }
280  catch (Exception ex) {
281  logger.log(Level.SEVERE, "Failed to interrupt the add image task..."); //NON-NLS
282  }
283  }
284  }
285 
286  /*
287  * Interrupt the add image process if it is still running
288  */
289  private void interrupt() throws Exception {
290 
291  try {
292  logger.log(Level.INFO, "interrupt() add image process"); //NON-NLS
293  addImageProcess.stop(); //it might take time to truly stop processing and writing to db
294  } catch (TskCoreException ex) {
295  throw new Exception(NbBundle.getMessage(this.getClass(), "AddImageTask.interrupt.exception.msg"), ex);
296  }
297  }
298 
299  /*
300  * Revert - if image has already been added but not committed yet
301  */
302  private void revert() {
303 
304  if (!reverted) {
305  logger.log(Level.INFO, "Revert after add image process"); //NON-NLS
306  try {
307  addImageProcess.revert();
308  } catch (TskCoreException ex) {
309  logger.log(Level.WARNING, "Error reverting add image process", ex); //NON-NLS
310  }
311  reverted = true;
312  }
313  }
314 
315  private boolean cancelRequested() {
316  synchronized (lock) {
317  return cancelRequested;
318  }
319  }
320  }

Copyright © 2012-2015 Basis Technology. Generated on: Mon Oct 19 2015
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.