#include "header.h" #include "bitmap.h" #include "blocks.h" #include "snapshot.h" #include #include char* headerError; void writeHeader(FILE* fp, size_t diffLength, uint64_t previousTimestamp) { // Magic, identifies a BlockDiff snapshot uint8_t* magic = "BD"; fwrite((void*)magic, 2, sizeof(uint8_t), fp); // Endianess indicator, allows the reconstructing process to know whether // or not it needs to byteswap data fields. uint16_t endianCheck = 0xBEEF; fwrite((void*)&endianCheck, 1, sizeof(uint16_t), fp); // Block size of the snapshot, self explanatory. Must be the same for all // snapshots in a chain. fwrite((void*)&blockSize, 1, sizeof(uint32_t), fp); // The number of blocks that changed in this snapshot. Set to -1 when the // snapshot is a complete disk image and not a diff. uint64_t lengthField = (uint64_t)diffLength; fwrite((void*)&lengthField, 1, sizeof(uint64_t), fp); // Current time of the snapshot being made. This also functions as the // snapshot's identity when reconstructing disk image from snapshots. struct timeval now; gettimeofday(&now, NULL); uint64_t timestamp = (uint64_t)now.tv_sec; fwrite((void*)×tamp, 1, sizeof(uint64_t), fp); // The timestamp of the disk image this one was diffed from. Set to -1 in // the initial snapshot as it has no previous. fwrite((void*)&previousTimestamp, 1, sizeof(uint64_t), fp); } void writeBlockList(FILE* fp, uint64_t totalNumBlocks, uint32_t* bitmap, uint64_t* blockNums) { uint64_t found = 0; for(size_t i = 0; i < totalNumBlocks; i++) { if(getBit(bitmap, i) == 1) { uint64_t blockNum = i; blockNums[found] = blockNum; found += 1; fwrite(&blockNum, 1, sizeof(uint64_t), fp); } } } bool readHeader(FILE* fp, uint64_t* numBlocks, uint64_t* timestamp, uint64_t* previousTimestamp) { uint8_t magic[2]; fread(magic, 2, sizeof(uint8_t), fp); if(magic[0] != 'B' || magic[1] != 'D') { headerError = "Incorrect header magic string. Expected \"BD\".\n"; return false; } uint16_t endianCheck; fread(&endianCheck, 1, sizeof(uint16_t), fp); if(endianCheck == 0xEFBE) { headerError = "Incorrect endian. Not yet supported.\n"; return false; } if(endianCheck != 0xBEEF) { fprintf(stderr, "Incorrect endian check bytes 0x%04X. Expected 0xBEEF or 0xEFBE.\n"); return false; } // TODO: Check that this matches what's already there. fread(&blockSize, 1, sizeof(uint32_t), fp); fread(numBlocks, 1, sizeof(uint64_t), fp); fread(timestamp, 1, sizeof(uint64_t), fp); fread(previousTimestamp, 1, sizeof(uint64_t), fp); return true; } size_t preambleSize(size_t blockCount) { size_t header = HEADER_LENGTH; size_t blockList = blockCount * sizeof(uint64_t); return header + blockList; }