diff --git a/src/config.c b/src/config.c index f7f8d1949..4bcbaf7fa 100644 --- a/src/config.c +++ b/src/config.c @@ -1196,7 +1196,6 @@ load_hard_disks(void) ini_section_delete_var(cat, temp); memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); - memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); sprintf(temp, "hdd_%02i_fn", c + 1); p = ini_section_get_string(cat, temp, ""); @@ -1229,6 +1228,13 @@ load_hard_disks(void) } path_normalize(hdd[c].fn); + sprintf(temp, "hdd_%02i_vhd_blocksize", c + 1); + hdd[c].vhd_blocksize = ini_section_get_int(cat, temp, 0); + + sprintf(temp, "hdd_%02i_vhd_parent", c + 1); + p = ini_section_get_string(cat, temp, ""); + strncpy(hdd[c].vhd_parent, p, sizeof(hdd[c].vhd_parent) - 1); + /* If disk is empty or invalid, mark it for deletion. */ if (!hdd_is_valid(c)) { sprintf(temp, "hdd_%02i_parameters", c + 1); @@ -2806,6 +2812,19 @@ save_hard_disks(void) } else ini_section_delete_var(cat, temp); + sprintf(temp, "hdd_%02i_vhd_blocksize", c + 1); + if (hdd_is_valid(c) && (hdd[c].vhd_blocksize > 0)) + ini_section_set_int(cat, temp, hdd[c].vhd_blocksize); + else + ini_section_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_vhd_parent", c + 1); + if (hdd_is_valid(c) && hdd[c].vhd_parent[0]) { + path_normalize(hdd[c].vhd_parent); + ini_section_set_string(cat, temp, hdd[c].vhd_parent); + } else + ini_section_delete_var(cat, temp); + sprintf(temp, "hdd_%02i_speed", c + 1); if (!hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE && hdd[c].bus != HDD_BUS_ESDI)) ini_section_delete_var(cat, temp); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 2f3389403..856fc382c 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -334,11 +334,35 @@ hdd_image_load(int id) full_size = ((uint64_t) hdd[id].spt) * ((uint64_t) hdd[id].hpc) * ((uint64_t) hdd[id].tracks) << 9LL; hdd_images[id].last_sector = (full_size >> 9LL) - 1; - hdd_images[id].vhd = mvhd_create_fixed(fn, geometry, &vhd_error, NULL); - if (hdd_images[id].vhd == NULL) - fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); + if (hdd[id].vhd_blocksize || hdd[id].vhd_parent[0]) { + MVHDCreationOptions options; +retry_vhd: + options.block_size_in_sectors = hdd[id].vhd_blocksize; + options.path = fn; + options.size_in_bytes = 0; + options.geometry = geometry; + if (hdd[id].vhd_parent[0]) { + options.type = MVHD_TYPE_DIFF; + options.parent_path = hdd[id].vhd_parent; + } else { + options.type = MVHD_TYPE_DYNAMIC; + options.parent_path = NULL; + } + hdd_images[id].vhd = mvhd_create_ex(options, &vhd_error); + } else { + hdd_images[id].vhd = mvhd_create_fixed(fn, geometry, &vhd_error, NULL); + } + if (hdd_images[id].vhd == NULL) { + /* Don't lock out if the parent of a differential VHD doesn't exist. */ + if (hdd[id].vhd_parent[0]) { + hdd[id].vhd_parent[0] = '\0'; + goto retry_vhd; + } + fatal("hdd_image_load(): VHD: Could not create VHD : %s\n", mvhd_strerr(vhd_error)); + } hdd_images[id].type = HDD_IMAGE_VHD; + return 1; } else { hdd_images[id].type = HDD_IMAGE_RAW; @@ -429,9 +453,12 @@ hdd_image_load(int id) fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn); } - hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; - hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; - hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + hdd[id].tracks = hdd_images[id].vhd->footer.geom.cyl; + hdd[id].hpc = hdd_images[id].vhd->footer.geom.heads; + hdd[id].spt = hdd_images[id].vhd->footer.geom.spt; + hdd[id].vhd_blocksize = (hdd_images[id].vhd->footer.disk_type == MVHD_TYPE_FIXED) ? 0 : (hdd_images[id].vhd->sparse.block_sz / MVHD_SECTOR_SIZE); + if (hdd_images[id].vhd->parent && hdd_images[id].vhd->parent->filename[0]) + strncpy(hdd[id].vhd_parent, hdd_images[id].vhd->parent->filename, sizeof(hdd[id].vhd_parent) - 1); full_size = ((uint64_t) hdd[id].spt) * ((uint64_t) hdd[id].hpc) * ((uint64_t) hdd[id].tracks) << 9LL; hdd_images[id].type = HDD_IMAGE_VHD; /* If we're here, this means there is a valid VHD footer in the @@ -628,9 +655,6 @@ hdd_image_unload(uint8_t id, int fn_preserve) hdd_images[id].last_sector = -1; - memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); - if (fn_preserve) - strcpy(hdd[id].prev_fn, hdd[id].fn); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); } diff --git a/src/include/86box/hdd.h b/src/include/86box/hdd.h index 58fff9ffd..1508939ba 100644 --- a/src/include/86box/hdd.h +++ b/src/include/86box/hdd.h @@ -154,8 +154,8 @@ typedef struct { void *priv; - char fn[1024], /* Name of current image file */ - prev_fn[1024]; /* Name of previous image file */ + char fn[1024]; /* Name of current image file */ + char vhd_parent[1041]; /* Differential VHD parent file */ uint32_t res0, pad1, base, @@ -176,6 +176,7 @@ typedef struct { uint32_t cur_addr; uint32_t speed_preset; + uint32_t vhd_blocksize; double avg_rotation_lat_usec; double full_stroke_usec;