19 package org.sleuthkit.autopsy.modules.embeddedfileextractor;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.nio.file.Files;
26 import java.nio.file.Paths;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collections;
30 import java.util.Date;
31 import java.util.HashMap;
32 import java.util.LinkedHashMap;
33 import java.util.List;
35 import java.util.concurrent.ConcurrentHashMap;
36 import java.util.logging.Level;
37 import net.sf.sevenzipjbinding.ArchiveFormat;
38 import static net.sf.sevenzipjbinding.ArchiveFormat.RAR;
39 import net.sf.sevenzipjbinding.ExtractAskMode;
40 import net.sf.sevenzipjbinding.ISequentialOutStream;
41 import net.sf.sevenzipjbinding.ISevenZipInArchive;
42 import net.sf.sevenzipjbinding.SevenZip;
43 import net.sf.sevenzipjbinding.SevenZipException;
44 import net.sf.sevenzipjbinding.SevenZipNativeInitializationException;
45 import net.sf.sevenzipjbinding.ExtractOperationResult;
46 import net.sf.sevenzipjbinding.IArchiveExtractCallback;
47 import net.sf.sevenzipjbinding.ICryptoGetTextPassword;
48 import net.sf.sevenzipjbinding.PropID;
49 import org.netbeans.api.progress.ProgressHandle;
50 import org.openide.util.NbBundle;
51 import org.openide.util.NbBundle.Messages;
76 class SevenZipExtractor {
78 private static final Logger logger = Logger.getLogger(SevenZipExtractor.class.getName());
79 private IngestServices services = IngestServices.getInstance();
80 private final IngestJobContext context;
81 private final FileTypeDetector fileTypeDetector;
83 private static final String ENCRYPTION_FILE_LEVEL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class,
84 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFileLevel");
85 private static final String ENCRYPTION_FULL = NbBundle.getMessage(EmbeddedFileExtractorIngestModule.class,
86 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.encryptionFull");
88 private static final int MAX_DEPTH = 4;
89 private static final int MAX_COMPRESSION_RATIO = 600;
90 private static final long MIN_COMPRESSION_RATIO_SIZE = 500 * 1000000L;
91 private static final long MIN_FREE_DISK_SPACE = 1 * 1000 * 1000000L;
93 private String moduleDirRelative;
94 private String moduleDirAbsolute;
96 private Blackboard blackboard;
98 private String getLocalRootAbsPath(String uniqueArchiveFileName) {
99 return moduleDirAbsolute + File.separator + uniqueArchiveFileName;
114 XRAR(
"application/x-rar-compressed");
119 this.mimeType = mimeType;
124 return this.mimeType;
129 SevenZipExtractor(
IngestJobContext context,
FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute)
throws SevenZipNativeInitializationException {
130 if (!SevenZip.isInitializedSuccessfully() && (SevenZip.getLastInitializationException() == null)) {
131 SevenZip.initSevenZipFromPlatformJAR();
133 this.context = context;
134 this.fileTypeDetector = fileTypeDetector;
135 this.moduleDirRelative = moduleDirRelative;
136 this.moduleDirAbsolute = moduleDirAbsolute;
147 boolean isSevenZipExtractionSupported(AbstractFile file) {
148 String fileMimeType = fileTypeDetector.getMIMEType(file);
149 for (SupportedArchiveExtractionFormats mimeType : SupportedArchiveExtractionFormats.values()) {
150 if (mimeType.toString().equals(fileMimeType)) {
179 private boolean isZipBombArchiveItemCheck(AbstractFile archiveFile, ISevenZipInArchive inArchive,
int inArchiveItemIndex, ConcurrentHashMap<Long, Archive> depthMap, String escapedFilePath) {
181 final Long archiveItemSize = (Long) inArchive.getProperty(
182 inArchiveItemIndex, PropID.SIZE);
185 if (archiveItemSize == null || archiveItemSize < MIN_COMPRESSION_RATIO_SIZE) {
189 final Long archiveItemPackedSize = (Long) inArchive.getProperty(
190 inArchiveItemIndex, PropID.PACKED_SIZE);
192 if (archiveItemPackedSize == null || archiveItemPackedSize <= 0) {
193 logger.log(Level.WARNING,
"Cannot getting compression ratio, cannot detect if zipbomb: {0}, item: {1}",
194 new Object[]{archiveFile.getName(), (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH)});
198 int cRatio = (int) (archiveItemSize / archiveItemPackedSize);
200 if (cRatio >= MAX_COMPRESSION_RATIO) {
201 Archive rootArchive = depthMap.get(depthMap.get(archiveFile.getId()).getRootArchiveId());
202 String details = NbBundle.getMessage(SevenZipExtractor.class,
203 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnDetails",
204 cRatio, FileUtil.escapeFileName(getArchiveFilePath(rootArchive.getArchiveFile())));
206 flagRootArchiveAsZipBomb(rootArchive, archiveFile, details, escapedFilePath);
212 }
catch (SevenZipException ex) {
213 logger.log(Level.WARNING,
"Error getting archive item size and cannot detect if zipbomb. ", ex);
229 private void flagRootArchiveAsZipBomb(Archive rootArchive, AbstractFile archiveFile, String details, String escapedFilePath) {
230 rootArchive.flagAsZipBomb();
231 logger.log(Level.INFO, details);
232 String msg = NbBundle.getMessage(SevenZipExtractor.class,
233 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.isZipBombCheck.warnMsg", archiveFile.getName(), escapedFilePath);
235 BlackboardArtifact artifact = rootArchive.getArchiveFile().newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT);
236 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, EmbeddedFileExtractorModuleFactory.getModuleName(),
237 "Possible Zip Bomb"));
238 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION,
239 EmbeddedFileExtractorModuleFactory.getModuleName(),
240 Bundle.SevenZipExtractor_zipBombArtifactCreation_text(archiveFile.getName())));
241 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT,
242 EmbeddedFileExtractorModuleFactory.getModuleName(),
246 blackboard.indexArtifact(artifact);
247 }
catch (Blackboard.BlackboardException ex) {
248 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
249 MessageNotifyUtil.Notify.error(
250 Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
252 services.fireModuleDataEvent(
new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT));
253 }
catch (TskCoreException ex) {
254 logger.log(Level.SEVERE,
"Error creating blackboard artifact for Zip Bomb Detection for file: " + escapedFilePath, ex);
256 services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
267 private ArchiveFormat get7ZipOptions(AbstractFile archiveFile) {
269 String detectedFormat;
270 detectedFormat = archiveFile.getMIMEType();
272 if (detectedFormat == null) {
273 logger.log(Level.WARNING,
"Could not detect format for file: {0}", archiveFile);
276 String extension = archiveFile.getNameExtension();
277 if (
"rar".equals(extension))
286 }
else if (detectedFormat.contains(
"application/x-rar-compressed"))
307 private long getRootArchiveId(AbstractFile file)
throws TskCoreException {
308 long id = file.getId();
309 Content parentContent = file.getParent();
310 while (parentContent != null) {
311 id = parentContent.getId();
312 parentContent = parentContent.getParent();
331 private List<AbstractFile> getAlreadyExtractedFiles(AbstractFile archiveFile, String archiveFilePath)
throws TskCoreException, NoCurrentCaseException {
334 if (archiveFile.hasChildren() &&
new File(moduleDirAbsolute, EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile)).exists()) {
335 return Case.getCurrentCaseThrows().getServices().getFileManager().findFilesByParentPath(getRootArchiveId(archiveFile), archiveFilePath);
337 return new ArrayList<>();
347 private String getArchiveFilePath(AbstractFile archiveFile) {
349 return archiveFile.getUniquePath();
350 }
catch (TskCoreException ex) {
351 return archiveFile.getParentPath() + archiveFile.getName();
361 private void makeLocalDirectories(String uniqueArchiveFileName) {
362 final String localRootAbsPath = getLocalRootAbsPath(uniqueArchiveFileName);
363 final File localRoot =
new File(localRootAbsPath);
364 if (!localRoot.exists()) {
381 private String getPathInArchive(ISevenZipInArchive archive,
int inArchiveItemIndex, AbstractFile archiveFile)
throws SevenZipException {
382 String pathInArchive = (String) archive.getProperty(
383 inArchiveItemIndex, PropID.PATH);
385 if (pathInArchive == null || pathInArchive.isEmpty()) {
391 String archName = archiveFile.getName();
392 int dotI = archName.lastIndexOf(
".");
393 String useName = null;
395 String base = archName.substring(0, dotI);
396 String ext = archName.substring(dotI);
397 int colonIndex = ext.lastIndexOf(
":");
398 if (colonIndex != -1) {
401 ext = ext.substring(0, colonIndex);
408 useName = base +
".tar";
415 if (useName == null) {
416 pathInArchive =
"/" + archName +
"/" + Integer.toString(inArchiveItemIndex);
418 pathInArchive =
"/" + useName;
420 String msg = NbBundle.getMessage(SevenZipExtractor.class,
421 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.unknownPath.msg",
422 getArchiveFilePath(archiveFile), pathInArchive);
423 logger.log(Level.WARNING, msg);
425 return pathInArchive;
432 private String getKeyAbstractFile(AbstractFile fileInDatabase) {
433 return fileInDatabase == null ? null : fileInDatabase.getParentPath() + fileInDatabase.getName();
440 private String getKeyFromUnpackedNode(UnpackedTree.UnpackedNode node, String archiveFilePath) {
441 return node == null ? null : archiveFilePath +
"/" + node.getFileName();
453 void unpack(AbstractFile archiveFile, ConcurrentHashMap<Long, Archive> depthMap) {
454 unpack(archiveFile, depthMap, null);
468 @Messages({
"SevenZipExtractor.indexError.message=Failed to index encryption detected artifact for keyword search.",
469 "# {0} - rootArchive",
470 "SevenZipExtractor.zipBombArtifactCreation.text=Zip Bomb Detected {0}"})
471 boolean unpack(AbstractFile archiveFile, ConcurrentHashMap<Long, Archive> depthMap, String password) {
472 boolean unpackSuccessful =
true;
473 boolean hasEncrypted =
false;
474 boolean fullEncryption =
true;
475 boolean progressStarted =
false;
476 final String archiveFilePath = getArchiveFilePath(archiveFile);
477 final String escapedArchiveFilePath = FileUtil.escapeFileName(archiveFilePath);
478 HashMap<String, ZipFileStatusWrapper> statusMap =
new HashMap<>();
479 List<AbstractFile> unpackedFiles = Collections.<AbstractFile>emptyList();
480 ISevenZipInArchive inArchive = null;
482 SevenZipContentReadStream stream = null;
483 final ProgressHandle progress = ProgressHandle.createHandle(Bundle.EmbeddedFileExtractorIngestModule_ArchiveExtractor_moduleName());
487 blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard();
488 }
catch (NoCurrentCaseException ex) {
489 logger.log(Level.INFO,
"Exception while getting open case.", ex);
490 unpackSuccessful =
false;
491 return unpackSuccessful;
495 List<AbstractFile> existingFiles = getAlreadyExtractedFiles(archiveFile, archiveFilePath);
496 for (AbstractFile file : existingFiles) {
497 statusMap.put(getKeyAbstractFile(file),
new ZipFileStatusWrapper(file, ZipFileStatus.EXISTS));
499 }
catch (TskCoreException e) {
500 logger.log(Level.INFO,
"Error checking if file already has been processed, skipping: {0}", escapedArchiveFilePath);
501 unpackSuccessful =
false;
502 return unpackSuccessful;
503 }
catch (NoCurrentCaseException ex) {
504 logger.log(Level.INFO,
"No open case was found while trying to unpack the archive file {0}", escapedArchiveFilePath);
505 unpackSuccessful =
false;
506 return unpackSuccessful;
508 parentAr = depthMap.get(archiveFile.getId());
509 if (parentAr == null) {
510 parentAr =
new Archive(0, archiveFile.getId(), archiveFile);
511 depthMap.put(archiveFile.getId(), parentAr);
513 Archive rootArchive = depthMap.get(parentAr.getRootArchiveId());
514 if (rootArchive.isFlaggedAsZipBomb()) {
516 unpackSuccessful =
false;
517 return unpackSuccessful;
518 }
else if (parentAr.getDepth() == MAX_DEPTH) {
519 String details = NbBundle.getMessage(SevenZipExtractor.class,
520 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.warnDetails.zipBomb",
521 parentAr.getDepth(), FileUtil.escapeFileName(getArchiveFilePath(rootArchive.getArchiveFile())));
522 flagRootArchiveAsZipBomb(rootArchive, archiveFile, details, escapedArchiveFilePath);
523 unpackSuccessful =
false;
524 return unpackSuccessful;
528 stream =
new SevenZipContentReadStream(
new ReadContentInputStream(archiveFile));
532 ArchiveFormat options = get7ZipOptions(archiveFile);
533 if (password == null) {
534 inArchive = SevenZip.openInArchive(options, stream);
536 inArchive = SevenZip.openInArchive(options, stream, password);
538 int numItems = inArchive.getNumberOfItems();
539 logger.log(Level.INFO,
"Count of items in archive: {0}: {1}",
new Object[]{escapedArchiveFilePath, numItems});
540 progress.start(numItems);
541 progressStarted =
true;
542 progress.progress(archiveFile.getName() +
": Analyzing archive metadata and creating local files");
545 final String uniqueArchiveFileName = FileUtil.escapeFileName(EmbeddedFileExtractorIngestModule.getUniqueName(archiveFile));
547 makeLocalDirectories(uniqueArchiveFileName);
548 }
catch (SecurityException e) {
549 logger.log(Level.SEVERE,
"Error setting up output path for archive root: {0}", getLocalRootAbsPath(uniqueArchiveFileName));
551 unpackSuccessful =
false;
552 return unpackSuccessful;
556 SevenZipExtractor.UnpackedTree unpackedTree =
new SevenZipExtractor.UnpackedTree(moduleDirRelative +
"/" + uniqueArchiveFileName, archiveFile);
560 freeDiskSpace = services.getFreeDiskSpace();
561 }
catch (NullPointerException ex) {
564 freeDiskSpace = IngestMonitor.DISK_FREE_SPACE_UNKNOWN;
567 Map<Integer, InArchiveItemDetails> archiveDetailsMap =
new LinkedHashMap<>();
568 for (
int inArchiveItemIndex = 0; inArchiveItemIndex < numItems; inArchiveItemIndex++) {
569 if (isZipBombArchiveItemCheck(archiveFile, inArchive, inArchiveItemIndex, depthMap, escapedArchiveFilePath)) {
570 unpackSuccessful =
false;
571 return unpackSuccessful;
574 String pathInArchive = getPathInArchive(inArchive, inArchiveItemIndex, archiveFile);
575 SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode = unpackedTree.addNode(pathInArchive);
577 final boolean isEncrypted = (Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.ENCRYPTED);
579 if (isEncrypted && password == null) {
580 logger.log(Level.WARNING,
"Skipping encrypted file in archive: {0}", pathInArchive);
582 unpackSuccessful =
false;
585 fullEncryption =
false;
592 Long archiveItemSize = (Long) inArchive.getProperty(
593 inArchiveItemIndex, PropID.SIZE);
594 if (freeDiskSpace != IngestMonitor.DISK_FREE_SPACE_UNKNOWN && archiveItemSize != null && archiveItemSize > 0) {
595 String archiveItemPath = (String) inArchive.getProperty(
596 inArchiveItemIndex, PropID.PATH);
597 long newDiskSpace = freeDiskSpace - archiveItemSize;
598 if (newDiskSpace < MIN_FREE_DISK_SPACE) {
599 String msg = NbBundle.getMessage(SevenZipExtractor.class,
600 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.msg",
601 escapedArchiveFilePath, archiveItemPath);
602 String details = NbBundle.getMessage(SevenZipExtractor.class,
603 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.notEnoughDiskSpace.details");
604 services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
605 logger.log(Level.INFO,
"Skipping archive item due to insufficient disk space: {0}, {1}",
new String[]{escapedArchiveFilePath, archiveItemPath});
606 logger.log(Level.INFO,
"Available disk space: {0}",
new Object[]{freeDiskSpace});
607 unpackSuccessful =
false;
611 freeDiskSpace = newDiskSpace;
614 final String uniqueExtractedName = FileUtil.escapeFileName(uniqueArchiveFileName + File.separator + (inArchiveItemIndex / 1000) + File.separator + inArchiveItemIndex +
"_" +
new File(pathInArchive).getName());
615 final String localAbsPath = moduleDirAbsolute + File.separator + uniqueExtractedName;
616 final String localRelPath = moduleDirRelative + File.separator + uniqueExtractedName;
619 File localFile =
new java.io.File(localAbsPath);
621 if (!localFile.exists()) {
623 if ((Boolean) inArchive.getProperty(
624 inArchiveItemIndex, PropID.IS_FOLDER)) {
627 localFile.getParentFile().mkdirs();
629 localFile.createNewFile();
630 }
catch (IOException e) {
631 logger.log(Level.SEVERE,
"Error creating extracted file: "
632 + localFile.getAbsolutePath(), e);
635 }
catch (SecurityException e) {
636 logger.log(Level.SEVERE,
"Error setting up output path for unpacked file: {0}",
643 if (localFile.exists() ==
false) {
651 archiveDetailsMap.put(inArchiveItemIndex,
new InArchiveItemDetails(
652 unpackedNode, localAbsPath, localRelPath));
655 int[] extractionIndices = getExtractableFilesFromDetailsMap(archiveDetailsMap);
657 StandardIArchiveExtractCallback archiveCallBack
658 =
new StandardIArchiveExtractCallback(
659 inArchive, archiveFile, progress,
660 archiveDetailsMap, password, freeDiskSpace);
665 inArchive.extract(extractionIndices,
false, archiveCallBack);
667 unpackSuccessful = unpackSuccessful & archiveCallBack.wasSuccessful();
672 unpackedTree.updateOrAddFileToCaseRec(statusMap, archiveFilePath);
673 unpackedFiles = unpackedTree.getAllFileObjects();
675 for (AbstractFile unpackedFile : unpackedFiles) {
676 if (unpackedFile == null) {
679 if (isSevenZipExtractionSupported(unpackedFile)) {
680 Archive child =
new Archive(parentAr.getDepth() + 1, parentAr.getRootArchiveId(), archiveFile);
681 parentAr.addChild(child);
682 depthMap.put(unpackedFile.getId(), child);
686 }
catch (TskCoreException | NoCurrentCaseException e) {
687 logger.log(Level.SEVERE,
"Error populating complete derived file hierarchy from the unpacked dir structure", e);
691 }
catch (SevenZipException ex) {
692 logger.log(Level.WARNING,
"Error unpacking file: " + archiveFile, ex);
696 if (archiveFile.isMetaFlagSet(TskData.TSK_FS_META_FLAG_ENUM.ALLOC)) {
697 String msg = NbBundle.getMessage(SevenZipExtractor.class,
698 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.msg",
699 archiveFile.getName());
700 String details = NbBundle.getMessage(SevenZipExtractor.class,
701 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.errUnpacking.details",
702 escapedArchiveFilePath, ex.getMessage());
703 services.postMessage(IngestMessage.createErrorMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
706 if (inArchive != null) {
709 }
catch (SevenZipException e) {
710 logger.log(Level.SEVERE,
"Error closing archive: " + archiveFile, e);
714 if (stream != null) {
717 }
catch (IOException ex) {
718 logger.log(Level.SEVERE,
"Error closing stream after unpacking archive: " + archiveFile, ex);
723 if (progressStarted) {
730 String encryptionType = fullEncryption ? ENCRYPTION_FULL : ENCRYPTION_FILE_LEVEL;
732 BlackboardArtifact artifact = archiveFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
733 artifact.addAttribute(
new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, EmbeddedFileExtractorModuleFactory.getModuleName(), encryptionType));
737 blackboard.indexArtifact(artifact);
738 }
catch (Blackboard.BlackboardException ex) {
739 logger.log(Level.SEVERE,
"Unable to index blackboard artifact " + artifact.getArtifactID(), ex);
740 MessageNotifyUtil.Notify.error(
741 Bundle.SevenZipExtractor_indexError_message(), artifact.getDisplayName());
744 services.fireModuleDataEvent(
new ModuleDataEvent(EmbeddedFileExtractorModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED));
745 }
catch (TskCoreException ex) {
746 logger.log(Level.SEVERE,
"Error creating blackboard artifact for encryption detected for file: " + escapedArchiveFilePath, ex);
749 String msg = NbBundle.getMessage(SevenZipExtractor.class,
750 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.msg");
751 String details = NbBundle.getMessage(SevenZipExtractor.class,
752 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.unpack.encrFileDetected.details",
753 archiveFile.getName(), EmbeddedFileExtractorModuleFactory.getModuleName());
754 services.postMessage(IngestMessage.createWarningMessage(EmbeddedFileExtractorModuleFactory.getModuleName(), msg, details));
758 if (!unpackedFiles.isEmpty()) {
760 services.fireModuleContentEvent(
new ModuleContentEvent(archiveFile));
761 if (context != null) {
762 context.addFilesToJob(unpackedFiles);
765 return unpackSuccessful;
772 private int[] getExtractableFilesFromDetailsMap(
773 Map<Integer, InArchiveItemDetails> archiveDetailsMap) {
775 Integer[] wrappedExtractionIndices = archiveDetailsMap.keySet()
776 .toArray(
new Integer[archiveDetailsMap.size()]);
778 return Arrays.stream(wrappedExtractionIndices)
779 .mapToInt(Integer::intValue)
786 private abstract static class UnpackStream implements ISequentialOutStream {
794 output =
new EncodedFileOutputStream(
new FileOutputStream(localAbsPath), TskData.EncodingType.XOR1);
795 }
catch (IOException ex) {
796 logger.log(Level.SEVERE,
"Error writing extracted file: " + localAbsPath, ex);
801 public abstract long getSize();
803 OutputStream getOutput() {
807 String getLocalAbsPath() {
812 if (output != null) {
816 }
catch (IOException e) {
817 logger.log(Level.SEVERE,
"Error closing unpack stream for file: {0}", localAbsPath);
843 public int write(byte[] bytes)
throws SevenZipException {
849 getOutput().write(bytes);
853 this.bytesWritten += bytes.length;
854 this.freeDiskSpace -= bytes.length;
856 this.outOfSpace =
true;
857 logger.log(Level.INFO, NbBundle.getMessage(
858 SevenZipExtractor.class,
859 "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg"));
860 throw new SevenZipException(
861 NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg"));
863 }
catch (IOException ex) {
864 throw new SevenZipException(
865 NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
866 getLocalAbsPath()), ex);
873 if (getOutput() != null) {
877 if (this.outOfSpace) {
878 Files.delete(Paths.get(getLocalAbsPath()));
880 }
catch (IOException e) {
881 logger.log(Level.SEVERE,
"Error closing unpack stream for file: {0}", getLocalAbsPath());
905 public int write(byte[] bytes)
throws SevenZipException {
907 getOutput().write(bytes);
908 }
catch (IOException ex) {
909 throw new SevenZipException(
910 NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg",
911 getLocalAbsPath()), ex);
922 private final SevenZipExtractor.UnpackedTree.UnpackedNode
unpackedNode;
927 SevenZipExtractor.UnpackedTree.UnpackedNode
unpackedNode,
928 String localAbsPath, String localRelPath) {
952 implements IArchiveExtractCallback, ICryptoGetTextPassword {
970 private boolean unpackSuccessful =
true;
973 AbstractFile archiveFile, ProgressHandle progressHandle,
974 Map<Integer, InArchiveItemDetails> archiveDetailsMap,
975 String password,
long freeDiskSpace) {
998 public ISequentialOutStream
getStream(
int inArchiveItemIndex,
999 ExtractAskMode mode)
throws SevenZipException {
1003 isFolder = (Boolean) inArchive
1004 .getProperty(inArchiveItemIndex, PropID.IS_FOLDER);
1005 if (isFolder || mode != ExtractAskMode.EXTRACT) {
1009 final Long archiveItemSize = (Long) inArchive.getProperty(
1010 inArchiveItemIndex, PropID.SIZE);
1011 final String localAbsPath = archiveDetailsMap.get(
1012 inArchiveItemIndex).getLocalAbsPath();
1014 if (archiveItemSize != null) {
1015 unpackStream =
new SevenZipExtractor.KnownSizeUnpackStream(
1016 localAbsPath, archiveItemSize);
1018 unpackStream =
new SevenZipExtractor.UnknownSizeUnpackStream(
1019 localAbsPath, freeDiskSpace);
1034 final Date createTime = (Date) inArchive.getProperty(
1035 inArchiveItemIndex, PropID.CREATION_TIME);
1036 final Date accessTime = (Date) inArchive.getProperty(
1037 inArchiveItemIndex, PropID.LAST_ACCESS_TIME);
1038 final Date writeTime = (Date) inArchive.getProperty(
1039 inArchiveItemIndex, PropID.LAST_WRITE_TIME);
1041 createTimeInSeconds = createTime == null ? 0L
1042 : createTime.getTime() / 1000;
1043 modTimeInSeconds = writeTime == null ? 0L
1044 : writeTime.getTime() / 1000;
1045 accessTimeInSeconds = accessTime == null ? 0L
1046 : accessTime.getTime() / 1000;
1059 progressHandle.progress(archiveFile.getName() +
": "
1060 + (String) inArchive.getProperty(inArchiveItemIndex, PropID.PATH),
1063 final SevenZipExtractor.UnpackedTree.UnpackedNode unpackedNode
1064 = archiveDetailsMap.get(inArchiveItemIndex).getUnpackedNode();
1065 final String localRelPath = archiveDetailsMap.get(
1066 inArchiveItemIndex).getLocalRelPath();
1068 unpackedNode.addDerivedInfo(0,
1069 !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
1075 final String localAbsPath = archiveDetailsMap.get(
1076 inArchiveItemIndex).getLocalAbsPath();
1077 if (result != ExtractOperationResult.OK) {
1078 logger.log(Level.WARNING,
"Extraction of : {0} encountered error {1}",
1079 new Object[]{localAbsPath, result});
1080 unpackSuccessful =
false;
1085 !(Boolean) inArchive.getProperty(inArchiveItemIndex, PropID.IS_FOLDER),
1092 public void setTotal(
long value)
throws SevenZipException {
1136 UnpackedTree(String localPathRoot, AbstractFile archiveFile) {
1138 this.rootNode.setFile(archiveFile);
1139 this.rootNode.setFileName(archiveFile.getName());
1140 this.rootNode.setLocalRelPath(localPathRoot);
1153 String[] toks = filePath.split(
"[\\/\\\\]");
1154 List<String> tokens =
new ArrayList<>();
1155 for (
int i = 0; i < toks.length; ++i) {
1156 if (!toks[i].isEmpty()) {
1157 tokens.add(toks[i]);
1160 return addNode(rootNode, tokens);
1173 if (tokenPath.isEmpty()) {
1178 String childName = tokenPath.remove(0);
1181 if (child == null) {
1183 parent.addChild(child);
1187 return addNode(child, tokenPath);
1196 List<AbstractFile> getRootFileObjects() {
1197 List<AbstractFile> ret =
new ArrayList<>();
1198 for (UnpackedNode child : rootNode.getChildren()) {
1199 ret.add(child.getFile());
1210 List<AbstractFile> getAllFileObjects() {
1211 List<AbstractFile> ret =
new ArrayList<>();
1212 for (UnpackedNode child : rootNode.getChildren()) {
1219 list.add(parent.getFile());
1229 void updateOrAddFileToCaseRec(HashMap<String, ZipFileStatusWrapper> statusMap, String archiveFilePath)
throws TskCoreException,
NoCurrentCaseException {
1231 for (UnpackedNode child : rootNode.getChildren()) {
1232 updateOrAddFileToCaseRec(child, fileManager, statusMap, archiveFilePath);
1253 String nameInDatabase = getKeyFromUnpackedNode(node, archiveFilePath);
1254 ZipFileStatusWrapper existingFile = nameInDatabase == null ? null : statusMap.get(nameInDatabase);
1255 if (existingFile == null) {
1256 df = fileManager.
addDerivedFile(node.getFileName(), node.getLocalRelPath(), node.getSize(),
1257 node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
1259 "",
"", TskData.EncodingType.XOR1);
1262 String key = getKeyAbstractFile(existingFile.
getFile());
1265 statusMap.put(key, existingFile);
1269 String mimeType = existingFile.
getFile().getMIMEType().equalsIgnoreCase(
"application/octet-stream") ? null : existingFile.
getFile().getMIMEType();
1271 node.getCtime(), node.getCrtime(), node.getAtime(), node.getMtime(),
1273 "",
"", TskData.EncodingType.XOR1);
1277 df = (DerivedFile) existingFile.
getFile();
1281 }
catch (TskCoreException ex) {
1282 logger.log(Level.SEVERE,
"Error adding a derived file to db:" + node.getFileName(), ex);
1283 throw new TskCoreException(
1284 NbBundle.getMessage(SevenZipExtractor.class,
"EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackedTree.exception.msg",
1285 node.getFileName()), ex);
1289 updateOrAddFileToCaseRec(child, fileManager, statusMap, getKeyFromUnpackedNode(node, archiveFilePath));
1300 private final List<UnpackedNode>
children =
new ArrayList<>();
1301 private String localRelPath =
"";
1303 private long ctime, crtime, atime, mtime;
1315 this.localRelPath = parent.getLocalRelPath() + File.separator +
fileName;
1334 void setFileName(String fileName) {
1343 void addChild(UnpackedNode child) {
1344 children.add(child);
1353 List<UnpackedNode> getChildren() {
1362 UnpackedNode getParent() {
1366 void addDerivedInfo(
long size,
1368 long ctime,
long crtime,
long atime,
long mtime, String relLocalPath) {
1372 this.crtime = crtime;
1375 this.localRelPath = relLocalPath;
1378 void setFile(AbstractFile file) {
1389 UnpackedNode getChild(String childFileName) {
1390 UnpackedNode ret = null;
1391 for (UnpackedNode child : children) {
1392 if (child.getFileName().equals(childFileName)) {
1400 String getFileName() {
1404 AbstractFile getFile() {
1408 String getLocalRelPath() {
1418 void setLocalRelPath(String localRelativePath) {
1419 localRelPath = localRelativePath;
1426 boolean isIsFile() {
1436 static class Archive {
1439 private final int depth;
1440 private final List<Archive> children;
1441 private final long rootArchiveId;
1442 private boolean flaggedAsZipBomb =
false;
1443 private final AbstractFile archiveFile;
1457 Archive(
int depth,
long rootArchiveId, AbstractFile archiveFile) {
1458 this.children =
new ArrayList<>();
1460 this.rootArchiveId = rootArchiveId;
1461 this.archiveFile = archiveFile;
1470 void addChild(Archive child) {
1471 children.add(child);
1478 synchronized void flagAsZipBomb() {
1479 flaggedAsZipBomb =
true;
1487 synchronized boolean isFlaggedAsZipBomb() {
1488 return flaggedAsZipBomb;
1496 AbstractFile getArchiveFile() {
1505 long getRootArchiveId() {
1506 return rootArchiveId;
1514 long getObjectId() {
1515 return archiveFile.getId();
1547 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 final int DISK_FREE_SPACE_UNKNOWN
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)