diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java index b0934c1216..6ffa1df07e 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/SevenZipExtractor.java @@ -146,7 +146,7 @@ class SevenZipExtractor { * @param abstractFile The AbstractFilw whose mimetype is to be determined. * * @return This method returns true if the file format is currently - * supported. Else it returns false. + * supported. Else it returns false. */ boolean isSevenZipExtractionSupported(AbstractFile abstractFile) { try { @@ -180,7 +180,7 @@ class SevenZipExtractor { * * More heuristics to be added here * - * @param archiveName the parent archive + * @param archiveName the parent archive * @param archiveFileItem the archive item * * @return true if potential zip bomb, false otherwise @@ -279,7 +279,7 @@ class SevenZipExtractor { * Unpack the file to local folder and return a list of derived files * * @param pipelineContext current ingest context - * @param archiveFile file to unpack + * @param archiveFile file to unpack * * @return list of unpacked derived files */ @@ -502,7 +502,10 @@ class SevenZipExtractor { SevenZipExtractor.UnpackStream unpackStream = null; if (!isDir) { try { - unpackStream = new SevenZipExtractor.UnpackStream(localAbsPath, freeDiskSpace, size == null); + if (size != null) + unpackStream = new SevenZipExtractor.KnownSizeUnpackStream(localAbsPath, size); + else + unpackStream = new SevenZipExtractor.UnknownSizeUnpackStream(localAbsPath, freeDiskSpace); item.extractSlow(unpackStream); } catch (Exception e) { //could be something unexpected with this file, move on @@ -510,22 +513,14 @@ class SevenZipExtractor { } finally { if (unpackStream != null) { //record derived data in unode, to be traversed later after unpacking the archive - if (size != null) { - // unpackedNode.bytesWritten will not be set in - // this case. Use 'size' which has been set - // previously. - unpackedNode.addDerivedInfo(size, !isDir, - 0L, createtime, accesstime, modtime, localRelPath); - } else { - // since size is unknown, use - // unpackStream.getNumberOfBytesWritten() to get - // the size. - unpackedNode.addDerivedInfo(unpackStream.getNumberOfBytesWritten(), !isDir, - 0L, createtime, accesstime, modtime, localRelPath); - } + unpackedNode.addDerivedInfo(unpackStream.getSize(), !isDir, + 0L, createtime, accesstime, modtime, localRelPath); unpackStream.close(); } } + } else { // this is a directory, size is always 0 + unpackedNode.addDerivedInfo(0, !isDir, + 0L, createtime, accesstime, modtime, localRelPath); } //update units for progress bar @@ -615,18 +610,12 @@ class SevenZipExtractor { /** * Stream used to unpack the archive to local file */ - private static class UnpackStream implements ISequentialOutStream { + private abstract static class UnpackStream implements ISequentialOutStream { private OutputStream output; private String localAbsPath; - private long freeDiskSpace; - private boolean sizeUnknown = false; - private boolean outOfSpace = false; - private long bytesWritten = 0; - UnpackStream(String localAbsPath, long freeDiskSpace, boolean sizeUnknown) { - this.sizeUnknown = sizeUnknown; - this.freeDiskSpace = freeDiskSpace; + UnpackStream(String localAbsPath) { this.localAbsPath = localAbsPath; try { output = new BufferedOutputStream(new FileOutputStream(localAbsPath)); @@ -636,41 +625,14 @@ class SevenZipExtractor { } - public long getNumberOfBytesWritten() { - return this.bytesWritten; + public abstract long getSize(); + + OutputStream getOutput() { + return output; } - - @Override - public int write(byte[] bytes) throws SevenZipException { - try { - if (!sizeUnknown) { - output.write(bytes); - } else { - // If the content size is unknown, cautiously write to disk. - // Write only if byte array is less than 80% of the current - // free disk space. - if (freeDiskSpace == IngestMonitor.DISK_FREE_SPACE_UNKNOWN || bytes.length < 0.8 * freeDiskSpace) { - output.write(bytes); - // NOTE: this method is called multiple times for a - // single extractSlow() call. Update bytesWritten and - // freeDiskSpace after every write operation. - this.bytesWritten += bytes.length; - this.freeDiskSpace -= bytes.length; - } else { - this.outOfSpace = true; - logger.log(Level.INFO, NbBundle.getMessage( - SevenZipExtractor.class, - "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg")); - throw new SevenZipException( - NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg")); - } - } - } catch (IOException ex) { - throw new SevenZipException( - NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg", - localAbsPath), ex); - } - return bytes.length; + + String getLocalAbsPath() { + return localAbsPath; } public void close() { @@ -678,9 +640,6 @@ class SevenZipExtractor { try { output.flush(); output.close(); - if (this.outOfSpace) { - Files.delete(Paths.get(this.localAbsPath)); - } } catch (IOException e) { logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", localAbsPath); //NON-NLS } @@ -688,6 +647,100 @@ class SevenZipExtractor { } } + /** + * Stream used to unpack the archive of unknown size to local file + */ + private static class UnknownSizeUnpackStream extends UnpackStream { + + private long freeDiskSpace; + private boolean outOfSpace = false; + private long bytesWritten = 0; + + UnknownSizeUnpackStream(String localAbsPath, long freeDiskSpace) { + super(localAbsPath); + this.freeDiskSpace = freeDiskSpace; + } + + @Override + public long getSize() { + return this.bytesWritten; + } + + @Override + public int write(byte[] bytes) throws SevenZipException { + try { + // If the content size is unknown, cautiously write to disk. + // Write only if byte array is less than 80% of the current + // free disk space. + if (freeDiskSpace == IngestMonitor.DISK_FREE_SPACE_UNKNOWN || bytes.length < 0.8 * freeDiskSpace) { + getOutput().write(bytes); + // NOTE: this method is called multiple times for a + // single extractSlow() call. Update bytesWritten and + // freeDiskSpace after every write operation. + this.bytesWritten += bytes.length; + this.freeDiskSpace -= bytes.length; + } else { + this.outOfSpace = true; + logger.log(Level.INFO, NbBundle.getMessage( + SevenZipExtractor.class, + "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg")); + throw new SevenZipException( + NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.noSpace.msg")); + } + } catch (IOException ex) { + throw new SevenZipException( + NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg", + getLocalAbsPath()), ex); + } + return bytes.length; + } + + @Override + public void close() { + if (getOutput() != null) { + try { + getOutput().flush(); + getOutput().close(); + if (this.outOfSpace) { + Files.delete(Paths.get(getLocalAbsPath())); + } + } catch (IOException e) { + logger.log(Level.SEVERE, "Error closing unpack stream for file: {0}", getLocalAbsPath()); //NON-NLS + } + } + } + } + + /** + * Stream used to unpack the archive of known size to local file + */ + private static class KnownSizeUnpackStream extends UnpackStream { + + private long size; + + KnownSizeUnpackStream(String localAbsPath, long size) { + super(localAbsPath); + this.size = size; + } + + @Override + public long getSize() { + return this.size; + } + + @Override + public int write(byte[] bytes) throws SevenZipException { + try { + getOutput().write(bytes); + } catch (IOException ex) { + throw new SevenZipException( + NbBundle.getMessage(SevenZipExtractor.class, "EmbeddedFileExtractorIngestModule.ArchiveExtractor.UnpackStream.write.exception.msg", + getLocalAbsPath()), ex); + } + return bytes.length; + } + } + /** * Representation of the files in the archive. Used to track of local tree * file hierarchy, archive depth, and files created to easily and reliably @@ -702,8 +755,8 @@ class SevenZipExtractor { /** * * @param localPathRoot Path in module output folder that files will be - * saved to - * @param archiveFile Archive file being extracted + * saved to + * @param archiveFile Archive file being extracted * @param fileManager */ UnpackedTree(String localPathRoot, AbstractFile archiveFile) { @@ -962,7 +1015,7 @@ class SevenZipExtractor { /** * Add a new archive to track of depth * - * @param parent parent archive or null + * @param parent parent archive or null * @param objectId object id of the new archive * * @return the archive added @@ -1003,4 +1056,4 @@ class SevenZipExtractor { } } -} \ No newline at end of file +} diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 8df9518e7b..ef6d9e0c2a 100755 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -552,7 +552,7 @@ SORT_MEMBER_DOCS = YES # this will also influence the order of the classes in the class list. # The default value is: NO. -SORT_BRIEF_DOCS = NO +SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and @@ -564,14 +564,14 @@ SORT_BRIEF_DOCS = NO # detailed member documentation. # The default value is: NO. -SORT_MEMBERS_CTORS_1ST = NO +SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. -SORT_GROUP_NAMES = NO +SORT_GROUP_NAMES = YES # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will diff --git a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java index 7ce482c293..43008b5d05 100755 --- a/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java +++ b/thunderbirdparser/src/org/sleuthkit/autopsy/thunderbirdparser/PstParser.java @@ -256,10 +256,16 @@ class PstParser { int bufferSize = 8176; byte[] buffer = new byte[bufferSize]; int count = attachmentStream.read(buffer); + + if(count == -1) { + throw new IOException("attachmentStream invalid (read() fails). File "+attach.getLongFilename()+ " skipped"); + } + while (count == bufferSize) { out.write(buffer); count = attachmentStream.read(buffer); } + byte[] endBuffer = new byte[count]; System.arraycopy(buffer, 0, endBuffer, 0, count); out.write(endBuffer);