#define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE #define _GNU_SOURCE #include #include "ibm.h" #include "hdd_file.h" #include "minivhd/minivhd.h" #include "minivhd/minivhd_util.h" void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks, int read_only) { if (hdd->f == NULL) { /* Try to open existing hard disk image */ if (read_only) hdd->f = (void*)fopen64(fn, "rb"); else hdd->f = (void*)fopen64(fn, "rb+"); if (hdd->f != NULL) { hdd->img_type = HDD_IMG_RAW; /* Check if the file we opened is a VHD */ if (mvhd_file_is_vhd((FILE*)hdd->f)) { int err; fclose((FILE*)hdd->f); MVHDMeta *vhdm = mvhd_open(fn, (bool)read_only, &err); if (vhdm == NULL) { hdd->f = NULL; if (err == MVHD_ERR_FILE) { pclog("Cannot open VHD file '%s' : %s", fn, strerror(mvhd_errno)); } else { pclog("Cannot open VHD file '%s' : %s", fn, mvhd_strerr(err)); } return; } else if (err == MVHD_ERR_TIMESTAMP) { pclog("VHD: Parent/child timestamp mismatch"); mvhd_close(vhdm); hdd->f = NULL; return; } hdd->f = (void*)vhdm; hdd->img_type = HDD_IMG_VHD; } } else { /* Failed to open existing hard disk image */ if (errno == ENOENT && !read_only) { /* Failed because it does not exist, so try to create new file */ hdd->f = (void*)fopen64(fn, "wb+"); if (hdd->f == NULL) { pclog("Cannot create file '%s': %s", fn, strerror(errno)); return; } } else { /* Failed for another reason */ pclog("Cannot open file '%s': %s", fn, strerror(errno)); return; } hdd->img_type = HDD_IMG_RAW; } } if (hdd->img_type == HDD_IMG_VHD) { MVHDMeta *vhdm = (MVHDMeta*)hdd->f; MVHDGeom geom = mvhd_get_geometry(vhdm); hdd->spt = geom.spt; hdd->hpc = geom.heads; hdd->tracks = geom.cyl; } else if (hdd->img_type == HDD_IMG_RAW) { hdd->spt = spt; hdd->hpc = hpc; hdd->tracks = tracks; } hdd->sectors = hdd->spt * hdd->hpc * hdd->tracks; hdd->read_only = read_only; } void hdd_load(hdd_file_t *hdd, int d, const char *fn) { hdd_load_ext(hdd, fn, hdc[d].spt, hdc[d].hpc, hdc[d].tracks, 0); } void hdd_close(hdd_file_t *hdd) { if (hdd->f) { if (hdd->img_type == HDD_IMG_VHD) mvhd_close((MVHDMeta*)hdd->f); else if (hdd->img_type == HDD_IMG_RAW) fclose((FILE*)hdd->f); } hdd->img_type = HDD_IMG_RAW; hdd->f = NULL; } int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) { if (hdd->img_type == HDD_IMG_VHD) { return mvhd_read_sectors((MVHDMeta*)hdd->f, offset, nr_sectors, buffer); } else if (hdd->img_type == HDD_IMG_RAW) { off64_t addr; int transfer_sectors = nr_sectors; if ((hdd->sectors - offset) < transfer_sectors) transfer_sectors = hdd->sectors - offset; addr = (uint64_t)offset * 512; fseeko64((FILE*)hdd->f, addr, SEEK_SET); fread(buffer, transfer_sectors*512, 1, (FILE*)hdd->f); if (nr_sectors != transfer_sectors) return 1; return 0; } /* Keep the compiler happy */ return 1; } int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) { if (hdd->img_type == HDD_IMG_VHD) { return mvhd_write_sectors((MVHDMeta*)hdd->f, offset, nr_sectors, buffer); } else if (hdd->img_type == HDD_IMG_RAW) { off64_t addr; int transfer_sectors = nr_sectors; if (hdd->read_only) return 1; if ((hdd->sectors - offset) < transfer_sectors) transfer_sectors = hdd->sectors - offset; addr = (uint64_t)offset * 512; fseeko64((FILE*)hdd->f, addr, SEEK_SET); fwrite(buffer, transfer_sectors*512, 1, (FILE*)hdd->f); if (nr_sectors != transfer_sectors) return 1; return 0; } /* Keep the compiler happy */ return 1; } int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors) { if (hdd->img_type == HDD_IMG_VHD) { return mvhd_format_sectors((MVHDMeta*)hdd->f, offset, nr_sectors); } else if (hdd->img_type == HDD_IMG_RAW) { off64_t addr; int c; uint8_t zero_buffer[512]; int transfer_sectors = nr_sectors; if (hdd->read_only) return 1; memset(zero_buffer, 0, 512); if ((hdd->sectors - offset) < transfer_sectors) transfer_sectors = hdd->sectors - offset; addr = (uint64_t)offset * 512; fseeko64((FILE*)hdd->f, addr, SEEK_SET); for (c = 0; c < transfer_sectors; c++) fwrite(zero_buffer, 512, 1, (FILE*)hdd->f); if (nr_sectors != transfer_sectors) return 1; return 0; } /* Keep the compiler happy */ return 1; }