bindiff/src/header.c
2025-05-23 15:16:40 +02:00

91 lines
2.9 KiB
C

#include "header.h"
#include "bitmap.h"
#include "blocks.h"
#include "snapshot.h"
#include <stdlib.h>
#include <sys/time.h>
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*)&timestamp, 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;
}