Autopsy  4.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-2016 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;
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 String timeZone;
47  private final ImageWriterSettings imageWriterSettings;
48  private final boolean ignoreFatOrphanFiles;
49  private final DataSourceProcessorProgressMonitor progressMonitor;
50  private final DataSourceProcessorCallback callback;
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 
66  @GuardedBy("tskAddImageProcessLock")
67  private boolean tskAddImageProcessStopped;
68  private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
69 
90  AddImageTask(String deviceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, ImageWriterSettings imageWriterSettings,
91  DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
92  this.deviceId = deviceId;
93  this.imagePath = imagePath;
94  this.timeZone = timeZone;
95  this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
96  this.imageWriterSettings = imageWriterSettings;
97  this.callback = callback;
98  this.progressMonitor = progressMonitor;
99  tskAddImageProcessLock = new Object();
100  }
101 
105  @Override
106  public void run() {
107  progressMonitor.setIndeterminate(true);
108  progressMonitor.setProgress(0);
109  Case currentCase = Case.getCurrentCase();
110  String imageWriterPath = "";
111  if (imageWriterSettings != null) {
112  imageWriterPath = imageWriterSettings.getPath();
113  }
114  List<String> errorMessages = new ArrayList<>();
115  List<Content> newDataSources = new ArrayList<>();
116  try {
117  currentCase.getSleuthkitCase().acquireExclusiveLock();
118  synchronized (tskAddImageProcessLock) {
119  if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess
120  tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true,
121  ignoreFatOrphanFiles, imageWriterPath);
122  } else {
123  return; //we have already cancelled so we do not want to add the image, returning will execute the finally block
124  }
125  }
126  Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
127  progressUpdateThread.start();
128  runAddImageProcess(errorMessages);
129  if (null != progressUpdateThread) {
130  progressUpdateThread.interrupt();
131  }
132  commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources);
133  progressMonitor.setProgress(100);
134  } finally {
135  currentCase.getSleuthkitCase().releaseExclusiveLock();
136  DataSourceProcessorCallback.DataSourceProcessorResult result;
137  if (criticalErrorOccurred) {
138  result = DataSourceProcessorResult.CRITICAL_ERRORS;
139  } else if (!errorMessages.isEmpty()) {
140  result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
141  } else {
142  result = DataSourceProcessorResult.NO_ERRORS;
143  }
144  callback.done(result, errorMessages, newDataSources);
145  }
146  }
147 
148  /*
149  * Attempts to cancel adding the image to the case database.
150  */
151  public void cancelTask() {
152  synchronized (tskAddImageProcessLock) {
153  tskAddImageProcessStopped = true;
154  if (null != tskAddImageProcess) {
155  try {
156  /*
157  * All this does is set a flag that will make the TSK add
158  * image process exit when the flag is checked between
159  * processing steps. The state of the flag is not
160  * accessible, so record it here so that it is known that
161  * the revert method of the process object needs to be
162  * called.
163  */
164  tskAddImageProcess.stop();
165 
166  } catch (TskCoreException ex) {
167  logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS
168  }
169  }
170  }
171  }
172 
179  private void runAddImageProcess(List<String> errorMessages) {
180  try {
181  tskAddImageProcess.run(deviceId, new String[]{imagePath});
182  } catch (TskCoreException ex) {
183  logger.log(Level.SEVERE, String.format("Critical error occurred adding image %s", imagePath), ex); //NON-NLS
184  criticalErrorOccurred = true;
185  errorMessages.add(ex.getMessage());
186  } catch (TskDataException ex) {
187  logger.log(Level.WARNING, String.format("Non-critical error occurred adding image %s", imagePath), ex); //NON-NLS
188  errorMessages.add(ex.getMessage());
189  }
190  }
191 
206  private void commitOrRevertAddImageProcess(Case currentCase, List<String> errorMessages, List<Content> newDataSources) {
207  synchronized (tskAddImageProcessLock) {
208  if (tskAddImageProcessStopped || criticalErrorOccurred) {
209  try {
210  tskAddImageProcess.revert();
211  } catch (TskCoreException ex) {
212  logger.log(Level.SEVERE, String.format("Error reverting adding image %s to the case database", imagePath), ex); //NON-NLS
213  errorMessages.add(ex.getMessage());
214  criticalErrorOccurred = true;
215  }
216  } else {
217  try {
218  long imageId = tskAddImageProcess.commit();
219  if (imageId != 0) {
220  Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
221  String verificationError = newImage.verifyImageSize();
222  if (!verificationError.isEmpty()) {
223  errorMessages.add(verificationError);
224  }
225  if (imageWriterSettings != null) {
226  ImageWriterService.createImageWriter(imageId, imageWriterSettings);
227  }
228  newDataSources.add(newImage);
229  } else {
230  String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
231  logger.log(Level.SEVERE, errorMessage);
232  errorMessages.add(errorMessage);
233  criticalErrorOccurred = true;
234  }
235  } catch (TskCoreException ex) {
236  logger.log(Level.SEVERE, String.format("Error committing adding image %s to the case database", imagePath), ex); //NON-NLS
237  errorMessages.add(ex.getMessage());
238  criticalErrorOccurred = true;
239  }
240  }
241  }
242  }
243 
248  private class ProgressUpdater implements Runnable {
249 
252 
261  this.progressMonitor = progressMonitor;
263  }
264 
269  @Override
270  public void run() {
271  try {
272  while (!Thread.currentThread().isInterrupted()) {
273  String currDir = tskAddImageProcess.currentDirectory();
274  if (currDir != null) {
275  if (!currDir.isEmpty()) {
276  progressMonitor.setProgressText(
277  NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
278  currDir));
279  }
280  }
281  /*
282  * The sleep here throttles the UI updates and provides a
283  * non-standard mechanism for completing this task by
284  * interrupting the thread in which it is running.
285  *
286  * TODO (AUT-1870): Replace this with giving the task to a
287  * java.util.concurrent.ScheduledThreadPoolExecutor that is
288  * shut down when the main task completes.
289  */
290  Thread.sleep(500);
291  }
292  } catch (InterruptedException expected) {
293  }
294  }
295  }
296 
297 }
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
final DataSourceProcessorProgressMonitor progressMonitor

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