diff --git a/ChangeLog b/ChangeLog index 4084de1..e50e95e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,14 @@ +-- v2.0.5 + +-- Re-Release of v2.0.4 with different build options enabled. + +-- v2.0.4 + ++ Further Improve compatibility with AFF4 producers. + -- v2.0.3 -+ Update zip header handling. Add compatibility for c-libaff4 implementation bugs and quirks. ++ Update zip header handling. Improve compatibility with AFF4 producers. -- v2.0.2 diff --git a/INSTALL b/INSTALL index cb0540b..c795e7a 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -libaff4 2.0.1 +libaff4 2.0.6 Requirements: ------------- diff --git a/README.md b/README.md index 19558fd..af83aba 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -AFF4 CPP Light v2.0.3 +AFF4 CPP Light v2.0 ------------- -Copyright Schatz Forensic Pty Ltd, 2017-2019 +Copyright Schatz Forensic Pty Ltd, 2017-2018 Released under the LGPL v3.0+ @@ -94,6 +94,6 @@ in the container. Notes: ------ -v2.0.3 is a near complete rewrite of the v1.0.0 of the library, and exhibits +v2.0.0 is a near complete rewrite of the v1.0.0 of the library, and exhibits a completely new API model. We did this so we have a simple, easy to read C++ implementation. diff --git a/configure.ac b/configure.ac index bd0df91..a7ecd3a 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.59]) -AC_INIT([aff4], [2.0.3], [info@evimetry.com]) +AC_INIT([aff4], [2.0.6], [info@evimetry.com]) AC_CONFIG_HEADERS([aff4config.h]) AC_CONFIG_SRCDIR([src/aff4.cc]) AC_CONFIG_MACRO_DIR([m4]) diff --git a/src/AFF4Containers.cc b/src/AFF4Containers.cc index b888af6..bd06a53 100644 --- a/src/AFF4Containers.cc +++ b/src/AFF4Containers.cc @@ -310,6 +310,9 @@ namespace aff4 { } aff4::IAFF4Resolver* createResolver(std::string path, bool scanSubFolders) noexcept { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Resolver : %s, %d \n", __FILE__, __LINE__, path.c_str(), scanSubFolders); +#endif if (path.empty()) { return nullptr; } @@ -323,6 +326,9 @@ namespace aff4 { * See if it exists. */ if (!aff4::util::fileExists(path)) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Resolver Path doesn't exist? %s, %d \n", __FILE__, __LINE__, path.c_str(), scanSubFolders); +#endif return nullptr; } diff --git a/src/AFF4Defaults.h b/src/AFF4Defaults.h index 1a6f886..37b18db 100644 --- a/src/AFF4Defaults.h +++ b/src/AFF4Defaults.h @@ -49,6 +49,11 @@ * XSD Data type prefix */ #define AFF4_XSD_PREFIX "http://www.w3.org/2001/XMLSchema#" + +/** + * Black Bag Technologies base URI for custom properties + */ +#define BBT_BASE_URI "https://blackbagtech.com/aff4/Schema#" /** * The default chunk size */ diff --git a/src/AFF4Lexicon.cc b/src/AFF4Lexicon.cc index 2465164..372dd4f 100644 --- a/src/AFF4Lexicon.cc +++ b/src/AFF4Lexicon.cc @@ -72,7 +72,8 @@ static const std::map lexiconMappings = { // { AFF4_DIGEST_SHA1, (AFF4_BASE_URI "SHA1") }, // { AFF4_DIGEST_SHA256, (AFF4_BASE_URI "SHA256") }, // { AFF4_DIGEST_SHA512, (AFF4_BASE_URI "SHA512") }, // - { AFF4_DIGEST_BLAKE2B, (AFF4_BASE_URI "Blake2b") }, // + { AFF4_DIGEST_BLAKE2B, (AFF4_BASE_URI "blake2b") }, // + { AFF4_DIGEST_BLAKE2B_, (AFF4_BASE_URI "Blake2b") }, // { AFF4_PAGESIZE, (AFF4_BASE_URI "pageSize") }, // { AFF4_MEMORY_PAGETABLE_ENTRY_OFFSET, (AFF4_BASE_URI "memoryPageTableEntryOffset") }, // { AFF4_MEMORY_INSTALLED_SIZE, (AFF4_BASE_URI "memoryInstalledSize") }, // @@ -93,6 +94,14 @@ static const std::map lexiconMappings = { // { AFF4_TOOL, (AFF4_BASE_URI "tool") }, // { AFF4_MINOR_VERSION, (AFF4_BASE_URI "toolMinorVersion") }, // { AFF4_MAJOR_VERSION, (AFF4_BASE_URI "toolMajorVersion") }, // + + /* Black Bag Technologies Custom Properties */ + { BBT_APFS_CONTAINER_TYPE, (BBT_BASE_URI "APFSContainerType") }, // + { BBT_APFS_CONTAINER_TYPE_STANDARD , (BBT_BASE_URI "APFSStandardContainerType") }, // + { BBT_APFS_CONTAINER_TYPE_T2, (BBT_BASE_URI "APFST2ContainerType") }, // + { BBT_APFS_CONTAINER_TYPE_FUSION, (BBT_BASE_URI "APFSFusionContainerType") }, // + { BBT_CONTAINS_EXTENTS, (BBT_BASE_URI "ContainsExtents") }, // + { BBT_CONTAINS_UNALLOCATED, (BBT_BASE_URI "ContainsUnallocated") }, // }; namespace lexicon { diff --git a/src/AFF4Lexicon.h b/src/AFF4Lexicon.h index 26a7ec2..a1a12ee 100644 --- a/src/AFF4Lexicon.h +++ b/src/AFF4Lexicon.h @@ -243,6 +243,10 @@ enum Lexicon { * aff4:BLAKE2B */ AFF4_DIGEST_BLAKE2B, + /** + * aff4:BLAKE2B + */ + AFF4_DIGEST_BLAKE2B_, /* * Map information @@ -347,6 +351,37 @@ enum Lexicon { * Optional RDF type to define case examiner who performed the acquisition. */ AFF4_CASE_EXAMINER, + + /* + * BlackBag Technologies Custom Properties + */ + + /** + * APFS Container type + */ + BBT_APFS_CONTAINER_TYPE, + /** + * APFS Container type (T2) + */ + BBT_APFS_CONTAINER_TYPE_T2, + /** + * APFS Container type (Fusion) + */ + BBT_APFS_CONTAINER_TYPE_FUSION, + /** + * APFS Container type (Standard disk) + */ + BBT_APFS_CONTAINER_TYPE_STANDARD, + /** + * Volume/Disk contains extents. + */ + BBT_CONTAINS_EXTENTS, + /** + * Volume/Disk contains unallocated regions (sparse). + */ + BBT_CONTAINS_UNALLOCATED, + + }; namespace lexicon { diff --git a/src/RDFValue.cc b/src/RDFValue.cc index f9a1352..7ecdb71 100644 --- a/src/RDFValue.cc +++ b/src/RDFValue.cc @@ -48,7 +48,9 @@ static const std::map aff4Mappings = { // { (AFF4_BASE_URI "SHA1"), aff4::Lexicon::AFF4_DIGEST_SHA1 }, // { (AFF4_BASE_URI "SHA256"), aff4::Lexicon::AFF4_DIGEST_SHA256 }, // { (AFF4_BASE_URI "SHA512"), aff4::Lexicon::AFF4_DIGEST_SHA512 }, // - { (AFF4_BASE_URI "BLAKE2B"), aff4::Lexicon::AFF4_DIGEST_BLAKE2B }, // + { (AFF4_BASE_URI "BLAKE2B"), aff4::Lexicon::AFF4_DIGEST_BLAKE2B }, // Evimetry Legacy + { (AFF4_BASE_URI "Blake2b"), aff4::Lexicon::AFF4_DIGEST_BLAKE2B }, // Evimetry Legacy + { (AFF4_BASE_URI "blake2b"), aff4::Lexicon::AFF4_DIGEST_BLAKE2B }, // AFF4 v1.0 std { (AFF4_BASE_URI "blockMapHashSHA512"), aff4::Lexicon::AFF4_DIGEST_BLOCK_MAP_HASH_SHA512 }, // }; diff --git a/src/codec/CompressionCodec.cc b/src/codec/CompressionCodec.cc index fe80c69..9f33390 100644 --- a/src/codec/CompressionCodec.cc +++ b/src/codec/CompressionCodec.cc @@ -34,14 +34,29 @@ std::shared_ptr getCodec(aff4::Lexicon resource, uint32_t chun switch (resource) { case Lexicon::AFF4_IMAGE_COMPRESSION_SNAPPY: case Lexicon::AFF4_IMAGE_COMPRESSION_SNAPPY2: +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Snappy Decompressor \n", __FILE__, __LINE__); +#endif return std::make_shared(chunkSize); case Lexicon::AFF4_IMAGE_COMPRESSION_LZ4: +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create LZ4 Decompressor \n", __FILE__, __LINE__); +#endif return std::make_shared(chunkSize); case Lexicon::AFF4_IMAGE_COMPRESSION_DEFLATE: +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Deflate Decompressor \n", __FILE__, __LINE__); +#endif return std::make_shared(chunkSize); case Lexicon::AFF4_IMAGE_COMPRESSION_STORED: +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Stored Decompressor \n", __FILE__, __LINE__); +#endif return std::make_shared(chunkSize); case Lexicon::AFF4_IMAGE_COMPRESSION_ZLIB: +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create ZLib Decompressor \n", __FILE__, __LINE__); +#endif return std::make_shared(chunkSize); default: break; diff --git a/src/image/AFF4Image.cc b/src/image/AFF4Image.cc index fd31433..c957795 100644 --- a/src/image/AFF4Image.cc +++ b/src/image/AFF4Image.cc @@ -22,7 +22,9 @@ namespace image { AFF4Image::AFF4Image(const std::string& resource, aff4::container::AFF4ZipContainer* parent) : AFF4Resource(resource), parent(parent) { - +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create Image? %s\n", __FILE__, __LINE__, resource.c_str()); +#endif std::shared_ptr model = parent->getRDFModel(); // Add information about THIS object to the object properties. std::map> elements = model->getObjectInformation(resource); @@ -70,6 +72,9 @@ AFF4Image::~AFF4Image() { std::shared_ptr AFF4Image::getMap() noexcept { // Find our dependentStream instance. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Open Map for Image. %s\n", __FILE__, __LINE__, getResourceID().c_str()); +#endif std::vector values = getProperty(aff4::Lexicon::AFF4_DATASTREAM); if (!values.empty()) { aff4::rdf::RDFValue v = values[0]; diff --git a/src/map/AFF4Map.cc b/src/map/AFF4Map.cc index 1f1c543..d6531f1 100644 --- a/src/map/AFF4Map.cc +++ b/src/map/AFF4Map.cc @@ -53,7 +53,7 @@ AFF4Map::AFF4Map(const std::string& resource, aff4::container::AFF4ZipContainer* } } #if DEBUG - fprintf(aff4::getDebugOutput(), "%s[%d] : Length %" PRIu64 " (%" PRIx64 ")\n", __FILE__, __LINE__, length, length); + fprintf(aff4::getDebugOutput(), "%s[%d] : Map Length %" PRIu64 " (%" PRIx64 ")\n", __FILE__, __LINE__, length, length); #endif /* diff --git a/src/resolver/LightResolver.cc b/src/resolver/LightResolver.cc index 04a6f66..0cfdf22 100644 --- a/src/resolver/LightResolver.cc +++ b/src/resolver/LightResolver.cc @@ -117,6 +117,9 @@ void LightResolver::scanForAFF4Volumes(const std::string& path) { // We don't have this file std::string resID = aff4::container::getResourceID(absoluteFilename); if (!resID.empty()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Adding Volume %s => %s \n", __FILE__, __LINE__, resID.c_str(), absoluteFilename.c_str()); +#endif volumes[resID] = absoluteFilename; } } @@ -145,6 +148,9 @@ void LightResolver::scanForAFF4Volumes(const std::string& path) { // We don't have this file std::string resID = aff4::container::getResourceID(absoluteFilename); if (!resID.empty()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Adding Volume %s => %s \n", __FILE__, __LINE__, resID.c_str(), absoluteFilename.c_str()); +#endif volumes[resID] = absoluteFilename; } } diff --git a/src/stream/ImageStream.cc b/src/stream/ImageStream.cc index 666e896..a0fa755 100644 --- a/src/stream/ImageStream.cc +++ b/src/stream/ImageStream.cc @@ -156,6 +156,9 @@ uint64_t ImageStream::size() noexcept { void ImageStream::close() noexcept { if (!closed.exchange(true)) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Close aff4:ImageStream %s \n", __FILE__, __LINE__, getResourceID().c_str()); +#endif parent = nullptr; } } @@ -172,11 +175,17 @@ inline uint64_t floor(uint64_t offset, uint64_t size) { int64_t ImageStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { if (closed) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIu64 " : %" PRIu64 " on Closed Stream \n", __FILE__, __LINE__, offset, count); +#endif errno = EPERM; return -1; } // If offset beyond end, return. if (offset > size()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIu64 " : %" PRIu64 "? Offset Greater than Stream size \n", __FILE__, __LINE__, offset, count); +#endif return 0; } // If offset + count, will go beyond end, truncate count. @@ -185,7 +194,7 @@ int64_t ImageStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { } #if DEBUG - //fprintf( stderr, "%s[%d] : Reading %" PRIu64 " : %" PRIu64 " \n", __FILE__, __LINE__, offset, count); + fprintf( aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); #endif uint64_t leftToRead = count; @@ -201,6 +210,9 @@ int64_t ImageStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { cacheBuffer_t entry = chunkCache->get(chunkOffset); if (entry.second == 0) { // failed to read. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " => %" PRIx64 " FAILED READ \n", __FILE__, __LINE__, offset, count, chunkOffset); +#endif return -1; } uint64_t delta = offset - chunkOffset; @@ -213,6 +225,9 @@ int64_t ImageStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { leftToRead -= toCopy; buffer += toCopy; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Completed Read %" PRIx64 " : %" PRIx64 " => %" PRIx64 " \n", __FILE__, __LINE__, offset - actualRead, count, actualRead); +#endif return actualRead; } diff --git a/src/stream/ImageStreamFactory.cc b/src/stream/ImageStreamFactory.cc index ec44d53..d81c924 100644 --- a/src/stream/ImageStreamFactory.cc +++ b/src/stream/ImageStreamFactory.cc @@ -20,26 +20,44 @@ namespace aff4 { namespace stream { std::shared_ptr createZeroStream() { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Zero stream \n", __FILE__, __LINE__); +#endif return std::make_shared(aff4::lexicon::getLexiconString(aff4::Lexicon::AFF4_IMAGESTREAM_ZERO), (uint8_t) 0); } std::shared_ptr createUnknownStream() { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Unknown stream \n", __FILE__, __LINE__); +#endif return std::make_shared(aff4::lexicon::getLexiconString(aff4::Lexicon::AFF4_IMAGESTREAM_UNKNOWN), "UNKNOWN"); } std::shared_ptr createUnknownStream(const std::string& resource) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Unknown stream with Resource %s \n", __FILE__, __LINE__, resource.c_str()); +#endif return std::make_shared(resource, "UNKNOWN"); } std::shared_ptr createUnreadableStream() { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Unreadable stream \n", __FILE__, __LINE__); +#endif return std::make_shared(aff4::lexicon::getLexiconString(aff4::Lexicon::AFF4_IMAGESTREAM_UNREADABLE), "UNREADABLEDATA"); } std::shared_ptr createSymbolicStream(const std::string& resource) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Symbolic stream %s \n", __FILE__, __LINE__, resource.c_str()); +#endif return std::make_shared(resource); } std::shared_ptr createSymbolicStream(uint8_t symbol) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Create aff4:Symbolic stream %02X \n", __FILE__, __LINE__, symbol); +#endif std::string resource = aff4::lexicon::getLexiconString(aff4::Lexicon::AFF4_IMAGESTREAM_SYMBOLIC_PREFIX); char buf[4]; std::snprintf(buf, 3, "%02X", symbol); diff --git a/src/stream/MapStream.cc b/src/stream/MapStream.cc index 85ff244..f067f91 100644 --- a/src/stream/MapStream.cc +++ b/src/stream/MapStream.cc @@ -18,6 +18,8 @@ #include "MapStream.h" #include "PortableEndian.h" +#include + using namespace aff4::stream::structs; namespace aff4 { @@ -48,6 +50,9 @@ uint64_t MapStream::size() noexcept { void MapStream::close() noexcept { if (!closed.exchange(true)) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Close aff4:Map %s \n", __FILE__, __LINE__, getResourceID().c_str()); +#endif parent = nullptr; streams.clear(); externalContainers.clear(); @@ -56,11 +61,17 @@ void MapStream::close() noexcept { int64_t MapStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { if (closed) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIu64 " : %" PRIu64 " on Closed Map Stream \n", __FILE__, __LINE__, offset, count); +#endif errno = EPERM; return -1; } // If offset beyond end, return. if (offset > size()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIu64 " : %" PRIu64 "? Offset Greater than Stream size \n", __FILE__, __LINE__, offset, count); +#endif return 0; } // If offset + count, will go beyond end, truncate count. @@ -69,7 +80,6 @@ int64_t MapStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { } #if DEBUG -// fprintf( stderr, "%s[%d] : Reading %" PRIu64 " : %" PRIu64 " \n", __FILE__, __LINE__, offset, count); fprintf( aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); #endif @@ -106,6 +116,10 @@ int64_t MapStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { int64_t res = stream->read(buffer, streadReadLength, streamReadOffset); if (res <= 0) { // fail it. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %s %" PRIx64 " : %" PRIx64 " FAILED READ \n", __FILE__, __LINE__, + stream->getResourceID().c_str(), streamReadOffset, streadReadLength); +#endif return -1; } actualRead += streadReadLength; @@ -113,6 +127,9 @@ int64_t MapStream::read(void *buf, uint64_t count, uint64_t offset) noexcept { leftToRead -= streadReadLength; buffer += streadReadLength; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Completed Read %" PRIx64 " : %" PRIx64 " => %" PRIx64 " \n", __FILE__, __LINE__, offset - actualRead, count, actualRead); +#endif return actualRead; } @@ -122,6 +139,9 @@ void MapStream::initStreamVector(std::shared_ptr& unknownOver std::string segmentName = getResourceID() + "/idx"; std::shared_ptr stream = parent->getSegment(segmentName); if (stream == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Missing 'idx' %s \n", __FILE__, __LINE__, segmentName.c_str()); +#endif return; } std::unique_ptr bufferIDX(new char[stream->size()]); @@ -148,14 +168,26 @@ void MapStream::initStreamVector(std::shared_ptr& unknownOver } // We have this stream from the parent container if (stream != nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Local for Stream %s \n", __FILE__, __LINE__, line.c_str()); +#endif streams.push_back(stream); } else { // look at the resolver for this stream. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Query Resolver for Stream %s \n", __FILE__, __LINE__, line.c_str()); +#endif stream = queryResolver(parent->getResolver(), line); if (stream != nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Resolver provided Stream %s \n", __FILE__, __LINE__, line.c_str()); +#endif streams.push_back(stream); } else { // Nothing from the resolver. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Resolver FAILED to locate Stream %s \n", __FILE__, __LINE__, line.c_str()); +#endif streams.push_back(aff4::stream::createUnknownStream(line)); } } @@ -170,6 +202,9 @@ void MapStream::initMap(std::shared_ptr& mapGapStream) { std::shared_ptr stream = parent->getSegment(segmentName); if (stream == nullptr) { // reset the stream length +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Missing 'map' %s \n", __FILE__, __LINE__, segmentName.c_str()); +#endif length = 0; return; } @@ -202,11 +237,20 @@ void MapStream::initMap(std::shared_ptr& mapGapStream) { buffer[i] = mapPoint; } #endif - + std::vector points; uint64_t offset = 0; // We have our map. + // Materialise all map entry points. for (uint32_t i = 0; i < size; i++) { MapEntryPoint mapPoint = buffer[i]; + points.push_back(mapPoint); + } + // Sort all map entries + std::sort(points.begin(), points.end(), ::aff4::stream::structs::mapEntryPointCompare); + + // Construct the map. + for (uint32_t i = 0; i < size; i++) { + MapEntryPoint mapPoint = points[i]; #if DEBUG fprintf( aff4::getDebugOutput(), "%s[%d] : MapEntry : %" PRIx64" : %" PRIx64" : %" PRIx64" : %" PRIx32"\n", __FILE__, __LINE__, mapPoint.offset, mapPoint.length, mapPoint.streamOffset, mapPoint.streamID); @@ -255,12 +299,18 @@ void MapStream::initMap(std::shared_ptr& mapGapStream) { if (length == 0) { length = offset; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Created aff4:Map %s on length %" PRIu64 " \n", __FILE__, __LINE__, segmentName.c_str(), length); +#endif } std::shared_ptr MapStream::queryResolver(aff4::IAFF4Resolver* resolver, const std::string& resource) { if (resolver == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No resolver? \n", __FILE__, __LINE__); +#endif return nullptr; } // Our parent doesn't have it, so check the external resolver. @@ -341,6 +391,13 @@ std::map* MapStream::getMap() { return ↦ } -} -/* namespace stream */ + +/* Add the map entry point comparison. */ +namespace structs { + bool mapEntryPointCompare(const MapEntryPoint& i, const MapEntryPoint& j) { + return i.offset < j.offset; + } +} /* namespace structs */ + +} /* namespace stream */ } /* namespace aff4 */ diff --git a/src/stream/RepeatedImageStream.cc b/src/stream/RepeatedImageStream.cc index 8043c1c..4ae66c8 100644 --- a/src/stream/RepeatedImageStream.cc +++ b/src/stream/RepeatedImageStream.cc @@ -21,6 +21,7 @@ #include "RepeatedImageStream.h" #include +#include namespace aff4 { namespace stream { @@ -74,6 +75,9 @@ int64_t RepeatedImageStream::read(void *buf, uint64_t count, uint64_t offset) no return 0; } uint64_t remaining = count; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); +#endif char* buffer = static_cast(buf); // Specification for repeated pattern ImageStream works on 1MB boundaries. @@ -89,6 +93,9 @@ int64_t RepeatedImageStream::read(void *buf, uint64_t count, uint64_t offset) no // calculate next read/copy size. limit = std::min(remainder, (uint64_t)UNITS_M); } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Completed Read %" PRIx64 " : %" PRIx64 " => %" PRIx64 " \n", __FILE__, __LINE__, offset, count, remaining); +#endif return remaining; } diff --git a/src/stream/SymbolicImageStream.cc b/src/stream/SymbolicImageStream.cc index a8976d7..146f579 100644 --- a/src/stream/SymbolicImageStream.cc +++ b/src/stream/SymbolicImageStream.cc @@ -17,6 +17,7 @@ #include "SymbolicImageStream.h" #include "StringUtil.h" +#include namespace aff4 { namespace stream { @@ -75,7 +76,13 @@ int64_t SymbolicImageStream::read(void *buf, uint64_t count, uint64_t offset) no if ((count == 0) || (buf == nullptr)) { return 0; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); +#endif ::memset(buf, symbol, count); +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Completed Read %" PRIx64 " : %" PRIx64 " => %" PRIx64 " \n", __FILE__, __LINE__, offset, count, count); +#endif return count; } diff --git a/src/stream/struct/BevvyIndex.cc b/src/stream/struct/BevvyIndex.cc index 6e13d8f..9e81db9 100644 --- a/src/stream/struct/BevvyIndex.cc +++ b/src/stream/struct/BevvyIndex.cc @@ -47,6 +47,9 @@ BevvyIndex::BevvyIndex(const std::string& resource, uint32_t bevvyID, aff4::cont #endif std::shared_ptr stream = parent->getSegment(segmentName); if (stream == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Loading Bevvy Index Failed - missing segment? \n", __FILE__, __LINE__); +#endif buffer = nullptr; return; } @@ -56,6 +59,9 @@ BevvyIndex::BevvyIndex(const std::string& resource, uint32_t bevvyID, aff4::cont buffer = std::unique_ptr(new ImageStreamPoint[size]); stream->read(buffer.get(), streamSize, 0); } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Loading Bevvy Index Size %" PRIu64 "? \n", __FILE__, __LINE__, streamSize); +#endif stream->close(); #if __BYTE_ORDER == __BIG_ENDIAN // Perform byte order swap for loaded fields, so getPoint() doesn't need to do it. @@ -84,6 +90,9 @@ uint64_t BevvyIndex::getDataOffset() const noexcept { ImageStreamPoint BevvyIndex::getPoint(uint32_t offset) const noexcept { if (offset >= size || buffer == nullptr || parent == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Unknown Point? %x \n", __FILE__, __LINE__, offset); +#endif ImageStreamPoint pt; pt.offset = 0; pt.length = 0; diff --git a/src/stream/struct/ChunkLoader.cc b/src/stream/struct/ChunkLoader.cc index 6a93037..350bb45 100644 --- a/src/stream/struct/ChunkLoader.cc +++ b/src/stream/struct/ChunkLoader.cc @@ -67,6 +67,11 @@ cacheBuffer_t ChunkLoader::load(uint64_t offset) { uint64_t chunkOffset = index->getDataOffset() + point.offset; uint64_t chunkLength = point.length; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : ChunkOffset %" PRIu64 " ChunkLength %" PRIu64 " \n", + __FILE__, __LINE__, chunkOffset, chunkLength); +#endif + /* * Chunk Offset and Chunk Length are for offsets into the direct ZIP level container. (we really * should get a IAFF4Stream for the zip segment, but lets shortcut and just read directly from the @@ -93,10 +98,22 @@ cacheBuffer_t ChunkLoader::load(uint64_t offset) { } if (chunkLength != chunkSize) { // decompress +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Decompress Chunk [%" PRIu32 " : %" PRIu64 "] \n", + __FILE__, __LINE__, chunkSize, chunkLength); +#endif std::shared_ptr dest(new uint8_t[chunkSize], std::default_delete()); - codec->decompress(buffer.get(), chunkLength, dest.get(), chunkSize); + uint64_t decSize = codec->decompress(buffer.get(), chunkLength, dest.get(), chunkSize); +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Decompressed Chunk [%" PRIu32 " : %" PRIu64 "] => %" PRIu64 " \n", + __FILE__, __LINE__, chunkSize, chunkLength, decSize); +#endif return std::make_pair(dest, chunkSize); } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Stored Chunk [%" PRIu32 " : %" PRIu64 "] \n", + __FILE__, __LINE__, chunkSize, chunkLength); +#endif // No decompression needed, just return. return std::make_pair(buffer, chunkSize); } diff --git a/src/stream/struct/MapEntryPoint.h b/src/stream/struct/MapEntryPoint.h index f2218fd..ab7228e 100644 --- a/src/stream/struct/MapEntryPoint.h +++ b/src/stream/struct/MapEntryPoint.h @@ -68,6 +68,15 @@ PACKED_STRUCT(MapEntryPoint { }); +/** +* Map Entry Compare Function. +* +* @param i The first map point. +* @param j The second map point. +* @return TRUE if the first map point is before the second map point. +*/ +bool mapEntryPointCompare(const MapEntryPoint& i, const MapEntryPoint& j); + } /* namespace structs */ } /* namespace stream */ } /* namespace aff4 */ diff --git a/src/zip/Zip.cc b/src/zip/Zip.cc index 7350a98..27f5d5a 100644 --- a/src/zip/Zip.cc +++ b/src/zip/Zip.cc @@ -353,6 +353,9 @@ void Zip::parseCD() noexcept { } int64_t Zip::fileRead(void *buf, uint64_t count, uint64_t offset) noexcept { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); +#endif if ((count == 0) || (buf == nullptr)) { return 0; } @@ -388,8 +391,14 @@ int64_t Zip::fileRead(void *buf, uint64_t count, uint64_t offset) noexcept { readDetails.OffsetHigh = (DWORD)((offset & 0xffffffff00000000L) >> 32); if (!ReadFile(fileHandle, buf, byteRead, &bytesRead, &readDetails)) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading %" PRIx64 " : %" PRIx64 " FAILED \n", __FILE__, __LINE__, offset, count); +#endif return -1; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Completed Read %" PRIx64 " : %" PRIx64 " => %" PRIx32 " \n", __FILE__, __LINE__, offset, count, byteRead); +#endif return byteRead; #endif diff --git a/src/zip/ZipStream.cc b/src/zip/ZipStream.cc index 753551c..e8a34c9 100644 --- a/src/zip/ZipStream.cc +++ b/src/zip/ZipStream.cc @@ -16,6 +16,7 @@ */ #include "ZipStream.h" +#include namespace aff4 { namespace stream { @@ -100,7 +101,9 @@ std::vector ZipSegmentStream::getProperty(aff4::Lexicon res */ int64_t ZipSegmentStream::readCompressed(void *buf, uint64_t count, uint64_t offset) noexcept { - +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading Compressed Zip Segment %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); +#endif // If the size of the stream is less than 32MB, take a poor mans implementation. if (size() <= ZIP_WHOLE_STREAM) { /* @@ -136,7 +139,9 @@ int64_t ZipSegmentStream::readCompressed(void *buf, uint64_t count, uint64_t off } else { // greater than 32MB - +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Reading Compressed Zip Segment TOO LARGE %" PRIx64 " : %" PRIx64 " \n", __FILE__, __LINE__, offset, count); +#endif // FIXME: IMPLEMENT. } // failed? diff --git a/win32/INSTALL.txt b/win32/INSTALL.txt index 55c673e..3b4009d 100644 --- a/win32/INSTALL.txt +++ b/win32/INSTALL.txt @@ -1,4 +1,4 @@ -libaff4 2.0.1 +libaff4 2.0.3 Installation Instructions for Visual Studio 2015+. diff --git a/win32/libaff4/aff4config.h b/win32/libaff4/aff4config.h index d81fb4f..66e828e 100644 --- a/win32/libaff4/aff4config.h +++ b/win32/libaff4/aff4config.h @@ -22,7 +22,7 @@ along with AFF4 CPP. If not, see . #define PACKAGE_NAME "aff4" /* Define to the full name and version of this package. */ -#define PACKAGE_STRING "aff4 2.0.3" +#define PACKAGE_STRING "aff4 2.0.6" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "aff4" @@ -31,7 +31,7 @@ along with AFF4 CPP. If not, see . #define PACKAGE_URL "" /* Define to the version of this package. */ -#define PACKAGE_VERSION "2.0.3" +#define PACKAGE_VERSION "2.0.6" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 diff --git a/win32/libaff4/libaff4.vcxproj.filters b/win32/libaff4/libaff4.vcxproj.filters index 578c336..08d637e 100644 --- a/win32/libaff4/libaff4.vcxproj.filters +++ b/win32/libaff4/libaff4.vcxproj.filters @@ -147,6 +147,15 @@ Header Files + + Header Files + + + Header Files + + + Header Files + @@ -239,6 +248,18 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + diff --git a/win32/xways.txt b/win32/xways.txt index df68eb5..0a643d3 100644 --- a/win32/xways.txt +++ b/win32/xways.txt @@ -1,15 +1,14 @@ X-Ways AFF4 Plugin ------------------- -Copyright Schatz Forensic Pty Ltd, 2017 +Copyright Schatz Forensic Pty Ltd, 2017-2019 Released under the LGPL v3.0+ Plugin Binary Package ---------------------- -This packages contains imageAFF4.dll, libaff4.dll and dependencies built using Visual Studio 2015. +This packages contains ImageIOAFF4.dll, libaff4.dll and dependencies built using Visual Studio 2015. -The libaff4.dll also requires MSVCP140.dll and MSVCRUNTIME140.dll. (MS VC++ 2015 Runtime). - -Install as per X-Way Forensic documentation. \ No newline at end of file +Download and install the Visual C++ Redistributable for Visual Studio 2015 from +https://www.microsoft.com/en-us/download/details.aspx?id=48145 \ No newline at end of file diff --git a/win32/xwaysPlugin/xwaysPlugin.cc b/win32/xwaysPlugin/xwaysPlugin.cc index 75f0776..cacd67c 100644 --- a/win32/xwaysPlugin/xwaysPlugin.cc +++ b/win32/xwaysPlugin/xwaysPlugin.cc @@ -24,6 +24,9 @@ along with AFF4 CPP. If not, see . #include #include #include +#include +#include +#include /** * Next handle. @@ -55,6 +58,71 @@ static HWND mainWnd; */ static std::shared_ptr> handles = std::make_shared>(); +/** + * Debug logging options + */ +#if DEBUG +FILE* loggerHandle = nullptr; + +std::wstring randomString(std::wstring::size_type length) +{ + static auto& chrs = "0123456789" + "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + thread_local static std::mt19937 rg{ std::random_device{}() }; + thread_local static std::uniform_int_distribution pick(0, sizeof(chrs) - 2); + + std::wstring s; + + s.reserve(length); + + while (length--) + s += chrs[pick(rg)]; + + return s; +} + +static void setupLog() { + if (loggerHandle != nullptr) { + return; + } + // Create the file to log to, and set aff4::setDebugOutput() + TCHAR lpTempPathBuffer[MAX_PATH]; + DWORD dwRetVal = 0; + + dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer); // buffer for path + if (dwRetVal > MAX_PATH || (dwRetVal == 0)) { + return; + } + std::wstring filename(lpTempPathBuffer); + filename = filename + L"\\libaff4."+ randomString(8) + L".log"; + loggerHandle = (FILE*)malloc(sizeof(FILE)); + ZeroMemory(loggerHandle, sizeof(FILE)); + errno_t res = _wfopen_s(&loggerHandle, filename.c_str(), L"w+"); + if (res == 0) { + aff4::setDebugOutput(loggerHandle); + } else { + ::free(loggerHandle); + loggerHandle = nullptr; + } +} + +static void closeLog() { + if (loggerHandle == nullptr) { + return; + } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Close Log File \n", __FILE__, __LINE__); +#endif + aff4::setDebugOutput(stderr); + fclose(loggerHandle); + //::free(loggerHandle); + loggerHandle = nullptr; +} + +#endif + extern "C" { /* @@ -73,10 +141,20 @@ extern "C" { std::lock_guard lock(apiLock); mainWnd = (HWND)hMainWnd; +#if DEBUG + setupLog(); +#endif + if (lpFilePath == NULL) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No Filename provided? \n", __FILE__, __LINE__); +#endif return NULL; } if (pImgInfo == NULL) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No Image Information Packet provided? \n", __FILE__, __LINE__); +#endif return NULL; } @@ -93,24 +171,41 @@ extern "C" { std::wstring wfile(lpFilePath); if (wfile.empty()) { errno = ENOENT; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Filename provided is empty? \n", __FILE__, __LINE__); +#endif return NULL; } // Convert wstring (utf-16) to string (utf-8) std::string file = ws2s(wfile); - +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Attempt to open: %s \n", __FILE__, __LINE__, file.c_str()); +#endif // Attempt to open the file. std::shared_ptr container = aff4::container::openAFF4Container(file); if (container == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No AFF4 Container materialised? %s \n", __FILE__, __LINE__, file.c_str()); +#endif if (!aff4::container::isAFF4Container(file)) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Filename does not appear to be an AFF4 Container? %s \n", __FILE__, __LINE__, file.c_str()); +#endif errno = ENOENT; return NULL; } std::string resource = aff4::container::getResourceID(file); pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; if (resource.empty()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Invalid AFF4 Container - Missing Resource Identifier? %s \n", __FILE__, __LINE__, file.c_str()); +#endif pImgInfo->lpTextualDescr = createText(L"Invalid AFF4 Container - Missing Resource Identifier"); } else { // Have a Resource ID? Possible empty container. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Invalid AFF4 Container - Missing Contents? %s \n", __FILE__, __LINE__, file.c_str()); +#endif pImgInfo->lpTextualDescr = createText(L"Invalid AFF4 Container - Missing Contents"); } // We MUST return a handle for the user to be given the above error message. @@ -120,6 +215,9 @@ extern "C" { // Attempt to start a resolver std::shared_ptr resolver(aff4::container::createResolver(file, false)); if (resolver == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Unable to construct Resolver at location. \n", __FILE__, __LINE__); +#endif errno = ENOENT; pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; pImgInfo->lpTextualDescr = createText(L"Unable to construct Resolver at location."); @@ -130,12 +228,18 @@ extern "C" { // Open the first image. std::vector> images = container->getImages(); if (images.empty()) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No Images contained or available in the AFF4 Container.\n", __FILE__, __LINE__); +#endif errno = ENOENT; pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; pImgInfo->lpTextualDescr = createText(L"No Images contained or available in the AFF4 Container."); return (PVOID)(nextHandle++); } if (images[0] == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : No Images contained or available in the AFF4 Container.\n", __FILE__, __LINE__); +#endif errno = ENOENT; pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; pImgInfo->lpTextualDescr = createText(L"No Images contained or available in the AFF4 Container."); @@ -144,6 +248,9 @@ extern "C" { // Get the map for the first image. std::shared_ptr map = images[0]->getMap(); if (map == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Primary Image is missing required Datastream Map.\n", __FILE__, __LINE__); +#endif errno = ENOENT; pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; pImgInfo->lpTextualDescr = createText(L"Primary Image is missing required Datastream Map."); @@ -151,6 +258,9 @@ extern "C" { } std::shared_ptr stream = map->getStream(); if (stream == nullptr) { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Datastream for Image is not available or corrupted.\n", __FILE__, __LINE__); +#endif errno = ENOENT; pImgInfo->nFlags = IIO_INIT_ERROR_GIVE_UP; pImgInfo->lpTextualDescr = createText(L"Datastream for Image is not available or corrupted."); @@ -159,6 +269,9 @@ extern "C" { container_t handleEntry = std::make_tuple(resolver, container, stream); int handle = nextHandle++; (*handles)[handle] = handleEntry; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Created aff4:Image instance. Handle %d\n", __FILE__, __LINE__, handle); +#endif /* * Add return parameters. */ @@ -170,15 +283,40 @@ extern "C" { if (!properties.empty()) { for (aff4::rdf::RDFValue v : properties) { if (v.getType() == aff4::Lexicon::AFF4_DISK_IMAGE_TYPE) { - pImgInfo->nFlags += IIO_INIT_DISK; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Setting Disk Image\n", __FILE__, __LINE__); +#endif + pImgInfo->nFlags |= IIO_INIT_DISK; break; } if (v.getType() == aff4::Lexicon::AFF4_VOLUME_IMAGE_TYPE) { - pImgInfo->nFlags += IIO_INIT_VOLUME; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Setting Volume Image\n", __FILE__, __LINE__); +#endif + pImgInfo->nFlags |= IIO_INIT_VOLUME; break; } } } + if ((pImgInfo->nFlags & (IIO_INIT_DISK | IIO_INIT_VOLUME)) == 0) { + // Disk/Volume type not set, check for Black Bag Technologies container type property + properties = image->getProperty(aff4::Lexicon::BBT_APFS_CONTAINER_TYPE); + if (!properties.empty()) { + for (aff4::rdf::RDFValue v : properties) { + if (v.getType() == aff4::Lexicon::BBT_APFS_CONTAINER_TYPE_T2 + || v.getType() == aff4::Lexicon::BBT_APFS_CONTAINER_TYPE_FUSION + || v.getType() == aff4::Lexicon::BBT_APFS_CONTAINER_TYPE_STANDARD) { + // Big assumption that these all represent a volume... + // I'm sure someone will file a bug report if this is incorrect. +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Setting Volume Image (bbt:Std/T2/Fusion)\n", __FILE__, __LINE__); +#endif + pImgInfo->nFlags |= IIO_INIT_VOLUME; + break; + } + } + } + } // Get Sector Size. properties = image->getProperty(aff4::Lexicon::AFF4_BLOCKSIZE); @@ -191,6 +329,9 @@ extern "C" { pImgInfo->nSectorSize = (DWORD)v.getLong(); } } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Setting Sector Size %d\n", __FILE__, __LINE__, pImgInfo->nSectorSize); +#endif // Get Sector Count. properties = image->getProperty(aff4::Lexicon::AFF4_DISK_DEVICE_SECTOR_COUNT); @@ -207,6 +348,9 @@ extern "C" { // No defined sector size, so get the size of the stream and divide by block size. pImgInfo->nSectorCount = (INT64)stream->size() / (INT64)pImgInfo->nSectorSize; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Setting Sector Count %" PRIi64 "\n", __FILE__, __LINE__, pImgInfo->nSectorCount); +#endif /* * Now: what do we do about returning metadata? */ @@ -238,14 +382,17 @@ extern "C" { container_t container; // Find our image. + INT handle = (INT)lpImage; try { std::lock_guard lock(apiLock); - INT handle = (INT)lpImage; auto it = handles->find(handle); if (it != handles->end()) { container = it->second; } else { +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Unknown Handle %d\n", __FILE__, __LINE__, handle); +#endif errno = ENOENT; return 0; } @@ -256,6 +403,10 @@ extern "C" { } std::shared_ptr stream = std::get<2>(container); +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : (%d) Read : %" PRIx64 ":%" PRIx64 "\n", __FILE__, __LINE__, handle, nOfs, nSize); +#endif + // See if a request for Sparse detection was requested. if ((flags & IIO_CHECK_FOR_SPARSE) == IIO_CHECK_FOR_SPARSE) { // Ensure to cap at end of disk @@ -276,6 +427,9 @@ extern "C" { if (isSparse(stream, nOfs, nSize)) { // Only set the bit as required leaving the contents as is. *pFlags |= IIO_SPARSE_DETECTED; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : (%d) Returning Sparse Region %" PRIx64 ":%" PRIx64 "\n", __FILE__, __LINE__, handle, nOfs, nSize); +#endif return nSize; } // We are not sparse, so fall through. @@ -291,6 +445,9 @@ extern "C" { if (read < 0) { read = 0; } +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : (%d) Read complete: %" PRIx64 ":%" PRIx64 " => %" PRIx64 "\n", __FILE__, __LINE__, handle, nOfs, nSize, read); +#endif return read; }; @@ -304,6 +461,9 @@ extern "C" { ) { std::lock_guard lock(apiLock); INT handle = (INT)lpImage; +#if DEBUG + fprintf(aff4::getDebugOutput(), "%s[%d] : Close Handle %d\n", __FILE__, __LINE__, handle); +#endif auto it = handles->find(handle); if (it != handles->end()) { container_t con = it->second; @@ -312,9 +472,20 @@ extern "C" { // And remove the map entry. handles->erase(it); } +#if DEBUG + else { + fprintf(aff4::getDebugOutput(), "%s[%d] : Unknown Handle %d\n", __FILE__, __LINE__, handle); + } +#endif if (lpTextualDescr != NULL) { ::free(lpTextualDescr); } + +#if DEBUG + if (handles->empty()) { + closeLog(); + } +#endif return 1; };