91 lines
2.9 KiB
C
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*)×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;
|
|
}
|