Add VHD support.

This commit is contained in:
Stephen McKinney
2020-11-17 23:31:38 -06:00
parent 3085b1579f
commit d91056586e
11 changed files with 763 additions and 332 deletions

View File

@@ -32,14 +32,21 @@
#include <86box/plat.h>
#include <86box/random.h>
#include <86box/hdd.h>
#include "minivhd/minivhd.h"
#include "minivhd/minivhd_internal.h"
#define HDD_IMAGE_RAW 0
#define HDD_IMAGE_HDI 1
#define HDD_IMAGE_HDX 2
#define HDD_IMAGE_VHD 3
typedef struct
{
FILE *file;
FILE *file; /* Used for HDD_IMAGE_RAW, HDD_IMAGE_HDI, and HDD_IMAGE_HDX. */
MVHDMeta* vhd; /* Used for HDD_IMAGE_VHD. */
uint32_t base;
uint32_t pos, last_sector;
uint8_t type;
uint8_t type; /* HDD_IMAGE_RAW, HDD_IMAGE_HDI, HDD_IMAGE_HDX, or HDD_IMAGE_VHD */
uint8_t loaded;
} hdd_image_t;
@@ -59,16 +66,15 @@ hdd_image_log(const char *fmt, ...)
va_list ap;
if (hdd_image_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
#define hdd_image_log(fmt, ...)
#endif
int
image_is_hdi(const wchar_t *s)
{
@@ -77,12 +83,12 @@ image_is_hdi(const wchar_t *s)
char *ws = (char *) s;
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (! wcscasecmp(ext, L".HDI"))
return 1;
return 1;
else
return 0;
return 0;
}
@@ -97,34 +103,34 @@ image_is_hdx(const wchar_t *s, int check_signature)
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (wcscasecmp(ext, L".HDX") == 0) {
if (check_signature) {
f = plat_fopen((wchar_t *)s, L"rb");
if (!f)
return 0;
if (fseeko64(f, 0, SEEK_END))
fatal("image_is_hdx(): Error while seeking");
filelen = ftello64(f);
if (fseeko64(f, 0, SEEK_SET))
fatal("image_is_hdx(): Error while seeking");
if (filelen < 44) {
if (f != NULL)
fclose(f);
return 0;
}
if (fread(&signature, 1, 8, f) != 8)
fatal("image_is_hdx(): Error reading signature\n");
fclose(f);
if (signature == 0xD778A82044445459ll)
return 1;
else
return 0;
} else
return 1;
if (check_signature) {
f = plat_fopen((wchar_t *)s, L"rb");
if (!f)
return 0;
if (fseeko64(f, 0, SEEK_END))
fatal("image_is_hdx(): Error while seeking");
filelen = ftello64(f);
if (fseeko64(f, 0, SEEK_SET))
fatal("image_is_hdx(): Error while seeking");
if (filelen < 44) {
if (f != NULL)
fclose(f);
return 0;
}
if (fread(&signature, 1, 8, f) != 8)
fatal("image_is_hdx(): Error reading signature\n");
fclose(f);
if (signature == 0xD778A82044445459ll)
return 1;
else
return 0;
} else
return 1;
} else
return 0;
return 0;
}
@@ -132,22 +138,26 @@ int
image_is_vhd(const wchar_t *s, int check_signature)
{
int len;
FILE* f;
char *ws = (char *) s;
wchar_t ext[5] = { 0, 0, 0, 0, 0 };
len = wcslen(s);
if ((len < 4) || (s[0] == L'.'))
return 0;
return 0;
memcpy(ext, ws + ((len - 4) << 1), 8);
if (wcscasecmp(ext, L".VHD") == 0) {
if (check_signature) {
// if is VHD
return 1;
// else
// return 0;
} else
return 1;
if (check_signature) {
f = plat_fopen((wchar_t*)s, L"rb");
if (!f)
return 0;
bool is_vhd = mvhd_file_is_vhd(f);
fclose(f);
return is_vhd ? 1 : 0;
} else
return 1;
} else
return 0;
return 0;
}
void
@@ -158,28 +168,28 @@ hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size)
uint64_t ts = ((uint64_t) size) << 11LL;
uint32_t spt, heads, cyl, cth;
if (ts > 65535 * 16 * 255)
ts = 65535 * 16 * 255;
ts = 65535 * 16 * 255;
if (ts >= 65535 * 16 * 63) {
spt = 255;
heads = 16;
cth = (uint32_t) (ts / spt);
spt = 255;
heads = 16;
cth = (uint32_t) (ts / spt);
} else {
spt = 17;
cth = (uint32_t) (ts / spt);
heads = (cth +1023) / 1024;
if (heads < 4)
heads = 4;
if ((cth >= (heads * 1024)) || (heads > 16)) {
spt = 31;
heads = 16;
cth = (uint32_t) (ts / spt);
}
if (cth >= (heads * 1024)) {
spt = 63;
heads = 16;
cth = (uint32_t) (ts / spt);
}
spt = 17;
cth = (uint32_t) (ts / spt);
heads = (cth +1023) / 1024;
if (heads < 4)
heads = 4;
if ((cth >= (heads * 1024)) || (heads > 16)) {
spt = 31;
heads = 16;
cth = (uint32_t) (ts / spt);
}
if (cth >= (heads * 1024)) {
spt = 63;
heads = 16;
cth = (uint32_t) (ts / spt);
}
}
cyl = cth / heads;
*c = cyl;
@@ -209,18 +219,18 @@ prepare_new_hard_disk(uint8_t id, uint64_t full_size)
/* First, write all the 1 MB blocks. */
if (t > 0) {
for (i = 0; i < t; i++) {
fseek(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file);
pclog("#");
}
for (i = 0; i < t; i++) {
fseek(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector_1mb, 1, 1048576, hdd_images[id].file);
pclog("#");
}
}
/* Then, write the remainder. */
if (size > 0) {
fseek(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector_1mb, 1, size, hdd_images[id].file);
pclog("#");
fseek(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector_1mb, 1, size, hdd_images[id].file);
pclog("#");
}
pclog("]\n");
/* Switch the suppression of seen messages back on. */
@@ -242,7 +252,7 @@ hdd_image_init(void)
int i;
for (i = 0; i < HDD_NUM; i++)
memset(&hdd_images[i], 0, sizeof(hdd_image_t));
memset(&hdd_images[i], 0, sizeof(hdd_image_t));
}
int
@@ -256,19 +266,25 @@ hdd_image_load(int id)
int c, ret;
uint64_t s = 0;
wchar_t *fn = hdd[id].fn;
char fn_multibyte_buf[1200];
int is_hdx[2] = { 0, 0 };
int is_vhd[2] = { 0, 0 };
int is_vhd[2] = { 0, 0 };
int vhd_error = 0;
memset(empty_sector, 0, sizeof(empty_sector));
hdd_images[id].base = 0;
if (hdd_images[id].loaded) {
if (hdd_images[id].file) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
hdd_images[id].loaded = 0;
if (hdd_images[id].file) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
else if (hdd_images[id].vhd) {
mvhd_close(hdd_images[id].vhd);
hdd_images[id].vhd = NULL;
}
hdd_images[id].loaded = 0;
}
is_hdx[0] = image_is_hdx(fn, 0);
@@ -281,172 +297,199 @@ hdd_image_load(int id)
/* Try to open existing hard disk image */
if (fn[0] == '.') {
hdd_image_log("File name starts with .\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
hdd_image_log("File name starts with .\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].file = plat_fopen(fn, L"rb+");
if (hdd_images[id].file == NULL) {
/* Failed to open existing hard disk image */
if (errno == ENOENT) {
/* Failed because it does not exist,
so try to create new file */
if (hdd[id].wp) {
hdd_image_log("A write-protected image must exist\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
/* Failed to open existing hard disk image */
if (errno == ENOENT) {
/* Failed because it does not exist,
so try to create new file */
if (hdd[id].wp) {
hdd_image_log("A write-protected image must exist\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
hdd_images[id].file = plat_fopen(fn, L"wb+");
if (hdd_images[id].file == NULL) {
hdd_image_log("Unable to open image\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
} else {
if (image_is_hdi(fn)) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x1000;
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fwrite(&full_size, 1, 4, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
for (c = 0; c < 0x3f8; c++)
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 1;
} else if (is_hdx[0]) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x28;
fwrite(&signature, 1, 8, hdd_images[id].file);
fwrite(&full_size, 1, 8, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
}
else
hdd_images[id].type = 0;
hdd_images[id].last_sector = 0;
}
hdd_images[id].file = plat_fopen(fn, L"wb+");
if (hdd_images[id].file == NULL) {
hdd_image_log("Unable to open image\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
} else {
if (image_is_hdi(fn)) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x1000;
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file);
fwrite(&full_size, 1, 4, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
for (c = 0; c < 0x3f8; c++)
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = HDD_IMAGE_HDI;
} else if (is_hdx[0]) {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].base = 0x28;
fwrite(&signature, 1, 8, hdd_images[id].file);
fwrite(&full_size, 1, 8, hdd_images[id].file);
fwrite(&sector_size, 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
fwrite(&zero, 1, 4, hdd_images[id].file);
hdd_images[id].type = HDD_IMAGE_HDX;
} else if (is_vhd[0]) {
fclose(hdd_images[id].file);
MVHDGeom geometry;
geometry.cyl = hdd[id].tracks;
geometry.heads = hdd[id].hpc;
geometry.spt = hdd[id].spt;
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
s = full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf);
hdd_images[id].vhd = mvhd_create_fixed(fn_multibyte_buf, 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));
ret = prepare_new_hard_disk(id, full_size);
hdd_images[id].type = HDD_IMAGE_VHD;
return 1;
} else {
hdd_images[id].type = HDD_IMAGE_RAW;
}
hdd_images[id].last_sector = 0;
}
if (is_vhd[0]) {
/* VHD image. */
hdd_images[id].type = 3;
}
s = full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
return ret;
} else {
/* Failed for another reason */
hdd_image_log("Failed for another reason\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
ret = prepare_new_hard_disk(id, full_size);
return ret;
} else {
/* Failed for another reason */
hdd_image_log("Failed for another reason\n");
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
} else {
if (image_is_hdi(fn)) {
if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n");
if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading base offset\n");
if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n");
full_size = 0LL;
if (fread(&full_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading full size\n");
if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n");
if (fread(&sector_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sector size\n");
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDI: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
if (fread(&spt, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sectors per track\n");
if (fread(&hpc, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n");
if (fread(&tracks, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading number of tracks\n");
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = 1;
} else if (is_hdx[1]) {
hdd_images[id].base = 0x28;
if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1)
fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n");
if (fread(&full_size, 1, 8, hdd_images[id].file) != 8)
fatal("hdd_image_load(): HDX: Error reading full size\n");
if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1)
fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n");
if (fread(&sector_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDX: Error reading sector size\n");
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDX: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
if (fread(&spt, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sectors per track\n");
if (fread(&hpc, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n");
if (fread(&tracks, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDX: Error reading number of tracks\n");
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = 2;
} else if (is_vhd[1]) {
// full_size = VHD size in bytes
// hdd[id].tracks = VHD cylinders
// hdd[id].hpc = VHD heads
// hdd[id].spt = VHD spt
hdd_images[id].type = 3;
/* If we're here, this means there is a valid VHD footer in the
image, which means that by definition, all valid sectors
are there. */
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
return 1;
} else {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].type = 0;
}
if (image_is_hdi(fn)) {
if (fseeko64(hdd_images[id].file, 0x8, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offset 0x8\n");
if (fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading base offset\n");
if (fseeko64(hdd_images[id].file, 0xC, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offest 0xC\n");
full_size = 0LL;
if (fread(&full_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading full size\n");
if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1)
fatal("hdd_image_load(): HDI: Error seeking to offset 0x10\n");
if (fread(&sector_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sector size\n");
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDI: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
if (fread(&spt, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sectors per track\n");
if (fread(&hpc, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n");
if (fread(&tracks, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading number of tracks\n");
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = HDD_IMAGE_HDI;
} else if (is_hdx[1]) {
hdd_images[id].base = 0x28;
if (fseeko64(hdd_images[id].file, 8, SEEK_SET) == -1)
fatal("hdd_image_load(): HDX: Error seeking to offset 0x8\n");
if (fread(&full_size, 1, 8, hdd_images[id].file) != 8)
fatal("hdd_image_load(): HDX: Error reading full size\n");
if (fseeko64(hdd_images[id].file, 0x10, SEEK_SET) == -1)
fatal("hdd_image_load(): HDX: Error seeking to offset 0x10\n");
if (fread(&sector_size, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDX: Error reading sector size\n");
if (sector_size != 512) {
/* Sector size is not 512 */
hdd_image_log("HDX: Sector size is not 512\n");
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
return 0;
}
if (fread(&spt, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading sectors per track\n");
if (fread(&hpc, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDI: Error reading heads per cylinder\n");
if (fread(&tracks, 1, 4, hdd_images[id].file) != 4)
fatal("hdd_image_load(): HDX: Error reading number of tracks\n");
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
hdd_images[id].type = HDD_IMAGE_HDX;
} else if (is_vhd[1]) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
wcstombs(fn_multibyte_buf, fn, sizeof fn_multibyte_buf);
hdd_images[id].vhd = mvhd_open(fn_multibyte_buf, (bool)0, &vhd_error);
if (hdd_images[id].vhd == NULL)
{
if (vhd_error == MVHD_ERR_FILE)
fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, strerror(mvhd_errno));
else
fatal("hdd_image_load(): VHD: Error opening VHD file '%s': %s\n", fn_multibyte_buf, mvhd_strerr(vhd_error));
}
else if (vhd_error == MVHD_ERR_TIMESTAMP)
{
fatal("hdd_image_load(): VHD: Parent/child timestamp mismatch for VHD file '%s'\n", fn_multibyte_buf);
}
full_size = hdd_images[id].vhd->footer.curr_sz;
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_images[id].type = HDD_IMAGE_VHD;
/* If we're here, this means there is a valid VHD footer in the
image, which means that by definition, all valid sectors
are there. */
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
return 1;
} else {
full_size = ((uint64_t) hdd[id].spt) *
((uint64_t) hdd[id].hpc) *
((uint64_t) hdd[id].tracks) << 9LL;
hdd_images[id].type = HDD_IMAGE_RAW;
}
}
if (fseeko64(hdd_images[id].file, 0, SEEK_END) == -1)
fatal("hdd_image_load(): Error seeking to the end of file\n");
fatal("hdd_image_load(): Error seeking to the end of file\n");
s = ftello64(hdd_images[id].file);
if (s < (full_size + hdd_images[id].base))
ret = prepare_new_hard_disk(id, full_size);
ret = prepare_new_hard_disk(id, full_size);
else {
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
ret = 1;
hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1;
hdd_images[id].loaded = 1;
ret = 1;
}
return ret;
@@ -460,36 +503,47 @@ hdd_image_seek(uint8_t id, uint32_t sector)
addr = (uint64_t)sector << 9LL;
hdd_images[id].pos = sector;
if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1)
fatal("hdd_image_seek(): Error seeking\n");
if (hdd_images[id].type != HDD_IMAGE_VHD) {
if (fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET) == -1)
fatal("hdd_image_seek(): Error seeking\n");
}
}
void
hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
int i;
if (hdd_images[id].type == HDD_IMAGE_VHD) {
int non_transferred_sectors = mvhd_read_sectors(hdd_images[id].vhd, sector, count, buffer);
hdd_images[id].pos = sector + count - non_transferred_sectors - 1;
} else {
int i;
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Read error during seek\n", id);
return;
}
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Read error during seek\n", id);
return;
}
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
hdd_images[id].pos = sector + i;
fread(buffer + (i << 9), 1, 512, hdd_images[id].file);
}
hdd_images[id].pos = sector + i;
fread(buffer + (i << 9), 1, 512, hdd_images[id].file);
}
}
}
uint32_t
hdd_sectors(uint8_t id)
{
fseeko64(hdd_images[id].file, 0, SEEK_END);
return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9);
if (hdd_images[id].type == HDD_IMAGE_VHD) {
return (uint32_t) (hdd_images[id].vhd->footer.curr_sz >> 9);
} else {
fseeko64(hdd_images[id].file, 0, SEEK_END);
return (uint32_t)((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9);
}
}
@@ -500,12 +554,12 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
transfer_sectors = sectors - sector;
hdd_image_read(id, sector, transfer_sectors, buffer);
if (count != transfer_sectors)
return 1;
return 1;
return 0;
}
@@ -513,20 +567,25 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
void
hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
{
int i;
if (hdd_images[id].type == HDD_IMAGE_VHD) {
int non_transferred_sectors = mvhd_write_sectors(hdd_images[id].vhd, sector, count, buffer);
hdd_images[id].pos = sector + count - non_transferred_sectors - 1;
} else {
int i;
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Write error during seek\n", id);
return;
}
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Write error during seek\n", id);
return;
}
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
hdd_images[id].pos = sector + i;
fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file);
}
hdd_images[id].pos = sector + i;
fwrite(buffer + (i << 9), 512, 1, hdd_images[id].file);
}
}
}
@@ -537,12 +596,12 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
transfer_sectors = sectors - sector;
hdd_image_write(id, sector, transfer_sectors, buffer);
if (count != transfer_sectors)
return 1;
return 1;
return 0;
}
@@ -550,22 +609,27 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
void
hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
{
uint32_t i = 0;
if (hdd_images[id].type == HDD_IMAGE_VHD) {
int non_transferred_sectors = mvhd_format_sectors(hdd_images[id].vhd, sector, count);
hdd_images[id].pos = sector + count - non_transferred_sectors - 1;
} else {
uint32_t i = 0;
memset(empty_sector, 0, 512);
memset(empty_sector, 0, 512);
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Zero error during seek\n", id);
return;
}
if (fseeko64(hdd_images[id].file, ((uint64_t)(sector) << 9LL) + hdd_images[id].base, SEEK_SET) == -1) {
fatal("Hard disk image %i: Zero error during seek\n", id);
return;
}
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
for (i = 0; i < count; i++) {
if (feof(hdd_images[id].file))
break;
hdd_images[id].pos = sector + i;
fwrite(empty_sector, 512, 1, hdd_images[id].file);
}
hdd_images[id].pos = sector + i;
fwrite(empty_sector, 512, 1, hdd_images[id].file);
}
}
}
@@ -576,12 +640,12 @@ hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count)
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
transfer_sectors = sectors - sector;
hdd_image_zero(id, sector, transfer_sectors);
if (count != transfer_sectors)
return 1;
return 1;
return 0;
}
@@ -611,21 +675,24 @@ void
hdd_image_unload(uint8_t id, int fn_preserve)
{
if (wcslen(hdd[id].fn) == 0)
return;
return;
if (hdd_images[id].loaded) {
if (hdd_images[id].file != NULL) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
}
hdd_images[id].loaded = 0;
if (hdd_images[id].file != NULL) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
} else if (hdd_images[id].vhd != NULL) {
mvhd_close(hdd_images[id].vhd);
hdd_images[id].vhd = NULL;
}
hdd_images[id].loaded = 0;
}
hdd_images[id].last_sector = -1;
memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn));
if (fn_preserve)
wcscpy(hdd[id].prev_fn, hdd[id].fn);
wcscpy(hdd[id].prev_fn, hdd[id].fn);
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
}
@@ -636,12 +703,16 @@ hdd_image_close(uint8_t id)
hdd_image_log("hdd_image_close(%i)\n", id);
if (!hdd_images[id].loaded)
return;
return;
if (hdd_images[id].file != NULL) {
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
} else if (hdd_images[id].vhd != NULL) {
mvhd_close(hdd_images[id].vhd);
hdd_images[id].vhd = NULL;
}
memset(&hdd_images[id], 0, sizeof(hdd_image_t));
hdd_images[id].loaded = 0;
}