Autopsy  4.16.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AddMultipleImagesTask.java
Go to the documentation of this file.
1 /*
2  * Autopsy
3  *
4  * Copyright 2019 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.logicalimager.dsp;
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.Messages;
31 import org.sleuthkit.datamodel.Content;
32 import org.sleuthkit.datamodel.DefaultAddDataSourceCallbacks;
33 import org.sleuthkit.datamodel.Image;
34 import org.sleuthkit.datamodel.SleuthkitCase;
35 import org.sleuthkit.datamodel.SleuthkitJNI;
36 import org.sleuthkit.datamodel.TskCoreException;
37 import org.sleuthkit.datamodel.TskDataException;
38 import org.sleuthkit.datamodel.TskFileRange;
39 
45 @Messages({
46  "AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type"
47 })
48 class AddMultipleImagesTask implements Runnable {
49 
50  private static final Logger LOGGER = Logger.getLogger(AddMultipleImagesTask.class.getName());
51  public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImagesTask_fsTypeUnknownErr();
52  private static final long TWO_GB = 2000000000L;
53  private final String deviceId;
54  private final List<String> imageFilePaths;
55  private final String timeZone;
56  private final long chunkSize = TWO_GB;
57  private final DataSourceProcessorProgressMonitor progressMonitor;
58  private final Case currentCase;
59  private boolean criticalErrorOccurred;
60  private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = null;
61  private List<String> errorMessages = new ArrayList<>();
62  private DataSourceProcessorResult result;
63  private List<Content> newDataSources = new ArrayList<>();
64  private Image currentImage = null;
65 
66  /*
67  * The cancellation requested flag and SleuthKit add image process are
68  * guarded by a lock to synchronize cancelling the process (setting the flag
69  * and calling its stop method) and calling either its commit or revert
70  * method.
71  */
72  private final Object tskAddImageProcessLock;
73  @GuardedBy("tskAddImageProcessLock")
74  private boolean tskAddImageProcessStopped;
75 
93  @Messages({
94  "# {0} - file", "AddMultipleImagesTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.",
95  "# {0} - deviceId", "# {1} - exceptionMessage",
96  "AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}",})
97  AddMultipleImagesTask(String deviceId, List<String> imageFilePaths, String timeZone,
98  DataSourceProcessorProgressMonitor progressMonitor) throws NoCurrentCaseException {
99  this.deviceId = deviceId;
100  this.imageFilePaths = imageFilePaths;
101  this.timeZone = timeZone;
102  this.progressMonitor = progressMonitor;
103  currentCase = Case.getCurrentCaseThrows();
104  this.criticalErrorOccurred = false;
105  tskAddImageProcessLock = new Object();
106  }
107 
108  @Messages({
109  "AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted",
110  "# {0} - image path",
111  "AddMultipleImagesTask.imageError=Error adding image {0} to the database"
112  })
113  @Override
114  public void run() {
115  errorMessages = new ArrayList<>();
116  newDataSources = new ArrayList<>();
117  List<Content> emptyDataSources = new ArrayList<>();
118 
119  /*
120  * Try to add the input image files as images.
121  */
122  List<String> corruptedImageFilePaths = new ArrayList<>();
123  progressMonitor.setIndeterminate(true);
124  for (String imageFilePath : imageFilePaths) {
125  try {
126  currentImage = SleuthkitJNI.addImageToDatabase(currentCase.getSleuthkitCase(), new String[]{imageFilePath},
127  0, timeZone, "", "", "", deviceId);
128  } catch (TskCoreException ex) {
129  LOGGER.log(Level.SEVERE, "Error adding image " + imageFilePath + " to database", ex);
130  errorMessages.add(Bundle.AddMultipleImagesTask_imageError(imageFilePath));
131  result = DataSourceProcessorResult.CRITICAL_ERRORS;
132  }
133 
134  synchronized (tskAddImageProcessLock) {
135 
136  if (!tskAddImageProcessStopped) {
137  addImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, false, false, "");
138  } else {
139  return;
140  }
141  }
142  run(imageFilePath, currentImage, corruptedImageFilePaths, errorMessages);
143  finishAddImageProcess(imageFilePath, errorMessages, newDataSources);
144  synchronized (tskAddImageProcessLock) {
145  if (tskAddImageProcessStopped) {
146  errorMessages.add(Bundle.AddMultipleImagesTask_cancelled());
147  result = DataSourceProcessorResult.CRITICAL_ERRORS;
148  newDataSources = emptyDataSources;
149  return;
150  }
151  }
152  }
153 
154  /*
155  * Try to add any input image files that did not have file systems as a
156  * single an unallocated space file with the device id as the root virtual
157  * directory name.
158  */
159  if (!tskAddImageProcessStopped && !corruptedImageFilePaths.isEmpty()) {
160  SleuthkitCase caseDatabase;
161  caseDatabase = currentCase.getSleuthkitCase();
162  try {
163  progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
164 
165  Image dataSource = caseDatabase.addImageInfo(0, corruptedImageFilePaths, timeZone);
166  newDataSources.add(dataSource);
167  List<TskFileRange> fileRanges = new ArrayList<>();
168 
169  long imageSize = dataSource.getSize();
170  int sequence = 0;
171  //start byte and end byte
172  long start = 0;
173  if (chunkSize > 0 && imageSize >= TWO_GB) {
174  for (double size = TWO_GB; size < dataSource.getSize(); size += TWO_GB) {
175  fileRanges.add(new TskFileRange(start, TWO_GB, sequence));
176  start += TWO_GB;
177  sequence++;
178  }
179  }
180  double leftoverSize = imageSize - sequence * TWO_GB;
181  fileRanges.add(new TskFileRange(start, (long)leftoverSize, sequence));
182 
183  caseDatabase.addLayoutFiles(dataSource, fileRanges);
184  } catch (TskCoreException ex) {
185  errorMessages.add(Bundle.AddMultipleImagesTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
186  criticalErrorOccurred = true;
187  }
188  }
189 
190  /*
191  * This appears to be the best that can be done to indicate completion
192  * with the DataSourceProcessorProgressMonitor in its current form.
193  */
194  progressMonitor.setProgress(0);
195  progressMonitor.setProgress(100);
196 
197  if (criticalErrorOccurred) {
198  result = DataSourceProcessorResult.CRITICAL_ERRORS;
199  } else if (!errorMessages.isEmpty()) {
200  result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
201  } else {
202  result = DataSourceProcessorResult.NO_ERRORS;
203  }
204  }
205 
210  void cancelTask() {
211  LOGGER.log(Level.WARNING, "AddMultipleImagesTask cancelled, processing may be incomplete"); // NON-NLS
212  synchronized (tskAddImageProcessLock) {
213  tskAddImageProcessStopped = true;
214  if (addImageProcess != null) {
215  try {
216  /*
217  * All this does is set a flag that will make the TSK add
218  * image process exit when the flag is checked between
219  * processing steps. The state of the flag is not
220  * accessible, so record it here so that it is known that
221  * the revert method of the process object needs to be
222  * called.
223  */
224  addImageProcess.stop();
225  } catch (TskCoreException ex) {
226  LOGGER.log(Level.SEVERE, "Cancellation: addImagePRocess.stop failed", ex); // NON-NLS
227  }
228  }
229  }
230  }
231 
246  @Messages({
247  "# {0} - imageFilePath", "AddMultipleImagesTask.adding=Adding: {0}",
248  "# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
249  "# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
250  "# {0} - imageFilePath", "# {1} - deviceId", "# {2} - exceptionMessage", "AddMultipleImagesTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
251  private void run(String imageFilePath, Image image, List<String> corruptedImageFilePaths, List<String> errorMessages) {
252  /*
253  * Try to add the image to the case database as a data source.
254  */
255  progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_adding(imageFilePath));
256  try {
257  addImageProcess.run(deviceId, image, 0, new DefaultAddDataSourceCallbacks());
258  } catch (TskCoreException ex) {
259  if (ex.getMessage().contains(TSK_FS_TYPE_UNKNOWN_ERR_MSG)) {
260  /*
261  * If Sleuth Kit failed to add the image because it did not find
262  * a file system, save the image path so it can be added to the
263  * case as an unallocated space file. All other
264  * errors are critical.
265  */
266  corruptedImageFilePaths.add(imageFilePath);
267  } else {
268  errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
269  criticalErrorOccurred = true;
270  }
271  } catch (TskDataException ex) {
272  errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
273  }
274  }
275 
288  private void finishAddImageProcess(String imageFilePath, List<String> errorMessages, List<Content> newDataSources) {
289  synchronized (tskAddImageProcessLock) {
290  /*
291  * Add the new image to the list of new data
292  * sources to be returned via the getter method.
293  */
294  newDataSources.add(currentImage);
295 
296  // Do no further processing if the user canceled
297  if (tskAddImageProcessStopped) {
298  return;
299  }
300 
301  /*
302  * Verify the size of the new image. Note that it may not be what is
303  * expected, but at least part of it was added to the case.
304  */
305  String verificationError = currentImage.verifyImageSize();
306  if (!verificationError.isEmpty()) {
307  errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
308  }
309  }
310  }
311 
316  public List<String> getErrorMessages() {
317  return errorMessages;
318  }
319 
324  public DataSourceProcessorResult getResult() {
325  return result;
326  }
327 
332  public List<Content> getNewDataSources() {
333  return newDataSources;
334  }
335 }

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.