19 package org.sleuthkit.autopsy.logicalimager.dsp;
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;
45 "AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type"
47 class AddMultipleImagesTask implements Runnable {
49 private static final Logger LOGGER = Logger.getLogger(AddMultipleImagesTask.class.getName());
50 public static final String TSK_FS_TYPE_UNKNOWN_ERR_MSG = Bundle.AddMultipleImagesTask_fsTypeUnknownErr();
51 private static final long TWO_GB = 2000000000L;
52 private final String deviceId;
53 private final List<String> imageFilePaths;
54 private final String timeZone;
55 private final long chunkSize = TWO_GB;
56 private final DataSourceProcessorProgressMonitor progressMonitor;
57 private final Case currentCase;
58 private boolean criticalErrorOccurred;
59 private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess = null;
60 private List<String> errorMessages =
new ArrayList<>();
61 private DataSourceProcessorResult result;
62 private List<Content> newDataSources =
new ArrayList<>();
70 private final Object tskAddImageProcessLock;
71 @GuardedBy(
"tskAddImageProcessLock")
72 private
boolean tskAddImageProcessStopped;
92 "# {0} - file",
"AddMultipleImagesTask.addingFileAsLogicalFile=Adding: {0} as an unallocated space file.",
93 "# {0} - deviceId",
"# {1} - exceptionMessage",
94 "AddMultipleImagesTask.errorAddingImgWithoutFileSystem=Error adding images without file systems for device {0}: {1}",})
95 AddMultipleImagesTask(String deviceId, List<String> imageFilePaths, String timeZone,
96 DataSourceProcessorProgressMonitor progressMonitor)
throws NoCurrentCaseException {
97 this.deviceId = deviceId;
98 this.imageFilePaths = imageFilePaths;
99 this.timeZone = timeZone;
100 this.progressMonitor = progressMonitor;
101 currentCase = Case.getCurrentCaseThrows();
102 this.criticalErrorOccurred =
false;
103 tskAddImageProcessLock =
new Object();
107 "AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted",
111 errorMessages =
new ArrayList<>();
112 newDataSources =
new ArrayList<>();
113 List<Content> emptyDataSources =
new ArrayList<>();
118 List<String> corruptedImageFilePaths =
new ArrayList<>();
120 currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock();
121 progressMonitor.setIndeterminate(
true);
122 for (String imageFilePath : imageFilePaths) {
123 synchronized (tskAddImageProcessLock) {
124 if (!tskAddImageProcessStopped) {
125 addImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone,
false,
false,
"");
130 run(imageFilePath, corruptedImageFilePaths, errorMessages);
131 commitOrRevertAddImageProcess(imageFilePath, errorMessages, newDataSources);
132 synchronized (tskAddImageProcessLock) {
133 if (tskAddImageProcessStopped) {
134 errorMessages.add(Bundle.AddMultipleImagesTask_cancelled());
135 result = DataSourceProcessorResult.CRITICAL_ERRORS;
136 newDataSources = emptyDataSources;
142 currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock();
150 if (!tskAddImageProcessStopped && !corruptedImageFilePaths.isEmpty()) {
151 SleuthkitCase caseDatabase;
152 caseDatabase = currentCase.getSleuthkitCase();
154 progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
156 caseDatabase.acquireSingleUserCaseWriteLock();
158 Image dataSource = caseDatabase.addImageInfo(0, corruptedImageFilePaths, timeZone);
159 newDataSources.add(dataSource);
160 List<TskFileRange> fileRanges =
new ArrayList<>();
162 long imageSize = dataSource.getSize();
166 if (chunkSize > 0 && imageSize >= TWO_GB) {
167 for (
double size = TWO_GB; size < dataSource.getSize(); size += TWO_GB) {
168 fileRanges.add(
new TskFileRange(start, TWO_GB, sequence));
173 double leftoverSize = imageSize - sequence * TWO_GB;
174 fileRanges.add(
new TskFileRange(start, (
long)leftoverSize, sequence));
176 caseDatabase.addLayoutFiles(dataSource, fileRanges);
177 }
catch (TskCoreException ex) {
178 errorMessages.add(Bundle.AddMultipleImagesTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
179 criticalErrorOccurred =
true;
181 caseDatabase.releaseSingleUserCaseWriteLock();
189 progressMonitor.setProgress(0);
190 progressMonitor.setProgress(100);
192 if (criticalErrorOccurred) {
193 result = DataSourceProcessorResult.CRITICAL_ERRORS;
194 }
else if (!errorMessages.isEmpty()) {
195 result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
197 result = DataSourceProcessorResult.NO_ERRORS;
206 LOGGER.log(Level.WARNING,
"AddMultipleImagesTask cancelled, processing may be incomplete");
207 synchronized (tskAddImageProcessLock) {
208 tskAddImageProcessStopped =
true;
209 if (addImageProcess != null) {
219 addImageProcess.stop();
220 }
catch (TskCoreException ex) {
221 LOGGER.log(Level.SEVERE,
"Cancellation: addImagePRocess.stop failed", ex);
241 "# {0} - imageFilePath",
"AddMultipleImagesTask.adding=Adding: {0}",
242 "# {0} - imageFilePath",
"# {1} - deviceId",
"# {2} - exceptionMessage",
"AddMultipleImagesTask.criticalErrorAdding=Critical error adding {0} for device {1}: {2}",
243 "# {0} - imageFilePath",
"# {1} - deviceId",
"# {2} - exceptionMessage",
"AddMultipleImagesTask.criticalErrorReverting=Critical error reverting add image process for {0} for device {1}: {2}",
244 "# {0} - imageFilePath",
"# {1} - deviceId",
"# {2} - exceptionMessage",
"AddMultipleImagesTask.nonCriticalErrorAdding=Non-critical error adding {0} for device {1}: {2}",})
245 private void run(String imageFilePath, List<String> corruptedImageFilePaths, List<String> errorMessages) {
249 progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_adding(imageFilePath));
251 addImageProcess.run(deviceId,
new String[]{imageFilePath});
252 }
catch (TskCoreException ex) {
253 if (ex.getMessage().contains(TSK_FS_TYPE_UNKNOWN_ERR_MSG)) {
260 corruptedImageFilePaths.add(imageFilePath);
262 errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
263 criticalErrorOccurred =
true;
265 }
catch (TskDataException ex) {
266 errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
282 private void commitOrRevertAddImageProcess(String imageFilePath, List<String> errorMessages, List<Content> newDataSources) {
283 synchronized (tskAddImageProcessLock) {
284 if (tskAddImageProcessStopped || criticalErrorOccurred) {
286 addImageProcess.revert();
287 }
catch (TskCoreException ex) {
288 errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorReverting(imageFilePath, deviceId, ex.getLocalizedMessage()));
289 criticalErrorOccurred =
true;
300 long imageId = addImageProcess.commit();
301 Image dataSource = currentCase.getSleuthkitCase().getImageById(imageId);
302 newDataSources.add(dataSource);
308 String verificationError = dataSource.verifyImageSize();
309 if (!verificationError.isEmpty()) {
310 errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
312 }
catch (TskCoreException ex) {
318 errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
319 criticalErrorOccurred =
true;
328 public List<String> getErrorMessages() {
329 return errorMessages;
336 public DataSourceProcessorResult getResult() {
344 public List<Content> getNewDataSources() {
345 return newDataSources;