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;
32 import org.
sleuthkit.datamodel.DefaultAddDataSourceCallbacks;
47 "AddMultipleImagesTask.fsTypeUnknownErr=Cannot determine file system type"
49 class AddMultipleImagesTask implements Runnable {
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;
74 private final Object tskAddImageProcessLock;
75 @GuardedBy(
"tskAddImageProcessLock")
76 private
boolean tskAddImageProcessStopped;
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,
101 DataSourceProcessorProgressMonitor progressMonitor)
throws NoCurrentCaseException {
102 this.deviceId = deviceId;
103 this.imageFilePaths = imageFilePaths;
104 this.timeZone = timeZone;
106 this.progressMonitor = progressMonitor;
107 currentCase = Case.getCurrentCaseThrows();
108 this.criticalErrorOccurred =
false;
109 tskAddImageProcessLock =
new Object();
113 "AddMultipleImagesTask.cancelled=Cancellation: Add image process reverted",
114 "# {0} - image path",
115 "AddMultipleImagesTask.imageError=Error adding image {0} to the database"
119 errorMessages =
new ArrayList<>();
120 newDataSources =
new ArrayList<>();
121 List<Content> emptyDataSources =
new ArrayList<>();
126 List<String> corruptedImageFilePaths =
new ArrayList<>();
127 progressMonitor.setIndeterminate(
true);
128 for (String imageFilePath : imageFilePaths) {
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));
135 result = DataSourceProcessorResult.CRITICAL_ERRORS;
138 synchronized (tskAddImageProcessLock) {
140 if (!tskAddImageProcessStopped) {
141 addImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone,
false,
false,
"");
146 run(imageFilePath, currentImage, corruptedImageFilePaths, errorMessages);
147 finishAddImageProcess(imageFilePath, errorMessages, newDataSources);
148 synchronized (tskAddImageProcessLock) {
149 if (tskAddImageProcessStopped) {
150 errorMessages.add(Bundle.AddMultipleImagesTask_cancelled());
151 result = DataSourceProcessorResult.CRITICAL_ERRORS;
152 newDataSources = emptyDataSources;
163 if (!tskAddImageProcessStopped && !corruptedImageFilePaths.isEmpty()) {
164 SleuthkitCase caseDatabase;
165 caseDatabase = currentCase.getSleuthkitCase();
167 progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_addingFileAsLogicalFile(corruptedImageFilePaths.toString()));
169 Image dataSource = caseDatabase.addImageInfo(0, corruptedImageFilePaths, timeZone);
170 newDataSources.add(dataSource);
171 List<TskFileRange> fileRanges =
new ArrayList<>();
173 long imageSize = dataSource.getSize();
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));
184 double leftoverSize = imageSize - sequence * TWO_GB;
185 fileRanges.add(
new TskFileRange(start, (
long)leftoverSize, sequence));
187 caseDatabase.addLayoutFiles(dataSource, fileRanges);
188 }
catch (TskCoreException ex) {
189 errorMessages.add(Bundle.AddMultipleImagesTask_errorAddingImgWithoutFileSystem(deviceId, ex.getLocalizedMessage()));
190 criticalErrorOccurred =
true;
198 progressMonitor.setProgress(0);
199 progressMonitor.setProgress(100);
201 if (criticalErrorOccurred) {
202 result = DataSourceProcessorResult.CRITICAL_ERRORS;
203 }
else if (!errorMessages.isEmpty()) {
204 result = DataSourceProcessorResult.NONCRITICAL_ERRORS;
206 result = DataSourceProcessorResult.NO_ERRORS;
215 LOGGER.log(Level.WARNING,
"AddMultipleImagesTask cancelled, processing may be incomplete");
216 synchronized (tskAddImageProcessLock) {
217 tskAddImageProcessStopped =
true;
218 if (addImageProcess != null) {
228 addImageProcess.stop();
229 }
catch (TskCoreException ex) {
230 LOGGER.log(Level.SEVERE,
"Cancellation: addImagePRocess.stop failed", ex);
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) {
259 progressMonitor.setProgressText(Bundle.AddMultipleImagesTask_adding(imageFilePath));
261 addImageProcess.run(deviceId, image, 0,
new DefaultAddDataSourceCallbacks());
262 }
catch (TskCoreException ex) {
263 if (ex.getMessage().contains(TSK_FS_TYPE_UNKNOWN_ERR_MSG)) {
270 corruptedImageFilePaths.add(imageFilePath);
272 errorMessages.add(Bundle.AddMultipleImagesTask_criticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
273 criticalErrorOccurred =
true;
275 }
catch (TskDataException ex) {
276 errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, ex.getLocalizedMessage()));
292 private void finishAddImageProcess(String imageFilePath, List<String> errorMessages, List<Content> newDataSources) {
293 synchronized (tskAddImageProcessLock) {
298 newDataSources.add(currentImage);
301 if (tskAddImageProcessStopped) {
309 String verificationError = currentImage.verifyImageSize();
310 if (!verificationError.isEmpty()) {
311 errorMessages.add(Bundle.AddMultipleImagesTask_nonCriticalErrorAdding(imageFilePath, deviceId, verificationError));
320 public List<String> getErrorMessages() {
321 return errorMessages;
328 public DataSourceProcessorResult getResult() {
336 public List<Content> getNewDataSources() {
337 return newDataSources;