#include #include #include #include #include #include #include #include #include #include #include #include #include using namespace boost; using namespace boost::filesystem; using namespace std; using namespace cryfs; using namespace cpputils; using namespace blockstore; using namespace blockstore::ondisk; using namespace blockstore::lowtohighlevel; using namespace blobstore::onblocks; using namespace blobstore::onblocks::datanodestore; using namespace cryfs::fsblobstore; void printNode(unique_ref node) { std::cout << "BlockId: " << node->blockId().ToString() << ", Depth: " << node->depth() << " "; auto innerNode = dynamic_pointer_move(node); if (innerNode != none) { std::cout << "Type: inner\n"; return; } auto leafNode = dynamic_pointer_move(node); if (leafNode != none) { std::cout << "Type: leaf\n"; return; } } set _getBlockstoreUnaccountedBlocks(const CryConfig &config) { auto onDiskBlockStore = make_unique_ref("/home/heinzi/basedir"); auto encryptedBlockStore = CryCiphers::find(config.Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config.EncryptionKey()); auto highLevelBlockStore = make_unique_ref(std::move(encryptedBlockStore)); auto nodeStore = make_unique_ref(std::move(highLevelBlockStore), config.BlocksizeBytes()); std::set unaccountedBlocks; uint32_t numBlocks = nodeStore->numNodes(); uint32_t i = 0; cout << "There are " << nodeStore->numNodes() << " blocks." << std::endl; // Add all blocks to unaccountedBlocks for (auto file = directory_iterator("/home/heinzi/basedir"); file != directory_iterator(); ++file) { cout << "\r" << (++i) << "/" << numBlocks << flush; if (file->path().filename() != "cryfs.config") { auto blockId = BlockId::FromString(file->path().filename().string().c_str()); unaccountedBlocks.insert(blockId); } } i = 0; cout << "\nRemove blocks that have a parent" << endl; //Remove root block from unaccountedBlocks unaccountedBlocks.erase(BlockId::FromString(config.RootBlob())); //Remove all blocks that have a parent node from unaccountedBlocks for (auto file = directory_iterator("/home/heinzi/basedir"); file != directory_iterator(); ++file) { cout << "\r" << (++i) << "/" << numBlocks << flush; if (file->path().filename() != "cryfs.config") { auto blockId = BlockId::FromString(file->path().filename().string().c_str()); auto node = nodeStore->load(blockId); auto innerNode = dynamic_pointer_move(*node); if (innerNode != none) { for (uint32_t childIndex = 0; childIndex < (*innerNode)->numChildren(); ++childIndex) { auto child = (*innerNode)->readChild(childIndex).blockId(); unaccountedBlocks.erase(child); } } } } return unaccountedBlocks; } set _getBlocksReferencedByDirEntries(const CryConfig &config) { auto onDiskBlockStore = make_unique_ref("/home/heinzi/basedir"); auto encryptedBlockStore = CryCiphers::find(config.Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config.EncryptionKey()); auto highLevelBlockStore = make_unique_ref(std::move(encryptedBlockStore)); auto fsBlobStore = make_unique_ref(make_unique_ref(std::move(highLevelBlockStore), config.BlocksizeBytes())); set blocksReferencedByDirEntries; uint32_t numBlocks = fsBlobStore->numBlocks(); uint32_t i = 0; cout << "\nRemove blocks referenced by dir entries" << endl; for (auto file = directory_iterator("/home/heinzi/basedir"); file != directory_iterator(); ++file) { cout << "\r" << (++i) << "/" << numBlocks << flush; if (file->path().filename() != "cryfs.config") { auto blockId = BlockId::FromString(file->path().filename().string().c_str()); try { auto blob = fsBlobStore->load(blockId); if (blob != none) { auto dir = dynamic_pointer_move(*blob); if (dir != none) { vector children; (*dir)->AppendChildrenTo(&children); for (const auto &child : children) { blocksReferencedByDirEntries.insert((*dir)->GetChild(child.name)->blockId()); } } } } catch (...) {} } } return blocksReferencedByDirEntries; } int main() { cout << "Password: "; string password; getline(cin, password); cout << "Loading config" << endl; auto config = CryConfigFile::load("/home/heinzi/basedir/cryfs.config", password); set unaccountedBlocks = _getBlockstoreUnaccountedBlocks(*config->config()); //Remove all blocks that are referenced by a directory entry from unaccountedBlocks set blocksReferencedByDirEntries = _getBlocksReferencedByDirEntries(*config->config()); for (const auto &blockId : blocksReferencedByDirEntries) { unaccountedBlocks.erase(blockId); } cout << "\nCalculate statistics" << endl; auto onDiskBlockStore = make_unique_ref("/home/heinzi/basedir"); auto encryptedBlockStore = CryCiphers::find(config->config()->Cipher()).createEncryptedBlockstore(std::move(onDiskBlockStore), config->config()->EncryptionKey()); auto highLevelBlockStore = make_unique_ref(std::move(encryptedBlockStore)); auto nodeStore = make_unique_ref(std::move(highLevelBlockStore), config->config()->BlocksizeBytes()); uint32_t numUnaccountedBlocks = unaccountedBlocks.size(); uint32_t numLeaves = 0; uint32_t numInner = 0; cout << "\nUnaccounted blocks: " << unaccountedBlocks.size() << endl; for (const auto &blockId : unaccountedBlocks) { std::cout << "\r" << (numLeaves+numInner) << "/" << numUnaccountedBlocks << flush; auto node = nodeStore->load(blockId); auto innerNode = dynamic_pointer_move(*node); if (innerNode != none) { ++numInner; printNode(std::move(*innerNode)); } auto leafNode = dynamic_pointer_move(*node); if (leafNode != none) { ++numLeaves; printNode(std::move(*leafNode)); } } cout << "\n" << numLeaves << " leaves and " << numInner << " inner nodes" << endl; }