Autopsy  4.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-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 org.openide.util.NbBundle;
29 import org.sleuthkit.datamodel.Content;
30 import org.sleuthkit.datamodel.Image;
31 import org.sleuthkit.datamodel.SleuthkitJNI;
32 import org.sleuthkit.datamodel.TskCoreException;
33 import org.sleuthkit.datamodel.TskDataException;
34 
35 /*
36  * A runnable that adds an image data source to the case database.
37  */
38 class AddImageTask implements Runnable {
39 
40  private final Logger logger = Logger.getLogger(AddImageTask.class.getName());
41  private final String deviceId;
42  private final String imagePath;
43  private final String timeZone;
44  private final boolean ignoreFatOrphanFiles;
45  private final DataSourceProcessorProgressMonitor progressMonitor;
46  private final DataSourceProcessorCallback callback;
47  private boolean criticalErrorOccurred;
48 
49  /*
50  * The cancellation requested flag and SleuthKit add image process are
51  * guarded by a monitor (called a lock here to avoid confusion with the
52  * progress monitor) to synchronize cancelling the process (setting the flag
53  * and calling its stop method) and calling either its commit or revert
54  * method. The built-in monitor of the add image process can't be used for
55  * this because it is already used to synchronize its run (init part),
56  * commit, revert, and currentDirectory methods.
57  *
58  * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
59  */
60  private final Object tskAddImageProcessLock;
61  private boolean tskAddImageProcessStopped;
62  private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
63 
81  AddImageTask(String deviceId, String imagePath, String timeZone, boolean ignoreFatOrphanFiles, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) {
82  this.deviceId = deviceId;
83  this.imagePath = imagePath;
84  this.timeZone = timeZone;
85  this.ignoreFatOrphanFiles = ignoreFatOrphanFiles;
86  this.callback = callback;
87  this.progressMonitor = progressMonitor;
88  tskAddImageProcessLock = new Object();
89  }
90 
94  @Override
95  public void run() {
96  progressMonitor.setIndeterminate(true);
97  progressMonitor.setProgress(0);
98  Case currentCase = Case.getCurrentCase();
99  List<String> errorMessages = new ArrayList<>();
100  List<Content> newDataSources = new ArrayList<>();
101  try {
102  currentCase.getSleuthkitCase().acquireExclusiveLock();
103  synchronized (tskAddImageProcessLock) {
104  tskAddImageProcess = currentCase.makeAddImageProcess(timeZone, true, ignoreFatOrphanFiles);
105  }
106  Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
107  progressUpdateThread.start();
108  runAddImageProcess(errorMessages);
109  if (null != progressUpdateThread) {
110  progressUpdateThread.interrupt();
111  }
112  commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources);
113  progressMonitor.setProgress(100);
114  } finally {
115  currentCase.getSleuthkitCase().releaseExclusiveLock();
116  DataSourceProcessorCallback.DataSourceProcessorResult result;
117  if (criticalErrorOccurred) {
118  result = DataSourceProcessorResult.CRITICAL_ERRORS;
119  } else if (!errorMessages.isEmpty()) {
120  result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
121  } else {
122  result = DataSourceProcessorResult.NO_ERRORS;
123  }
124  callback.done(result, errorMessages, newDataSources);
125  }
126  }
127 
128  /*
129  * Attempts to cancel adding the image to the case database.
130  */
131  public void cancelTask() {
132  synchronized (tskAddImageProcessLock) {
133  if (null != tskAddImageProcess) {
134  try {
135  /*
136  * All this does is set a flag that will make the TSK add
137  * image process exit when the flag is checked between
138  * processing steps. The state of the flag is not
139  * accessible, so record it here so that it is known that
140  * the revert method of the process object needs to be
141  * called.
142  */
143  tskAddImageProcess.stop();
144  tskAddImageProcessStopped = true;
145  } catch (TskCoreException ex) {
146  logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS
147  }
148  }
149  }
150  }
151 
158  private void runAddImageProcess(List<String> errorMessages) {
159  try {
160  tskAddImageProcess.run(deviceId, new String[]{imagePath});
161  } catch (TskCoreException ex) {
162  logger.log(Level.SEVERE, String.format("Critical error occurred adding image %s", imagePath), ex); //NON-NLS
163  criticalErrorOccurred = true;
164  errorMessages.add(ex.getMessage());
165  } catch (TskDataException ex) {
166  logger.log(Level.WARNING, String.format("Non-critical error occurred adding image %s", imagePath), ex); //NON-NLS
167  errorMessages.add(ex.getMessage());
168  }
169  }
170 
185  private void commitOrRevertAddImageProcess(Case currentCase, List<String> errorMessages, List<Content> newDataSources) {
186  synchronized (tskAddImageProcessLock) {
187  if (tskAddImageProcessStopped || criticalErrorOccurred) {
188  try {
189  tskAddImageProcess.revert();
190  } catch (TskCoreException ex) {
191  logger.log(Level.SEVERE, String.format("Error reverting adding image %s to the case database", imagePath), ex); //NON-NLS
192  errorMessages.add(ex.getMessage());
193  criticalErrorOccurred = true;
194  }
195  } else {
196  try {
197  long imageId = tskAddImageProcess.commit();
198  if (imageId != 0) {
199  Image newImage = currentCase.getSleuthkitCase().getImageById(imageId);
200  String verificationError = newImage.verifyImageSize();
201  if (!verificationError.isEmpty()) {
202  errorMessages.add(verificationError);
203  }
204  newDataSources.add(newImage);
205  } else {
206  String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
207  logger.log(Level.SEVERE, errorMessage);
208  errorMessages.add(errorMessage);
209  criticalErrorOccurred = true;
210  }
211  } catch (TskCoreException ex) {
212  logger.log(Level.SEVERE, String.format("Error committing adding image %s to the case database", imagePath), ex); //NON-NLS
213  errorMessages.add(ex.getMessage());
214  criticalErrorOccurred = true;
215  }
216  }
217  }
218  }
219 
224  private class ProgressUpdater implements Runnable {
225 
227  private final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
228 
236  ProgressUpdater(DataSourceProcessorProgressMonitor progressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess) {
237  this.progressMonitor = progressMonitor;
239  }
240 
245  @Override
246  public void run() {
247  try {
248  while (!Thread.currentThread().isInterrupted()) {
249  String currDir = tskAddImageProcess.currentDirectory();
250  if (currDir != null) {
251  if (!currDir.isEmpty()) {
252  progressMonitor.setProgressText(
253  NbBundle.getMessage(this.getClass(), "AddImageTask.run.progress.adding",
254  currDir));
255  }
256  }
257  /*
258  * The sleep here throttles the UI updates and provides a
259  * non-standard mechanism for completing this task by
260  * interrupting the thread in which it is running.
261  *
262  * TODO (AUT-1870): Replace this with giving the task to a
263  * java.util.concurrent.ScheduledThreadPoolExecutor that is
264  * shut down when the main task completes.
265  */
266  Thread.sleep(500);
267  }
268  } catch (InterruptedException expected) {
269  }
270  }
271  }
272 
273 }
final SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess
final DataSourceProcessorProgressMonitor progressMonitor

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