19 package org.sleuthkit.autopsy.report;
21 import java.util.logging.Level;
22 import java.io.BufferedReader;
24 import java.io.InputStreamReader;
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;
34 import org.apache.commons.io.FileUtils;
35 import org.openide.modules.InstalledFileLocator;
36 import org.openide.util.NbBundle;
58 import org.
sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction;
69 class PortableCaseReportModule
implements ReportModule {
70 private static final Logger logger = Logger.getLogger(PortableCaseReportModule.class.getName());
71 private static final String FILE_FOLDER_NAME =
"PortableCaseFiles";
72 private static final String UNKNOWN_FILE_TYPE_FOLDER =
"Other";
73 private static final String MAX_ID_TABLE_NAME =
"portable_case_max_ids";
74 private PortableCaseOptions options;
77 private static final List<FileTypeCategory> FILE_TYPE_CATEGORIES = Arrays.asList(FileTypeCategory.AUDIO, FileTypeCategory.DOCUMENTS,
78 FileTypeCategory.EXECUTABLE, FileTypeCategory.IMAGE, FileTypeCategory.VIDEO);
80 private Case currentCase = null;
81 private SleuthkitCase portableSkCase = null;
82 private final String caseName;
83 private File caseFolder = null;
84 private File copiedFilesFolder = null;
87 private final Map<Long, Content> oldIdToNewContent =
new HashMap<>();
90 private final Map<Long, Content> newIdToContent =
new HashMap<>();
93 private final Map<TagName, TagName> oldTagNameToNewTagName =
new HashMap<>();
96 private final Map<Integer, Integer> oldArtTypeIdToNewArtTypeId =
new HashMap<>();
99 private final Map<Integer, BlackboardAttribute.Type> oldAttrTypeIdToNewAttrType =
new HashMap<>();
102 private final Map<Long, BlackboardArtifact> oldArtifactIdToNewArtifact =
new HashMap<>();
104 PortableCaseReportModule() {
105 caseName = Case.getCurrentCase().getDisplayName() +
" (Portable)";
109 "PortableCaseReportModule.getName.name=Portable Case"
112 public String getName() {
113 return Bundle.PortableCaseReportModule_getName_name();
117 "PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared"
120 public String getDescription() {
121 return Bundle.PortableCaseReportModule_getDescription_description();
125 public String getRelativeFilePath() {
134 private void handleCancellation(ReportProgressPanel progressPanel) {
135 logger.log(Level.INFO,
"Portable case creation canceled by user");
136 progressPanel.setIndeterminate(
false);
137 progressPanel.complete(ReportProgressPanel.ReportStatus.CANCELED);
151 private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) {
153 logger.log(Level.WARNING, logWarning);
155 logger.log(Level.SEVERE, logWarning, ex);
157 MessageNotifyUtil.Message.error(dialogWarning);
158 progressPanel.setIndeterminate(
false);
159 progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR);
164 "PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...",
165 "PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...",
166 "PortableCaseReportModule.generateReport.copyingTags=Copying tags...",
168 "PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}...",
170 "PortableCaseReportModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
171 "# {0} - output folder",
172 "PortableCaseReportModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
173 "# {0} - output folder",
174 "PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
175 "PortableCaseReportModule.generateReport.caseClosed=Current case has been closed",
176 "PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items",
177 "PortableCaseReportModule.generateReport.noContentToCopy=No interesting files, results, or tagged items to copy",
178 "PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags",
179 "PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files",
180 "PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
181 "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
182 "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
183 "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
184 "# {0} - attribute type name",
185 "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
186 "PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
187 "PortableCaseReportModule.generateReport.errorCreatingReportFolder=Could not make report folder",
188 "PortableCaseReportModule.generateReport.errorGeneratingUCOreport=Problem while generating CASE-UCO report"
191 void generateReport(String reportPath, PortableCaseOptions options, ReportProgressPanel progressPanel) {
192 this.options = options;
193 progressPanel.setIndeterminate(
true);
194 progressPanel.start();
195 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_verifying());
201 File outputDir =
new File(reportPath);
202 if (! outputDir.exists()) {
203 handleError(
"Output folder " + outputDir.toString() +
" does not exist",
204 Bundle.PortableCaseReportModule_generateReport_outputDirDoesNotExist(outputDir.toString()), null, progressPanel);
208 if (! outputDir.isDirectory()) {
209 handleError(
"Output folder " + outputDir.toString() +
" is not a folder",
210 Bundle.PortableCaseReportModule_generateReport_outputDirIsNotDir(outputDir.toString()), null, progressPanel);
216 currentCase = Case.getCurrentCaseThrows();
217 }
catch (NoCurrentCaseException ex) {
218 handleError(
"Current case has been closed",
219 Bundle.PortableCaseReportModule_generateReport_caseClosed(), null, progressPanel);
224 List<TagName> tagNames = options.getSelectedTagNames();
225 List<String> setNames = options.getSelectedSetNames();
226 if (tagNames.isEmpty() && setNames.isEmpty()) {
227 handleError(
"No content to copy",
228 Bundle.PortableCaseReportModule_generateReport_noContentToCopy(), null, progressPanel);
234 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_creatingCase());
235 createCase(outputDir, progressPanel);
236 if (portableSkCase == null) {
242 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
243 handleCancellation(progressPanel);
249 initializeImageTags(progressPanel);
250 }
catch (TskCoreException ex) {
251 handleError(
"Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel);
256 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
258 for(TagName tagName:tagNames) {
259 TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus());
260 oldTagNameToNewTagName.put(tagName, newTagName);
262 }
catch (TskCoreException ex) {
263 handleError(
"Error copying tags", Bundle.PortableCaseReportModule_generateReport_errorCopyingTags(), ex, progressPanel);
268 for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) {
269 oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
271 for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) {
273 oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel()));
274 }
catch (TskCoreException ex) {
275 handleError(
"Error looking up attribute name " + type.getLabel(),
276 Bundle.PortableCaseReportModule_generateReport_errorLookingUpAttrType(type.getLabel()),
283 for(TagName tagName:tagNames) {
285 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
286 handleCancellation(progressPanel);
289 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingFiles(tagName.getDisplayName()));
290 addFilesToPortableCase(tagName, progressPanel);
293 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
294 handleCancellation(progressPanel);
298 }
catch (TskCoreException ex) {
299 handleError(
"Error copying tagged files", Bundle.PortableCaseReportModule_generateReport_errorCopyingFiles(), ex, progressPanel);
305 for(TagName tagName:tagNames) {
307 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
308 handleCancellation(progressPanel);
311 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
312 addArtifactsToPortableCase(tagName, progressPanel);
315 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
316 handleCancellation(progressPanel);
320 }
catch (TskCoreException ex) {
321 handleError(
"Error copying tagged artifacts", Bundle.PortableCaseReportModule_generateReport_errorCopyingArtifacts(), ex, progressPanel);
326 if (! setNames.isEmpty()) {
328 List<BlackboardArtifact> interestingFiles = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
329 for (BlackboardArtifact art:interestingFiles) {
331 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
332 handleCancellation(progressPanel);
336 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
337 if (setNames.contains(setAttr.getValueString())) {
338 copyContentToPortableCase(art, progressPanel);
341 }
catch (TskCoreException ex) {
342 handleError(
"Error copying interesting files", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingFiles(), ex, progressPanel);
347 List<BlackboardArtifact> interestingResults = currentCase.getSleuthkitCase().getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT);
348 for (BlackboardArtifact art:interestingResults) {
350 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
351 handleCancellation(progressPanel);
354 BlackboardAttribute setAttr = art.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME));
355 if (setNames.contains(setAttr.getValueString())) {
356 copyContentToPortableCase(art, progressPanel);
359 }
catch (TskCoreException ex) {
360 handleError(
"Error copying interesting results", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel);
366 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
367 handleCancellation(progressPanel);
371 File reportsFolder = Paths.get(caseFolder.toString(),
"Reports").toFile();
372 if(!reportsFolder.mkdir()) {
373 handleError(
"Could not make report folder", Bundle.PortableCaseReportModule_generateReport_errorCreatingReportFolder(), null, progressPanel);
378 CaseUcoFormatExporter.export(tagNames, setNames, reportsFolder, progressPanel);
379 }
catch (IOException | SQLException | NoCurrentCaseException | TskCoreException ex) {
380 handleError(
"Problem while generating CASE-UCO report",
381 Bundle.PortableCaseReportModule_generateReport_errorGeneratingUCOreport(), ex, progressPanel);
385 if (options.shouldCompress()) {
386 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
388 boolean success = compressCase(progressPanel);
391 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
392 handleCancellation(progressPanel);
405 progressPanel.complete(ReportProgressPanel.ReportStatus.COMPLETE);
417 "# {0} - case folder",
418 "PortableCaseReportModule.createCase.caseDirExists=Case folder {0} already exists",
419 "PortableCaseReportModule.createCase.errorCreatingCase=Error creating case",
421 "PortableCaseReportModule.createCase.errorCreatingFolder=Error creating folder {0}",
422 "PortableCaseReportModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",
424 private void createCase(File outputDir, ReportProgressPanel progressPanel) {
427 caseFolder = Paths.get(outputDir.toString(), caseName).toFile();
429 if (caseFolder.exists()) {
430 handleError(
"Case folder " + caseFolder.toString() +
" already exists",
431 Bundle.PortableCaseReportModule_createCase_caseDirExists(caseFolder.toString()), null, progressPanel);
437 portableSkCase = currentCase.createPortableCase(caseName, caseFolder);
438 }
catch (TskCoreException ex) {
439 handleError(
"Error creating case " + caseName +
" in folder " + caseFolder.toString(),
440 Bundle.PortableCaseReportModule_createCase_errorCreatingCase(), ex, progressPanel);
447 }
catch (TskCoreException ex) {
448 handleError(
"Error storing maximum database IDs",
449 Bundle.PortableCaseReportModule_createCase_errorStoringMaxIds(), ex, progressPanel);
454 copiedFilesFolder = Paths.get(caseFolder.toString(), FILE_FOLDER_NAME).toFile();
455 if (! copiedFilesFolder.mkdir()) {
456 handleError(
"Error creating folder " + copiedFilesFolder.toString(),
457 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(copiedFilesFolder.toString()), null, progressPanel);
462 for (FileTypeCategory cat:FILE_TYPE_CATEGORIES) {
463 File subFolder = Paths.get(copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
464 if (! subFolder.mkdir()) {
465 handleError(
"Error creating folder " + subFolder.toString(),
466 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(subFolder.toString()), null, progressPanel);
470 File unknownTypeFolder = Paths.get(copiedFilesFolder.toString(), UNKNOWN_FILE_TYPE_FOLDER).toFile();
471 if (! unknownTypeFolder.mkdir()) {
472 handleError(
"Error creating folder " + unknownTypeFolder.toString(),
473 Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()), null, progressPanel);
484 private void saveHighestIds() throws TskCoreException {
486 CaseDbAccessManager currentCaseDbManager = currentCase.getSleuthkitCase().getCaseDbAccessManager();
488 String tableSchema =
"( table_name TEXT PRIMARY KEY, "
491 portableSkCase.getCaseDbAccessManager().createTable(MAX_ID_TABLE_NAME, tableSchema);
493 currentCaseDbManager.select(
"max(obj_id) as max_id from tsk_objects",
new StoreMaxIdCallback(
"tsk_objects"));
494 currentCaseDbManager.select(
"max(tag_id) as max_id from content_tags",
new StoreMaxIdCallback(
"content_tags"));
495 currentCaseDbManager.select(
"max(tag_id) as max_id from blackboard_artifact_tags",
new StoreMaxIdCallback(
"blackboard_artifact_tags"));
496 currentCaseDbManager.select(
"max(examiner_id) as max_id from tsk_examiners",
new StoreMaxIdCallback(
"tsk_examiners"));
506 private void initializeImageTags(ReportProgressPanel progressPanel)
throws TskCoreException {
509 CaseDbAccessManager portableDbAccessManager = portableSkCase.getCaseDbAccessManager();
510 if (! portableDbAccessManager.tableExists(ContentViewerTagManager.TABLE_NAME)) {
511 portableDbAccessManager.createTable(ContentViewerTagManager.TABLE_NAME, ContentViewerTagManager.TABLE_SCHEMA_SQLITE);
523 private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
throws TskCoreException {
526 List<ContentTag> tags = currentCase.getServices().getTagsManager().getContentTagsByTagName(oldTagName);
529 for (ContentTag tag : tags) {
532 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
536 Content content = tag.getContent();
537 if (content instanceof AbstractFile) {
539 long newFileId = copyContentToPortableCase(content, progressPanel);
542 if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
543 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
545 ContentTag newContentTag = portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
549 String appData = getImageTagDataForContentTag(tag);
550 if (! appData.isEmpty()) {
551 addImageTagToPortableCase(newContentTag, appData);
566 private String getImageTagDataForContentTag(ContentTag tag)
throws TskCoreException {
568 GetImageTagCallback callback =
new GetImageTagCallback();
569 String query =
"* FROM " + ContentViewerTagManager.TABLE_NAME +
" WHERE content_tag_id = " + tag.getId();
570 currentCase.getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
571 return callback.getAppData();
587 appData = rs.getString(
"app_data");
588 }
catch (SQLException ex) {
589 logger.log(Level.WARNING,
"Unable to get app_data from result set", ex);
592 }
catch (SQLException ex) {
593 logger.log(Level.WARNING,
"Failed to get next result for app_data", ex);
602 String getAppData() {
615 private void addImageTagToPortableCase(ContentTag newContentTag, String appData)
throws TskCoreException {
616 String insert =
"(content_tag_id, app_data) VALUES (" + newContentTag.getId() +
", '" + appData +
"')";
617 portableSkCase.getCaseDbAccessManager().insert(ContentViewerTagManager.TABLE_NAME, insert);
629 private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
throws TskCoreException {
631 List<BlackboardArtifactTag> tags = currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName);
634 for (BlackboardArtifactTag tag : tags) {
637 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
642 Content content = tag.getContent();
643 long newContentId = copyContentToPortableCase(content, progressPanel);
646 BlackboardArtifact newArtifact = copyArtifact(newContentId, tag.getArtifact());
649 if (! oldTagNameToNewTagName.containsKey(tag.getName())) {
650 throw new TskCoreException(
"TagName map is missing entry for ID " + tag.getName().getId() +
" with display name " + tag.getName().getDisplayName());
652 portableSkCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
666 private BlackboardArtifact copyArtifact(
long newContentId, BlackboardArtifact artifactToCopy)
throws TskCoreException {
668 if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
669 return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
673 BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(
new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
674 List<BlackboardAttribute> newAttrs =
new ArrayList<>();
675 if (oldAssociatedAttribute != null) {
676 BlackboardArtifact oldAssociatedArtifact = currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
677 BlackboardArtifact newAssociatedArtifact = copyArtifact(newContentId, oldAssociatedArtifact);
678 newAttrs.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT,
679 String.join(
",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
683 int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
684 BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId);
685 List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
688 for (BlackboardAttribute oldAttr:oldAttrs) {
691 if (oldAttr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
695 BlackboardAttribute.Type newAttributeType = getNewAttributeType(oldAttr);
696 switch (oldAttr.getValueType()) {
698 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
699 oldAttr.getValueBytes()));
702 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
703 oldAttr.getValueDouble()));
706 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
707 oldAttr.getValueInt()));
711 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
712 oldAttr.getValueLong()));
715 newAttrs.add(
new BlackboardAttribute(newAttributeType, String.join(
",", oldAttr.getSources()),
716 oldAttr.getValueString()));
719 throw new TskCoreException(
"Unexpected attribute value type found: " + oldAttr.getValueType().getLabel());
723 newArtifact.addAttributes(newAttrs);
725 oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
737 private int getNewArtifactTypeId(BlackboardArtifact oldArtifact)
throws TskCoreException {
738 if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
739 return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
742 BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName());
744 BlackboardArtifact.Type newCustomType = portableSkCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
745 oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
746 return newCustomType.getTypeID();
747 }
catch (TskDataException ex) {
748 throw new TskCoreException(
"Error creating new artifact type " + oldCustomType.getTypeName(), ex);
760 private BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute)
throws TskCoreException {
761 BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
762 if (oldAttrTypeIdToNewAttrType.containsKey(oldAttrType.getTypeID())) {
763 return oldAttrTypeIdToNewAttrType.get(oldAttrType.getTypeID());
767 BlackboardAttribute.Type newCustomType = portableSkCase.addArtifactAttributeType(oldAttrType.getTypeName(),
768 oldAttrType.getValueType(), oldAttrType.getDisplayName());
769 oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType);
770 return newCustomType;
771 }
catch (TskDataException ex) {
772 throw new TskCoreException(
"Error creating new attribute type " + oldAttrType.getTypeName(), ex);
788 "PortableCaseReportModule.copyContentToPortableCase.copyingFile=Copying file {0}",
790 private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel)
throws TskCoreException {
791 progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
792 return copyContent(content);
804 private long copyContent(Content content)
throws TskCoreException {
807 if (oldIdToNewContent.containsKey(content.getId())) {
808 return oldIdToNewContent.get(content.getId()).getId();
815 if (content.getParent() != null) {
816 parentId = copyContent(content.getParent());
820 if (content instanceof BlackboardArtifact) {
821 BlackboardArtifact artifactToCopy = (BlackboardArtifact)content;
822 newContent = copyArtifact(parentId, artifactToCopy);
824 CaseDbTransaction trans = portableSkCase.beginTransaction();
826 if (content instanceof Image) {
827 Image image = (Image)content;
828 newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
829 new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans);
830 }
else if (content instanceof VolumeSystem) {
831 VolumeSystem vs = (VolumeSystem)content;
832 newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
833 }
else if (content instanceof Volume) {
834 Volume vs = (Volume)content;
835 newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
836 vs.getDescription(), vs.getFlags(), trans);
837 }
else if (content instanceof FileSystem) {
838 FileSystem fs = (FileSystem)content;
839 newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
840 fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
841 fs.getName(), trans);
842 }
else if (content instanceof BlackboardArtifact) {
843 BlackboardArtifact artifactToCopy = (BlackboardArtifact)content;
844 newContent = copyArtifact(parentId, artifactToCopy);
845 }
else if (content instanceof AbstractFile) {
846 AbstractFile abstractFile = (AbstractFile)content;
848 if (abstractFile instanceof LocalFilesDataSource) {
849 LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile;
850 newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans);
852 if (abstractFile.isDir()) {
853 newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
857 String fileName = abstractFile.getId() +
"-" + FileUtil.escapeFileName(abstractFile.getName());
858 String exportSubFolder = getExportSubfolder(abstractFile);
859 File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
860 File localFile =
new File(exportFolder, fileName);
861 ContentUtils.writeToFile(abstractFile, localFile);
864 Content oldParent = abstractFile.getParent();
865 if (! oldIdToNewContent.containsKey(oldParent.getId())) {
866 throw new TskCoreException(
"Parent of file with ID " + abstractFile.getId() +
" has not been created");
868 Content newParent = oldIdToNewContent.get(oldParent.getId());
871 String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
873 newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
874 abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
875 abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
876 true, TskData.EncodingType.NONE,
878 }
catch (IOException ex) {
879 throw new TskCoreException(
"Error copying file " + abstractFile.getName() +
" with original obj ID "
880 + abstractFile.getId(), ex);
885 throw new TskCoreException(
"Trying to copy unexpected Content type " + content.getClass().getName());
888 }
catch (TskCoreException ex) {
895 oldIdToNewContent.put(content.getId(), newContent);
896 newIdToContent.put(newContent.getId(), newContent);
897 return oldIdToNewContent.get(content.getId()).getId();
907 private String getExportSubfolder(AbstractFile abstractFile) {
908 if (abstractFile.getMIMEType() == null || abstractFile.getMIMEType().isEmpty()) {
909 return UNKNOWN_FILE_TYPE_FOLDER;
912 for (FileTypeCategory cat:FILE_TYPE_CATEGORIES) {
913 if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
914 return cat.getDisplayName();
917 return UNKNOWN_FILE_TYPE_FOLDER;
923 private void cleanup() {
924 oldIdToNewContent.clear();
925 newIdToContent.clear();
926 oldTagNameToNewTagName.clear();
927 oldArtTypeIdToNewArtTypeId.clear();
928 oldAttrTypeIdToNewAttrType.clear();
929 oldArtifactIdToNewArtifact.clear();
931 closePortableCaseDatabase();
935 copiedFilesFolder = null;
941 private void closePortableCaseDatabase() {
942 if (portableSkCase != null) {
943 portableSkCase.close();
944 portableSkCase = null;
968 Long maxId = rs.getLong(
"max_id");
969 String query =
" (table_name, max_id) VALUES ('" + tableName +
"', '" + maxId +
"')";
970 portableSkCase.getCaseDbAccessManager().insert(MAX_ID_TABLE_NAME, query);
972 }
catch (SQLException ex) {
973 logger.log(Level.WARNING,
"Unable to get maximum ID from result set", ex);
974 }
catch (TskCoreException ex) {
975 logger.log(Level.WARNING,
"Unable to save maximum ID from result set", ex);
979 }
catch (SQLException ex) {
980 logger.log(Level.WARNING,
"Failed to get maximum ID from result set", ex);
986 "PortableCaseReportModule.compressCase.errorFinding7zip=Could not locate 7-Zip executable",
987 "# {0} - Temp folder path",
988 "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
989 "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
990 "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",
992 private boolean compressCase(ReportProgressPanel progressPanel) {
995 closePortableCaseDatabase();
998 File tempZipFolder = Paths.get(currentCase.getTempDirectory(),
"portableCase" + System.currentTimeMillis()).toFile();
999 if (! tempZipFolder.mkdir()) {
1000 handleError(
"Error creating temporary folder " + tempZipFolder.toString(),
1001 Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel);
1006 File sevenZipExe = locate7ZipExecutable();
1007 if (sevenZipExe == null) {
1008 handleError(
"Error finding 7-Zip exectuable", Bundle.PortableCaseReportModule_compressCase_errorFinding7zip(), null, progressPanel);
1013 String chunkOption =
"";
1014 if (options.getChunkSize() != ChunkSize.NONE) {
1015 chunkOption =
"-v" + options.getChunkSize().getSevenZipParam();
1018 File zipFile = Paths.get(tempZipFolder.getAbsolutePath(), caseName +
".zip").toFile();
1019 ProcessBuilder procBuilder =
new ProcessBuilder();
1020 procBuilder.command(
1021 sevenZipExe.getAbsolutePath(),
1023 zipFile.getAbsolutePath(),
1024 caseFolder.getAbsolutePath(),
1029 Process process = procBuilder.start();
1031 while (process.isAlive()) {
1032 if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
1038 int exitCode = process.exitValue();
1039 if (exitCode != 0) {
1041 StringBuilder sb =
new StringBuilder();
1042 try (BufferedReader br =
new BufferedReader(
new InputStreamReader(process.getErrorStream()))) {
1044 while ((line = br.readLine()) != null) {
1045 sb.append(line).append(System.getProperty(
"line.separator"));
1049 handleError(
"Error compressing case\n7-Zip output: " + sb.toString(), Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), null, progressPanel);
1052 }
catch (IOException | InterruptedException ex) {
1053 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1059 FileUtils.cleanDirectory(caseFolder);
1060 FileUtils.copyDirectory(tempZipFolder, caseFolder);
1061 FileUtils.deleteDirectory(tempZipFolder);
1062 }
catch (IOException ex) {
1063 handleError(
"Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel);
1075 private static File locate7ZipExecutable() {
1076 if (!PlatformUtil.isWindowsOS()) {
1080 String executableToFindName = Paths.get(
"7-Zip",
"7z.exe").toString();
1081 File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, PortableCaseReportModule.class.getPackage().getName(),
false);
1082 if (null == exeFile) {
1086 if (!exeFile.canExecute()) {
1099 NONE(
"Do not split",
""),
1100 ONE_HUNDRED_MB(
"Split into 100 MB chunks",
"100m"),
1101 CD(
"Split into 700 MB chunks (CD)",
"700m"),
1102 ONE_GB(
"Split into 1 GB chunks",
"1000m"),
1103 DVD(
"Split into 4.5 GB chunks (DVD)",
"4500m");
1105 private final String displayName;
1106 private final String sevenZipParam;
1114 private ChunkSize(String displayName, String sevenZipParam) {
1115 this.displayName = displayName;
1116 this.sevenZipParam = sevenZipParam;
1119 String getDisplayName() {
1123 String getSevenZipParam() {
1124 return sevenZipParam;
1128 public String toString() {
1136 static class PortableCaseOptions {
1138 private final List<TagName> tagNames =
new ArrayList<>();
1139 private final List<String> setNames =
new ArrayList<>();
1140 private boolean compress;
1141 private ChunkSize chunkSize;
1143 PortableCaseOptions(List<String> setNames, List<TagName> tagNames,
1144 boolean compress, ChunkSize chunkSize) {
1145 this.setNames.addAll(setNames);
1146 this.tagNames.addAll(tagNames);
1147 this.compress = compress;
1148 this.chunkSize = chunkSize;
1151 PortableCaseOptions() {
1152 this.compress =
false;
1153 this.chunkSize = ChunkSize.NONE;
1156 void updateSetNames(List<String> setNames) {
1157 this.setNames.clear();
1158 this.setNames.addAll(setNames);
1161 void updateTagNames(List<TagName> tagNames) {
1162 this.tagNames.clear();
1163 this.tagNames.addAll(tagNames);
1166 void updateCompression(
boolean compress, ChunkSize chunkSize) {
1167 this.compress = compress;
1168 this.chunkSize = chunkSize;
1172 return (( !setNames.isEmpty()) || ( ! tagNames.isEmpty()));
1175 List<String> getSelectedSetNames() {
1176 return new ArrayList<>(setNames);
1179 List<TagName> getSelectedTagNames() {
1180 return new ArrayList<>(tagNames);
1183 boolean shouldCompress() {
1187 ChunkSize getChunkSize() {
void process(ResultSet rs)
void process(ResultSet rs)
synchronized static Logger getLogger(String name)