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

Copyright © 2012-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.