Implement differencing read function

This commit is contained in:
shermp
2019-06-09 22:08:26 +12:00
parent 72c50c5b1e
commit c12e02acfa
3 changed files with 53 additions and 0 deletions

View File

@@ -59,6 +59,7 @@ typedef struct MVHDSparseHeader {
typedef struct MVHDBlock {
uint8_t* bitmap;
uint32_t offset;
bool bitmap_cached;
} MVHDBlock;
bool mvhd_is_conectix_str(const void* buffer);

View File

@@ -3,6 +3,13 @@
#include "minivhd_internal.h"
#include "minivhd.h"
/* The following bit array macros adapted from
http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */
#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) )
#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) )
#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) )
static inline void mvhd_check_sectors(int offset, int num_sectors, int total_sectors, int* transfer_sect, int* trunc_sect) {
*transfer_sect = num_sectors;
*trunc_sect = 0;
@@ -11,6 +18,20 @@ static inline void mvhd_check_sectors(int offset, int num_sectors, int total_sec
*trunc_sect = num_sectors - *transfer_sect;
}
}
static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) {
if (!vhdm->block[blk].bitmap_cached) {
if (vhdm->block[blk].bitmap == NULL) {
vhdm->block[blk].bitmap = calloc(vhdm->bm_sect_count, MVHD_SECTOR_SIZE);
}
if (vhdm->block[blk].offset != MVHD_SPARSE_BLK) {
fseeko64(vhdm->f, vhdm->block[blk].offset * MVHD_SECTOR_SIZE, SEEK_SET);
fread(vhdm->block[blk].bitmap, vhdm->bm_sect_count * MVHD_SECTOR_SIZE, 1, vhdm->f);
}
vhdm->block[blk].bitmap_cached = true;
}
}
int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) {
int64_t addr;
int transfer_sectors, truncated_sectors;
@@ -47,4 +68,34 @@ int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff
buff += MVHD_SECTOR_SIZE;
}
return truncated_sectors;
}
int mvhd_diff_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) {
int transfer_sectors, truncated_sectors;
int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt;
mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors);
uint8_t* buff = (uint8_t*)out_buff;
MVHDMeta* curr_vhdm = vhdm;
int s, ls, blk, sib;
ls = offset + transfer_sectors;
for (s = offset; s <= ls; s++) {
blk = s / vhdm->sect_per_block;
sib = s % vhdm->sect_per_block;
while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) {
mvhd_read_sect_bitmap(vhdm, blk);
if (VHD_TESTBIT(curr_vhdm->block[blk].bitmap, sib)) {
curr_vhdm = curr_vhdm->parent;
} else { break; }
}
/* We handle actual sector reading using the fixed or sparse functions,
as a differencing VHD is also a sparse VHD */
if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
mvhd_sparse_read(curr_vhdm, s, 1, buff);
} else {
mvhd_fixed_read(curr_vhdm, s, 1, buff);
}
curr_vhdm = vhdm;
buff += MVHD_SECTOR_SIZE;
}
return truncated_sectors;
}

View File

@@ -83,6 +83,7 @@ static MVHDBlock* mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) {
for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) {
fread(&vhdm->block[i].offset, sizeof vhdm->block[i].offset, 1, vhdm->f);
vhdm->block[i].bitmap = NULL;
vhdm->block[i].bitmap_cached = false;
}
return vhdm->block;
}