翻墻不方便。不方便的地方在于前天的梯子,今天就會沒用。所以把手頭用到的東西記錄到墻內(nèi)顯得尤為重要,哪怕只不過是芝麻點兒的小事。
// 小端存儲
struct sparse_header_t {
uint32_t magic; // 幻數(shù), 值為 0xed26ff3a
uint16_t major_version; // 主版本號
uint16_t minor_version; // 副版本號
uint16_t file_hdr_sz; // 文件頭大小, 為28字節(jié),就是這個結(jié)構(gòu)體的尺寸
uint16_t chunk_hdr_sz; // CHUNK的頭大小, 1.0中 固定為12
uint32_t blk_sz; // 塊大小, 必須為4的整數(shù)倍,默認值為:4096
uint32_t total_blks; // 總塊數(shù)
uint32_t total_chunks; // 總CHUNK數(shù)
uint32_t image_checksum; // CRC, 802.3多項式
};
// 什么是CHUNK,什么是BLOCK?
// CHUNK是sparse文件的基本單元,一個sparse文件由28字節(jié)的文件頭加上
// 連續(xù)的CHUNK組成。BLOCK為CHUNK的基本單元,一個CHUNK由一個
// CHUNK頭(12字節(jié))和若干個BLOCK組成,每個BLOCK的大小由文件頭中
// 的blk_sz決定.
enum ChunkType {
CHUNK_TYPE_RAW = 0xcac1, // 該CHUNK中的數(shù)據(jù)為原始數(shù)據(jù), 由若干(頭中的chunk_sz)個塊組成
CHUNK_TYPE_FILL = 0xcac2, // 該CHUNK是填充塊, CHUNK中有4個字節(jié)
// 表示CHUNK定義的若干(頭中的chunk_sz)個塊全部填充為CHUNK中附帶的4個字節(jié)數(shù)據(jù)
CHUNK_TYPE_DONT_CARE = 0xcac3, // 無需關(guān)心的塊, 跳過即可
CHUNK_TYPE_CRC32 = 0xcac4 // CHUNK中數(shù)據(jù)為CRC32, 4字節(jié)
};
#define SPARSE_HEADER_MAGIC 0xed26ff3a
struct chunk_header_t {
uint16_t chunk_type; // CHUNK的類型
uint16_t reserved; // 保留, 用于結(jié)構(gòu)體對齊
uint32_t chunk_sz; // CHUNK中塊的個數(shù)
uint32_t total_sz; // CHUNK的大小, 以字節(jié)為單位,表示CHUNK頭的大小加CHUNK中
// 數(shù)據(jù)大大小, 例如, 對于填充的CHUNK,total_sz為16,對于RAW,
// total_sz為blk_sz * chunk_sz + sizeof(chunk_header_t)
};
測試程序
// 將輸入sparse格式的文件轉(zhuǎn)存為原始格式
void dump(const char* file, const char* file_raw)
{
FILE* fp = fopen(file, "rb");
if (!fp) {
printf("can't open file:%s\n", file);
} else {
sparse_header_t hdr;
ssize_t hdr_sz = fread(&hdr, 1, sizeof(hdr), fp);
if (!check_file_format(&hdr, hdr_sz)) {
printf("\"%s\" is not a sparse file\n", file);
} else {
FILE* fp_raw = fopen(file_raw, "wb");
if (fp_raw) {
// allocate
uint32_t raw_sz = hdr.blk_sz * hdr.total_blks;
printf("Allocated %10u bytes\n", raw_sz);
char* blk = new char[hdr.blk_sz]; memset(blk, 0, hdr.blk_sz);
for (uint32_t k = 0; k < hdr.total_blks; ++k) {
fwrite(blk, 1, hdr.blk_sz, fp_raw);
}
rewind(fp_raw);
uint32_t chunk_cnt = 0;
while (!feof(fp)) {
chunk_header_t chunk;
ssize_t chunk_sz = fread(&chunk, 1, sizeof(chunk), fp);
if (chunk_sz != sizeof(chunk)) break;
switch (chunk.chunk_type) {
case CHUNK_TYPE_RAW:
printf("write raw chunk: %10u bytes\n", hdr.blk_sz*chunk.chunk_sz);
for (uint32_t k = 0; k < chunk.chunk_sz; ++k) {
fread(blk, 1, hdr.blk_sz, fp);
fwrite(blk, 1, hdr.blk_sz, fp_raw);
}
break;
case CHUNK_TYPE_FILL:
uint32_t pattern; fread(&pattern, 1, 4, fp);
for (uint32_t k = 0; k < hdr.blk_sz / 4; ++k) {
*(uint32_t*)(blk + k*4) = pattern;
}
printf("write fil chunk: %10u bytes, pattern:%08x\n",
4*chunk.chunk_sz,
*(uint32_t*)blk);
for (uint32_t k = 0; k < chunk.chunk_sz; ++k) {
fwrite(blk, 1, hdr.blk_sz, fp_raw);
}
break;
case CHUNK_TYPE_CRC32:
fread(blk, 1, 4, fp);
break;
}
}
delete[] blk;
fclose(fp_raw);
} else {
printf("can't create file:%s\n", file_raw);
}
}
fclose(fp);
}
}