Autopsy  4.10.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
CreatePortableCaseModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
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.report;
20 
21 import org.openide.util.lookup.ServiceProvider;
22 import javax.swing.JPanel;
23 import java.util.logging.Level;
24 import java.io.File;
25 import java.io.IOException;
26 import java.nio.file.Paths;
27 import java.sql.ResultSet;
28 import java.sql.SQLException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import org.openide.util.NbBundle;
42 import org.sleuthkit.datamodel.AbstractFile;
43 import org.sleuthkit.datamodel.BlackboardArtifact;
44 import org.sleuthkit.datamodel.BlackboardArtifactTag;
45 import org.sleuthkit.datamodel.BlackboardAttribute;
46 import org.sleuthkit.datamodel.CaseDbAccessManager;
47 import org.sleuthkit.datamodel.Content;
48 import org.sleuthkit.datamodel.ContentTag;
49 import org.sleuthkit.datamodel.FileSystem;
50 import org.sleuthkit.datamodel.Image;
51 import org.sleuthkit.datamodel.LocalFilesDataSource;
52 import org.sleuthkit.datamodel.SleuthkitCase;
53 import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
54 import org.sleuthkit.datamodel.TagName;
55 import org.sleuthkit.datamodel.TskCoreException;
56 import org.sleuthkit.datamodel.TskDataException;
57 import org.sleuthkit.datamodel.TskData;
58 import org.sleuthkit.datamodel.Volume;
59 import org.sleuthkit.datamodel.VolumeSystem;
60 
64 @ServiceProvider(service = GeneralReportModule.class)
66  private static final Logger logger = Logger.getLogger(CreatePortableCaseModule.class.getName());
67  private static final String FILE_FOLDER_NAME = "PortableCaseFiles";
68  private static final String UNKNOWN_FILE_TYPE_FOLDER = "Other";
69  private static final String MAX_ID_TABLE_NAME = "portable_case_max_ids";
70  private CreatePortableCasePanel configPanel;
71 
72  // These are the types for the exported file subfolders
73  private static final List<FileTypeCategory> FILE_TYPE_CATEGORIES = Arrays.asList(FileTypeCategory.AUDIO, FileTypeCategory.DOCUMENTS,
75 
76  private Case currentCase = null;
77  private SleuthkitCase portableSkCase = null;
78  private File caseFolder = null;
79  private File copiedFilesFolder = null;
80 
81  // Maps old object ID from current case to new object in portable case
82  private final Map<Long, Content> oldIdToNewContent = new HashMap<>();
83 
84  // Maps new object ID to the new object
85  private final Map<Long, Content> newIdToContent = new HashMap<>();
86 
87  // Maps old TagName to new TagName
88  private final Map<TagName, TagName> oldTagNameToNewTagName = new HashMap<>();
89 
90  // Map of old artifact type ID to new artifact type ID. There will only be changes if custom artifact types are present.
91  private final Map<Integer, Integer> oldArtTypeIdToNewArtTypeId = new HashMap<>();
92 
93  // Map of old attribute type ID to new attribute type ID. There will only be changes if custom attr types are present.
94  private final Map<Integer, BlackboardAttribute.Type> oldAttrTypeIdToNewAttrType = new HashMap<>();
95 
96  // Map of old artifact ID to new artifact
97  private final Map<Long, BlackboardArtifact> oldArtifactIdToNewArtifact = new HashMap<>();
98 
100  // Nothing to do here
101  }
102 
103  @NbBundle.Messages({
104  "CreatePortableCaseModule.getName.name=Portable Case"
105  })
106  @Override
107  public String getName() {
108  return Bundle.CreatePortableCaseModule_getName_name();
109  }
110 
111  @NbBundle.Messages({
112  "CreatePortableCaseModule.getDescription.description=Copies selected tagged items to a new single-user case that will work anywhere"
113  })
114  @Override
115  public String getDescription() {
116  return Bundle.CreatePortableCaseModule_getDescription_description();
117  }
118 
119  @Override
120  public String getRelativeFilePath() {
121  return "";
122  }
123 
134  private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) {
135  if (ex == null) {
136  logger.log(Level.WARNING, logWarning);
137  } else {
138  logger.log(Level.SEVERE, logWarning, ex);
139  }
140  MessageNotifyUtil.Message.error(dialogWarning);
141  progressPanel.setIndeterminate(false);
143  cleanup();
144  }
145 
146  @NbBundle.Messages({
147  "CreatePortableCaseModule.generateReport.verifying=Verifying selected parameters...",
148  "CreatePortableCaseModule.generateReport.creatingCase=Creating portable case database...",
149  "CreatePortableCaseModule.generateReport.copyingTags=Copying tags...",
150  "# {0} - tag name",
151  "CreatePortableCaseModule.generateReport.copyingFiles=Copying files tagged as {0}...",
152  "# {0} - tag name",
153  "CreatePortableCaseModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
154  "# {0} - output folder",
155  "CreatePortableCaseModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
156  "# {0} - output folder",
157  "CreatePortableCaseModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
158  "CreatePortableCaseModule.generateReport.noTagsSelected=No tags selected for export.",
159  "CreatePortableCaseModule.generateReport.caseClosed=Current case has been closed",
160  "CreatePortableCaseModule.generateReport.errorCopyingTags=Error copying tags",
161  "CreatePortableCaseModule.generateReport.errorCopyingFiles=Error copying tagged files",
162  "CreatePortableCaseModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
163  "# {0} - attribute type name",
164  "CreatePortableCaseModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
165  })
166  @Override
167  public void generateReport(String reportPath, ReportProgressPanel progressPanel) {
168  progressPanel.setIndeterminate(true);
169  progressPanel.start();
170  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_verifying());
171 
172  // Clear out any old values
173  cleanup();
174 
175  // Validate the input parameters
176  File outputDir = new File(configPanel.getOutputFolder());
177  if (! outputDir.exists()) {
178  handleError("Output folder " + outputDir.toString() + " does not exist",
179  Bundle.CreatePortableCaseModule_generateReport_outputDirDoesNotExist(outputDir.toString()), null, progressPanel);
180  return;
181  }
182 
183  if (! outputDir.isDirectory()) {
184  handleError("Output folder " + outputDir.toString() + " is not a folder",
185  Bundle.CreatePortableCaseModule_generateReport_outputDirIsNotDir(outputDir.toString()), null, progressPanel);
186  return;
187  }
188 
189  List<TagName> tagNames = configPanel.getSelectedTagNames();
190  if (tagNames.isEmpty()) {
191  handleError("No tags selected for export",
192  Bundle.CreatePortableCaseModule_generateReport_noTagsSelected(), null, progressPanel);
193  return;
194  }
195 
196  // Save the current case object
197  try {
198  currentCase = Case.getCurrentCaseThrows();
199  } catch (NoCurrentCaseException ex) {
200  handleError("Current case has been closed",
201  Bundle.CreatePortableCaseModule_generateReport_caseClosed(), null, progressPanel);
202  return;
203  }
204 
205 
206  // Create the case.
207  // portableSkCase and caseFolder will be set here.
208  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_creatingCase());
209  createCase(outputDir, progressPanel);
210  if (portableSkCase == null) {
211  // The error has already been handled
212  return;
213  }
214 
215  // Check for cancellation
216  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
217  cleanup();
218  return;
219  }
220 
221  // Copy the selected tags
222  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingTags());
223  try {
224  for(TagName tagName:tagNames) {
225  TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
226  oldTagNameToNewTagName.put(tagName, newTagName);
227  }
228  } catch (TskCoreException ex) {
229  handleError("Error copying tags", Bundle.CreatePortableCaseModule_generateReport_errorCopyingTags(), ex, progressPanel);
230  return;
231  }
232 
233  // Copy the tagged files
234  try {
235  for(TagName tagName:tagNames) {
236  // Check for cancellation
237  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
238  return;
239  }
240  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingFiles(tagName.getDisplayName()));
241  addFilesToPortableCase(tagName, progressPanel);
242  }
243  } catch (TskCoreException ex) {
244  handleError("Error copying tagged files", Bundle.CreatePortableCaseModule_generateReport_errorCopyingFiles(), ex, progressPanel);
245  return;
246  }
247 
248  // Set up tracking to support any custom artifact or attribute types
249  for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) {
250  oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
251  }
252  for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
253  try {
254  oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel()));
255  } catch (TskCoreException ex) {
256  handleError("Error looking up attribute name " + type.getLabel(),
257  Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()),
258  ex, progressPanel);
259  }
260  }
261 
262  // Copy the tagged artifacts and associated files
263  try {
264  for(TagName tagName:tagNames) {
265  // Check for cancellation
266  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
267  return;
268  }
269  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
270  addArtifactsToPortableCase(tagName, progressPanel);
271  }
272  } catch (TskCoreException ex) {
273  handleError("Error copying tagged artifacts", Bundle.CreatePortableCaseModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
274  return;
275  }
276 
277  // Close the case connections and clear out the maps
278  cleanup();
279 
281 
282  }
283 
291  @NbBundle.Messages({
292  "# {0} - case folder",
293  "CreatePortableCaseModule.createCase.caseDirExists=Case folder {0} already exists",
294  "CreatePortableCaseModule.createCase.errorCreatingCase=Error creating case",
295  "# {0} - folder",
296  "CreatePortableCaseModule.createCase.errorCreatingFolder=Error creating folder {0}",
297  "CreatePortableCaseModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",
298  })
299  private void createCase(File outputDir, ReportProgressPanel progressPanel) {
300 
301  // Create the case folder
302  String caseName = currentCase.getDisplayName() + " (Portable)";
303  caseFolder = Paths.get(outputDir.toString(), caseName).toFile();
304 
305  if (caseFolder.exists()) {
306  handleError("Case folder " + caseFolder.toString() + " already exists",
307  Bundle.CreatePortableCaseModule_createCase_caseDirExists(caseFolder.toString()), null, progressPanel);
308  return;
309  }
310 
311  // Create the case
312  try {
313  portableSkCase = currentCase.createPortableCase(caseName, caseFolder);
314  } catch (TskCoreException ex) {
315  handleError("Error creating case " + caseName + " in folder " + caseFolder.toString(),
316  Bundle.CreatePortableCaseModule_createCase_errorCreatingCase(), ex, progressPanel);
317  return;
318  }
319 
320  // Store the highest IDs
321  try {
322  saveHighestIds();
323  } catch (TskCoreException ex) {
324  handleError("Error storing maximum database IDs",
325  Bundle.CreatePortableCaseModule_createCase_errorStoringMaxIds(), ex, progressPanel);
326  return;
327  }
328 
329  // Create the base folder for the copied files
330  copiedFilesFolder = Paths.get(caseFolder.toString(), FILE_FOLDER_NAME).toFile();
331  if (! copiedFilesFolder.mkdir()) {
332  handleError("Error creating folder " + copiedFilesFolder.toString(),
333  Bundle.CreatePortableCaseModule_createCase_errorCreatingFolder(copiedFilesFolder.toString()), null, progressPanel);
334  return;
335  }
336 
337  // Create subfolders for the copied files
338  for (FileTypeCategory cat:FILE_TYPE_CATEGORIES) {
339  File subFolder = Paths.get(copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
340  if (! subFolder.mkdir()) {
341  handleError("Error creating folder " + subFolder.toString(),
342  Bundle.CreatePortableCaseModule_createCase_errorCreatingFolder(subFolder.toString()), null, progressPanel);
343  return;
344  }
345  }
346  File unknownTypeFolder = Paths.get(copiedFilesFolder.toString(), UNKNOWN_FILE_TYPE_FOLDER).toFile();
347  if (! unknownTypeFolder.mkdir()) {
348  handleError("Error creating folder " + unknownTypeFolder.toString(),
349  Bundle.CreatePortableCaseModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()), null, progressPanel);
350  return;
351  }
352 
353  }
354 
360  private void saveHighestIds() throws TskCoreException {
361 
362  CaseDbAccessManager currentCaseDbManager = currentCase.getSleuthkitCase().getCaseDbAccessManager();
363 
364  String tableSchema = "( table_name TEXT PRIMARY KEY, "
365  + " max_id TEXT)";
366 
367  portableSkCase.getCaseDbAccessManager().createTable(MAX_ID_TABLE_NAME, tableSchema);
368 
369  currentCaseDbManager.select("max(obj_id) as max_id from tsk_objects", new StoreMaxIdCallback("tsk_objects"));
370  currentCaseDbManager.select("max(tag_id) as max_id from content_tags", new StoreMaxIdCallback("content_tags"));
371  currentCaseDbManager.select("max(tag_id) as max_id from blackboard_artifact_tags", new StoreMaxIdCallback("blackboard_artifact_tags"));
372  currentCaseDbManager.select("max(examiner_id) as max_id from tsk_examiners", new StoreMaxIdCallback("tsk_examiners"));
373  }
374 
383  private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
384 
385  // Get all the tags in the current case
386  List<ContentTag> tags = currentCase.getServices().getTagsManager().getContentTagsByTagName(oldTagName);
387 
388  // Copy the files into the portable case and tag
389  for (ContentTag tag : tags) {
390 
391  // Check for cancellation
392  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
393  return;
394  }
395 
396  Content content = tag.getContent();
397  if (content instanceof AbstractFile) {
398  long newFileId = copyContentToPortableCase(content, progressPanel);
399 
400  // Tag the file
401  if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
402  throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName());
403  }
404  portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
405  }
406  }
407  }
408 
417  private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
418 
419  List<BlackboardArtifactTag> tags = currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName);
420 
421  // Copy the artifacts into the portable case along with their content and tag
422  for (BlackboardArtifactTag tag : tags) {
423 
424  // Check for cancellation
425  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
426  return;
427  }
428 
429  // Copy the source content
430  Content content = tag.getContent();
431  long newContentId = copyContentToPortableCase(content, progressPanel);
432 
433  // Copy the artifact
434  BlackboardArtifact newArtifact = copyArtifact(newContentId, tag.getArtifact());
435 
436  // Tag the artfiact
437  if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
438  throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName());
439  }
440  portableSkCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
441  }
442  }
443 
454  private BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy) throws TskCoreException {
455 
456  if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
457  return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
458  }
459 
460  // First create the associated artifact (if present)
461  BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
462  List<BlackboardAttribute> newAttrs = new ArrayList<>();
463  if (oldAssociatedAttribute != null) {
464  BlackboardArtifact oldAssociatedArtifact = currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
465  BlackboardArtifact newAssociatedArtifact = copyArtifact(newContentId, oldAssociatedArtifact);
466  newAttrs.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
467  String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
468  }
469 
470  // Create the new artifact
471  int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
472  BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId);
473  List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
474 
475  // Copy over each attribute, making sure the type is in the new case.
476  for (BlackboardAttribute oldAttr:oldAttrs) {
477 
478  // The associated artifact has already been handled
479  if (oldAttr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
480  continue;
481  }
482 
483  BlackboardAttribute.Type newAttributeType = getNewAttributeType(oldAttr);
484  switch (oldAttr.getValueType()) {
485  case BYTE:
486  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
487  oldAttr.getValueBytes()));
488  break;
489  case DOUBLE:
490  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
491  oldAttr.getValueDouble()));
492  break;
493  case INTEGER:
494  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
495  oldAttr.getValueInt()));
496  break;
497  case DATETIME:
498  case LONG:
499  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
500  oldAttr.getValueLong()));
501  break;
502  case STRING:
503  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
504  oldAttr.getValueString()));
505  break;
506  default:
507  throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
508  }
509  }
510 
511  newArtifact.addAttributes(newAttrs);
512 
513  oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
514  return newArtifact;
515  }
516 
525  private int getNewArtifactTypeId(BlackboardArtifact oldArtifact) throws TskCoreException {
526  if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
527  return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
528  }
529 
530  BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
531  try {
532  BlackboardArtifact.Type newCustomType = portableSkCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
533  oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
534  return newCustomType.getTypeID();
535  } catch (TskDataException ex) {
536  throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex);
537  }
538  }
539 
548  private BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute) throws TskCoreException {
549  BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
550  if (oldAttrTypeIdToNewAttrType.containsKey(oldAttrType.getTypeID())) {
551  return oldAttrTypeIdToNewAttrType.get(oldAttrType.getTypeID());
552  }
553 
554  try {
555  BlackboardAttribute.Type newCustomType = portableSkCase.addArtifactAttributeType(oldAttrType.getTypeName(),
556  oldAttrType.getValueType(), oldAttrType.getDisplayName());
557  oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType);
558  return newCustomType;
559  } catch (TskDataException ex) {
560  throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex);
561  }
562  }
563 
574  @NbBundle.Messages({
575  "# {0} - File name",
576  "CreatePortableCaseModule.copyContentToPortableCase.copyingFile=Copying file {0}",
577  })
578  private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel) throws TskCoreException {
579  progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
580 
581  long newFileId;
582  CaseDbTransaction trans = portableSkCase.beginTransaction();
583  try {
584  newFileId = copyContent(content, trans);
585  trans.commit();
586  return newFileId;
587  } catch (TskCoreException ex) {
588  trans.rollback();
589  throw(ex);
590  }
591  }
592 
603  private long copyContent(Content content, CaseDbTransaction trans) throws TskCoreException {
604 
605  // Check if we've already copied this content
606  if (oldIdToNewContent.containsKey(content.getId())) {
607  return oldIdToNewContent.get(content.getId()).getId();
608  }
609 
610  // Otherwise:
611  // - Make parent of this object (if applicable)
612  // - Copy this content
613  long parentId = 0;
614  if (content.getParent() != null) {
615  parentId = copyContent(content.getParent(), trans);
616  }
617 
618  Content newContent;
619  if (content instanceof Image) {
620  Image image = (Image)content;
621  newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
622  new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
623  } else if (content instanceof VolumeSystem) {
624  VolumeSystem vs = (VolumeSystem)content;
625  newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
626  } else if (content instanceof Volume) {
627  Volume vs = (Volume)content;
628  newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
629  vs.getDescription(), vs.getFlags(), trans);
630  } else if (content instanceof FileSystem) {
631  FileSystem fs = (FileSystem)content;
632  newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
633  fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
634  fs.getName(), trans);
635  } else if (content instanceof AbstractFile) {
636  AbstractFile abstractFile = (AbstractFile)content;
637 
638  if (abstractFile instanceof LocalFilesDataSource) {
639  LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile;
640  newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
641  } else {
642  if (abstractFile.isDir()) {
643  newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
644  } else {
645  try {
646  // Copy the file
647  String fileName = abstractFile.getId() + "-" + FileUtil.escapeFileName(abstractFile.getName());
648  String exportSubFolder = getExportSubfolder(abstractFile);
649  File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
650  File localFile = new File(exportFolder, fileName);
651  ContentUtils.writeToFile(abstractFile, localFile);
652 
653  // Get the new parent object in the portable case database
654  Content oldParent = abstractFile.getParent();
655  if (! oldIdToNewContent.containsKey(oldParent.getId())) {
656  throw new TskCoreException("Parent of file with ID " + abstractFile.getId() + " has not been created");
657  }
658  Content newParent = oldIdToNewContent.get(oldParent.getId());
659 
660  // Construct the relative path to the copied file
661  String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
662 
663  newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
664  abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
665  abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
666  true, TskData.EncodingType.NONE,
667  newParent, trans);
668  } catch (IOException ex) {
669  throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID "
670  + abstractFile.getId(), ex);
671  }
672  }
673  }
674  } else {
675  throw new TskCoreException("Trying to copy unexpected Content type " + content.getClass().getName());
676  }
677 
678  // Save the new object
679  oldIdToNewContent.put(content.getId(), newContent);
680  newIdToContent.put(newContent.getId(), newContent);
681  return oldIdToNewContent.get(content.getId()).getId();
682  }
683 
691  private String getExportSubfolder(AbstractFile abstractFile) {
692  if (abstractFile.getMIMEType() == null || abstractFile.getMIMEType().isEmpty()) {
693  return UNKNOWN_FILE_TYPE_FOLDER;
694  }
695 
696  for (FileTypeCategory cat:FILE_TYPE_CATEGORIES) {
697  if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
698  return cat.getDisplayName();
699  }
700  }
701  return UNKNOWN_FILE_TYPE_FOLDER;
702  }
703 
707  private void cleanup() {
708  oldIdToNewContent.clear();
709  newIdToContent.clear();
710  oldTagNameToNewTagName.clear();
711  oldArtTypeIdToNewArtTypeId.clear();
712  oldAttrTypeIdToNewAttrType.clear();
713  oldArtifactIdToNewArtifact.clear();
714 
715  currentCase = null;
716  if (portableSkCase != null) {
717  portableSkCase.close();
718  portableSkCase = null;
719  }
720  caseFolder = null;
721  copiedFilesFolder = null;
722  }
723 
724  @Override
725  public JPanel getConfigurationPanel() {
726  configPanel = new CreatePortableCasePanel();
727  return configPanel;
728  }
729 
730  private class StoreMaxIdCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
731 
732  private final String tableName;
733 
734  StoreMaxIdCallback(String tableName) {
735  this.tableName = tableName;
736  }
737 
738  @Override
739  public void process(ResultSet rs) {
740 
741  try {
742  while (rs.next()) {
743  try {
744  Long maxId = rs.getLong("max_id");
745  String query = " (table_name, max_id) VALUES ('" + tableName + "', '" + maxId + "')";
746  portableSkCase.getCaseDbAccessManager().insert(MAX_ID_TABLE_NAME, query);
747 
748  } catch (SQLException ex) {
749  logger.log(Level.WARNING, "Unable to get maximum ID from result set", ex);
750  } catch (TskCoreException ex) {
751  logger.log(Level.WARNING, "Unable to save maximum ID from result set", ex);
752  }
753 
754  }
755  } catch (SQLException ex) {
756  logger.log(Level.WARNING, "Failed to get maximum ID from result set", ex);
757  }
758  }
759  }
760 }
BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy)
void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel)
void generateReport(String reportPath, ReportProgressPanel progressPanel)
void createCase(File outputDir, ReportProgressPanel progressPanel)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName)
SleuthkitCase createPortableCase(String caseName, File portableCaseFolder)
Definition: Case.java:2042
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel)
List< ContentTag > getContentTagsByTagName(TagName tagName)
long copyContent(Content content, CaseDbTransaction trans)
BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute)
void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.