From c12e02acfa580b3d79b4df3406de533ceeefaf84 Mon Sep 17 00:00:00 2001 From: shermp <14854761+shermp@users.noreply.github.com> Date: Sun, 9 Jun 2019 22:08:26 +1200 Subject: [PATCH] Implement differencing read function --- src/minivhd_internal.h | 1 + src/minivhd_io.c | 51 ++++++++++++++++++++++++++++++++++++++++++ src/minivhd_manage.c | 1 + 3 files changed, 53 insertions(+) diff --git a/src/minivhd_internal.h b/src/minivhd_internal.h index 58dc96f..e805d26 100644 --- a/src/minivhd_internal.h +++ b/src/minivhd_internal.h @@ -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); diff --git a/src/minivhd_io.c b/src/minivhd_io.c index b0e8493..520a5f2 100644 --- a/src/minivhd_io.c +++ b/src/minivhd_io.c @@ -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; } \ No newline at end of file diff --git a/src/minivhd_manage.c b/src/minivhd_manage.c index 09cda17..6558589 100644 --- a/src/minivhd_manage.c +++ b/src/minivhd_manage.c @@ -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; }