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 = archiveFile.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);
 
  711             } 
catch (TskCoreException | NoCurrentCaseException e) {
 
  712                 logger.log(Level.SEVERE, 
"Error populating complete derived file hierarchy from the unpacked dir structure", e); 
 
  716         } 
catch (SevenZipException ex) {
 
  717             logger.log(Level.WARNING, 
"Error unpacking file: " + archiveFile, ex); 
 
  721             if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
 
  722                 String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  723                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg",
 
  725                 String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  726                         "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details",
 
  727                         escapedArchiveFilePath, ex.getMessage());
 
  728                 services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  731             if (inArchive != null) {
 
  734                 } 
catch (SevenZipException e) {
 
  735                     logger.log(Level.SEVERE, 
"Error closing archive: " + archiveFile, e); 
 
  739             if (stream != null) {
 
  742                 } 
catch (IOException ex) {
 
  743                     logger.log(Level.SEVERE, 
"Error closing stream after unpacking archive: " + archiveFile, ex); 
 
  748             if (progressStarted) {
 
  755             String encryptionType = fullEncryption ? ENCRYPTION_FULL : ENCRYPTION_FILE_LEVEL;
 
  757                 BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
 
  758                 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EmbeddedFileExtractorModuleFactory.getModuleName(), encryptionType));
 
  762                     blackboard.indexArtifact(artifact);
 
  763                 } 
catch (Blackboard.BlackboardException ex) {
 
  764                     logger.log(Level.SEVERE, 
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex); 
 
  765                     MessageNotifyUtil.Notify.error(
 
  766                             Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
 
  769                 services.fireModuleDataEvent(
new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
 
  770             } 
catch (TskCoreException ex) {
 
  771                 logger.log(Level.SEVERE, 
"Error creating blackboard artifact for encryption detected for file: " + escapedArchiveFilePath, ex); 
 
  774             String msg = NbBundle.getMessage(SevenZipExtractor.class,
 
  775                     "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg");
 
  776             String details = NbBundle.getMessage(SevenZipExtractor.class,
 
  777                     "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details",
 
  778                     currentArchiveName, EmbeddedFileExtractorModuleFactory.getModuleName());
 
  779             services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
 
  783         if (!unpackedFiles.isEmpty()) {
 
  785             services.fireModuleContentEvent(
new ModuleContentEvent(archiveFile));
 
  786             if (context != null) {
 
  787                 context.addFilesToJob(unpackedFiles);
 
  790         return unpackSuccessful;
 
  797     private int[] getExtractableFilesFromDetailsMap(
 
  798             Map<Integer, InArchiveItemDetails> archiveDetailsMap) {
 
  800         Integer[] wrappedExtractionIndices = archiveDetailsMap.keySet()
 
  801                 .toArray(
new Integer[archiveDetailsMap.size()]);
 
  803         return Arrays.stream(wrappedExtractionIndices)
 
  804                 .mapToInt(Integer::intValue)
 
  815     private final static class UnpackStream implements ISequentialOutStream {
 
  822             this.output = 
new EncodedFileOutputStream(
new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
 
  824             this.bytesWritten = 0;
 
  829             this.output = 
new EncodedFileOutputStream(
new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
 
  831             this.bytesWritten = 0;
 
  839         public int write(byte[] bytes) 
throws SevenZipException {
 
  842                 this.bytesWritten += bytes.length;
 
  843             } 
catch (IOException ex) {
 
  844                 throw new SevenZipException(
 
  845                         NbBundle.getMessage(SevenZipExtractor.class,
 
  846                                 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
 
  852         public void close() throws IOException {
 
  853             try (EncodedFileOutputStream out = output) {
 
  865         private final SevenZipExtractor.UnpackedTree.UnpackedNode 
unpackedNode;
 
  870                 SevenZipExtractor.UnpackedTree.UnpackedNode 
unpackedNode,
 
  871                 String localAbsPath, String localRelPath) {
 
  895             implements IArchiveExtractCallback, ICryptoGetTextPassword {
 
  912         private boolean unpackSuccessful = 
true;
 
  915                 AbstractFile archiveFile, ProgressHandle progressHandle,
 
  916                 Map<Integer, InArchiveItemDetails> archiveDetailsMap,
 
  917                 String password, 
long freeDiskSpace) {
 
  941         public ISequentialOutStream 
getStream(
int inArchiveItemIndex,
 
  942                 ExtractAskMode mode) 
throws SevenZipException {
 
  946             isFolder = (Boolean) inArchive
 
  947                     .getProperty(inArchiveItemIndex, PropID.IS_FOLDER);
 
  948             if (isFolder || mode != ExtractAskMode.EXTRACT) {
 
  952             final String localAbsPath = archiveDetailsMap.get(
 
  953                     inArchiveItemIndex).getLocalAbsPath();
 
  961                 if (unpackStream != null) {
 
  966             } 
catch (IOException ex) {
 
  967                 logger.log(Level.WARNING, String.format(
"Error opening or setting new stream "  
  968                         + 
"for archive file at %s", localAbsPath), ex.getMessage()); 
 
  985             final Date createTime = (Date) inArchive.getProperty(
 
  986                     inArchiveItemIndex, PropID.CREATION_TIME);
 
  987             final Date accessTime = (Date) inArchive.getProperty(
 
  988                     inArchiveItemIndex, PropID.LAST_ACCESS_TIME);
 
  989             final Date writeTime = (Date) inArchive.getProperty(
 
  990                     inArchiveItemIndex, PropID.LAST_WRITE_TIME);
 
  992             createTimeInSeconds = createTime == null ? 0L
 
  993                     : createTime.getTime() / 1000;
 
  994             modTimeInSeconds = writeTime == null ? 0L
 
  995                     : writeTime.getTime() / 1000;
 
  996             accessTimeInSeconds = accessTime == null ? 0L
 
  997                     : accessTime.getTime() / 1000;
 
  999             progressHandle.progress(archiveFile.getName() + 
": " 
 1000                     + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH),
 
 1015             final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode
 
 1016                     = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode();
 
 1017             final String localRelPath = archiveDetailsMap.get(
 
 1018                     inArchiveItemIndex).getLocalRelPath();
 
 1020                 unpackedNode.addDerivedInfo(0,
 
 1021                         !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
 
 1027             final String localAbsPath = archiveDetailsMap.get(
 
 1028                     inArchiveItemIndex).getLocalAbsPath();
 
 1029             if (result != ExtractOperationResult.OK) {
 
 1030                 logger.log(Level.WARNING, 
"Extraction of : {0} encountered error {1}", 
 
 1031                         new Object[]{localAbsPath, result});
 
 1032                 unpackSuccessful = 
false;
 
 1036             unpackedNode.addDerivedInfo(unpackStream.
getSize(),
 
 1037                     !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
 
 1041                 unpackStream.
close();
 
 1042             } 
catch (IOException e) {
 
 1043                 logger.log(Level.WARNING, 
"Error closing unpack stream for file: {0}", localAbsPath); 
 
 1048         public void setTotal(
long value) 
throws SevenZipException {
 
 1093         UnpackedTree(String localPathRoot, AbstractFile archiveFile) {
 
 1095             this.rootNode.setFile(archiveFile);
 
 1096             this.rootNode.setFileName(archiveFile.getName());
 
 1097             this.rootNode.setLocalRelPath(localPathRoot);
 
 1109         UnpackedNode addNode(String filePath) {
 
 1110             String[] toks = filePath.split(
"[\\/\\\\]");
 
 1111             List<String> tokens = 
new ArrayList<>();
 
 1112             for (
int i = 0; i < toks.length; ++i) {
 
 1113                 if (!toks[i].isEmpty()) {
 
 1114                     tokens.add(toks[i]);
 
 1117             return addNode(rootNode, tokens);
 
 1130             if (tokenPath.isEmpty()) {
 
 1135             String childName = tokenPath.remove(0);
 
 1138             if (child == null) {
 
 1140                 parent.addChild(child);
 
 1144             return addNode(child, tokenPath);
 
 1153         List<AbstractFile> getRootFileObjects() {
 
 1154             List<AbstractFile> ret = 
new ArrayList<>();
 
 1155             rootNode.getChildren().forEach((child) -> {
 
 1156                 ret.add(child.getFile());
 
 1167         List<AbstractFile> getAllFileObjects() {
 
 1168             List<AbstractFile> ret = 
new ArrayList<>();
 
 1169             rootNode.getChildren().forEach((child) -> {
 
 1176             list.add(parent.getFile());
 
 1177             parent.getChildren().forEach((child) -> {
 
 1186         void updateOrAddFileToCaseRec(HashMap<String, ZipFileStatusWrapper> statusMap, String archiveFilePath) 
throws TskCoreException, 
NoCurrentCaseException {
 
 1188             for (UnpackedNode child : rootNode.getChildren()) {
 
 1189                 updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath);
 
 1209             progress.progress(String.format(
"%s: Adding/updating files in case database (%d of %d)", currentArchiveName, ++nodesProcessed, numItems));
 
 1211                 String nameInDatabase = getKeyFromUnpackedNode(node, archiveFilePath);
 
 1212                 ZipFileStatusWrapper existingFile = nameInDatabase == null ? null : statusMap.get(nameInDatabase);
 
 1213                 if (existingFile == null) {
 
 1214                     df = fileManager.
addDerivedFile(node.getFileName(), node.getLocalRelPath(), node.getSize(),
 
 1215                             node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
 
 1217                             "", 
"", TskData.EncodingType.XOR1);
 
 1220                     String key = getKeyAbstractFile(existingFile.
getFile());
 
 1223                         statusMap.put(key, existingFile);
 
 1227                         String mimeType = existingFile.
getFile().getMIMEType().equalsIgnoreCase(
"application/octet-stream") ? null : existingFile.
getFile().getMIMEType();
 
 1229                                 node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
 
 1231                                 "", 
"", TskData.EncodingType.XOR1);
 
 1235                         df = (DerivedFile) existingFile.
getFile();
 
 1239             } 
catch (TskCoreException ex) {
 
 1240                 logger.log(Level.SEVERE, 
"Error adding a derived file to db:" + node.getFileName(), ex); 
 
 1241                 throw new TskCoreException(
 
 1242                         NbBundle.getMessage(SevenZipExtractor.class, 
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackedTree.exception.msg",
 
 1243                                 node.getFileName()), ex);
 
 1247                 updateOrAddFileToCaseRec(child, fileManager, statusMap, getKeyFromUnpackedNode(node, archiveFilePath));
 
 1258             private final List<UnpackedNode> 
children = 
new ArrayList<>();
 
 1259             private String localRelPath = 
"";
 
 1261             private long ctime, crtime, atime, mtime;
 
 1273                 this.localRelPath = parent.getLocalRelPath() + File.separator + 
fileName;
 
 1292             void setFileName(String fileName) {
 
 1301             void addChild(UnpackedNode child) {
 
 1302                 children.add(child);
 
 1311             List<UnpackedNode> getChildren() {
 
 1320             UnpackedNode getParent() {
 
 1324             void addDerivedInfo(
long size,
 
 1326                     long ctime, 
long crtime, 
long atime, 
long mtime, String relLocalPath) {
 
 1330                 this.crtime = crtime;
 
 1333                 this.localRelPath = relLocalPath;
 
 1336             void setFile(AbstractFile file) {
 
 1347             UnpackedNode getChild(String childFileName) {
 
 1348                 UnpackedNode ret = null;
 
 1349                 for (UnpackedNode child : children) {
 
 1350                     if (child.getFileName().equals(childFileName)) {
 
 1358             String getFileName() {
 
 1362             AbstractFile getFile() {
 
 1366             String getLocalRelPath() {
 
 1376             void setLocalRelPath(String localRelativePath) {
 
 1377                 localRelPath = localRelativePath;
 
 1384             boolean isIsFile() {
 
 1394     static class Archive {
 
 1397         private final int depth;
 
 1398         private final List<Archive> children;
 
 1399         private final long rootArchiveId;
 
 1400         private boolean flaggedAsZipBomb = 
false;
 
 1401         private final AbstractFile archiveFile;
 
 1415         Archive(
int depth, 
long rootArchiveId, AbstractFile archiveFile) {
 
 1416             this.children = 
new ArrayList<>();
 
 1418             this.rootArchiveId = rootArchiveId;
 
 1419             this.archiveFile = archiveFile;
 
 1428         void addChild(Archive child) {
 
 1429             children.add(child);
 
 1436         synchronized void flagAsZipBomb() {
 
 1437             flaggedAsZipBomb = 
true;
 
 1445         synchronized boolean isFlaggedAsZipBomb() {
 
 1446             return flaggedAsZipBomb;
 
 1454         AbstractFile getArchiveFile() {
 
 1463         long getRootArchiveId() {
 
 1464             return rootArchiveId;
 
 1472         long getObjectId() {
 
 1473             return archiveFile.getId();
 
 1505             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)