New Syntax Highlighting Style Test - C++

08/10/2018

Just updated the code syntax highlighting style. This is a sample of C++ codes from btrForensics.

//! \file
//! \author Shujian Yang
//!
//! Implementation of class BtrfsPool.

#include <map>
#include <sstream>
#include <iomanip>
#include "BtrfsPool.h"
#include "Functions.h"

using namespace std;

namespace btrForensics {

//! Constructor of Btrfs pool
//!
//! \param img Image file.
//! \param end The endianess of the array.
//! \param devOffsets Offsets of different devices
//! \param fsRootId Id of root of Filesystem Tree.
//!
BtrfsPool::BtrfsPool(TSK_IMG_INFO *img, TSK_ENDIAN_ENUM end,
        vector<TSK_OFF_T> devOffsets, uint64_t fsRootId)
    :image(img), endian(end)
{
    uint64_t devCount(0);
    for(auto dev_off : devOffsets) {
        char *diskArr = new char[SuperBlock::SUPBLK_SIZE]();
        tsk_img_read(img, dev_off + SuperBlock::SUPBLK_ADDR, diskArr, SuperBlock::SUPBLK_SIZE);
        SuperBlock *supblk = new SuperBlock(TSK_LIT_ENDIAN, (uint8_t*)diskArr);

        if(fsUUID.isUnused()) {
            fsUUID = supblk->fsUUID;
        }
        else if(fsUUID != supblk->fsUUID) {
            ostringstream oss;
            oss << "Found superblocks do not belong to the same pool.\n";
            oss << "The following different filesystem UUIDs were found:\n";
            oss << supblk->fsUUID.encode() << '\n';
            oss << fsUUID.encode() << '\n';
            throw FsDeviceException(oss.str());
        }

        const DevData *dev = &(supblk->devItemData);
        deviceTable[dev->deviceId] = new DeviceRecord(dev->deviceId,
                                        dev_off, dev->devUUID, supblk);

        devCount = supblk->numDevices;
    }

    if(devOffsets.size() != devCount) {
        ostringstream oss;
        oss << "Input incomplete: device(s) missing.\n";
        oss << std::dec;
        oss << "Expected device number: " << devCount << '\n';
        oss << "Input device number: " << devOffsets.size() << '\n'; 
        throw FsDeviceException(oss.str());
    }
    
    primarySupblk = deviceTable[1]->superBlk;

    initializeChunkTree();
    initializeRootTree();
    initializeFileTree(fsRootId);
}


//! Destructor
BtrfsPool::~BtrfsPool()
{
    if(primarySupblk != nullptr)
        delete primarySupblk;
    for(auto &record : deviceTable) {
        delete record.second;
        record.second = nullptr;
    }
}


//! List devices of the pool
//!
//! \return String of device description
//!
string BtrfsPool::devInfo() const
{
    ostringstream oss;
    oss << "All devices accepted. Device number: " << deviceTable.size() << "\n";
    oss << "Pool UUID: " << fsUUID.encode() << "\n";
    oss << "-----------------------------------" << "\n";

    for(const auto dev : deviceTable) {
        oss << (dev.second)->devInfo() << "\n";
    }
    
    return oss.str();
}


//! Find device offset within the image in bytes
//! 
//! \param devId
//!
//! \return Device offset in bytes.
//!
uint64_t BtrfsPool::getDevOffset(uint64_t devId) const
{
    return deviceTable.at(devId)->deviceOffset;
}


//! Get the physical addresses from a chunk item.
//!
//! \param logicalAddr Logical address to convert.
//! \param key Key storing chunk logical address.
//! \param chunkData Chunk item data storing corresponding physical address.
//!
//! \return Mapped physical address. 0 if not valid.
//!
vector<uint64_t> BtrfsPool::getAddrFromChunk(uint64_t logicalAddr,
        const BtrfsKey* key, const ChunkData* chunkData) const
{
    vector<uint64_t> physicalAddrs;
    uint64_t chunkLogical = key->offset; //Key offset stores logical address.

    //Input logical address should be larger than chunk logial address.
    if(logicalAddr < chunkLogical)
        throw FsDamagedException("Superblock chunk item error."
                "Unable to map logical address to physical address.");

    //There should be at least one stripe within the chunk data.
    if(chunkData->numStripe == 0)
        throw FsDamagedException("Superblock chunk item error. No stripe found.");
    else if(chunkData->numStripe > 1)
        throw FsDamagedException("Test only: This chunk has more than 1 stripes!");

    for(const auto &stripe : chunkData->btrStripes) {
        //Get device offset from stripe device ID
        uint64_t deviceOffset = getDevOffset(stripe->deviceId);
        //Data offset stores relative physical address.
        uint64_t chunkPhysical = deviceOffset + stripe->offset; 
    
        physicalAddrs.push_back(logicalAddr - chunkLogical + chunkPhysical);
    }

    return physicalAddrs;
}


//! Read data from image based on given logical address and chunk.
//!
//! \param[out] data Array with data read from image
//! \param logicalAddr Logical address of data.
//! \param key Btrfs chunk item key.
//! \param chunkData Btrfs chunk item data.
//! \param size Size of data.
//!
//! \return Starting physcial address of data in the image.
//! 
uint64_t BtrfsPool::readChunkData(char *data, uint64_t logicalAddr,
        const BtrfsKey* key, const ChunkData* chunkData, const uint64_t size) const
{
    vector<uint64_t> physicalAddrs = getAddrFromChunk(logicalAddr, key, chunkData);

    uint64_t readSize(0);
    uint64_t length = chunkData->stripeLength;
    for(const auto &addr: physicalAddrs) {
        while(size - readSize > length) {
            tsk_img_read(image, addr + readSize, data + readSize, length);
            readSize += length;
        }
        tsk_img_read(image, addr + readSize, data + readSize, size - readSize);
    }

    return physicalAddrs[0];
}


//! Read data from image based on given logical address.
//!
//! \param[out] data Array with data read from image
//! \param logicalAddr Logical address of data.
//! \param size Size of data.
//!
//! \return Starting physcial address of data in the image.
//! 
uint64_t BtrfsPool::readData(char *data, uint64_t logicalAddr,
                            const uint64_t size) const
{
    const ChunkItem* chunk = chunkTree->getChunkItem(logicalAddr);
    return readChunkData(data, logicalAddr, &(chunk->itemHead->key), &(chunk->data), size);
}


//! Initialize the chunk tree of the pool
void BtrfsPool::initializeChunkTree()
{
    chunkTree = new ChunkTree(this);
}


//! Initialize root of Root Tree.
void BtrfsPool::initializeRootTree()
{
    uint64_t rootTreeLogAddr = primarySupblk->getRootLogAddr();

    char* diskArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
    uint64_t rootTreePhyAddr = readData(diskArr, rootTreeLogAddr, BtrfsHeader::SIZE_OF_HEADER);

    BtrfsHeader* rootHeader = new BtrfsHeader(endian, (uint8_t*)diskArr);
    delete [] diskArr;

    uint64_t itemListStart = rootTreePhyAddr + BtrfsHeader::SIZE_OF_HEADER;
    if(rootHeader->isLeafNode())
        rootTree = new LeafNode(image, rootHeader, endian, itemListStart);
    else
        rootTree = new InternalNode(image, rootHeader, endian, itemListStart);
}


//! Initialize file system tree.
//!
//! \param fsRootId Subvolume id
//!
void BtrfsPool::initializeFileTree(uint64_t fsRootId)
{
    if(fsRootId == 0){
        uint64_t defaultId = getDefaultFsId();

        fsTree = new FilesystemTree(rootTree, defaultId, this);
        fsTreeDefault = fsTree;
    }
    else{
        const BtrfsItem* foundItem;
        if(treeSearchById(rootTree, fsRootId,
            [&foundItem](const LeafNode* leaf, uint64_t targetId)
            { return searchForItem(leaf, targetId, ItemType::ROOT_BACKREF, foundItem); })) {
            fsTree = new FilesystemTree(rootTree, fsRootId, this);
            fsTreeDefault = fsTree;
        }
        else
            throw runtime_error("The argument of -s option is not a valid subvolume id.");
    }
}


//! Obatin root item id of default volume (filesystem tree).
uint64_t BtrfsPool::getDefaultFsId()
{
    //Technically, the default volume id should be found in offset 0x80 in superblock.
    //Currently, it is set as 6 by default.
    uint64_t defaultDirId(6);

    uint64_t defaultId(0);
    const BtrfsItem* foundItem;
    if(treeSearchById(rootTree, defaultDirId,
            [&foundItem](const LeafNode* leaf, uint64_t targetId)
            { return searchForItem(leaf, targetId, ItemType::DIR_ITEM, foundItem); })) {
        const DirItem* dir = static_cast<const DirItem*>(foundItem);
        defaultId = dir->targetKey.objId; //This is id of root item to filesystem tree.
    }
    else 
        throw FsDamagedException("Default directory dir item not found.");

    return defaultId;
}


//! Navigate to selected node and print information.
//!
//! \param root Starting root node.
//! \param os Output stream where the infomation is printed.
//! \param is Input stream telling which node is the one to be read.
//!
void BtrfsPool::navigateNodes(const BtrfsNode* root,
        std::ostream& os, std::istream& is) const
{
    const BtrfsNode *node = root;
    const BtrfsHeader *header;
    while(true) {
        header = node->nodeHeader;
        os << node->info() << endl;

        uint64_t offset(0);
        map<uint64_t, uint64_t> nodeAddrs;
        if(header->isLeafNode()){
            const LeafNode *leaf = static_cast<const LeafNode*>(node);

            for(auto item : leaf->itemList){
                if(item->getItemType() == ItemType::ROOT_ITEM){
                    const RootItem *rootItm = static_cast<const RootItem*>(item);
                    nodeAddrs[item->getId()]
                        = rootItm->getBlockNumber();
                }
            }
        }
        else {
            const InternalNode* internal = static_cast<const InternalNode*>(node);

            for(auto ptr : internal->keyPointers) {
                nodeAddrs[ptr->key.objId] = ptr->getBlkNum();
            }
        }

        if(nodeAddrs.size() == 0) {
            os << "This is a leaf node with no root items." << endl;
            break;
        }

        bool quit(false);
        string input;
        uint64_t inputId;
        while(true) {
            os << "Child nodes or tree roots with following object ids are found." << endl;
            for(auto addr : nodeAddrs) {
                if(header->isLeafNode())
                    os << dec << addr.first << " ";
                else
                    os << dec << "[" << addr.first << "] ";
            }
                
            os << endl;
            os << "To read a child node or a tree root, please enter its object id in the list: ";
            os << "(Enter 'q' to quit.)" << endl;
            is >> input;
            
            if(input == "q") return;

            stringstream(input) >> inputId;
            if(nodeAddrs.find(inputId) != nodeAddrs.end()) break;
            os << "Wrong object id, please enter a correct one.\n" << endl;
        }
        os << endl;

        bool nodeExisted(false);
        using ConstNodePtr = const BtrfsNode*;
        ConstNodePtr* childPtr(nullptr);
        if(!header->isLeafNode()) {
            const InternalNode* internal = static_cast<const InternalNode*>(node);

            for(auto ptr : internal->keyPointers) {
                if(ptr->key.objId == inputId && ptr->childNode != nullptr) {
                    node = ptr->childNode;
                    nodeExisted = true;
                    break;
                }
                else if(ptr->key.objId == inputId) {
                    childPtr = &ptr->childNode;
                    break;
                }
            }
        }
        if(nodeExisted) continue; //The child node has already been built.

        offset = nodeAddrs[inputId];
        char *headerArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
        uint64_t physicalAddr = readData(headerArr, offset, BtrfsHeader::SIZE_OF_HEADER);
        header = new BtrfsHeader(TSK_LIT_ENDIAN, (uint8_t*)headerArr);
        delete [] headerArr;

        uint64_t itemOffset = physicalAddr + BtrfsHeader::SIZE_OF_HEADER;

        if(header->isLeafNode()){
            node = new LeafNode(image, header, endian, itemOffset);
        }
        else {
            node = new InternalNode(image, header, endian, itemOffset);
        }

        if(childPtr!=nullptr)
            *childPtr = node;
    }
}


//! Switch to a subvolume or snapshot and exploere files within.
//!
//! \param os Output stream where the infomation is printed.
//! \param is Input stream telling which node is the one to be read.
//! \return True if switched.
//!
bool BtrfsPool::switchFsTrees(ostream& os, istream& is)
{
    vector<const BtrfsItem*> foundRootRefs;
    treeTraverse(rootTree, [&foundRootRefs](const LeafNode* leaf)
            { return filterItems(leaf, ItemType::ROOT_BACKREF, foundRootRefs); });
    
    if(foundRootRefs.size() == 0) {
        os << "\nNo subvolumes or snapshots are found.\n" << endl;
        return false;
    }

    uint64_t selectedId(0);
    while(true) {
        os << "The following subvolumes or snapshots are found:" << endl;
        int index(0);
        for(auto item : foundRootRefs) {
            const RootRef* ref = static_cast<const RootRef*>(item);
            os << "[" << dec << setfill(' ') << setw(2) << ++index << "] "
                << setw(7) << ref->getId() << "   " << ref->getDirName() << '\n';
        }
        os << endl;

        string input;
        os << "To visit a subvolume or snapshot, please enter its index in the list:\n";
        os << "(Enter ''q' to quit.)" << endl;
        is >> input;

        if(input == "q") return false;
        int inputIndex;
        stringstream(input) >> inputIndex;
        if(inputIndex > 0 && inputIndex <= foundRootRefs.size()) {
            selectedId = foundRootRefs[inputIndex-1]->getId();
            break;
        }
        os << "Wrong index, please enter a correct one.\n\n\n" << endl;
    }
    
    fsTree = new FilesystemTree(rootTree, selectedId, this);
    os << "\n" << std::string(60, '=') << "\n";
    os << endl;
    return true;
}


//! Recursively traverse child nodes and process it if it is a leaf node.
//!
//! \param node Node being processed.
//! \param readOnlyFunc A function type which accepts a LeafNode* 
//!        and a vector<uint64_t>& parameters and returns void.
//!
void BtrfsPool::treeTraverse(const BtrfsNode *node,
        function<void(const LeafNode*)> readOnlyFunc) const
{
    if(node->nodeHeader->isLeafNode()){
        const LeafNode* leaf = static_cast<const LeafNode*>(node);
        readOnlyFunc(leaf);
    }
    else {
        const InternalNode* internal = static_cast<const InternalNode*>(node);
        const BtrfsNode *newNode;

        for(auto ptr : internal->keyPointers) {
            if(ptr->childNode != nullptr) {
                newNode = ptr->childNode;
            }
            else {
                char *headerArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
                uint64_t physicalAddr = readData(headerArr, ptr->getBlkNum(),
                    BtrfsHeader::SIZE_OF_HEADER);
                BtrfsHeader *header = new BtrfsHeader(TSK_LIT_ENDIAN, (uint8_t*)headerArr);
                delete [] headerArr; 

                uint64_t itemOffset = physicalAddr + BtrfsHeader::SIZE_OF_HEADER;

                if(header->isLeafNode()){
                    newNode = new LeafNode(image, header, endian, itemOffset);
                }
                else {
                    newNode = new InternalNode(image, header, endian, itemOffset);
                }

                ptr->childNode = newNode;
            }

            if(newNode != nullptr)
                treeTraverse(newNode, readOnlyFunc);
        }
    }
}


//! Recursively traverse nodes in chunk tree and search if it is a leaf node.
//!
//! \param node Node being processed.
//! \param searchFunc A function type which accepts a LeafNode* 
//!        parameter and returns true if certain object is found.
//! \return True if target is found in leaf node.
//!
bool BtrfsPool::chunkTreeSearch(const BtrfsNode *node,
        function<bool(const LeafNode*)> searchFunc) const
{
    if(node->nodeHeader->isLeafNode()){
        const LeafNode *leaf = static_cast<const LeafNode*>(node);
        return searchFunc(leaf);
    }
    else {
        const InternalNode *internal = static_cast<const InternalNode*>(node);
        const BtrfsNode *newNode;

        for(auto ptr : internal->keyPointers) {
            if(ptr->childNode != nullptr) {
                newNode = ptr->childNode;
            }
            else {
                const SuperBlock *supBlk = primarySupblk;
                char *headerArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
                uint64_t physicalAddr = readChunkData(headerArr, ptr->getBlkNum(),
                    &(supBlk->chunkKey), &(supBlk->chunkData),
                    BtrfsHeader::SIZE_OF_HEADER);

                BtrfsHeader *header = new BtrfsHeader(TSK_LIT_ENDIAN, (uint8_t*)headerArr);
                delete [] headerArr; 

                uint64_t itemOffset = physicalAddr + BtrfsHeader::SIZE_OF_HEADER;
                
                if(header->isLeafNode()){
                    newNode = new LeafNode(image, header, endian, itemOffset);
                }
                else {
                    newNode = new InternalNode(image, header, endian, itemOffset);
                }

                ptr->childNode = newNode;
            }

            if(newNode != nullptr && treeSearch(newNode, searchFunc))
                return true;
        }
        return false;
    }
}


//! Recursively traverse child nodes and search if it is a leaf node.
//!
//! \param node Node being processed.
//! \param searchFunc A function type which accepts a LeafNode* 
//!        parameter and returns true if certain object is found.
//! \return True if target is found in leaf node.
//!
bool BtrfsPool::treeSearch(const BtrfsNode *node,
        function<bool(const LeafNode*)> searchFunc) const
{
    if(node->nodeHeader->isLeafNode()){
        const LeafNode *leaf = static_cast<const LeafNode*>(node);
        return searchFunc(leaf);
    }
    else {
        const InternalNode *internal = static_cast<const InternalNode*>(node);
        const BtrfsNode *newNode;

        for(auto ptr : internal->keyPointers) {
            if(ptr->childNode != nullptr) {
                newNode = ptr->childNode;
            }
            else {
                char *headerArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
                uint64_t physicalAddr = readData(headerArr, ptr->getBlkNum(),
                    BtrfsHeader::SIZE_OF_HEADER);

                BtrfsHeader *header = new BtrfsHeader(TSK_LIT_ENDIAN, (uint8_t*)headerArr);
                delete [] headerArr; 

                uint64_t itemOffset = physicalAddr + BtrfsHeader::SIZE_OF_HEADER;
                
                if(header->isLeafNode()){
                    newNode = new LeafNode(image, header, endian, itemOffset);
                }
                else {
                    newNode = new InternalNode(image, header, endian, itemOffset);
                }

                ptr->childNode = newNode;
            }

            if(newNode != nullptr && treeSearch(newNode, searchFunc))
                return true;
        }
        return false;
    }
}


//! Recursively traverse child nodes and search if it is a leaf node.
//!
//! \param node Node being processed.
//! \param targetId Object id of target to search for.
//! \param searchFunc A function type which accepts a LeafNode* 
//!        parameter and returns true if certain object is found.
//! \return True if target is found in leaf node.
//!
bool BtrfsPool::treeSearchById(const BtrfsNode *node, uint64_t targetId,
        function<bool(const LeafNode*, uint64_t)> searchFunc) const
{
    if(node->nodeHeader->isLeafNode()){
        const LeafNode *leaf = static_cast<const LeafNode*>(node);
        return searchFunc(leaf, targetId);
    }
    else {
        const InternalNode *internal = static_cast<const InternalNode*>(node);
        const BtrfsNode *newNode;

        const auto &vecPtr = internal->keyPointers;
        for(int i=0; i<vecPtr.size();++i) {
            auto ptr = vecPtr[i];
            if(ptr->key.objId > targetId)
                return false;
            if(ptr->key.objId<targetId && i!=vecPtr.size()-1
                    && vecPtr[i+1]->key.objId<targetId)
                continue;

            if(ptr->childNode != nullptr) {
                newNode = ptr->childNode;
            }
            else {
                char *headerArr = new char[BtrfsHeader::SIZE_OF_HEADER]();
                uint64_t physicalAddr = readData(headerArr, ptr->getBlkNum(),
                    BtrfsHeader::SIZE_OF_HEADER);
                BtrfsHeader *header = new BtrfsHeader(TSK_LIT_ENDIAN, (uint8_t*)headerArr);
                delete [] headerArr; 

                uint64_t itemOffset = physicalAddr + BtrfsHeader::SIZE_OF_HEADER;
                
                if(header->isLeafNode()){
                    newNode = new LeafNode(image, header, endian, itemOffset);
                }
                else {
                    newNode = new InternalNode(image, header, endian, itemOffset);
                }

                ptr->childNode = newNode;
            }

            if(newNode != nullptr && treeSearchById(newNode, targetId, searchFunc))
                return true;
        }
        return false;
    }
}

}
Back to Top

SYANG.IO © 2018