19 package org.sleuthkit.autopsy.modules.embeddedfileextractor;
 
   22 import java.io.FileOutputStream;
 
   23 import java.io.IOException;
 
   24 import java.util.ArrayList;
 
   25 import java.util.Arrays;
 
   26 import java.util.Collection;
 
   27 import java.util.Collections;
 
   28 import java.util.Date;
 
   29 import java.util.HashMap;
 
   30 import java.util.List;
 
   32 import java.util.concurrent.ConcurrentHashMap;
 
   33 import java.util.logging.Level;
 
   34 import net.sf.sevenzipjbinding.ArchiveFormat;
 
   35 import static net.sf.sevenzipjbinding.ArchiveFormat.RAR;
 
   36 import net.sf.sevenzipjbinding.ExtractAskMode;
 
   37 import net.sf.sevenzipjbinding.ISequentialOutStream;
 
   38 import net.sf.sevenzipjbinding.ISevenZipInArchive;
 
   39 import net.sf.sevenzipjbinding.SevenZip;
 
   40 import net.sf.sevenzipjbinding.SevenZipException;
 
   41 import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
 
   42 import net.sf.sevenzipjbinding.ExtractOperationResult;
 
   43 import net.sf.sevenzipjbinding.IArchiveExtractCallback;
 
   44 import net.sf.sevenzipjbinding.ICryptoGetTextPassword;
 
   45 import net.sf.sevenzipjbinding.PropID;
 
   46 import org.netbeans.api.progress.ProgressHandle;
 
   47 import org.openide.util.NbBundle;
 
   48 import org.openide.util.NbBundle.Messages;
 
   74 class SevenZipExtractor {
 
   76     private static final Logger logger = Logger.getLogger(SevenZipExtractor.class.getName());
 
   77     private IngestServices services = IngestServices.getInstance();
 
   78     private final IngestJobContext context;
 
   79     private final FileTypeDetector fileTypeDetector;
 
   81     private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class,
 
   82             "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel");
 
   83     private static final String ENCRYPTION_FULL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class,
 
   84             "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull");
 
   86     private static final int MAX_DEPTH = 4;
 
   87     private static final int MAX_COMPRESSION_RATIO = 600;
 
   88     private static final long MIN_COMPRESSION_RATIO_SIZE = 500 * 1000000L;
 
   89     private static final long MIN_FREE_DISK_SPACE = 1 * 1000 * 1000000L; 
 
   91     private String moduleDirRelative;
 
   92     private String moduleDirAbsolute;
 
   94     private Blackboard blackboard;
 
   96     private ProgressHandle progress;
 
   98     private String currentArchiveName;
 
  100     private String getLocalRootAbsPath(String uniqueArchiveFileName) {
 
  101         return moduleDirAbsolute + File.separator + uniqueArchiveFileName;
 
  116         XRAR(
"application/x-rar-compressed"); 
 
  121             this.mimeType = mimeType;
 
  126             return this.mimeType;
 
  131     SevenZipExtractor(
IngestJobContext context, 
FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) 
throws SevenZipNativeInitializationException {
 
  132         if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) {
 
  133             SevenZip.initSevenZipFromPlatformJAR();
 
  135         this.context = context;
 
  136         this.fileTypeDetector = fileTypeDetector;
 
  137         this.moduleDirRelative = moduleDirRelative;
 
  138         this.moduleDirAbsolute = moduleDirAbsolute;
 
  149     boolean isSevenZipExtractionSupported(AbstractFile file) {
 
  150         String fileMimeType = fileTypeDetector.getMIMEType(file);
 
  151         for (SupportedArchiveExtractionFormats mimeType : SupportedArchiveExtractionFormats.values()) {
 
  152             if (mimeType.toString().equals(fileMimeType)) {
 
  182     private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISevenZipInArchive inArchive, 
int inArchiveItemIndex, ConcurrentHashMap<Long, Archive> depthMap, String escapedFilePath) {
 
  188         if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC)) {
 
  193             final Long archiveItemSize = (Long) inArchive.getProperty(
 
  194                     inArchiveItemIndex, PropID.SIZE);
 
  197             if (archiveItemSize == null || archiveItemSize < MIN_COMPRESSION_RATIO_SIZE) {
 
  201             final Long archiveItemPackedSize = (Long) inArchive.getProperty(
 
  202                     inArchiveItemIndex, PropID.PACKED_SIZE);
 
  204             if (archiveItemPackedSize == null || archiveItemPackedSize <= 0) {
 
  205                 logger.log(Level.WARNING, 
"Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}", 
 
  206                         new Object[]{archiveFile.getName(), (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH)}); 
 
  210             int cRatio = (int) (archiveItemSize / archiveItemPackedSize);
 
  212             if (cRatio >= MAX_COMPRESSION_RATIO) {
 
  213                 Archive rootArchive = depthMap.get(depthMap.get(archiveFile.getId()).getRootArchiveId());
 
  214                 String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  215                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails",
 
  216                         cRatio, FileUtil.escapeFileName(getArchiveFilePath(rootArchive.getArchiveFile())));
 
  218                 flagRootArchiveAsZipBomb(rootArchive, archiveFile, details, escapedFilePath);
 
  224         } 
catch (SevenZipException ex) {
 
  225             logger.log(Level.WARNING, 
"Error getting archive item size and cannot detect if zipbomb. ", ex); 
 
  241     private void flagRootArchiveAsZipBomb(Archive rootArchive, AbstractFile archiveFile, String details, String escapedFilePath) {
 
  242         rootArchive.flagAsZipBomb();
 
  243         logger.log(Level.INFO, details); 
 
  244         String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  245                 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), escapedFilePath);
 
  247             Collection<BlackboardAttribute> attributes = 
new ArrayList<>();
 
  248             attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(),
 
  249                     "Possible Zip Bomb"));
 
  250             attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION,
 
  251                     EmbeddedFileExtractorModuleFactory.getModuleName(),
 
  252                     Bundle.SevenZipExtractor_zipBombArtifactCreation_text(archiveFile.getName())));
 
  253             attributes.add(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
 
  254                     EmbeddedFileExtractorModuleFactory.getModuleName(),
 
  257             SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
 
  258             org.
sleuthkit.datamodel.Blackboard tskBlackboard = tskCase.getBlackboard();
 
  260             if (!tskBlackboard.artifactExists(archiveFile, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, attributes)) {
 
  261                 BlackboardArtifact artifact = rootArchive.getArchiveFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
 
  262                 artifact.addAttributes(attributes);
 
  266                     blackboard.indexArtifact(artifact);
 
  267                 } 
catch (Blackboard.BlackboardException ex) {
 
  268                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  269                     MessageNotifyUtil.Notify.error(
 
  270                             Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
 
  273                 services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  275                 services.fireModuleDataEvent(
new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
 
  277         } 
catch (TskCoreException ex) {
 
  278             logger.log(Level.SEVERE, 
"Error creating blackboard artifact for Zip Bomb Detection for file: " + escapedFilePath, ex); 
 
  279         } 
catch (NoCurrentCaseException ex) {
 
  280             logger.log(Level.SEVERE, 
"Exception while getting open case.", ex); 
 
  292     private ArchiveFormat get7ZipOptions(AbstractFile archiveFile) {
 
  294         String detectedFormat;
 
  295         detectedFormat = archiveFile.getMIMEType();
 
  297         if (detectedFormat == null) {
 
  298             logger.log(Level.WARNING, 
"Could not detect format for file: {0}", archiveFile); 
 
  301             String extension = archiveFile.getNameExtension();
 
  302             if (
"rar".equals(extension)) 
 
  311         } 
else if (detectedFormat.contains(
"application/x-rar-compressed")) 
 
  332     private long getRootArchiveId(AbstractFile file) 
throws TskCoreException {
 
  333         long id = file.getId();
 
  334         Content parentContent = file.getParent();
 
  335         while (parentContent != null) {
 
  336             id = parentContent.getId();
 
  337             parentContent = parentContent.getParent();
 
  356     private List<AbstractFile> getAlreadyExtractedFiles(AbstractFile archiveFile, String archiveFilePath) 
throws TskCoreException, NoCurrentCaseException {
 
  359         if (archiveFile.hasChildren() && 
new File(moduleDirAbsolute, EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) {
 
  360             return Case.getCurrentCaseThrows().getServices().getFileManager().findFilesByParentPath(getRootArchiveId(archiveFile), archiveFilePath);
 
  362         return new ArrayList<>();
 
  372     private String getArchiveFilePath(AbstractFile archiveFile) {
 
  373         return archiveFile.getParentPath() + archiveFile.getName();
 
  382     private void makeLocalDirectories(String uniqueArchiveFileName) {
 
  383         final String localRootAbsPath = getLocalRootAbsPath(uniqueArchiveFileName);
 
  384         final File localRoot = 
new File(localRootAbsPath);
 
  385         if (!localRoot.exists()) {
 
  402     private String getPathInArchive(ISevenZipInArchive archive, 
int inArchiveItemIndex, AbstractFile archiveFile) 
throws SevenZipException {
 
  403         String pathInArchive = (String) archive.getProperty(
 
  404                 inArchiveItemIndex, PropID.PATH);
 
  406         if (pathInArchive == null || pathInArchive.isEmpty()) {
 
  412             String archName = archiveFile.getName();
 
  413             int dotI = archName.lastIndexOf(
".");
 
  414             String useName = null;
 
  416                 String base = archName.substring(0, dotI);
 
  417                 String ext = archName.substring(dotI);
 
  418                 int colonIndex = ext.lastIndexOf(
":");
 
  419                 if (colonIndex != -1) {
 
  422                     ext = ext.substring(0, colonIndex);
 
  429                         useName = base + 
".tar"; 
 
  436             if (useName == null) {
 
  437                 pathInArchive = 
"/" + archName + 
"/" + Integer.toString(inArchiveItemIndex);
 
  439                 pathInArchive = 
"/" + useName;
 
  441             String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  442                     "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg",
 
  443                     getArchiveFilePath(archiveFile), pathInArchive);
 
  444             logger.log(Level.WARNING, msg);
 
  446         return pathInArchive;
 
  453     private String getKeyAbstractFile(AbstractFile fileInDatabase) {
 
  454         return fileInDatabase == null ? null : fileInDatabase.getParentPath() + fileInDatabase.getName();
 
  461     private String getKeyFromUnpackedNode(UnpackedTree.UnpackedNode node, String archiveFilePath) {
 
  462         return node == null ? null : archiveFilePath + 
"/" + node.getFileName();
 
  474     void unpack(AbstractFile archiveFile, ConcurrentHashMap<Long, Archive> depthMap) {
 
  475         unpack(archiveFile, depthMap, null);
 
  489     @Messages({
"SevenZipExtractor.indexError.message=Failed to index encryption detected artifact for keyword search.",
 
  490         "# {0} -  rootArchive",
 
  491         "SevenZipExtractor.zipBombArtifactCreation.text=Zip Bomb Detected {0}"})
 
  492     boolean unpack(AbstractFile archiveFile, ConcurrentHashMap<Long, Archive> depthMap, String password) {
 
  493         boolean unpackSuccessful = 
true; 
 
  494         boolean hasEncrypted = 
false;
 
  495         boolean fullEncryption = 
true;
 
  496         boolean progressStarted = 
false;
 
  497         final String archiveFilePath = getArchiveFilePath(archiveFile);
 
  498         final String escapedArchiveFilePath = FileUtil.escapeFileName(archiveFilePath);
 
  499         HashMap<String, ZipFileStatusWrapper> statusMap = 
new HashMap<>();
 
  500         List<AbstractFile> unpackedFiles = Collections.<AbstractFile>emptyList();
 
  501         ISevenZipInArchive inArchive = null;
 
  502         currentArchiveName = archiveFile.getName();
 
  504         SevenZipContentReadStream stream = null;
 
  505         progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName());
 
  509             blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
 
  510         } 
catch (NoCurrentCaseException ex) {
 
  511             logger.log(Level.INFO, 
"Exception while getting open case.", ex); 
 
  512             unpackSuccessful = 
false;
 
  513             return unpackSuccessful;
 
  517             List<AbstractFile> existingFiles = getAlreadyExtractedFiles(archiveFile, archiveFilePath);
 
  518             for (AbstractFile file : existingFiles) {
 
  519                 statusMap.put(getKeyAbstractFile(file), 
new ZipFileStatusWrapper(file, ZipFileStatus.EXISTS));
 
  521         } 
catch (TskCoreException e) {
 
  522             logger.log(Level.INFO, 
"Error checking if file already has been processed, skipping: {0}", escapedArchiveFilePath); 
 
  523             unpackSuccessful = 
false;
 
  524             return unpackSuccessful;
 
  525         } 
catch (NoCurrentCaseException ex) {
 
  526             logger.log(Level.INFO, 
"No open case was found while trying to unpack the archive file {0}", escapedArchiveFilePath); 
 
  527             unpackSuccessful = 
false;
 
  528             return unpackSuccessful;
 
  530         parentAr = depthMap.get(archiveFile.getId());
 
  531         if (parentAr == null) {
 
  532             parentAr = 
new Archive(0, archiveFile.getId(), archiveFile);
 
  533             depthMap.put(archiveFile.getId(), parentAr);
 
  535             Archive rootArchive = depthMap.get(parentAr.getRootArchiveId());
 
  536             if (rootArchive.isFlaggedAsZipBomb()) {
 
  538                 unpackSuccessful = 
false;
 
  539                 return unpackSuccessful;
 
  540             } 
else if (parentAr.getDepth() == MAX_DEPTH) {
 
  541                 String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  542                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb",
 
  543                         parentAr.getDepth(), FileUtil.escapeFileName(getArchiveFilePath(rootArchive.getArchiveFile())));
 
  544                 flagRootArchiveAsZipBomb(rootArchive, archiveFile, details, escapedArchiveFilePath);
 
  545                 unpackSuccessful = 
false;
 
  546                 return unpackSuccessful;
 
  550             stream = 
new SevenZipContentReadStream(
new ReadContentInputStream(archiveFile));
 
  554             ArchiveFormat options = get7ZipOptions(archiveFile);
 
  555             if (password == null) {
 
  556                 inArchive = SevenZip.openInArchive(options, stream);
 
  558                 inArchive = SevenZip.openInArchive(options, stream, password);
 
  560             numItems = inArchive.getNumberOfItems();
 
  561             progress.start(numItems);
 
  562             progressStarted = 
true;
 
  565             final String uniqueArchiveFileName = FileUtil.escapeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile));
 
  567                 makeLocalDirectories(uniqueArchiveFileName);
 
  568             } 
catch (SecurityException e) {
 
  569                 logger.log(Level.SEVERE, 
"Error setting up output path for archive root: {0}", getLocalRootAbsPath(uniqueArchiveFileName)); 
 
  571                 unpackSuccessful = 
false;
 
  572                 return unpackSuccessful;
 
  576             SevenZipExtractor.UnpackedTree unpackedTree = 
new SevenZipExtractor.UnpackedTree(moduleDirRelative + 
"/" + uniqueArchiveFileName, archiveFile);
 
  580                 freeDiskSpace = services.getFreeDiskSpace();
 
  581             } 
catch (NullPointerException ex) {
 
  584                 freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN;
 
  587             Map<Integer, InArchiveItemDetails> archiveDetailsMap = 
new HashMap<>();
 
  588             for (
int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) {
 
  589                 progress.progress(String.format(
"%s: Analyzing archive metadata and creating local files (%d of %d)", currentArchiveName, inArchiveItemIndex + 1, numItems), 0);
 
  590                 if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) {
 
  591                     unpackSuccessful = 
false;
 
  592                     return unpackSuccessful;
 
  595                 String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile);
 
  596                 UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive);
 
  598                 final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED);
 
  600                 if (isEncrypted && password == null) {
 
  601                     logger.log(Level.WARNING, 
"Skipping encrypted file in archive: {0}", pathInArchive); 
 
  603                     unpackSuccessful = 
false;
 
  606                     fullEncryption = 
false;
 
  613                 Long archiveItemSize = (Long) inArchive.getProperty(
 
  614                         inArchiveItemIndex, PropID.SIZE);
 
  615                 if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && archiveItemSize != null && archiveItemSize > 0) { 
 
  616                     String archiveItemPath = (String) inArchive.getProperty(
 
  617                             inArchiveItemIndex, PropID.PATH);
 
  618                     long newDiskSpace = freeDiskSpace - archiveItemSize;
 
  619                     if (newDiskSpace < MIN_FREE_DISK_SPACE) {
 
  620                         String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  621                                 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg",
 
  622                                 escapedArchiveFilePath, archiveItemPath);
 
  623                         String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  624                                 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details");
 
  625                         services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  626                         logger.log(Level.INFO, 
"Skipping archive item due to insufficient disk space: {0}, {1}", 
new String[]{escapedArchiveFilePath, archiveItemPath}); 
 
  627                         logger.log(Level.INFO, 
"Available disk space: {0}", 
new Object[]{freeDiskSpace}); 
 
  628                         unpackSuccessful = 
false;
 
  632                         freeDiskSpace = newDiskSpace;
 
  635                 final String uniqueExtractedName = FileUtil.escapeFileName(uniqueArchiveFileName + File.separator + (inArchiveItemIndex / 1000) + File.separator + inArchiveItemIndex + 
"_" + 
new File(pathInArchive).getName());
 
  636                 final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName;
 
  637                 final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName;
 
  640                 File localFile = 
new java.io.File(localAbsPath);
 
  642                 if (!localFile.exists()) {
 
  644                         if ((Boolean) inArchive.getProperty(
 
  645                                 inArchiveItemIndex, PropID.IS_FOLDER)) {
 
  648                             localFile.getParentFile().mkdirs();
 
  650                                 localFile.createNewFile();
 
  651                             } 
catch (IOException e) {
 
  652                                 logger.log(Level.SEVERE, 
"Error creating extracted file: " 
  653                                         + localFile.getAbsolutePath(), e);
 
  656                     } 
catch (SecurityException e) {
 
  657                         logger.log(Level.SEVERE, 
"Error setting up output path for unpacked file: {0}", 
 
  664                 if (localFile.exists() == 
false) {
 
  672                 archiveDetailsMap.put(inArchiveItemIndex, 
new InArchiveItemDetails(
 
  673                         unpackedNode, localAbsPath, localRelPath));
 
  676             int[] extractionIndices = getExtractableFilesFromDetailsMap(archiveDetailsMap);
 
  678             StandardIArchiveExtractCallback archiveCallBack
 
  679                     = 
new StandardIArchiveExtractCallback(
 
  680                             inArchive, archiveFile, progress,
 
  681                             archiveDetailsMap, password, freeDiskSpace);
 
  686             inArchive.extract(extractionIndices, 
false, archiveCallBack);
 
  688             unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful();
 
  690             archiveDetailsMap = null;
 
  695                 unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath);
 
  696                 unpackedFiles = unpackedTree.getAllFileObjects();
 
  698                 for (
int i = 0; i < unpackedFiles.size(); i++) {
 
  699                     progress.progress(String.format(
"%s: Searching for nested archives (%d of %d)", currentArchiveName, i + 1, unpackedFiles.size()));
 
  700                     AbstractFile unpackedFile = unpackedFiles.get(i);
 
  701                     if (unpackedFile == null) {
 
  704                     if (isSevenZipExtractionSupported(unpackedFile)) {
 
  705                         Archive child = 
new Archive(parentAr.getDepth() + 1, parentAr.getRootArchiveId(), archiveFile);
 
  706                         parentAr.addChild(child);
 
  707                         depthMap.put(unpackedFile.getId(), child);
 
  709                     unpackedFile.close();
 
  712             } 
catch (TskCoreException | NoCurrentCaseException e) {
 
  713                 logger.log(Level.SEVERE, 
"Error populating complete derived file hierarchy from the unpacked dir structure", e); 
 
  717         } 
catch (SevenZipException ex) {
 
  718             logger.log(Level.WARNING, 
"Error unpacking file: " + archiveFile, ex); 
 
  722             if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
 
  723                 String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  724                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg",
 
  726                 String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  727                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details",
 
  728                         escapedArchiveFilePath, ex.getMessage());
 
  729                 services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  732             if (inArchive != null) {
 
  735                 } 
catch (SevenZipException e) {
 
  736                     logger.log(Level.SEVERE, 
"Error closing archive: " + archiveFile, e); 
 
  740             if (stream != null) {
 
  743                 } 
catch (IOException ex) {
 
  744                     logger.log(Level.SEVERE, 
"Error closing stream after unpacking archive: " + archiveFile, ex); 
 
  749             if (progressStarted) {
 
  756             String encryptionType = fullEncryption ? ENCRYPTION_FULL : ENCRYPTION_FILE_LEVEL;
 
  758                 BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
 
  759                 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EmbeddedFileExtractorModuleFactory.getModuleName(), encryptionType));
 
  763                     blackboard.indexArtifact(artifact);
 
  764                 } 
catch (Blackboard.BlackboardException ex) {
 
  765                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  766                     MessageNotifyUtil.Notify.error(
 
  767                             Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
 
  770                 services.fireModuleDataEvent(
new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
 
  771             } 
catch (TskCoreException ex) {
 
  772                 logger.log(Level.SEVERE, 
"Error creating blackboard artifact for encryption detected for file: " + escapedArchiveFilePath, ex); 
 
  775             String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  776                     "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg");
 
  777             String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  778                     "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details",
 
  779                     currentArchiveName, EmbeddedFileExtractorModuleFactory.getModuleName());
 
  780             services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  784         if (!unpackedFiles.isEmpty()) {
 
  786             services.fireModuleContentEvent(
new ModuleContentEvent(archiveFile));
 
  787             if (context != null) {
 
  788                 context.addFilesToJob(unpackedFiles);
 
  791         return unpackSuccessful;
 
  798     private int[] getExtractableFilesFromDetailsMap(
 
  799             Map<Integer, InArchiveItemDetails> archiveDetailsMap) {
 
  801         Integer[] wrappedExtractionIndices = archiveDetailsMap.keySet()
 
  802                 .toArray(
new Integer[archiveDetailsMap.size()]);
 
  804         return Arrays.stream(wrappedExtractionIndices)
 
  805                 .mapToInt(Integer::intValue)
 
  816     private final static class UnpackStream implements ISequentialOutStream {
 
  823             this.output = 
new EncodedFileOutputStream(
new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
 
  825             this.bytesWritten = 0;
 
  830             this.output = 
new EncodedFileOutputStream(
new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
 
  832             this.bytesWritten = 0;
 
  840         public int write(byte[] bytes) 
throws SevenZipException {
 
  843                 this.bytesWritten += bytes.length;
 
  844             } 
catch (IOException ex) {
 
  845                 throw new SevenZipException(
 
  846                         NbBundle.getMessage(SevenZipExtractor.class,
 
  847                                 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
 
  853         public void close() throws IOException {
 
  854             try (EncodedFileOutputStream out = output) {
 
  866         private final SevenZipExtractor.UnpackedTree.UnpackedNode 
unpackedNode;
 
  871                 SevenZipExtractor.UnpackedTree.UnpackedNode 
unpackedNode,
 
  872                 String localAbsPath, String localRelPath) {
 
  896             implements IArchiveExtractCallback, ICryptoGetTextPassword {
 
  913         private boolean unpackSuccessful = 
true;
 
  916                 AbstractFile archiveFile, ProgressHandle progressHandle,
 
  917                 Map<Integer, InArchiveItemDetails> archiveDetailsMap,
 
  918                 String password, 
long freeDiskSpace) {
 
  942         public ISequentialOutStream 
getStream(
int inArchiveItemIndex,
 
  943                 ExtractAskMode mode) 
throws SevenZipException {
 
  947             isFolder = (Boolean) inArchive
 
  948                     .getProperty(inArchiveItemIndex, PropID.IS_FOLDER);
 
  949             if (isFolder || mode != ExtractAskMode.EXTRACT) {
 
  953             final String localAbsPath = archiveDetailsMap.get(
 
  954                     inArchiveItemIndex).getLocalAbsPath();
 
  962                 if (unpackStream != null) {
 
  967             } 
catch (IOException ex) {
 
  968                 logger.log(Level.WARNING, String.format(
"Error opening or setting new stream "  
  969                         + 
"for archive file at %s", localAbsPath), ex.getMessage()); 
 
  986             final Date createTime = (Date) inArchive.getProperty(
 
  987                     inArchiveItemIndex, PropID.CREATION_TIME);
 
  988             final Date accessTime = (Date) inArchive.getProperty(
 
  989                     inArchiveItemIndex, PropID.LAST_ACCESS_TIME);
 
  990             final Date writeTime = (Date) inArchive.getProperty(
 
  991                     inArchiveItemIndex, PropID.LAST_WRITE_TIME);
 
  993             createTimeInSeconds = createTime == null ? 0L
 
  994                     : createTime.getTime() / 1000;
 
  995             modTimeInSeconds = writeTime == null ? 0L
 
  996                     : writeTime.getTime() / 1000;
 
  997             accessTimeInSeconds = accessTime == null ? 0L
 
  998                     : accessTime.getTime() / 1000;
 
 1000             progressHandle.progress(archiveFile.getName() + 
": " 
 1001                     + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH),
 
 1016             final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode
 
 1017                     = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode();
 
 1018             final String localRelPath = archiveDetailsMap.get(
 
 1019                     inArchiveItemIndex).getLocalRelPath();
 
 1021                 unpackedNode.addDerivedInfo(0,
 
 1022                         !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
 
 1028             final String localAbsPath = archiveDetailsMap.get(
 
 1029                     inArchiveItemIndex).getLocalAbsPath();
 
 1030             if (result != ExtractOperationResult.OK) {
 
 1031                 logger.log(Level.WARNING, 
"Extraction of : {0} encountered error {1}", 
 
 1032                         new Object[]{localAbsPath, result});
 
 1033                 unpackSuccessful = 
false;
 
 1037             unpackedNode.addDerivedInfo(unpackStream.
getSize(),
 
 1038                     !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
 
 1042                 unpackStream.
close();
 
 1043             } 
catch (IOException e) {
 
 1044                 logger.log(Level.WARNING, 
"Error closing unpack stream for file: {0}", localAbsPath); 
 
 1049         public void setTotal(
long value) 
throws SevenZipException {
 
 1094         UnpackedTree(String localPathRoot, AbstractFile archiveFile) {
 
 1096             this.rootNode.setFile(archiveFile);
 
 1097             this.rootNode.setFileName(archiveFile.getName());
 
 1098             this.rootNode.setLocalRelPath(localPathRoot);
 
 1110         UnpackedNode addNode(String filePath) {
 
 1111             String[] toks = filePath.split(
"[\\/\\\\]");
 
 1112             List<String> tokens = 
new ArrayList<>();
 
 1113             for (
int i = 0; i < toks.length; ++i) {
 
 1114                 if (!toks[i].isEmpty()) {
 
 1115                     tokens.add(toks[i]);
 
 1118             return addNode(rootNode, tokens);
 
 1131             if (tokenPath.isEmpty()) {
 
 1136             String childName = tokenPath.remove(0);
 
 1139             if (child == null) {
 
 1141                 parent.addChild(child);
 
 1145             return addNode(child, tokenPath);
 
 1154         List<AbstractFile> getRootFileObjects() {
 
 1155             List<AbstractFile> ret = 
new ArrayList<>();
 
 1156             rootNode.getChildren().forEach((child) -> {
 
 1157                 ret.add(child.getFile());
 
 1168         List<AbstractFile> getAllFileObjects() {
 
 1169             List<AbstractFile> ret = 
new ArrayList<>();
 
 1170             rootNode.getChildren().forEach((child) -> {
 
 1177             list.add(parent.getFile());
 
 1178             parent.getChildren().forEach((child) -> {
 
 1187         void updateOrAddFileToCaseRec(HashMap<String, ZipFileStatusWrapper> statusMap, String archiveFilePath) 
throws TskCoreException, 
NoCurrentCaseException {
 
 1189             for (UnpackedNode child : rootNode.getChildren()) {
 
 1190                 updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath);
 
 1210             progress.progress(String.format(
"%s: Adding/updating files in case database (%d of %d)", currentArchiveName, ++nodesProcessed, numItems));
 
 1212                 String nameInDatabase = getKeyFromUnpackedNode(node, archiveFilePath);
 
 1213                 ZipFileStatusWrapper existingFile = nameInDatabase == null ? null : statusMap.get(nameInDatabase);
 
 1214                 if (existingFile == null) {
 
 1215                     df = fileManager.
addDerivedFile(node.getFileName(), node.getLocalRelPath(), node.getSize(),
 
 1216                             node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
 
 1218                             "", 
"", TskData.EncodingType.XOR1);
 
 1221                     String key = getKeyAbstractFile(existingFile.
getFile());
 
 1224                         statusMap.put(key, existingFile);
 
 1228                         String mimeType = existingFile.
getFile().getMIMEType().equalsIgnoreCase(
"application/octet-stream") ? null : existingFile.
getFile().getMIMEType();
 
 1230                                 node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
 
 1232                                 "", 
"", TskData.EncodingType.XOR1);
 
 1236                         df = (DerivedFile) existingFile.
getFile();
 
 1240             } 
catch (TskCoreException ex) {
 
 1241                 logger.log(Level.SEVERE, 
"Error adding a derived file to db:" + node.getFileName(), ex); 
 
 1242                 throw new TskCoreException(
 
 1243                         NbBundle.getMessage(SevenZipExtractor.class, 
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackedTree.exception.msg",
 
 1244                                 node.getFileName()), ex);
 
 1248                 updateOrAddFileToCaseRec(child, fileManager, statusMap, getKeyFromUnpackedNode(node, archiveFilePath));
 
 1259             private final List<UnpackedNode> 
children = 
new ArrayList<>();
 
 1260             private String localRelPath = 
"";
 
 1262             private long ctime, crtime, atime, mtime;
 
 1274                 this.localRelPath = parent.getLocalRelPath() + File.separator + 
fileName;
 
 1293             void setFileName(String fileName) {
 
 1302             void addChild(UnpackedNode child) {
 
 1303                 children.add(child);
 
 1312             List<UnpackedNode> getChildren() {
 
 1321             UnpackedNode getParent() {
 
 1325             void addDerivedInfo(
long size,
 
 1327                     long ctime, 
long crtime, 
long atime, 
long mtime, String relLocalPath) {
 
 1331                 this.crtime = crtime;
 
 1334                 this.localRelPath = relLocalPath;
 
 1337             void setFile(AbstractFile file) {
 
 1348             UnpackedNode getChild(String childFileName) {
 
 1349                 UnpackedNode ret = null;
 
 1350                 for (UnpackedNode child : children) {
 
 1351                     if (child.getFileName().equals(childFileName)) {
 
 1359             String getFileName() {
 
 1363             AbstractFile getFile() {
 
 1367             String getLocalRelPath() {
 
 1377             void setLocalRelPath(String localRelativePath) {
 
 1378                 localRelPath = localRelativePath;
 
 1385             boolean isIsFile() {
 
 1395     static class Archive {
 
 1398         private final int depth;
 
 1399         private final List<Archive> children;
 
 1400         private final long rootArchiveId;
 
 1401         private boolean flaggedAsZipBomb = 
false;
 
 1402         private final AbstractFile archiveFile;
 
 1416         Archive(
int depth, 
long rootArchiveId, AbstractFile archiveFile) {
 
 1417             this.children = 
new ArrayList<>();
 
 1419             this.rootArchiveId = rootArchiveId;
 
 1420             this.archiveFile = archiveFile;
 
 1429         void addChild(Archive child) {
 
 1430             children.add(child);
 
 1437         synchronized void flagAsZipBomb() {
 
 1438             flaggedAsZipBomb = 
true;
 
 1446         synchronized boolean isFlaggedAsZipBomb() {
 
 1447             return flaggedAsZipBomb;
 
 1455         AbstractFile getArchiveFile() {
 
 1464         long getRootArchiveId() {
 
 1465             return rootArchiveId;
 
 1473         long getObjectId() {
 
 1474             return archiveFile.getId();
 
 1506             abstractFile = file;
 
FileManager getFileManager()
synchronized DerivedFile addDerivedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, Content parentObj, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)
static Case getCurrentCaseThrows()
synchronized DerivedFile updateDerivedFile(DerivedFile derivedFile, String localPath, long size, long ctime, long crtime, long atime, long mtime, boolean isFile, String mimeType, String rederiveDetails, String toolName, String toolVersion, String otherDetails, TskData.EncodingType encodingType)