Autopsy  4.21.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
PortableCaseReportModule.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
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  */
19 package org.sleuthkit.autopsy.report.modules.portablecase;
20 
21 import com.google.common.collect.ArrayListMultimap;
22 import com.google.common.collect.Multimap;
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.JsonElement;
26 import com.google.gson.stream.JsonWriter;
28 import java.util.logging.Level;
29 import java.io.BufferedReader;
30 import java.io.File;
31 import java.io.FileOutputStream;
32 import java.io.FileWriter;
33 import java.io.InputStreamReader;
34 import java.io.IOException;
35 import java.io.OutputStream;
36 import java.io.OutputStreamWriter;
37 import java.nio.file.Files;
38 import java.nio.file.Path;
39 import java.nio.file.Paths;
40 import java.sql.ResultSet;
41 import java.sql.SQLException;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.HashMap;
46 import java.util.List;
47 import java.util.Map;
48 import org.apache.commons.io.FileUtils;
49 import org.openide.modules.InstalledFileLocator;
50 import org.openide.util.NbBundle;
62 import org.sleuthkit.caseuco.CaseUcoExporter;
97 
101 public class PortableCaseReportModule implements ReportModule {
102 
104  private static final String FILE_FOLDER_NAME = "PortableCaseFiles"; // NON-NLS
105  private static final String UNKNOWN_FILE_TYPE_FOLDER = "Other"; // NON-NLS
106  private static final String MAX_ID_TABLE_NAME = "portable_case_max_ids"; // NON-NLS
107  private static final String CASE_UCO_FILE_NAME = "portable_CASE_UCO_output";
108  private static final String CASE_UCO_TMP_DIR = "case_uco_tmp";
110 
111  // These are the types for the exported file subfolders
112  private static final List<FileTypeCategory> FILE_TYPE_CATEGORIES = Arrays.asList(FileTypeCategory.AUDIO, FileTypeCategory.DOCUMENTS,
114 
115  // These are attribute types that have special handling and should not be copied
116  // into the new artifact directly.
117  private static final List<Integer> SPECIALLY_HANDLED_ATTRS = Arrays.asList(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID(),
119 
120  private Case currentCase = null;
122  private String caseName = "";
123  private File caseFolder = null;
124  private File copiedFilesFolder = null;
125 
126  // Maps old object ID from current case to new object in portable case
127  private final Map<Long, Content> oldIdToNewContent = new HashMap<>();
128 
129  // Maps new object ID to the new object
130  private final Map<Long, Content> newIdToContent = new HashMap<>();
131 
132  // Maps old TagName to new TagName
133  private final Map<TagName, TagName> oldTagNameToNewTagName = new HashMap<>();
134 
135  // Map of old artifact type ID to new artifact type ID. There will only be changes if custom artifact types are present.
136  private final Map<Integer, Integer> oldArtTypeIdToNewArtTypeId = new HashMap<>();
137 
138  // Map of old attribute type ID to new attribute type ID. There will only be changes if custom attr types are present.
139  private final Map<Integer, BlackboardAttribute.Type> oldAttrTypeIdToNewAttrType = new HashMap<>();
140 
141  // Map of old artifact ID to new artifact
142  private final Map<Long, BlackboardArtifact> oldArtifactIdToNewArtifact = new HashMap<>();
143 
144  // Map of old OS account id to new OS account
145  private final Map<Long, OsAccount> oldOsAccountIdToNewOsAccount = new HashMap<>();
146 
147  // Map of old OS account realm id to new OS account ream id
148  private final Map<Long, OsAccountRealm> oldRealmIdToNewRealm = new HashMap<>();
149 
150  // Map of the old host id to the new host
151  private final Map<Long, Host> oldHostIdToNewHost = new HashMap<>();
152 
154  }
155 
156  @NbBundle.Messages({
157  "PortableCaseReportModule.getName.name=Portable Case"
158  })
159  @Override
160  public String getName() {
161  return Bundle.PortableCaseReportModule_getName_name();
162  }
163 
164  @NbBundle.Messages({
165  "PortableCaseReportModule.getDescription.description=Copies selected items to a new single-user case that can be easily shared"
166  })
167  @Override
168  public String getDescription() {
169  return Bundle.PortableCaseReportModule_getDescription_description();
170  }
171 
172  @Override
173  public String getRelativeFilePath() {
174  try {
175  caseName = Case.getCurrentCaseThrows().getDisplayName() + " (Portable)"; // NON-NLS
176  } catch (NoCurrentCaseException ex) {
177  // a case may not be open yet
178  return "";
179  }
180  return caseName;
181  }
182 
188  private void handleCancellation(ReportProgressPanel progressPanel) {
189  logger.log(Level.INFO, "Portable case creation canceled by user"); // NON-NLS
190  progressPanel.setIndeterminate(false);
192  cleanup();
193  }
194 
205  private void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel) {
206  if (ex == null) {
207  logger.log(Level.WARNING, logWarning);
208  } else {
209  logger.log(Level.SEVERE, logWarning, ex);
210  }
211  progressPanel.setIndeterminate(false);
212  progressPanel.complete(ReportProgressPanel.ReportStatus.ERROR, dialogWarning);
213  cleanup();
214  }
215 
216  @NbBundle.Messages({
217  "PortableCaseReportModule.generateReport.verifying=Verifying selected parameters...",
218  "PortableCaseReportModule.generateReport.creatingCase=Creating portable case database...",
219  "PortableCaseReportModule.generateReport.copyingTags=Copying tags...",
220  "# {0} - tag name",
221  "PortableCaseReportModule.generateReport.copyingFiles=Copying files tagged as {0}...",
222  "# {0} - tag name",
223  "PortableCaseReportModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...",
224  "# {0} - output folder",
225  "PortableCaseReportModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist",
226  "# {0} - output folder",
227  "PortableCaseReportModule.generateReport.outputDirIsNotDir=Output folder {0} is not a folder",
228  "PortableCaseReportModule.generateReport.caseClosed=Current case has been closed",
229  "PortableCaseReportModule.generateReport.interestingItemError=Error loading intersting items",
230  "PortableCaseReportModule.generateReport.errorReadingTags=Error while reading tags from case database",
231  "PortableCaseReportModule.generateReport.errorReadingSets=Error while reading interesting items sets from case database",
232  "PortableCaseReportModule.generateReport.noContentToCopy=No interesting files, results, or tagged items to copy",
233  "PortableCaseReportModule.generateReport.errorCopyingTags=Error copying tags",
234  "PortableCaseReportModule.generateReport.errorCopyingFiles=Error copying tagged files",
235  "PortableCaseReportModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts",
236  "PortableCaseReportModule.generateReport.errorCopyingInterestingFiles=Error copying interesting files",
237  "PortableCaseReportModule.generateReport.errorCopyingInterestingResults=Error copying interesting results",
238  "PortableCaseReportModule.generateReport.errorCreatingImageTagTable=Error creating image tags table",
239  "PortableCaseReportModule.generateReport.errorCopyingAutopsy=Error copying application",
240  "# {0} - attribute type name",
241  "PortableCaseReportModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}",
242  "PortableCaseReportModule.generateReport.compressingCase=Compressing case...",
243  "PortableCaseReportModule_generateReport_copyingAutopsy=Copying application..."
244  })
249  @SuppressWarnings("deprecation")
250  public void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel) {
251  this.settings = options;
252  progressPanel.setIndeterminate(true);
253  progressPanel.start();
254  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_verifying());
255 
256  // Clear out any old values
257  cleanup();
258 
259  // Validate the input parameters
260  File outputDir = new File(reportPath);
261  if (!outputDir.exists()) {
262  handleError("Output folder " + outputDir.toString() + " does not exist",
263  Bundle.PortableCaseReportModule_generateReport_outputDirDoesNotExist(outputDir.toString()), null, progressPanel); // NON-NLS
264  return;
265  }
266 
267  if (!outputDir.isDirectory()) {
268  handleError("Output folder " + outputDir.toString() + " is not a folder",
269  Bundle.PortableCaseReportModule_generateReport_outputDirIsNotDir(outputDir.toString()), null, progressPanel); // NON-NLS
270  return;
271  }
272 
273  // Save the current case object
274  try {
275  currentCase = Case.getCurrentCaseThrows();
276  caseName = currentCase.getDisplayName() + " (Portable)"; // NON-NLS
277  } catch (NoCurrentCaseException ex) {
278  handleError("Current case has been closed",
279  Bundle.PortableCaseReportModule_generateReport_caseClosed(), null, progressPanel); // NON-NLS
280  return;
281  }
282 
283  // If the applciation is included add an extra level to the directory structure
284  if (options.includeApplication()) {
285  outputDir = Paths.get(outputDir.toString(), caseName).toFile();
286  }
287  // Check that there will be something to copy
288  List<TagName> tagNames;
289  if (options.areAllTagsSelected()) {
290  try {
293  handleError("Unable to get all tags",
294  Bundle.PortableCaseReportModule_generateReport_errorReadingTags(), ex, progressPanel); // NON-NLS
295  return;
296  }
297  } else {
298  tagNames = options.getSelectedTagNames();
299  }
300 
301  List<String> setNames;
302  if (options.areAllSetsSelected()) {
303  try {
304  setNames = getAllInterestingItemsSets();
306  handleError("Unable to get all interesting items sets",
307  Bundle.PortableCaseReportModule_generateReport_errorReadingSets(), ex, progressPanel); // NON-NLS
308  return;
309  }
310  } else {
311  setNames = options.getSelectedSetNames();
312  }
313 
314  if (tagNames.isEmpty() && setNames.isEmpty()) {
315  handleError("No content to copy",
316  Bundle.PortableCaseReportModule_generateReport_noContentToCopy(), null, progressPanel); // NON-NLS
317  return;
318  }
319 
320  // Create the case.
321  // portableSkCase and caseFolder will be set here.
322  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_creatingCase());
323  createCase(outputDir, progressPanel);
324  if (portableSkCase == null) {
325  // The error has already been handled
326  return;
327  }
328 
329  // Check for cancellation
330  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
331  handleCancellation(progressPanel);
332  return;
333  }
334 
335  // Set up the table for the image tags
336  try {
337  initializeImageTags(progressPanel);
338  } catch (TskCoreException ex) {
339  handleError("Error creating image tag table", Bundle.PortableCaseReportModule_generateReport_errorCreatingImageTagTable(), ex, progressPanel); // NON-NLS
340  return;
341  }
342 
343  // Copy the selected tags
344  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingTags());
345  try {
346  for (TagName tagName : tagNames) {
347  TagName newTagName = portableSkCase.getTaggingManager().addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getTagType());
348  oldTagNameToNewTagName.put(tagName, newTagName);
349  }
350  } catch (TskCoreException ex) {
351  handleError("Error copying tags", Bundle.PortableCaseReportModule_generateReport_errorCopyingTags(), ex, progressPanel); // NON-NLS
352  return;
353  }
354 
355  // Set up tracking to support any custom artifact or attribute types
357  oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID());
358  }
360  try {
361  oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getBlackboard().getAttributeType(type.getLabel()));
362  } catch (TskCoreException ex) {
363  handleError("Error looking up attribute name " + type.getLabel(),
364  Bundle.PortableCaseReportModule_generateReport_errorLookingUpAttrType(type.getLabel()),
365  ex, progressPanel); // NON-NLS
366  }
367  }
368 
369  // Copy the tagged files
370  try {
371  for (TagName tagName : tagNames) {
372  // Check for cancellation
373  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
374  handleCancellation(progressPanel);
375  return;
376  }
377  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingFiles(tagName.getDisplayName()));
378  addFilesToPortableCase(tagName, progressPanel);
379 
380  // Check for cancellation
381  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
382  handleCancellation(progressPanel);
383  return;
384  }
385  }
386  } catch (TskCoreException ex) {
387  handleError("Error copying tagged files", Bundle.PortableCaseReportModule_generateReport_errorCopyingFiles(), ex, progressPanel); // NON-NLS
388  return;
389  }
390 
391  // Copy the tagged artifacts and associated files
392  try {
393  for (TagName tagName : tagNames) {
394  // Check for cancellation
395  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
396  handleCancellation(progressPanel);
397  return;
398  }
399  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingArtifacts(tagName.getDisplayName()));
400  addArtifactsToPortableCase(tagName, progressPanel);
401 
402  // Check for cancellation
403  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
404  handleCancellation(progressPanel);
405  return;
406  }
407  }
408  } catch (TskCoreException ex) {
409  handleError("Error copying tagged artifacts", Bundle.PortableCaseReportModule_generateReport_errorCopyingArtifacts(), ex, progressPanel); // NON-NLS
410  return;
411  }
412 
413  // Copy interesting files and results
414  if (!setNames.isEmpty()) {
415  try {
416  List<AnalysisResult> interestingFiles = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_FILE_HIT.getTypeID());
417  for (AnalysisResult art : interestingFiles) {
418  // Check for cancellation
419  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
420  handleCancellation(progressPanel);
421  return;
422  }
423 
425  if (setNames.contains(setAttr.getValueString())) {
426  copyContentToPortableCase(art, progressPanel);
427  }
428  }
429  } catch (TskCoreException ex) {
430  handleError("Error copying interesting files", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingFiles(), ex, progressPanel); // NON-NLS
431  return;
432  }
433 
434  try {
435  List<AnalysisResult> interestingResults = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ARTIFACT_HIT.getTypeID());
436  for (AnalysisResult art : interestingResults) {
437  // Check for cancellation
438  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
439  handleCancellation(progressPanel);
440  return;
441  }
443  if (setNames.contains(setAttr.getValueString())) {
444  copyContentToPortableCase(art, progressPanel);
445  }
446  }
447  } catch (TskCoreException ex) {
448  handleError("Error copying interesting results", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel); // NON-NLS
449  return;
450  }
451 
452  try {
453  List<AnalysisResult> interestingResults = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultsByType(BlackboardArtifact.Type.TSK_INTERESTING_ITEM.getTypeID());
454  for (AnalysisResult art : interestingResults) {
455  // Check for cancellation
456  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
457  handleCancellation(progressPanel);
458  return;
459  }
461  if (setNames.contains(setAttr.getValueString())) {
462  copyContentToPortableCase(art, progressPanel);
463  }
464  }
465  } catch (TskCoreException ex) {
466  handleError("Error copying interesting items", Bundle.PortableCaseReportModule_generateReport_errorCopyingInterestingResults(), ex, progressPanel); // NON-NLS
467  return;
468  }
469  }
470 
471  // Check for cancellation
472  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
473  handleCancellation(progressPanel);
474  return;
475  }
476 
477  //Attempt to generate and included the CASE-UCO report.
478  generateCaseUcoReport(tagNames, setNames, progressPanel);
479 
480  if (options.includeApplication()) {
481  try {
482  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_copyingAutopsy());
483  copyApplication(getApplicationBasePath(), outputDir.getAbsolutePath());
484  createAppLaunchBatFile(outputDir.getAbsolutePath());
485  } catch (IOException ex) {
486  handleError("Error copying autopsy", Bundle.PortableCaseReportModule_generateReport_errorCopyingAutopsy(), ex, progressPanel); // NON-NLS
487  }
488  }
489 
490  // Compress the case (if desired)
491  if (options.shouldCompress()) {
492  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateReport_compressingCase());
493 
494  if (!compressCase(progressPanel, options.includeApplication() ? outputDir.getAbsolutePath() : caseFolder.getAbsolutePath())) {
495  // Errors have been handled already
496  return;
497  }
498 
499  // Check for cancellation
500  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
501  handleCancellation(progressPanel);
502  return;
503  }
504  }
505 
506  // Close the case connections and clear out the maps
507  cleanup();
508 
510 
511  }
512 
524  @NbBundle.Messages({
525  "PortableCaseReportModule.generateCaseUcoReport.errorCreatingReportFolder=Could not make report folder",
526  "PortableCaseReportModule.generateCaseUcoReport.errorGeneratingCaseUcoReport=Problem while generating CASE-UCO report",
527  "PortableCaseReportModule.generateCaseUcoReport.startCaseUcoReportGeneration=Creating a CASE-UCO report of the portable case",
528  "PortableCaseReportModule.generateCaseUcoReport.successCaseUcoReportGeneration=Successfully created a CASE-UCO report of the portable case"
529  })
530  private void generateCaseUcoReport(List<TagName> tagNames, List<String> setNames, ReportProgressPanel progressPanel) {
531  //Create the 'Reports' directory to include a CASE-UCO report.
532  Path reportsDirectory = Paths.get(caseFolder.toString(), "Reports");
533  if (!reportsDirectory.toFile().mkdir()) {
534  logger.log(Level.SEVERE, "Could not make the report folder... skipping "
535  + "CASE-UCO report generation for the portable case");
536  return;
537  }
538 
539  Path reportFile = reportsDirectory.resolve(CASE_UCO_FILE_NAME);
540 
541  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_startCaseUcoReportGeneration());
542  try (OutputStream stream = new FileOutputStream(reportFile.toFile());
543  JsonWriter reportWriter = new JsonWriter(new OutputStreamWriter(stream, "UTF-8"))) {
544  Gson gson = new GsonBuilder().setPrettyPrinting().create();
545  reportWriter.setIndent(" ");
546  reportWriter.beginObject();
547  reportWriter.name("@graph");
548  reportWriter.beginArray();
549 
550  String caseTempDirectory = currentCase.getTempDirectory();
551  SleuthkitCase skCase = currentCase.getSleuthkitCase();
552  TagsManager tagsManager = currentCase.getServices().getTagsManager();
553 
554  //Create temp directory to filter out duplicate files.
555  //Clear out the old directory if it exists.
556  Path tmpDir = Paths.get(caseTempDirectory, CASE_UCO_TMP_DIR);
557  FileUtils.deleteDirectory(tmpDir.toFile());
558  Files.createDirectory(tmpDir);
559 
560  CaseUcoExporter exporter = new CaseUcoExporter(currentCase.getSleuthkitCase());
561  for (JsonElement element : exporter.exportSleuthkitCase()) {
562  gson.toJson(element, reportWriter);
563  }
564 
565  //Load all interesting BlackboardArtifacts that belong to the selected SET_NAMEs
566  //binned by data source id.
567  Multimap<Long, BlackboardArtifact> artifactsWithSetName = getInterestingArtifactsBySetName(skCase, setNames);
568 
569  //Search each data source looking for content tags and interesting
570  //items that match the selected tag names and set names.
571  for (DataSource dataSource : currentCase.getSleuthkitCase().getDataSources()) {
572  // Helper flag to ensure each data source is only written once in
573  // a report.
574  boolean dataSourceHasBeenIncluded = false;
575 
576  //Search content tags and artifact tags that match
577  for (TagName tagName : tagNames) {
578  for (ContentTag ct : tagsManager.getContentTagsByTagName(tagName, dataSource.getId())) {
579  dataSourceHasBeenIncluded |= addUniqueFile(ct.getContent(),
580  dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
581  }
582  for (BlackboardArtifactTag bat : tagsManager.getBlackboardArtifactTagsByTagName(tagName, dataSource.getId())) {
583  dataSourceHasBeenIncluded |= addUniqueFile(bat.getContent(),
584  dataSource, tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
585  }
586  }
587  //Search artifacts that this data source contains
588  for (BlackboardArtifact bArt : artifactsWithSetName.get(dataSource.getId())) {
589  Content sourceContent = bArt.getParent();
590  dataSourceHasBeenIncluded |= addUniqueFile(sourceContent, dataSource,
591  tmpDir, gson, exporter, reportWriter, dataSourceHasBeenIncluded);
592  }
593  }
594 
595  // Finish the report.
596  reportWriter.endArray();
597  reportWriter.endObject();
598  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_successCaseUcoReportGeneration());
599  } catch (IOException | TskCoreException ex) {
600  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_generateCaseUcoReport_errorGeneratingCaseUcoReport());
601  logger.log(Level.SEVERE, "Error encountered while trying to create "
602  + "CASE-UCO output for portable case.. the portable case will be "
603  + "completed without a CASE-UCO report.", ex);
604  }
605  }
606 
615  @SuppressWarnings("deprecation")
616  private Multimap<Long, BlackboardArtifact> getInterestingArtifactsBySetName(SleuthkitCase skCase, List<String> setNames) throws TskCoreException {
617  Multimap<Long, BlackboardArtifact> artifactsWithSetName = ArrayListMultimap.create();
618  if (!setNames.isEmpty()) {
619  List<BlackboardArtifact> allArtifacts = skCase.getBlackboardArtifacts(
621  allArtifacts.addAll(skCase.getBlackboardArtifacts(
623  allArtifacts.addAll(skCase.getBlackboardArtifacts(
625 
626  for (BlackboardArtifact bArt : allArtifacts) {
627  BlackboardAttribute setAttr = bArt.getAttribute(
629  if (setNames.contains(setAttr.getValueString())) {
630  artifactsWithSetName.put(bArt.getDataSource().getId(), bArt);
631  }
632  }
633  }
634  return artifactsWithSetName;
635  }
636 
657  private boolean addUniqueFile(Content content, DataSource dataSource,
658  Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter,
659  boolean dataSourceHasBeenIncluded) throws IOException, TskCoreException {
660  if (content instanceof AbstractFile && !(content instanceof DataSource)) {
661  AbstractFile absFile = (AbstractFile) content;
662  Path filePath = tmpDir.resolve(Long.toString(absFile.getId()));
663  if (!absFile.isDir() && !Files.exists(filePath)) {
664  if (!dataSourceHasBeenIncluded) {
665  for (JsonElement element : exporter.exportDataSource(dataSource)) {
666  gson.toJson(element, reportWriter);
667  }
668  }
669  String subFolder = getExportSubfolder(absFile);
670  String fileName = absFile.getId() + "-" + FileUtil.escapeFileName(absFile.getName());
671  for (JsonElement element : exporter.exportAbstractFile(absFile, Paths.get(FILE_FOLDER_NAME, subFolder, fileName).toString())) {
672  gson.toJson(element, reportWriter);
673  }
674  Files.createFile(filePath);
675  return true;
676  }
677  }
678  return false;
679  }
680 
685  @SuppressWarnings("deprecation")
687 
688  // Get the set names in use for the current case.
689  List<String> setNames = new ArrayList<>();
690  Map<String, Long> setCounts;
691 
692  // There may not be a case open when configuring report modules for Command Line execution
693  // Get all SET_NAMEs from interesting item artifacts
694  String innerSelect = "SELECT (value_text) AS set_name FROM blackboard_attributes WHERE (artifact_type_id = '"
695  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID() + "' OR artifact_type_id = '"
696  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ITEM.getTypeID() + "' OR artifact_type_id = '"
697  + BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID() + "') AND attribute_type_id = '"
698  + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID() + "'"; // NON-NLS
699 
700  // Get the count of each SET_NAME
701  String query = "set_name, count(1) AS set_count FROM (" + innerSelect + ") set_names GROUP BY set_name"; // NON-NLS
702 
705  setCounts = callback.getSetCountMap();
706  setNames.addAll(setCounts.keySet());
707  return setNames;
708  }
709 
717  @NbBundle.Messages({
718  "# {0} - case folder",
719  "PortableCaseReportModule.createCase.caseDirExists=Case folder {0} already exists",
720  "PortableCaseReportModule.createCase.errorCreatingCase=Error creating case",
721  "# {0} - folder",
722  "PortableCaseReportModule.createCase.errorCreatingFolder=Error creating folder {0}",
723  "PortableCaseReportModule.createCase.errorStoringMaxIds=Error storing maximum database IDs",})
724  private void createCase(File outputDir, ReportProgressPanel progressPanel) {
725 
726  // Create the case folder
727  caseFolder = Paths.get(outputDir.toString(), caseName).toFile();
728 
729  if (caseFolder.exists()) {
730  handleError("Case folder " + caseFolder.toString() + " already exists",
731  Bundle.PortableCaseReportModule_createCase_caseDirExists(caseFolder.toString()), null, progressPanel); // NON-NLS
732  return;
733  }
734 
735  // Create the case
736  try {
737  portableSkCase = currentCase.createPortableCase(caseName, caseFolder);
738  } catch (TskCoreException ex) {
739  handleError("Error creating case " + caseName + " in folder " + caseFolder.toString(),
740  Bundle.PortableCaseReportModule_createCase_errorCreatingCase(), ex, progressPanel); // NON-NLS
741  return;
742  }
743 
744  // Store the highest IDs
745  try {
746  saveHighestIds();
747  } catch (TskCoreException ex) {
748  handleError("Error storing maximum database IDs",
749  Bundle.PortableCaseReportModule_createCase_errorStoringMaxIds(), ex, progressPanel); // NON-NLS
750  return;
751  }
752 
753  // Create the base folder for the copied files
754  copiedFilesFolder = Paths.get(caseFolder.toString(), FILE_FOLDER_NAME).toFile();
755  if (!copiedFilesFolder.mkdir()) {
756  handleError("Error creating folder " + copiedFilesFolder.toString(),
757  Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(copiedFilesFolder.toString()), null, progressPanel); // NON-NLS
758  return;
759  }
760 
761  // Create subfolders for the copied files
762  for (FileTypeCategory cat : FILE_TYPE_CATEGORIES) {
763  File subFolder = Paths.get(copiedFilesFolder.toString(), cat.getDisplayName()).toFile();
764  if (!subFolder.mkdir()) {
765  handleError("Error creating folder " + subFolder.toString(),
766  Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(subFolder.toString()), null, progressPanel); // NON-NLS
767  return;
768  }
769  }
770  File unknownTypeFolder = Paths.get(copiedFilesFolder.toString(), UNKNOWN_FILE_TYPE_FOLDER).toFile();
771  if (!unknownTypeFolder.mkdir()) {
772  handleError("Error creating folder " + unknownTypeFolder.toString(),
773  Bundle.PortableCaseReportModule_createCase_errorCreatingFolder(unknownTypeFolder.toString()), null, progressPanel); // NON-NLS
774  return;
775  }
776 
777  }
778 
784  private void saveHighestIds() throws TskCoreException {
785 
786  CaseDbAccessManager currentCaseDbManager = currentCase.getSleuthkitCase().getCaseDbAccessManager();
787 
788  String tableSchema = "( table_name TEXT PRIMARY KEY, "
789  + " max_id TEXT)"; // NON-NLS
790 
791  portableSkCase.getCaseDbAccessManager().createTable(MAX_ID_TABLE_NAME, tableSchema);
792 
793  currentCaseDbManager.select("max(obj_id) as max_id from tsk_objects", new StoreMaxIdCallback("tsk_objects")); // NON-NLS
794  currentCaseDbManager.select("max(tag_id) as max_id from content_tags", new StoreMaxIdCallback("content_tags")); // NON-NLS
795  currentCaseDbManager.select("max(tag_id) as max_id from blackboard_artifact_tags", new StoreMaxIdCallback("blackboard_artifact_tags")); // NON-NLS
796  currentCaseDbManager.select("max(examiner_id) as max_id from tsk_examiners", new StoreMaxIdCallback("tsk_examiners")); // NON-NLS
797  }
798 
806  private void initializeImageTags(ReportProgressPanel progressPanel) throws TskCoreException {
807 
808  // Create the image tags table in the portable case
809  CaseDbAccessManager portableDbAccessManager = portableSkCase.getCaseDbAccessManager();
810  if (!portableDbAccessManager.tableExists(ContentViewerTagManager.TABLE_NAME)) {
812  }
813  }
814 
823  private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
824 
825  // Get all the tags in the current case
826  List<ContentTag> tags = currentCase.getServices().getTagsManager().getContentTagsByTagName(oldTagName);
827 
828  // Copy the files into the portable case and tag
829  for (ContentTag tag : tags) {
830 
831  // Check for cancellation
832  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
833  return;
834  }
835 
836  Content content = tag.getContent();
837  if (content instanceof AbstractFile) {
838 
839  long newFileId = copyContentToPortableCase(content, progressPanel);
840 
841  // Tag the file
842  if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
843  throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); // NON-NLS
844  }
845  ContentTagChange newContentTag = portableSkCase.getTaggingManager().addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset());
846 
847  // Get the image tag data associated with this tag (empty string if there is none)
848  // and save it if present
849  String appData = getImageTagDataForContentTag(tag);
850  if (!appData.isEmpty()) {
851  addImageTagToPortableCase(newContentTag.getAddedTag(), appData);
852  }
853  }
854  }
855  }
856 
868 
869  GetImageTagCallback callback = new GetImageTagCallback();
870  String query = "* FROM " + ContentViewerTagManager.TABLE_NAME + " WHERE content_tag_id = " + tag.getId();
871  currentCase.getSleuthkitCase().getCaseDbAccessManager().select(query, callback);
872  return callback.getAppData();
873  }
874 
878  private static class GetImageTagCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
879 
880  private static final Logger logger = Logger.getLogger(PortableCaseReportModule.class.getName());
881  private String appData = "";
882 
883  @Override
884  public void process(ResultSet rs) {
885  try {
886  while (rs.next()) {
887  try {
888  appData = rs.getString("app_data"); // NON-NLS
889  } catch (SQLException ex) {
890  logger.log(Level.WARNING, "Unable to get app_data from result set", ex); // NON-NLS
891  }
892  }
893  } catch (SQLException ex) {
894  logger.log(Level.WARNING, "Failed to get next result for app_data", ex); // NON-NLS
895  }
896  }
897 
903  String getAppData() {
904  return appData;
905  }
906  }
907 
916  private void addImageTagToPortableCase(ContentTag newContentTag, String appData) throws TskCoreException {
917  String insert = "(content_tag_id, app_data) VALUES (" + newContentTag.getId() + ", '" + appData + "')";
919  }
920 
929  private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException {
930 
931  List<BlackboardArtifactTag> tags = currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName);
932 
933  // Copy the artifacts into the portable case along with their content and tag
934  for (BlackboardArtifactTag tag : tags) {
935 
936  // Check for cancellation
937  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
938  return;
939  }
940 
941  // Copy the source content
942  Content content = tag.getContent();
943  long newContentId = copyContentToPortableCase(content, progressPanel);
944 
945  // Copy the artifact
946  BlackboardArtifact newArtifact = copyArtifact(newContentId, tag.getArtifact());
947 
948  // Copy any attachments
949  copyAttachments(newArtifact, tag.getArtifact(), portableSkCase.getAbstractFileById(newContentId));
950 
951  // Copy any files associated with this artifact through the TSK_PATH_ID attribute
952  copyPathID(newArtifact, tag.getArtifact());
953 
954  // Tag the artfiact
955  if (!oldTagNameToNewTagName.containsKey(tag.getName())) {
956  throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); // NON-NLS
957  }
958  portableSkCase.getTaggingManager().addArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment());
959  }
960  }
961 
974  private BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy) throws TskCoreException {
975 
976  if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) {
977  return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID());
978  }
979 
980  // First create the associated artifact (if present)
981  BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
982  List<BlackboardAttribute> newAttrs = new ArrayList<>();
983  if (oldAssociatedAttribute != null) {
984  BlackboardArtifact oldAssociatedArtifact = currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong());
985  BlackboardArtifact newAssociatedArtifact = copyArtifact(newContentId, oldAssociatedArtifact);
987  String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID()));
988  }
989 
990  List<BlackboardAttribute> oldAttrs = artifactToCopy.getAttributes();
991 
992  // Copy over each attribute, making sure the type is in the new case.
993  for (BlackboardAttribute oldAttr : oldAttrs) {
994 
995  // Skip attributes that are handled elsewhere
996  if (SPECIALLY_HANDLED_ATTRS.contains(oldAttr.getAttributeType().getTypeID())) {
997  continue;
998  }
999 
1000  BlackboardAttribute.Type newAttributeType = getNewAttributeType(oldAttr);
1001  switch (oldAttr.getValueType()) {
1002  case BYTE:
1003  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
1004  oldAttr.getValueBytes()));
1005  break;
1006  case DOUBLE:
1007  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
1008  oldAttr.getValueDouble()));
1009  break;
1010  case INTEGER:
1011  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
1012  oldAttr.getValueInt()));
1013  break;
1014  case DATETIME:
1015  case LONG:
1016  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
1017  oldAttr.getValueLong()));
1018  break;
1019  case STRING:
1020  case JSON:
1021  newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()),
1022  oldAttr.getValueString()));
1023  break;
1024  default:
1025  throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel()); // NON-NLS
1026  }
1027  }
1028 
1029  // Figure out the data source ID. We can't always get it from newContent because it could be null
1030  // for OS accounts, which means we also can't assume it's been added to the case already.
1031  Long newDataSourceId;
1032  if (newIdToContent.get(newContentId).getDataSource() != null) {
1033  // We can use the new content to get the id since the data source is in its parent hierarchy.
1034  // Everything would have already been copied to the portable case.
1035  newDataSourceId = newIdToContent.get(newContentId).getDataSource().getId();
1036  } else {
1037  // The newContent has no data source parent, so we'll have to use the old artifact.
1038  if (artifactToCopy.getDataSource() == null) {
1039  // Shouldn't happen with the current code
1040  throw new TskCoreException("Can not copy artifact with ID: " + artifactToCopy.getArtifactID() + " because it is not associated with a data source");
1041  }
1042  newDataSourceId = copyContent(artifactToCopy.getDataSource());
1043  }
1044 
1045  // Create the new artifact
1046  int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy);
1047  BlackboardArtifact.Type newArtifactType = portableSkCase.getBlackboard().getArtifactType(newArtifactTypeId);
1048  BlackboardArtifact newArtifact;
1049 
1050  // First, check if the artifact being copied is an AnalysisResult or a DataArtifact. If it
1051  // is neither, attempt to reload it as the appropriate subclass.
1052  if (!((artifactToCopy instanceof AnalysisResult) || (artifactToCopy instanceof DataArtifact))) {
1053  try {
1054  if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1055  AnalysisResult ar = currentCase.getSleuthkitCase().getBlackboard().getAnalysisResultById(artifactToCopy.getId());
1056  if (ar != null) {
1057  artifactToCopy = ar;
1058  }
1059  } else {
1060  DataArtifact da = currentCase.getSleuthkitCase().getBlackboard().getDataArtifactById(artifactToCopy.getId());
1061  if (da != null) {
1062  artifactToCopy = da;
1063  }
1064  }
1065  } catch (TskCoreException ex) {
1066  // If the lookup failed, just use the orginal BlackboardArtifact
1067  }
1068  }
1069 
1070  try {
1071  if (artifactToCopy instanceof AnalysisResult) {
1072  AnalysisResult analysisResultToCopy = (AnalysisResult) artifactToCopy;
1073  newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1074  newDataSourceId, analysisResultToCopy.getScore(),
1075  analysisResultToCopy.getConclusion(), analysisResultToCopy.getConfiguration(),
1076  analysisResultToCopy.getJustification(), newAttrs).getAnalysisResult();
1077  } else if (artifactToCopy instanceof DataArtifact) {
1078  DataArtifact dataArtifactToCopy = (DataArtifact) artifactToCopy;
1079  Long newOsAccountId = null;
1080  if (dataArtifactToCopy.getOsAccountObjectId().isPresent()) {
1081  copyOsAccount(dataArtifactToCopy.getOsAccountObjectId().get());
1082  newOsAccountId = oldOsAccountIdToNewOsAccount.get((dataArtifactToCopy.getOsAccountObjectId().get())).getId();
1083  }
1084  newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1085  newDataSourceId,
1086  newAttrs, newOsAccountId);
1087  } else {
1088  if (newArtifactType.getCategory().equals(BlackboardArtifact.Category.ANALYSIS_RESULT)) {
1089  newArtifact = portableSkCase.getBlackboard().newAnalysisResult(newArtifactType, newContentId,
1090  newDataSourceId, Score.SCORE_NONE,
1091  null, null, null, newAttrs).getAnalysisResult();
1092  } else {
1093  newArtifact = portableSkCase.getBlackboard().newDataArtifact(newArtifactType, newContentId,
1094  newDataSourceId,
1095  newAttrs, null);
1096  }
1097  }
1098  } catch (BlackboardException ex) {
1099  throw new TskCoreException("Error copying artifact with ID: " + artifactToCopy.getId());
1100  }
1101 
1102  oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact);
1103  return newArtifact;
1104  }
1105 
1116  if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) {
1117  return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID());
1118  }
1119 
1120  BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getBlackboard().getArtifactType(oldArtifact.getArtifactTypeName());
1121  try {
1122  BlackboardArtifact.Type newCustomType = portableSkCase.getBlackboard().getOrAddArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName());
1123  oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID());
1124  return newCustomType.getTypeID();
1125  } catch (BlackboardException ex) {
1126  throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex); // NON-NLS
1127  }
1128  }
1129 
1140  BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType();
1141  if (oldAttrTypeIdToNewAttrType.containsKey(oldAttrType.getTypeID())) {
1142  return oldAttrTypeIdToNewAttrType.get(oldAttrType.getTypeID());
1143  }
1144 
1145  try {
1146  BlackboardAttribute.Type newCustomType = portableSkCase.getBlackboard().getOrAddAttributeType(oldAttrType.getTypeName(),
1147  oldAttrType.getValueType(), oldAttrType.getDisplayName());
1148  oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType);
1149  return newCustomType;
1150  } catch (BlackboardException ex) {
1151  throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex); // NON-NLS
1152  }
1153  }
1154 
1165  @NbBundle.Messages({
1166  "# {0} - File name",
1167  "PortableCaseReportModule.copyContentToPortableCase.copyingFile=Copying file {0}",})
1168  private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel) throws TskCoreException {
1169  progressPanel.updateStatusLabel(Bundle.PortableCaseReportModule_copyContentToPortableCase_copyingFile(content.getUniquePath()));
1170  return copyContent(content);
1171  }
1172 
1182  private long copyContent(Content content) throws TskCoreException {
1183 
1184  // Check if we've already copied this content
1185  if (oldIdToNewContent.containsKey(content.getId())) {
1186  return oldIdToNewContent.get(content.getId()).getId();
1187  }
1188 
1189  // Otherwise:
1190  // - Make parent of this object (if applicable)
1191  // - Copy this content
1192  long parentId = 0;
1193  if (content.getParent() != null) {
1194  parentId = copyContent(content.getParent());
1195  }
1196 
1197  Content newContent;
1198  if (content instanceof BlackboardArtifact) {
1199  BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1200  newContent = copyArtifact(parentId, artifactToCopy);
1201  } else if (content instanceof OsAccount) {
1202  newContent = copyOsAccount(content.getId());
1203  } else {
1204  // Get or create the host (if needed) before beginning transaction.
1205  Host newHost = null;
1206  if (content instanceof DataSource) {
1207  newHost = copyHost(((DataSource) content).getHost());
1208  }
1209 
1210  // Copy the associated OS account (if needed) before beginning transaction.
1211  if (content instanceof AbstractFile) {
1212  AbstractFile file = (AbstractFile) content;
1213  if (file.getOsAccountObjectId().isPresent()) {
1214  copyOsAccount(file.getOsAccountObjectId().get());
1215  }
1216  }
1217 
1218  // Load the hashes if we have an image to avoid getting new connections with an open transaction.
1219  String md5 = "";
1220  String sha1 = "";
1221  String sha256 = "";
1222  if (content instanceof Image) {
1223  md5 = ((Image) content).getMd5();
1224  sha1 = ((Image) content).getSha1();
1225  sha256 = ((Image) content).getSha256();
1226  }
1227 
1228  CaseDbTransaction trans = portableSkCase.beginTransaction();
1229  try {
1230  if (content instanceof Image) {
1231  Image image = (Image) content;
1232  newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(),
1233  new ArrayList<>(), image.getTimeZone(), md5, sha1, sha256, image.getDeviceId(), newHost, trans);
1234  } else if (content instanceof VolumeSystem) {
1235  VolumeSystem vs = (VolumeSystem) content;
1236  newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans);
1237  } else if (content instanceof Volume) {
1238  Volume vs = (Volume) content;
1239  newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(),
1240  vs.getDescription(), vs.getFlags(), trans);
1241  } else if (content instanceof Pool) {
1242  Pool pool = (Pool) content;
1243  newContent = portableSkCase.addPool(parentId, pool.getType(), trans);
1244  } else if (content instanceof FileSystem) {
1245  FileSystem fs = (FileSystem) content;
1246  newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(),
1247  fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(),
1248  fs.getName(), trans);
1249  } else if (content instanceof BlackboardArtifact) {
1250  BlackboardArtifact artifactToCopy = (BlackboardArtifact) content;
1251  newContent = copyArtifact(parentId, artifactToCopy);
1252  } else if (content instanceof AbstractFile) {
1253  AbstractFile abstractFile = (AbstractFile) content;
1254 
1255  if (abstractFile instanceof LocalFilesDataSource) {
1256  LocalFilesDataSource localFilesDS = (LocalFilesDataSource) abstractFile;
1257  newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), newHost, trans);
1258  } else {
1259  if (abstractFile.isDir()) {
1260  newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans);
1261  } else {
1262  try {
1263  // Copy the file
1264  String fileName = abstractFile.getId() + "-" + FileUtil.escapeFileName(abstractFile.getName());
1265  String exportSubFolder = getExportSubfolder(abstractFile);
1266  File exportFolder = Paths.get(copiedFilesFolder.toString(), exportSubFolder).toFile();
1267  File localFile = new File(exportFolder, fileName);
1268  ContentUtils.writeToFile(abstractFile, localFile);
1269 
1270  // Get the new parent object in the portable case database
1271  Content oldParent = abstractFile.getParent();
1272  if (!oldIdToNewContent.containsKey(oldParent.getId())) {
1273  throw new TskCoreException("Parent of file with ID " + abstractFile.getId() + " has not been created"); // NON-NLS
1274  }
1275  Content newParent = oldIdToNewContent.get(oldParent.getId());
1276 
1277  // Construct the relative path to the copied file
1278  String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName;
1279 
1280  Long newOsAccountId = null;
1281  if (abstractFile.getOsAccountObjectId().isPresent()) {
1282  newOsAccountId = oldOsAccountIdToNewOsAccount.get(abstractFile.getOsAccountObjectId().get()).getId();
1283  }
1284 
1285  newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(),
1286  abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(),
1287  abstractFile.getMd5Hash(), abstractFile.getSha256Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(),
1288  true, TskData.EncodingType.NONE,
1289  newOsAccountId, abstractFile.getOwnerUid().orElse(null),
1290  newParent, trans);
1291  } catch (IOException ex) {
1292  throw new TskCoreException("Error copying file " + abstractFile.getName() + " with original obj ID "
1293  + abstractFile.getId(), ex); // NON-NLS
1294  }
1295  }
1296  }
1297  } else {
1298  throw new TskCoreException("Trying to copy unexpected Content type " + content.getClass().getName()); // NON-NLS
1299  }
1300  trans.commit();
1301  } catch (TskCoreException ex) {
1302  trans.rollback();
1303  throw (ex);
1304  }
1305  }
1306 
1307  // Save the new object
1308  oldIdToNewContent.put(content.getId(), newContent);
1309  newIdToContent.put(newContent.getId(), newContent);
1310  return oldIdToNewContent.get(content.getId()).getId();
1311  }
1312 
1323  private Host copyHost(Host oldHost) throws TskCoreException {
1324  Host newHost;
1325  if (oldHostIdToNewHost.containsKey(oldHost.getHostId())) {
1326  newHost = oldHostIdToNewHost.get(oldHost.getHostId());
1327  } else {
1328  newHost = portableSkCase.getHostManager().newHost(oldHost.getName());
1329  oldHostIdToNewHost.put(oldHost.getHostId(), newHost);
1330  }
1331  return newHost;
1332  }
1333 
1340  private OsAccount copyOsAccount(Long oldOsAccountId) throws TskCoreException {
1341  // If it has already been copied, we're done.
1342  if (oldOsAccountIdToNewOsAccount.containsKey(oldOsAccountId)) {
1343  return oldOsAccountIdToNewOsAccount.get(oldOsAccountId);
1344  }
1345 
1346  // Load the OS account from the current case.
1347  OsAccountManager oldOsAcctManager = currentCase.getSleuthkitCase().getOsAccountManager();
1348  OsAccount oldOsAccount = oldOsAcctManager.getOsAccountByObjectId(oldOsAccountId);
1349 
1350  // Load the realm associated with the OS account.
1351  OsAccountRealmManager oldRealmManager = currentCase.getSleuthkitCase().getOsAccountRealmManager();
1352  OsAccountRealm oldRealm = oldRealmManager.getRealmByRealmId(oldOsAccount.getRealmId());
1353 
1354  // Copy the realm to the portable case if necessary.
1355  if (!oldRealmIdToNewRealm.containsKey(oldOsAccount.getRealmId())) {
1356  OsAccountRealmManager newRealmManager = portableSkCase.getOsAccountRealmManager();
1357 
1358  Host newHost = null;
1359  if (oldRealm.getScopeHost().isPresent()) {
1360  Host host = oldRealm.getScopeHost().get();
1361  newHost = copyHost(host);
1362  } else {
1363  if (oldRealm.getScope().equals(OsAccountRealm.RealmScope.DOMAIN)) {
1364  // There is currently no way to get a domain-scoped host in Autopsy. When this changes
1365  // we will need to update this code. This will require a new version of newWindowsRealm() that
1366  // does not require a host, or some other way to create a realm with no host.
1367  throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " - can not currently handle domain-scoped hosts");
1368  } else {
1369  throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId() + " because it is non-domain scoped but has no scope host");
1370  }
1371  }
1372 
1373  // We currently only support one realm name.
1374  String realmName = null;
1375  List<String> names = oldRealm.getRealmNames();
1376  if (!names.isEmpty()) {
1377  realmName = names.get(0);
1378  }
1379 
1380  try {
1381  OsAccountRealm newRealm = newRealmManager.newWindowsRealm(oldOsAccount.getAddr().orElse(null), realmName, newHost, oldRealm.getScope());
1382  oldRealmIdToNewRealm.put(oldOsAccount.getRealmId(), newRealm);
1383  } catch (NotUserSIDException ex) {
1384  throw new TskCoreException("Failed to copy OsAccountRealm with ID=" + oldOsAccount.getRealmId(), ex);
1385  }
1386  }
1387 
1388  OsAccountManager newOsAcctManager = portableSkCase.getOsAccountManager();
1389  try {
1390  OsAccount newOsAccount = newOsAcctManager.newWindowsOsAccount(oldOsAccount.getAddr().orElse(null),
1391  oldOsAccount.getLoginName().orElse(null), oldRealmIdToNewRealm.get(oldOsAccount.getRealmId()));
1392  oldOsAccountIdToNewOsAccount.put(oldOsAccountId, newOsAccount);
1393  return newOsAccount;
1394  } catch (NotUserSIDException ex) {
1395  throw new TskCoreException("Failed to copy OsAccount with ID=" + oldOsAccount.getId(), ex);
1396  }
1397  }
1398 
1408  private void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact) throws TskCoreException {
1409  // Get the path ID attribute
1410  BlackboardAttribute oldPathIdAttr = oldArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PATH_ID));
1411  if (oldPathIdAttr != null) {
1412  // Copy the file and remake the attribute if the path ID is valid
1413  long oldContentId = oldPathIdAttr.getValueLong();
1414  if (oldContentId > 0) {
1415  Content oldContent = currentCase.getSleuthkitCase().getContentById(oldContentId);
1416  long newContentId = copyContent(oldContent);
1418  String.join(",", oldPathIdAttr.getSources()), newContentId));
1419  }
1420  }
1421  }
1422 
1434  private void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile) throws TskCoreException {
1435  // Get the attachments from TSK_ATTACHMENTS attribute.
1436  BlackboardAttribute attachmentsAttr = oldArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
1437  if (attachmentsAttr != null) {
1438  try {
1439  MessageAttachments msgAttachments = BlackboardJsonAttrUtil.fromAttribute(attachmentsAttr, MessageAttachments.class);
1440 
1441  Collection<MessageAttachments.FileAttachment> oldFileAttachments = msgAttachments.getFileAttachments();
1442  List<MessageAttachments.FileAttachment> newFileAttachments = new ArrayList<>();
1443  for (MessageAttachments.FileAttachment oldFileAttachment : oldFileAttachments) {
1444  long attachedFileObjId = oldFileAttachment.getObjectId();
1445  if (attachedFileObjId >= 0) {
1446  // Copy the attached file and save to the MessageAttachments object
1447  AbstractFile attachedFile = currentCase.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
1448  if (attachedFile == null) {
1449  throw new TskCoreException("Error loading file with object ID " + attachedFileObjId + " from portable case");
1450  }
1451  long newFileID = copyContent(attachedFile);
1452  newFileAttachments.add(new MessageAttachments.FileAttachment(portableSkCase.getAbstractFileById(newFileID)));
1453  }
1454  }
1455 
1456  // Get the name of the module(s) that created the attachment
1457  String newSourceStr = "";
1458  List<String> oldSources = attachmentsAttr.getSources();
1459  if (!oldSources.isEmpty()) {
1460  newSourceStr = String.join(",", oldSources);
1461  }
1462 
1463  // Add the attachment. The account type specified in the constructor will not be used.
1464  CommunicationArtifactsHelper communicationArtifactsHelper = new CommunicationArtifactsHelper(currentCase.getSleuthkitCase(),
1465  newSourceStr, newFile, Account.Type.EMAIL, null);
1466  communicationArtifactsHelper.addAttachments(newArtifact, new MessageAttachments(newFileAttachments, msgAttachments.getUrlAttachments()));
1468  throw new TskCoreException(String.format("Unable to parse json for MessageAttachments object in artifact: %s", oldArtifact.getName()), ex);
1469  }
1470  } else { // backward compatibility - email message attachments are derived files, children of the message.
1471  for (Content childContent : oldArtifact.getChildren()) {
1472  if (childContent instanceof AbstractFile) {
1473  copyContent(childContent);
1474  }
1475  }
1476  }
1477  }
1478 
1486  private String getExportSubfolder(AbstractFile abstractFile) {
1487  if (abstractFile.getMIMEType() == null || abstractFile.getMIMEType().isEmpty()) {
1488  return UNKNOWN_FILE_TYPE_FOLDER;
1489  }
1490 
1491  for (FileTypeCategory cat : FILE_TYPE_CATEGORIES) {
1492  if (cat.getMediaTypes().contains(abstractFile.getMIMEType())) {
1493  return cat.getDisplayName();
1494  }
1495  }
1496  return UNKNOWN_FILE_TYPE_FOLDER;
1497  }
1498 
1504  private Path getApplicationBasePath() {
1505  return getAutopsyExePath().getParent().getParent();
1506  }
1507 
1513  private Path getAutopsyExePath() {
1514  // If this is an installed version, there should be an <appName>64.exe file in the bin folder
1515  String exeName = getAutopsyExeName();
1516  String installPath = PlatformUtil.getInstallPath();
1517 
1518  return Paths.get(installPath, "bin", exeName);
1519  }
1520 
1526  private String getAutopsyExeName() {
1527  String appName = UserPreferences.getAppName();
1528  return appName + "64.exe";
1529  }
1530 
1539  private void copyApplication(Path sourceFolder, String destBaseFolder) throws IOException {
1540 
1541  // Create an appName folder in the destination
1542  Path destAppFolder = Paths.get(destBaseFolder, UserPreferences.getAppName());
1543  if (!destAppFolder.toFile().exists() && !destAppFolder.toFile().mkdirs()) {
1544  throw new IOException("Failed to create directory " + destAppFolder.toString());
1545  }
1546 
1547  // Now copy the files
1548  FileUtils.copyDirectory(sourceFolder.toFile(), destAppFolder.toFile());
1549  }
1550 
1558  private void createAppLaunchBatFile(String destBaseFolder) throws IOException {
1559  Path filePath = Paths.get(destBaseFolder, "open.bat");
1560  String appName = UserPreferences.getAppName();
1561  String exePath = "\"%~dp0" + appName + "\\bin\\" + getAutopsyExeName() + "\"";
1562  String casePath = "..\\" + caseName;
1563  try (FileWriter writer = new FileWriter(filePath.toFile())) {
1564  writer.write(exePath + " \"" + casePath + "\"");
1565  }
1566  }
1567 
1571  private void cleanup() {
1572  oldIdToNewContent.clear();
1573  newIdToContent.clear();
1574  oldTagNameToNewTagName.clear();
1575  oldArtTypeIdToNewArtTypeId.clear();
1577  oldArtifactIdToNewArtifact.clear();
1578  oldOsAccountIdToNewOsAccount.clear();
1579  oldRealmIdToNewRealm.clear();
1580  oldHostIdToNewHost.clear();
1581 
1583 
1584  currentCase = null;
1585  caseFolder = null;
1586  copiedFilesFolder = null;
1587  }
1588 
1592  private void closePortableCaseDatabase() {
1593  if (portableSkCase != null) {
1594  portableSkCase.close();
1595  portableSkCase = null;
1596  }
1597  }
1598 
1599  /*
1600  * @Override public JPanel getConfigurationPanel() { configPanel = new
1601  * CreatePortableCasePanel(); return configPanel; }
1602  */
1603  private class StoreMaxIdCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
1604 
1605  private final String tableName;
1606 
1607  StoreMaxIdCallback(String tableName) {
1608  this.tableName = tableName;
1609  }
1610 
1611  @Override
1612  public void process(ResultSet rs) {
1613 
1614  try {
1615  while (rs.next()) {
1616  try {
1617  Long maxId = rs.getLong("max_id"); // NON-NLS
1618  String query = " (table_name, max_id) VALUES ('" + tableName + "', '" + maxId + "')"; // NON-NLS
1619  portableSkCase.getCaseDbAccessManager().insert(MAX_ID_TABLE_NAME, query);
1620 
1621  } catch (SQLException ex) {
1622  logger.log(Level.WARNING, "Unable to get maximum ID from result set", ex); // NON-NLS
1623  } catch (TskCoreException ex) {
1624  logger.log(Level.WARNING, "Unable to save maximum ID from result set", ex); // NON-NLS
1625  }
1626 
1627  }
1628  } catch (SQLException ex) {
1629  logger.log(Level.WARNING, "Failed to get maximum ID from result set", ex); // NON-NLS
1630  }
1631  }
1632  }
1633 
1634  @NbBundle.Messages({
1635  "PortableCaseReportModule.compressCase.errorFinding7zip=Could not locate 7-Zip executable",
1636  "# {0} - Temp folder path",
1637  "PortableCaseReportModule.compressCase.errorCreatingTempFolder=Could not create temporary folder {0}",
1638  "PortableCaseReportModule.compressCase.errorCompressingCase=Error compressing case",
1639  "PortableCaseReportModule.compressCase.canceled=Compression canceled by user",})
1640  private boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress) {
1641 
1643 
1644  // Make a temporary folder for the compressed case
1645  Path dirToCompress = Paths.get(folderToCompress);
1646  File tempZipFolder = Paths.get(dirToCompress.getParent().toString(), "temp", "portableCase" + System.currentTimeMillis()).toFile();
1647  if (!tempZipFolder.mkdirs()) {
1648  handleError("Error creating temporary folder " + tempZipFolder.toString(),
1649  Bundle.PortableCaseReportModule_compressCase_errorCreatingTempFolder(tempZipFolder.toString()), null, progressPanel); // NON-NLS
1650  return false;
1651  }
1652 
1653  // Find 7-Zip
1654  File sevenZipExe = locate7ZipExecutable();
1655  if (sevenZipExe == null) {
1656  handleError("Error finding 7-Zip exectuable", Bundle.PortableCaseReportModule_compressCase_errorFinding7zip(), null, progressPanel); // NON-NLS
1657  return false;
1658  }
1659 
1660  // Create the chunk option
1661  String chunkOption = "";
1663  chunkOption = "-v" + settings.getChunkSize().getSevenZipParam();
1664  }
1665 
1666  File zipFile = Paths.get(tempZipFolder.getAbsolutePath(), caseName + ".zip").toFile(); // NON-NLS
1667  ProcessBuilder procBuilder = new ProcessBuilder();
1668  procBuilder.command(
1669  sevenZipExe.getAbsolutePath(),
1670  "a", // Add to archive
1671  zipFile.getAbsolutePath(),
1672  dirToCompress.toAbsolutePath().toString(),
1673  chunkOption
1674  );
1675 
1676  try {
1677  Process process = procBuilder.start();
1678 
1679  while (process.isAlive()) {
1680  if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) {
1681  process.destroy();
1682  return false;
1683  }
1684  Thread.sleep(200);
1685  }
1686  int exitCode = process.exitValue();
1687  if (exitCode != 0) {
1688  // Save any errors so they can be logged
1689  StringBuilder sb = new StringBuilder();
1690  try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
1691  String line;
1692  while ((line = br.readLine()) != null) {
1693  sb.append(line).append(System.getProperty("line.separator")); // NON-NLS
1694  }
1695  }
1696 
1697  handleError("Error compressing case\n7-Zip output: " + sb.toString(), Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), null, progressPanel); // NON-NLS
1698  return false;
1699  }
1700  } catch (IOException | InterruptedException ex) {
1701  handleError("Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel); // NON-NLS
1702  return false;
1703  }
1704 
1705  // Delete everything in the case folder then copy over the compressed file(s)
1706  try {
1707  FileUtils.cleanDirectory(dirToCompress.toFile());
1708  FileUtils.copyDirectory(tempZipFolder, dirToCompress.toFile());
1709  FileUtils.deleteDirectory(new File(tempZipFolder.getParent()));
1710  } catch (IOException ex) {
1711  handleError("Error compressing case", Bundle.PortableCaseReportModule_compressCase_errorCompressingCase(), ex, progressPanel); // NON-NLS
1712  return false;
1713  }
1714 
1715  return true;
1716  }
1717 
1723  private static File locate7ZipExecutable() {
1724  if (!PlatformUtil.isWindowsOS()) {
1725  return null;
1726  }
1727 
1728  String executableToFindName = Paths.get("7-Zip", "7z.exe").toString(); // NON-NLS
1729  File exeFile = InstalledFileLocator.getDefault().locate(executableToFindName, PortableCaseReportModule.class.getPackage().getName(), false);
1730  if (null == exeFile) {
1731  return null;
1732  }
1733 
1734  if (!exeFile.canExecute()) {
1735  return null;
1736  }
1737 
1738  return exeFile;
1739  }
1740 
1744  public static class GetInterestingItemSetNamesCallback implements CaseDbAccessManager.CaseDbAccessQueryCallback {
1745 
1746  private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(GetInterestingItemSetNamesCallback.class.getName());
1747  private final Map<String, Long> setCounts = new HashMap<>();
1748 
1749  @Override
1750  public void process(ResultSet rs) {
1751  try {
1752  while (rs.next()) {
1753  try {
1754  Long setCount = rs.getLong("set_count"); // NON-NLS
1755  String setName = rs.getString("set_name"); // NON-NLS
1756 
1757  setCounts.put(setName, setCount);
1758 
1759  } catch (SQLException ex) {
1760  logger.log(Level.WARNING, "Unable to get data_source_obj_id or value from result set", ex); // NON-NLS
1761  }
1762  }
1763  } catch (SQLException ex) {
1764  logger.log(Level.WARNING, "Failed to get next result for values by datasource", ex); // NON-NLS
1765  }
1766  }
1767 
1773  public Map<String, Long> getSetCountMap() {
1774  return setCounts;
1775  }
1776  }
1777 }
void handleError(String logWarning, String dialogWarning, Exception ex, ReportProgressPanel progressPanel)
TagName addOrUpdateTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus)
AnalysisResult getAnalysisResultById(long artifactObjId)
OsAccountRealm newWindowsRealm(String accountSid, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope)
OsAccount getOsAccountByObjectId(long osAccountObjId)
long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel)
DataArtifact newDataArtifact(BlackboardArtifact.Type artifactType, long sourceObjId, Long dataSourceObjId, Collection< BlackboardAttribute > attributes, Long osAccountId)
void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
BlackboardArtifactTagChange addArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment)
synchronized CaseDbAccessManager getCaseDbAccessManager()
DataArtifact getDataArtifactById(long artifactObjId)
static< T > T fromAttribute(BlackboardAttribute attr, Class< T > clazz)
void copyAttachments(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact, AbstractFile newFile)
TskData.TSK_IMG_TYPE_ENUM getType()
Multimap< Long, BlackboardArtifact > getInterestingArtifactsBySetName(SleuthkitCase skCase, List< String > setNames)
static< T > long writeToFile(Content content, java.io.File outputFile, ProgressHandle progress, Future< T > worker, boolean source)
synchronized TaggingManager getTaggingManager()
BlackboardArtifact getBlackboardArtifact(long artifactID)
OsAccountRealmManager getOsAccountRealmManager()
Logger(String name, String resourceBundleName)
Definition: Logger.java:160
AbstractFile getAbstractFileById(long id)
BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute)
Pool addPool(long parentObjId, TskData.TSK_POOL_TYPE_ENUM type, CaseDbTransaction transaction)
void copyPathID(BlackboardArtifact newArtifact, BlackboardArtifact oldArtifact)
String toString(boolean preserveState)
void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel)
synchronized BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName)
void generateReport(String reportPath, PortableCaseReportModuleSettings options, ReportProgressPanel progressPanel)
void createTable(final String tableName, final String tableSchema)
BlackboardArtifact.Type getArtifactType(String artTypeName)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByTagName(TagName tagName)
Image addImage(TskData.TSK_IMG_TYPE_ENUM type, long sectorSize, long size, String displayName, List< String > imagePaths, String timezone, String md5, String sha1, String sha256, String deviceId, CaseDbTransaction transaction)
ContentTagChange addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset)
FileSystem addFileSystem(long parentObjId, long imgOffset, TskData.TSK_FS_TYPE_ENUM type, long blockSize, long blockCount, long rootInum, long firstInum, long lastInum, String displayName, CaseDbTransaction transaction)
TSK_POOL_TYPE_ENUM getType()
BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy)
void generateCaseUcoReport(List< TagName > tagNames, List< String > setNames, ReportProgressPanel progressPanel)
LocalFile addLocalFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, TskData.EncodingType encodingType, AbstractFile parent)
AnalysisResultAdded newAnalysisResult(BlackboardArtifact.Type artifactType, long objId, Long dataSourceObjId, Score score, String conclusion, String configuration, String justification, Collection< BlackboardAttribute > attributesList)
void select(final String sql, final CaseDbAccessQueryCallback queryCallback)
SleuthkitCase createPortableCase(String caseName, File portableCaseFolder)
Definition: Case.java:2542
BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName)
boolean addUniqueFile(Content content, DataSource dataSource, Path tmpDir, Gson gson, CaseUcoExporter exporter, JsonWriter reportWriter, boolean dataSourceHasBeenIncluded)
static String escapeFileName(String fileName)
Definition: FileUtil.java:169
VolumeSystem addVolumeSystem(long parentObjId, TskData.TSK_VS_TYPE_ENUM type, long imgOffset, long blockSize, CaseDbTransaction transaction)
boolean compressCase(ReportProgressPanel progressPanel, String folderToCompress)
TskData.TSK_FS_TYPE_ENUM getFsType()
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
Volume addVolume(long parentObjId, long addr, long start, long length, String desc, long flags, CaseDbTransaction transaction)
long insert(final String tableName, final String sql)
BlackboardAttribute.Type getAttributeType(String attrTypeName)
List< ContentTag > getContentTagsByTagName(TagName tagName)
void addAttachments(BlackboardArtifact message, MessageAttachments attachments)
LocalFilesDataSource addLocalFilesDataSource(String deviceId, String rootDirectoryName, String timeZone, CaseDbTransaction transaction)
OsAccount newWindowsOsAccount(String sid, String loginName, String realmName, Host referringHost, OsAccountRealm.RealmScope realmScope)
List< AnalysisResult > getAnalysisResultsByType(int artifactTypeId)
LocalDirectory addLocalDirectory(long parentId, String directoryName)

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