Autopsy 4.22.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
AddLogicalImageTask.java
Go to the documentation of this file.
1/*
2 * Autopsy
3 *
4 * Copyright 2019-2021 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.io.BufferedReader;
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FilenameFilter;
25import java.io.IOException;
26import java.io.InputStreamReader;
27import java.nio.file.Files;
28import java.nio.file.Path;
29import java.nio.file.Paths;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.HashMap;
33import java.util.Iterator;
34import java.util.List;
35import java.util.Map;
36import java.util.logging.Level;
37import javax.annotation.concurrent.GuardedBy;
38import org.apache.commons.io.FileUtils;
39import org.openide.util.NbBundle.Messages;
40import org.sleuthkit.autopsy.casemodule.Case;
41import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
42import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
43import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
44import org.sleuthkit.autopsy.coreutils.Logger;
45import org.sleuthkit.autopsy.datamodel.utils.LocalFileImporter;
46import org.sleuthkit.datamodel.AbstractFile;
47import org.sleuthkit.datamodel.Blackboard;
48import org.sleuthkit.datamodel.BlackboardArtifact;
49import org.sleuthkit.datamodel.BlackboardAttribute;
50import org.sleuthkit.datamodel.Content;
51import org.sleuthkit.datamodel.Host;
52import org.sleuthkit.datamodel.LocalFilesDataSource;
53import org.sleuthkit.datamodel.Score;
54import org.sleuthkit.datamodel.SleuthkitCase;
55import org.sleuthkit.datamodel.TskCoreException;
56
62final class AddLogicalImageTask implements Runnable {
63
68 private static class FileId {
69
70 private final long dataSourceId;
71 private final long fileId;
72
79 FileId(long dataSourceId, long fileId) {
80 this.dataSourceId = dataSourceId;
81 this.fileId = fileId;
82 }
83
89 long getDataSourceId() {
90 return dataSourceId;
91 }
92
98 long getFileId() {
99 return fileId;
100 }
101 }
102
103 private final static Logger LOGGER = Logger.getLogger(AddLogicalImageTask.class.getName());
104 private final static String SEARCH_RESULTS_TXT = "SearchResults.txt"; //NON-NLS
105 private final static String USERS_TXT = "_users.txt"; //NON-NLS
106 private final static String MODULE_NAME = "Logical Imager"; //NON-NLS
107 private final static String ROOT_STR = "root"; // NON-NLS
108 private final static String VHD_EXTENSION = ".vhd"; // NON-NLS
109 private final static int REPORT_PROGRESS_INTERVAL = 100;
110 private final static int POST_ARTIFACT_INTERVAL = 1000;
111 private final String deviceId;
112 private final String timeZone;
113 private final File src;
114 private final File dest;
115 private final Host host;
116 private final DataSourceProcessorCallback callback;
117 private final DataSourceProcessorProgressMonitor progressMonitor;
118 private final Blackboard blackboard;
119 private final Case currentCase;
120
121 private volatile boolean cancelled;
122 private volatile boolean createVHD;
123 private long totalFiles;
124 private Map<String, Long> imagePathToObjIdMap;
125
126 private final Object addMultipleImagesLock;
127 @GuardedBy("addMultipleImagesLock")
128 private AddMultipleImagesTask addMultipleImagesTask = null;
129
130 AddLogicalImageTask(String deviceId,
131 String timeZone,
132 File src, File dest, Host host,
133 DataSourceProcessorProgressMonitor progressMonitor,
134 DataSourceProcessorCallback callback
135 ) throws NoCurrentCaseException {
136 this.deviceId = deviceId;
137 this.timeZone = timeZone;
138 this.src = src;
139 this.dest = dest;
140 this.host = host;
141 this.progressMonitor = progressMonitor;
142 this.callback = callback;
143 this.currentCase = Case.getCurrentCase();
144 this.blackboard = this.currentCase.getServices().getArtifactsBlackboard();
145 this.addMultipleImagesLock = new Object();
146 }
147
152 @Messages({
153 "# {0} - src", "# {1} - dest", "AddLogicalImageTask.copyingImageFromTo=Copying image from {0} to {1}",
154 "AddLogicalImageTask.doneCopying=Done copying",
155 "# {0} - src", "# {1} - dest", "AddLogicalImageTask.failedToCopyDirectory=Failed to copy directory {0} to {1}",
156 "# {0} - file", "AddLogicalImageTask.addingToReport=Adding {0} to report",
157 "# {0} - file", "AddLogicalImageTask.doneAddingToReport=Done adding {0} to report",
158 "AddLogicalImageTask.ingestionCancelled=Ingestion cancelled",
159 "# {0} - file", "AddLogicalImageTask.failToGetCanonicalPath=Fail to get canonical path for {0}",
160 "# {0} - sparseImageDirectory", "AddLogicalImageTask.directoryDoesNotContainSparseImage=Directory {0} does not contain any images",
161 "AddLogicalImageTask.noCurrentCase=No current case",
162 "AddLogicalImageTask.addingInterestingFiles=Adding search results as interesting files",
163 "AddLogicalImageTask.doneAddingInterestingFiles=Done adding search results as interesting files",
164 "# {0} - SearchResults.txt", "# {1} - directory", "AddLogicalImageTask.cannotFindFiles=Cannot find {0} in {1}",
165 "# {0} - reason", "AddLogicalImageTask.failedToAddInterestingFiles=Failed to add interesting files: {0}",
166 "AddLogicalImageTask.addingExtractedFiles=Adding extracted files",
167 "AddLogicalImageTask.doneAddingExtractedFiles=Done adding extracted files",
168 "# {0} - reason", "AddLogicalImageTask.failedToGetTotalFilesCount=Failed to get total files count: {0}",
169 "AddLogicalImageTask.addImageCancelled=Add image cancelled"
170 })
171 @Override
172 public void run() {
173 List<String> errorList = new ArrayList<>();
174 List<Content> emptyDataSources = new ArrayList<>();
175
176 try {
177 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_copyingImageFromTo(src.toString(), dest.toString()));
178 FileUtils.copyDirectory(src, dest);
179 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneCopying());
180 } catch (IOException ex) {
181 // Copy directory failed
182 String msg = Bundle.AddLogicalImageTask_failedToCopyDirectory(src.toString(), dest.toString());
183 errorList.add(msg);
184 }
185
186 if (cancelled) {
187 // Don't delete destination directory once we started adding interesting files.
188 // At this point the database and destination directory are complete.
189 deleteDestinationDirectory();
190 errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
191 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
192 return;
193 }
194
195 // Add the SearchResults.txt and *_users.txt to the case report
196 String resultsFilename;
197 if (Paths.get(dest.toString(), SEARCH_RESULTS_TXT).toFile().exists()) {
198 resultsFilename = SEARCH_RESULTS_TXT;
199 } else {
200 errorList.add(Bundle.AddLogicalImageTask_cannotFindFiles(SEARCH_RESULTS_TXT, dest.toString()));
201 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
202 return;
203 }
204
205 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(resultsFilename));
206 String status = addReport(Paths.get(dest.toString(), resultsFilename), resultsFilename + " " + src.getName());
207 if (status != null) {
208 errorList.add(status);
209 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
210 return;
211 }
212 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(resultsFilename));
213
214 // All all *_users.txt files to report
215 File[] userFiles = dest.listFiles(new FilenameFilter() {
216 @Override
217 public boolean accept(File dir, String name) {
218 return name.endsWith(USERS_TXT);
219 }
220 });
221
222 for (File userFile : userFiles) {
223 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingToReport(userFile.getName()));
224 status = addReport(userFile.toPath(), userFile.getName() + " " + src.getName());
225 if (status != null) {
226 errorList.add(status);
227 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
228 return;
229 }
230 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingToReport(userFile.getName()));
231 }
232
233 // Get all VHD files in the dest directory
234 List<String> imagePaths = new ArrayList<>();
235 for (File f : dest.listFiles()) {
236 if (f.getName().endsWith(VHD_EXTENSION)) {
237 try {
238 imagePaths.add(f.getCanonicalPath());
239 } catch (IOException ioe) {
240 String msg = Bundle.AddLogicalImageTask_failToGetCanonicalPath(f.getName());
241 errorList.add(msg);
242 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
243 return;
244 }
245 }
246 }
247
248 Path resultsPath = Paths.get(dest.toString(), resultsFilename);
249 try {
250 totalFiles = Files.lines(resultsPath).count() - 1; // skip the header line
251 } catch (IOException ex) {
252 errorList.add(Bundle.AddLogicalImageTask_failedToGetTotalFilesCount(ex.getMessage()));
253 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
254 return;
255 }
256
257 List<Content> newDataSources = new ArrayList<>();
258 Map<String, List<FileId>> interestingFileMap = new HashMap<>();
259
260 if (imagePaths.isEmpty()) {
261 createVHD = false;
262 // No VHD in src directory, try ingest the root directory as local files
263 File root = Paths.get(dest.toString(), ROOT_STR).toFile();
264 if (root.exists() && root.isDirectory()) {
265 imagePaths.add(root.getAbsolutePath());
266 } else {
267 String msg = Bundle.AddLogicalImageTask_directoryDoesNotContainSparseImage(dest);
268 errorList.add(msg);
269 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
270 return;
271 }
272
273 try {
274 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFiles());
275 interestingFileMap = addExtractedFiles(dest, resultsPath, host, newDataSources);
276 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingExtractedFiles());
277 } catch (IOException | TskCoreException ex) {
278 errorList.add(ex.getMessage());
279 LOGGER.log(Level.SEVERE, String.format("Failed to add datasource: %s", ex.getMessage()), ex); // NON-NLS
280 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
281 return;
282 }
283 } else {
284 createVHD = true;
285 // ingest the VHDs
286 try {
287 synchronized (addMultipleImagesLock) {
288 if (cancelled) {
289 LOGGER.log(Level.SEVERE, "Add VHD cancelled"); // NON-NLS
290 errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
291 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
292 return;
293 }
294 addMultipleImagesTask = new AddMultipleImagesTask(deviceId, imagePaths, timeZone, host, progressMonitor);
295 }
296 addMultipleImagesTask.run();
297 if (addMultipleImagesTask.getResult() == DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS) {
298 LOGGER.log(Level.SEVERE, "Failed to add VHD datasource"); // NON-NLS
299 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, addMultipleImagesTask.getErrorMessages(), emptyDataSources);
300 return;
301 }
302 try {
303 interestingFileMap = getInterestingFileMapForVHD(Paths.get(dest.toString(), resultsFilename));
304 } catch (TskCoreException | IOException ex) {
305 errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
306 LOGGER.log(Level.SEVERE, "Failed to add interesting files", ex); // NON-NLS
307 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS, errorList, emptyDataSources);
308 }
309
310 } catch (NoCurrentCaseException ex) {
311 String msg = Bundle.AddLogicalImageTask_noCurrentCase();
312 errorList.add(msg);
313 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
314 return;
315 }
316 }
317
318 if (cancelled) {
319 if (!createVHD) {
320 // TODO: When 5453 is fixed, we should be able to delete it when adding VHD.
321 deleteDestinationDirectory();
322 }
323 errorList.add(Bundle.AddLogicalImageTask_addImageCancelled());
324 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS, errorList, emptyDataSources);
325 return;
326 }
327
328 try {
329 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFiles());
330 addInterestingFiles(interestingFileMap);
331 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_doneAddingInterestingFiles());
332 if (createVHD) {
333 callback.done(addMultipleImagesTask.getResult(), addMultipleImagesTask.getErrorMessages(), addMultipleImagesTask.getNewDataSources());
334 } else {
335 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS, errorList, newDataSources);
336 }
337 } catch (IOException | TskCoreException ex) {
338 errorList.add(Bundle.AddLogicalImageTask_failedToAddInterestingFiles(ex.getMessage()));
339 LOGGER.log(Level.SEVERE, "Failed to add interesting files", ex); // NON-NLS
340 callback.done(DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS, errorList, emptyDataSources);
341 }
342 }
343
353 @Messages({
354 "# {0} - file", "# {1} - exception message", "AddLogicalImageTask.failedToAddReport=Failed to add report {0}. Reason= {1}"
355 })
356 private String addReport(Path reportPath, String reportName) {
357 if (!reportPath.toFile().exists()) {
358 return null; // if the reportPath doesn't exist, just ignore it.
359 }
360 try {
361 Case.getCurrentCase().addReport(reportPath.toString(), "LogicalImager", reportName); //NON-NLS
362 return null;
363 } catch (TskCoreException ex) {
364 String msg = Bundle.AddLogicalImageTask_failedToAddReport(reportPath.toString(), ex.getMessage());
365 LOGGER.log(Level.SEVERE, String.format("Failed to add report %s. Reason= %s", reportPath.toString(), ex.getMessage()), ex); // NON-NLS
366 return msg;
367 }
368 }
369
374 void cancelTask() {
375 LOGGER.log(Level.WARNING, "AddLogicalImageTask cancelled, processing may be incomplete"); // NON-NLS
376 synchronized (addMultipleImagesLock) {
377 cancelled = true;
378 if (addMultipleImagesTask != null) {
379 addMultipleImagesTask.cancelTask();
380 }
381 }
382 }
383
384 private Map<String, Long> imagePathsToDataSourceObjId(Map<Long, List<String>> imagePaths) {
385 Map<String, Long> imagePathToObjId = new HashMap<>();
386 for (Map.Entry<Long, List<String>> entry : imagePaths.entrySet()) {
387 Long key = entry.getKey();
388 List<String> names = entry.getValue();
389 for (String name : names) {
390 imagePathToObjId.put(name, key);
391 }
392 }
393 return imagePathToObjId;
394 }
395
396 @Messages({
397 "# {0} - line number", "# {1} - fields length", "# {2} - expected length", "AddLogicalImageTask.notEnoughFields=File does not contain enough fields at line {0}, got {1}, expecting {2}",
398 "# {0} - target image path", "AddLogicalImageTask.cannotFindDataSourceObjId=Cannot find obj_id in tsk_image_names for {0}",
399 "# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingInterestingFile=Adding interesting files ({0}/{1})",
400 "AddLogicalImageTask.logicalImagerResults=Logical Imager results"
401 })
402 private void addInterestingFiles(Map<String, List<FileId>> interestingFileMap) throws IOException, TskCoreException {
403 int lineNumber = 0;
404 List<BlackboardArtifact> artifacts = new ArrayList<>();
405
406 Iterator<Map.Entry<String, List<FileId>>> iterator = interestingFileMap.entrySet().iterator();
407 while (iterator.hasNext()) {
408
409 if (cancelled) {
410 // Don't delete destination directory once we started adding interesting files.
411 // At this point the database and destination directory are complete.
412 break;
413 }
414
415 Map.Entry<String, List<FileId>> entry = iterator.next();
416 String key = entry.getKey();
417 String ruleName;
418 String[] split = key.split("\t");
419 ruleName = split[1];
420
421 List<FileId> fileIds = entry.getValue();
422 for (FileId fileId : fileIds) {
423 if (cancelled) {
424 postArtifacts(artifacts);
425 return;
426 }
427 if (lineNumber % REPORT_PROGRESS_INTERVAL == 0) {
428 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingInterestingFile(lineNumber, totalFiles));
429 }
430 if (lineNumber % POST_ARTIFACT_INTERVAL == 0) {
431 postArtifacts(artifacts);
432 artifacts.clear();
433 }
434 addInterestingFileToArtifacts(fileId.getFileId(), fileId.getDataSourceId(), Bundle.AddLogicalImageTask_logicalImagerResults(), ruleName, artifacts);
435 lineNumber++;
436 }
437 iterator.remove();
438 }
439 postArtifacts(artifacts);
440 }
441
442 private void addInterestingFileToArtifacts(long fileId, long dataSourceId, String ruleSetName, String ruleName, List<BlackboardArtifact> artifacts) throws TskCoreException {
443 BlackboardArtifact artifact;
444 try {
445 artifact = this.blackboard.newAnalysisResult(
446 BlackboardArtifact.Type.TSK_INTERESTING_ITEM, fileId, dataSourceId,
447 Score.SCORE_LIKELY_NOTABLE,
448 null, ruleSetName, null,
449 Arrays.asList(
450 new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, ruleSetName),
451 new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ruleName)
452 ))
453 .getAnalysisResult();
454 } catch (Blackboard.BlackboardException ex) {
455 throw new TskCoreException("Unable to create analysis result.", ex);
456 }
457
458 artifacts.add(artifact);
459 }
460
461 @Messages({
462 "# {0} - file number", "# {1} - total files", "AddLogicalImageTask.searchingInterestingFile=Searching for interesting files ({0}/{1})"
463 })
464 private Map<String, List<FileId>> getInterestingFileMapForVHD(Path resultsPath) throws TskCoreException, IOException {
465 Map<Long, List<String>> objIdToimagePathsMap = currentCase.getSleuthkitCase().getImagePaths();
466 imagePathToObjIdMap = imagePathsToDataSourceObjId(objIdToimagePathsMap);
467 Map<String, List<FileId>> interestingFileMap = new HashMap<>();
468
469 try (BufferedReader br = new BufferedReader(new InputStreamReader(
470 new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
471 String line;
472 br.readLine(); // skip the header line
473 int lineNumber = 2;
474 while ((line = br.readLine()) != null) {
475 if (cancelled) {
476 // Don't delete destination directory once we started adding interesting files.
477 // At this point the database and destination directory are complete.
478 break;
479 }
480 String[] fields = line.split("\t", -1); // NON-NLS
481 if (fields.length != 14) {
482 throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 14));
483 }
484 String vhdFilename = fields[0];
485// String fileSystemOffsetStr = fields[1];
486 String fileMetaAddressStr = fields[2];
487// String extractStatusStr = fields[3];
488 String ruleSetName = fields[4];
489 String ruleName = fields[5];
490// String description = fields[6];
491 String filename = fields[7];
492 String parentPath = fields[8];
493
494 if (lineNumber % REPORT_PROGRESS_INTERVAL == 0) {
495 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_searchingInterestingFile(lineNumber, totalFiles));
496 }
497
498 String query = makeQuery(vhdFilename, fileMetaAddressStr, parentPath, filename);
499 List<AbstractFile> matchedFiles = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(query);
500 List<FileId> fileIds = new ArrayList<>();
501 for (AbstractFile file : matchedFiles) {
502 fileIds.add(new FileId(file.getDataSourceObjectId(), file.getId()));
503 }
504 String key = String.format("%s\t%s", ruleSetName, ruleName);
505 interestingFileMap.computeIfAbsent(key, (k) -> new ArrayList<>())
506 .addAll(fileIds);
507
508 lineNumber++;
509 } // end reading file
510 }
511 return interestingFileMap;
512 }
513
514 private void postArtifacts(List<BlackboardArtifact> artifacts) {
515 try {
516 blackboard.postArtifacts(artifacts, MODULE_NAME, null);
517 } catch (Blackboard.BlackboardException ex) {
518 LOGGER.log(Level.SEVERE, "Unable to post artifacts to blackboard", ex); //NON-NLS
519 }
520 }
521
522 @Messages({
523 "# {0} - file number", "# {1} - total files", "AddLogicalImageTask.addingExtractedFile=Adding extracted files ({0}/{1})"
524 })
525 private Map<String, List<FileId>> addExtractedFiles(File src, Path resultsPath, Host host, List<Content> newDataSources) throws TskCoreException, IOException {
526 SleuthkitCase skCase = Case.getCurrentCase().getSleuthkitCase();
527 SleuthkitCase.CaseDbTransaction trans = null;
528 Map<String, List<FileId>> interestingFileMap = new HashMap<>();
529
530 try {
531 trans = skCase.beginTransaction();
532 LocalFilesDataSource localFilesDataSource = skCase.addLocalFilesDataSource(deviceId, this.src.getName(), timeZone, host, trans);
533 LocalFileImporter fileImporter = new LocalFileImporter(skCase, trans);
534
535 try (BufferedReader br = new BufferedReader(new InputStreamReader(
536 new FileInputStream(resultsPath.toFile()), "UTF8"))) { // NON-NLS
537 String line;
538 br.readLine(); // skip the header line
539 int lineNumber = 2;
540 while ((line = br.readLine()) != null) {
541 if (cancelled) {
542 rollbackTransaction(trans);
543 return new HashMap<>();
544 }
545 String[] fields = line.split("\t", -1); // NON-NLS
546 if (fields.length != 14) {
547 rollbackTransaction(trans);
548 throw new IOException(Bundle.AddLogicalImageTask_notEnoughFields(lineNumber, fields.length, 14));
549 }
550 String vhdFilename = fields[0];
551// String fileSystemOffsetStr = fields[1];
552// String fileMetaAddressStr = fields[2];
553// String extractStatusStr = fields[3];
554 String ruleSetName = fields[4];
555 String ruleName = fields[5];
556// String description = fields[6];
557 String filename = fields[7];
558 String parentPath = fields[8];
559 String extractedFilePath = fields[9];
560 String crtime = fields[10];
561 String mtime = fields[11];
562 String atime = fields[12];
563 String ctime = fields[13];
564 parentPath = ROOT_STR + "/" + vhdFilename + "/" + parentPath;
565
566 if (lineNumber % REPORT_PROGRESS_INTERVAL == 0) {
567 progressMonitor.setProgressText(Bundle.AddLogicalImageTask_addingExtractedFile(lineNumber, totalFiles));
568 }
569
570 //addLocalFile here
571 AbstractFile fileAdded = fileImporter.addLocalFile(
572 Paths.get(src.toString(), extractedFilePath).toFile(),
573 filename,
574 parentPath,
575 Long.parseLong(ctime),
576 Long.parseLong(crtime),
577 Long.parseLong(atime),
578 Long.parseLong(mtime),
579 localFilesDataSource);
580 String key = String.format("%s\t%s", ruleSetName, ruleName);
581
582 long dataSourceId = fileAdded.getDataSourceObjectId();
583 long fileId = fileAdded.getId();
584 interestingFileMap.computeIfAbsent(key, (k) -> new ArrayList<>())
585 .add(new FileId(dataSourceId, fileId));
586 lineNumber++;
587 } // end reading file
588 }
589 trans.commit();
590 newDataSources.add(localFilesDataSource);
591 return interestingFileMap;
592
593 } catch (NumberFormatException | TskCoreException ex) {
594 LOGGER.log(Level.SEVERE, "Error adding extracted files", ex); // NON-NLS
595 rollbackTransaction(trans);
596 throw new TskCoreException("Error adding extracted files", ex);
597 }
598 }
599
600 private void rollbackTransaction(SleuthkitCase.CaseDbTransaction trans) throws TskCoreException {
601 if (null != trans) {
602 try {
603 trans.rollback();
604 } catch (TskCoreException ex) {
605 LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction: %s", ex.getMessage()), ex); // NON-NLS
606 }
607 }
608 }
609
610 private boolean deleteDestinationDirectory() {
611 try {
612 FileUtils.deleteDirectory(dest);
613 LOGGER.log(Level.INFO, String.format("Cancellation: Deleted directory %s", dest.toString())); // NON-NLS
614 return true;
615 } catch (IOException ex) {
616 LOGGER.log(Level.WARNING, String.format("Cancellation: Failed to delete directory %s", dest.toString()), ex); // NON-NLS
617 return false;
618 }
619 }
620
621 String makeQuery(String vhdFilename, String fileMetaAddressStr, String parentPath, String filename) throws TskCoreException {
622 String query;
623 String targetImagePath = Paths.get(dest.toString(), vhdFilename).toString();
624 Long dataSourceObjId = imagePathToObjIdMap.get(targetImagePath);
625 if (dataSourceObjId == null) {
626 throw new TskCoreException(Bundle.AddLogicalImageTask_cannotFindDataSourceObjId(targetImagePath));
627 }
628 query = String.format("data_source_obj_id = '%s' AND meta_addr = '%s' AND name = '%s'", // NON-NLS
629 dataSourceObjId.toString(), fileMetaAddressStr, filename.replace("'", "''"));
630 // TODO - findAllFilesWhere should SQL-escape the query
631 return query;
632 }
633
634}

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