diff --git a/src/vdisk.c b/src/vdisk.c index f9d2cee..509b069 100644 --- a/src/vdisk.c +++ b/src/vdisk.c @@ -52,6 +52,8 @@ // uint32_t internal = 0; // Internal flags + uint32_t sign32; + uint64_t sign64; switch (vd->format) { case VDISK_FORMAT_VDI: @@ -84,12 +86,12 @@ break; default: // Attempt at different offsets - // Fixed VHD: 512 bytes before EOF + // VHD: (Fixed) 512 bytes before EOF if (os_fseek(vd->fd, -512, SEEK_END)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, &vd->vhdhdr, sizeof(VHD_HDR))) + if (os_fread(vd->fd, &sign64, 8)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhdhdr.magic == VHD_MAGIC) { + if (sign64 == VHD_MAGIC) { vd->format = VDISK_FORMAT_VHD; internal = 2; goto L_FORMAT_CASE_VHD; @@ -105,6 +107,9 @@ // vdisk_create // +//TODO: VDISK *vd, void *meta, uint64_t capacity, uint32_t flags +// The meta pointer serves for cloning/copying + int vdisk_create(VDISK *vd, const oschar *path, int format, uint64_t capacity, uint16_t flags) { if (flags & VDISK_CREATE_TEMP) { @@ -135,10 +140,7 @@ return vdisk_i_err(vd, VVD_EVDFORMAT, __LINE__, __func__); } - if (e) - return vd->err.num; - - return vdisk_update(vd); + return e ? e : vdisk_update(vd); } // @@ -170,7 +172,6 @@ // int vdisk_update(VDISK *vd) { - switch (vd->format) { case VDISK_FORMAT_VDI: //TODO: Move pre-header signature in creation function @@ -181,14 +182,14 @@ // skip signature if (os_fseek(vd->fd, VDI_SIGNATURE_SIZE, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fwrite(vd->fd, vd->vdi.hdr, sizeof(VDI_HDR))) + if (os_fwrite(vd->fd, &vd->vdi->hdr, sizeof(VDI_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fwrite(vd->fd, vd->vdi.v1, sizeof(VDI_HEADERv1))) + if (os_fwrite(vd->fd, &vd->vdi->v1, sizeof(VDI_HEADERv1))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); // blocks - if (os_fseek(vd->fd, vd->vdi.v1->offBlocks, SEEK_SET)) + if (os_fseek(vd->fd, vd->vdi->v1.offBlocks, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fwrite(vd->fd, vd->vdi.in->offsets, vd->vdi.v1->blk_total * 4)) + if (os_fwrite(vd->fd, vd->vdi->in.offsets, vd->vdi->v1.blk_total << 2)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); break; /*case VDISK_FORMAT_VMDK: diff --git a/src/vdisk.h b/src/vdisk.h index 7f5a9e2..f53b639 100644 --- a/src/vdisk.h +++ b/src/vdisk.h @@ -11,6 +11,8 @@ #include "vdisk/qcow.h" #include "vdisk/phdd.h" +#define VDISK_M_ERR(vd,ERR) vdisk_i_err(vd,ERR,__LINE__,__func__) + // // Constants // @@ -122,11 +124,13 @@ uint64_t capacity; // (Posix) File descriptor (Windows) File HANDLE __OSFILE fd; + // Error structure struct { int num; // Error number int line; // Source file line number const char *func; // Function name } err; + // Callback structure struct { // Read from a disk sector with a LBA index int (*lba_read)(struct VDISK*, void*, uint64_t); @@ -137,100 +141,14 @@ // Read a sector with a LBA index int (*blk_write)(struct VDISK*, void*, uint64_t); } cb; + // Meta union union { - // deprecated - uint64_t *u64block; - // deprecated - uint32_t *u32block; - }; - union { - // deprecated - uint64_t u64blockcount; - // deprecated - uint32_t u32blockcount; - }; - union { - // deprecated - uint64_t blockmask64; - // deprecated - uint32_t blockmask; - }; - // deprecated - uint32_t blockshift; - union { - struct { - VDI_HDR *hdr; // Pre-header - VDI_HEADERv0 *v0; // Header v0 - VDI_HEADERv1 *v1; // Header v1 - VDI_INTERNALS *in; // VDI internals - } vdi; - struct { - VMDK_HDR *hdr; - VMDK_INTERNALS *in; - } vmdk; - struct { - VHD_HDR *hdr; - VHD_DYN_HDR *dynhdr; - VHD_INTERNALS *in; - } vhd; - struct { - VHDX_HDR *hdr; - VHDX_HEADER1 *v1; - VHDX_REGION_HDR *region_hdr; - VHDX_LOG_HDR *log_hdr; - VHDX_METADATA_HDR *meta_hdr; - VHDX_INTERNALS *in; - } vhdx; - struct { - QED_HDR *hdr; - QED_L2CACHE *l2; - QED_INTERNALS *in; - } qed; - }; - // (Internal) Heap buffer for containing header information. This is - // done in order to reduce the number of seperate allocations. The - // back-end also has freedom on the size and layout it wishes to - // allocate. - void *buffer_headers; - // Deprecated: - union { - /*struct { - VDI_HDR vdihdr; // pre-header - VDI_HEADERv0 vdiv0; - VDI_HEADERv1 vdiv1; - // Dynamic disk block mask for remaining offset to LBA. - uint32_t vdi_blockmask; - // Dynamic disk block index shift number. Populated by fpow2. - uint32_t vdi_blockshift; - };*/ - struct { - VMDK_HDR vmdkhdr; - uint64_t vmdk_blockmask; - uint32_t vmdk_blockshift; - }; - struct { - VHD_HDR vhdhdr; - VHD_DYN_HDR vhddyn; - uint32_t vhd_blockmask; - uint32_t vhd_blockshift; - }; - struct { - VHDX_HDR vhdxhdr; - VHDX_HEADER1 vhdxhdrv1; - VHDX_REGION_HDR vhdxreg; - }; - struct { - QED_HDR qedhdr; - uint64_t *qed_L1; // L1 table - QED_L2CACHE qed_L2; - uint64_t qed_offset_mask; - uint64_t qed_L2_mask; - uint32_t qed_L2_shift; - uint64_t qed_L1_mask; - uint32_t qed_L1_shift; - }; - QCOW_HDR qcow; - PHDD_HDR phdd; + void *meta; + VDI_META *vdi; + VMDK_META *vmdk; + VHD_META *vhd; + QED_META *qed; + VHDX_META *vhdx; }; } VDISK; diff --git a/src/vdisk/qed.c b/src/vdisk/qed.c index 2aafc3e..67b42c4 100644 --- a/src/vdisk/qed.c +++ b/src/vdisk/qed.c @@ -4,52 +4,50 @@ #include int vdisk_qed_open(VDISK *vd, uint32_t flags, uint32_t internal) { - - if (os_fread(vd->fd, &vd->qedhdr, sizeof(QED_HDR))) + if ((vd->meta = malloc(QED_META_ALLOC)) == NULL) + return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); + + if (os_fread(vd->fd, &vd->qed->hdr, sizeof(QED_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->qedhdr.cluster_size < QED_CLUSTER_MIN || - vd->qedhdr.cluster_size > QED_CLUSTER_MAX || - pow2(vd->qedhdr.cluster_size) == 0) + if (vd->qed->hdr.cluster_size < QED_CLUSTER_MIN || + vd->qed->hdr.cluster_size > QED_CLUSTER_MAX || + pow2(vd->qed->hdr.cluster_size) == 0) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - if (vd->qedhdr.table_size < QED_TABLE_MIN || - vd->qedhdr.table_size > QED_TABLE_MAX || - pow2(vd->qedhdr.table_size) == 0) + if (vd->qed->hdr.table_size < QED_TABLE_MIN || + vd->qed->hdr.table_size > QED_TABLE_MAX || + pow2(vd->qed->hdr.table_size) == 0) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - if (vd->qedhdr.features > QED_FEATS) + if (vd->qed->hdr.features > QED_FEATS) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); // assert(header.image_size <= TABLE_NOFFSETS * TABLE_NOFFSETS * header.cluster_size) - uint32_t table_size = vd->qed_L2.tablesize = - vd->qedhdr.cluster_size * vd->qedhdr.table_size; - uint32_t table_entries = vd->qed_L2.entries = - table_size / sizeof(uint64_t); - uint32_t clusterbits = fpow2(vd->qedhdr.cluster_size); + uint32_t table_size = vd->qed->in.tablesize = + vd->qed->hdr.cluster_size * vd->qed->hdr.table_size; + uint32_t table_entries = vd->qed->in.entries = table_size / sizeof(uint64_t); + uint32_t clusterbits = fpow2(vd->qed->hdr.cluster_size); uint32_t tablebits = fpow2(table_entries); - if ((vd->qed_L1 = malloc(table_size)) == NULL) + if ((vd->qed->in.L1.offsets = malloc(table_size)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - if ((vd->qed_L2.offsets = malloc(table_size)) == NULL) + if ((vd->qed->in.L2.offsets = malloc(table_size)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - if (os_fseek(vd->fd, vd->qedhdr.cluster_size, SEEK_SET)) + if (os_fseek(vd->fd, vd->qed->hdr.l1_offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, vd->qed_L1, table_size)) + if (os_fread(vd->fd, vd->qed->in.L1.offsets, table_size)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); // assert(clusterbits + (2 * tablebits) <= 64); - vd->qed_offset_mask = vd->qedhdr.cluster_size - 1; - vd->qed_L2_mask = (table_entries - 1) << clusterbits; - vd->qed_L2_shift = clusterbits; - vd->qed_L1_mask = (table_entries - 1) << (clusterbits + tablebits); - vd->qed_L1_shift = clusterbits + tablebits; + vd->qed->in.mask = vd->qed->hdr.cluster_size - 1; + vd->qed->in.L2.mask = (table_entries - 1) << clusterbits; + vd->qed->in.L2.shift = clusterbits; + vd->qed->in.L1.mask = (table_entries - 1) << (clusterbits + tablebits); + vd->qed->in.L1.mask = clusterbits + tablebits; - vd->capacity = vd->qedhdr.capacity; - vd->offset = vd->qedhdr.cluster_size + table_size; // header + L1 - vd->u64block = vd->qed_L1; - vd->u32blockcount = table_entries; + vd->capacity = vd->qed->hdr.capacity; vd->cb.lba_read = vdisk_qed_read_sector; @@ -57,33 +55,31 @@ } int vdisk_qed_L2_load(VDISK *vd, uint64_t offset) { - - if (vd->qed_L2.offset == offset) // L2 already loaded + if (vd->qed->in.L2.current == offset) // L2 already loaded return 0; if (os_fseek(vd->fd, offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, vd->qed_L2.offsets, vd->qed_L2.tablesize)) + if (os_fread(vd->fd, vd->qed->in.L2.offsets, vd->qed->in.tablesize)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - vd->qed_L2.offset = offset; + vd->qed->in.L2.current = offset; return 0; } int vdisk_qed_read_sector(VDISK *vd, void *buffer, uint64_t index) { - uint64_t offset = SECTOR_TO_BYTE(index); - uint32_t l1 = (offset >> vd->qed_L1_shift) & vd->qed_L1_mask; - uint32_t l2 = (offset >> vd->qed_L2_shift) & vd->qed_L2_mask; + uint32_t l1 = (offset >> vd->qed->in.L1.shift) & vd->qed->in.L1.mask; + uint32_t l2 = (offset >> vd->qed->in.L2.shift) & vd->qed->in.L2.mask; - if (l1 >= vd->qed_L2.entries || l2 >= vd->qed_L2.entries) + if (l1 >= vd->qed->in.entries || l2 >= vd->qed->in.entries) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - if (vdisk_qed_L2_load(vd, vd->qed_L1[l1])) - return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); + if (vdisk_qed_L2_load(vd, vd->qed->in.L1.offsets[l1])) + return vd->err.num; - offset = (uint64_t)vd->qed_L2.offsets[l2] + (offset & vd->qed_offset_mask); + offset = (uint64_t)vd->qed->in.L2.offsets[l2] + (offset & vd->qed->in.mask); if (os_fseek(vd->fd, offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); diff --git a/src/vdisk/qed.h b/src/vdisk/qed.h index 7c621c6..cd4a471 100644 --- a/src/vdisk/qed.h +++ b/src/vdisk/qed.h @@ -88,22 +88,29 @@ } QED_L2CACHE; typedef struct { - // L1 table + uint32_t tablesize; // Calculated table size in bytes (table_size * cluster_size) + uint32_t entries; // Number of entries + uint64_t mask; // Offset mask after L1/L2 calculations struct { uint64_t *offsets; uint64_t mask; uint32_t shift; - } L1; - // L2 table + } L1; // L1 table struct { uint64_t *offsets; uint64_t mask; uint32_t shift; uint64_t current; // Last L2 offset loaded - } L2; - uint64_t mask; // Offset mask after L1/L2 calculations + } L2; // L2 table } QED_INTERNALS; +typedef struct { + QED_HDR hdr; + QED_INTERNALS in; +} QED_META; + +static const uint32_t QED_META_ALLOC = sizeof(QED_META); + struct VDISK; int vdisk_qed_open(struct VDISK *vd, uint32_t flags, uint32_t internal); diff --git a/src/vdisk/vdi.c b/src/vdisk/vdi.c index b0ae7c0..2bad383 100644 --- a/src/vdisk/vdi.c +++ b/src/vdisk/vdi.c @@ -12,39 +12,30 @@ // int vdisk_vdi_open(VDISK *vd, uint32_t flags, uint32_t internal) { - - if ((vd->buffer_headers = malloc(VDI_HDR_ALLOC)) == NULL) + if ((vd->meta = malloc(VDI_META_ALLOC)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - vd->vdi.hdr = vd->buffer_headers; - if (os_fseek(vd->fd, 0, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, vd->vdi.hdr, sizeof(VDI_HDR))) + if (os_fread(vd->fd, &vd->vdi->hdr, sizeof(VDI_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vdi.hdr->magic != VDI_HEADER_MAGIC) + if (vd->vdi->hdr.magic != VDI_HEADER_MAGIC) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - switch (vd->vdi.hdr->majorver) { // Use latest major version natively - case 1: // Includes v1.1 - vd->vdi.v1 = (void*)vd->vdi.hdr + sizeof(VDI_HDR); - if (os_fread(vd->fd, vd->vdi.v1, sizeof(VDI_HEADERv1))) + switch (vd->vdi->hdr.majorver) { // Use latest major version natively + case 1: // v1.1 + if (os_fread(vd->fd, &vd->vdi->v1, sizeof(VDI_HEADERv1))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - vd->vdi.v0 = NULL; - vd->vdi.in = (void*)vd->vdi.v1 + sizeof(VDI_HEADERv1); break; /*case 0: - vd->vdi.v0 = vd->vdi.hdr + sizeof(VDI_HDR); - if (os_fread(vd->fd, vd->vdi.v0, sizeof(VDI_HEADERv0))) + if (os_fread(vd->fd, &vd->vdi->v0, sizeof(VDI_HEADERv0))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - vd->vdi.v1 = NULL; - vd->vdi.in = vd->vdi.v0 + sizeof(VDI_HEADERv1); break;*/ default: return vdisk_i_err(vd, VVD_EVDVERSION, __LINE__, __func__); } - switch (vd->vdi.v1->type) { + switch (vd->vdi->v1.type) { case VDI_DISK_DYN: case VDI_DISK_FIXED: break; default: @@ -54,22 +45,22 @@ // Allocation table //TODO: Consider if this is an error (or warning) - if (vd->vdi.v1->blk_size == 0) - vd->vdi.v1->blk_size = VDI_BLOCKSIZE; - if (os_fseek(vd->fd, vd->vdi.v1->offBlocks, SEEK_SET)) + if (vd->vdi->v1.blk_size == 0) + vd->vdi->v1.blk_size = VDI_BLOCKSIZE; + if (os_fseek(vd->fd, vd->vdi->v1.offBlocks, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - int bsize = vd->vdi.v1->blk_total << 2; // * sizeof(u32) - if ((vd->vdi.in->offsets = malloc(bsize)) == NULL) + + int bsize = vd->vdi->v1.blk_total << 2; // * sizeof(u32) + if ((vd->vdi->in.offsets = malloc(bsize)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - if (os_fread(vd->fd, vd->vdi.in->offsets, bsize)) + if (os_fread(vd->fd, vd->vdi->in.offsets, bsize)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); // Internals / calculated values - vd->offset = vd->vdi.v1->offData; - vd->capacity = vd->vdi.v1->capacity; - vd->vdi.in->bmask = vd->vdi.v1->blk_size - 1; - vd->vdi.in->bshift = fpow2(vd->vdi.v1->blk_size); + vd->capacity = vd->vdi->v1.capacity; + vd->vdi->in.mask = vd->vdi->v1.blk_size - 1; + vd->vdi->in.shift = fpow2(vd->vdi->v1.blk_size); // Function pointers @@ -79,76 +70,72 @@ } int vdisk_vdi_create(VDISK *vd, uint64_t capacity, uint32_t flags) { - - if ((vd->buffer_headers = malloc(VDI_HDR_ALLOC)) == NULL) + if ((vd->meta = malloc(VDI_META_ALLOC)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); if (capacity == 0) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - vd->vdi.hdr = vd->buffer_headers; - vd->vdi.v1 = (void*)vd->vdi.hdr + sizeof(VDI_HDR); - vd->vdi.in = (void*)vd->vdi.v1 + sizeof(VDI_HEADERv1); - uint32_t bcount = capacity / VDI_BLOCKSIZE; - if ((vd->vdi.in->offsets = malloc(bcount << 2)) == NULL) + if ((vd->vdi->in.offsets = malloc(bcount << 2)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); vd->format = VDISK_FORMAT_VDI; // Pre-header - strcpy(vd->vdi.hdr->signature, VDI_SIGNATURE); - vd->vdi.hdr->magic = VDI_HEADER_MAGIC; - vd->vdi.hdr->majorver = 1; - vd->vdi.hdr->minorver = 1; + strcpy(vd->vdi->hdr.signature, VDI_SIGNATURE); + vd->vdi->hdr.magic = VDI_HEADER_MAGIC; + vd->vdi->hdr.majorver = 1; + vd->vdi->hdr.minorver = 1; // Header - vd->vdi.v1->blk_alloc = 0; - vd->vdi.v1->blk_extra = 0; - vd->vdi.v1->blk_size = VDI_BLOCKSIZE; - vd->vdi.v1->cbSector = vd->vdi.v1->LegacyGeometry.cbSector = 512; - vd->vdi.v1->cCylinders = - vd->vdi.v1->cHeads = - vd->vdi.v1->cSectors = - vd->vdi.v1->LegacyGeometry.cCylinders = - vd->vdi.v1->LegacyGeometry.cHeads = - vd->vdi.v1->LegacyGeometry.cSectors = 0; - vd->vdi.v1->capacity = capacity; - vd->vdi.v1->fFlags = 0; - vd->vdi.v1->hdrsize = (uint32_t)sizeof(VDI_HEADERv1); - vd->vdi.v1->offBlocks = VDI_BLOCKSIZE; - vd->vdi.v1->offData = VDI_BLOCKSIZE * 2; - vd->vdi.v1->blk_total = 0; - vd->vdi.v1->type = VDI_DISK_DYN; - vd->vdi.v1->u32Dummy = 0; // Always - memset(vd->vdi.v1->szComment, 0, VDI_COMMENT_SIZE); - memset(&vd->vdi.v1->uuidCreate, 0, 16); - memset(&vd->vdi.v1->uuidLinkage, 0, 16); - memset(&vd->vdi.v1->uuidModify, 0, 16); - memset(&vd->vdi.v1->uuidParentModify, 0, 16); + vd->vdi->v1.blk_alloc = 0; + vd->vdi->v1.blk_extra = 0; + vd->vdi->v1.blk_size = VDI_BLOCKSIZE; + vd->vdi->v1.cbSector = vd->vdi->v1.LegacyGeometry.cbSector = 512; + vd->vdi->v1.cCylinders = + vd->vdi->v1.cHeads = + vd->vdi->v1.cSectors = + vd->vdi->v1.LegacyGeometry.cCylinders = + vd->vdi->v1.LegacyGeometry.cHeads = + vd->vdi->v1.LegacyGeometry.cSectors = 0; + vd->vdi->v1.capacity = capacity; + vd->vdi->v1.fFlags = 0; + vd->vdi->v1.hdrsize = (uint32_t)sizeof(VDI_HEADERv1); + vd->vdi->v1.offBlocks = VDI_BLOCKSIZE; + vd->vdi->v1.offData = VDI_BLOCKSIZE * 2; + vd->vdi->v1.blk_total = 0; + vd->vdi->v1.type = VDI_DISK_DYN; + vd->vdi->v1.u32Dummy = 0; // Always + memset(vd->vdi->v1.szComment, 0, VDI_COMMENT_SIZE); + memset(&vd->vdi->v1.uuidCreate, 0, 16); + memset(&vd->vdi->v1.uuidLinkage, 0, 16); + memset(&vd->vdi->v1.uuidModify, 0, 16); + memset(&vd->vdi->v1.uuidParentModify, 0, 16); // Data - uint32_t *offsets = vd->vdi.in->offsets; + uint32_t *offsets = vd->vdi->in.offsets; uint8_t *buffer; + uint32_t blk_total = vd->vdi->v1.blk_total; switch (flags & VDISK_CREATE_TYPE_MASK) { case VDISK_CREATE_TYPE_DYNAMIC: - vd->vdi.v1->type = VDI_DISK_DYN; - for (size_t i = 0; i < vd->vdi.v1->blk_total; ++i) + vd->vdi->v1.type = VDI_DISK_DYN; + for (size_t i = 0; i < blk_total; ++i) offsets[i] = VDI_BLOCK_ZERO; break; case VDISK_CREATE_TYPE_FIXED: - vd->vdi.v1->type = VDI_DISK_FIXED; - if ((buffer = malloc(vd->vdi.v1->blk_size)) == NULL) + vd->vdi->v1.type = VDI_DISK_FIXED; + if ((buffer = calloc(1, vd->vdi->v1.blk_size)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - os_fseek(vd->fd, vd->vdi.v1->offData, SEEK_SET); - for (size_t i = 0; i < vd->vdi.v1->blk_total; ++i) { + os_fseek(vd->fd, vd->vdi->v1.offData, SEEK_SET); + for (size_t i = 0; i < blk_total; ++i) { offsets[i] = VDI_BLOCK_FREE; - os_fwrite(vd->fd, buffer, vd->vdi.v1->blk_size); + os_fwrite(vd->fd, buffer, vd->vdi->v1.blk_size); } break; default: @@ -163,14 +150,13 @@ // int vdisk_vdi_read_sector(VDISK *vd, void *buffer, uint64_t index) { - uint64_t offset = SECTOR_TO_BYTE(index); // Byte offset - size_t bi = offset >> vd->vdi.in->bshift; + size_t bi = offset >> vd->vdi->in.shift; - if (bi >= vd->vdi.v1->blk_total) // out of bounds + if (bi >= vd->vdi->v1.blk_total) // out of bounds return vdisk_i_err(vd, VVD_EVDBOUND, __LINE__, __func__); - uint32_t block = vd->vdi.in->offsets[bi]; + uint32_t block = vd->vdi->in.offsets[bi]; switch (block) { case VDI_BLOCK_ZERO: //TODO: Should this be zero'd too? return vdisk_i_err(vd, VVD_EVDUNALLOC, __LINE__, __func__); @@ -179,9 +165,9 @@ return 0; } - offset = vd->offset + - ((uint64_t)block * vd->vdi.v1->blk_size) + - (offset & vd->vdi.in->bmask); + offset = vd->vdi->v1.offData + + ((uint64_t)block * vd->vdi->v1.blk_size) + + (offset & vd->vdi->in.mask); #ifdef TRACE printf("%s: lba=%" PRId64 " -> offset=0x%" PRIX64 "\n", __func__, index, offset); @@ -200,8 +186,7 @@ // int vdisk_vdi_compact(VDISK *vd, void(*cb)(uint32_t type, void *data)) { - - if (vd->vdi.v1->type != VDI_DISK_DYN) + if (vd->vdi->v1.type != VDI_DISK_DYN) return vdisk_i_err(vd, VVD_EVDTYPE, __LINE__, __func__); uint32_t *blks2; // back resolving array @@ -214,8 +199,8 @@ return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); // This verifies that there are actually data blocks available - bk_alloc = (uint32_t)((fsize - vd->vdi.v1->offData - vd->vdi.v1->offBlocks) >> vd->vdi.in->bshift); - if (bk_alloc == 0 || vd->vdi.v1->blk_alloc == 0) + bk_alloc = (uint32_t)((fsize - vd->vdi->v1.offData - vd->vdi->v1.offBlocks) >> vd->vdi->in.shift); + if (bk_alloc == 0 || vd->vdi->v1.blk_alloc == 0) return 0; blks2 = malloc(bk_alloc << 2); @@ -226,17 +211,17 @@ uint32_t d = 0; uint32_t blk_index = 0; - uint32_t *blks = vd->vdi.in->offsets; + uint32_t *blks = vd->vdi->in.offsets; // 2. Check and fix allocation errors before compacting - for (; blk_index < vd->vdi.v1->blk_total; ++blk_index) { + for (; blk_index < vd->vdi->v1.blk_total; ++blk_index) { uint32_t bi = blks[blk_index]; // block index if (bi >= VDI_BLOCK_FREE) { continue; } - if (bi < vd->vdi.v1->blk_alloc) { + if (bi < vd->vdi->v1.blk_alloc) { if (blks[bi] == VDI_BLOCK_FREE) { blks[bi] = blk_index; } else { @@ -255,7 +240,7 @@ // 3. Find redundant information and update the block pointers accordingly - uint32_t blk_count = vd->vdi.v1->blk_total; + uint32_t blk_count = vd->vdi->v1.blk_total; for (blk_index = 0; blk_index < blk_count; ++blk_index) { uint32_t bi = blks[blk_index]; // block index @@ -266,7 +251,7 @@ // 4. Fill bubbles with other data if available -// for (i = 0; o < vd->vdi.blk_alloc +// for (i = 0; o < vd->vdiold.blk_alloc // 5. Update fields in-memory and on-disk diff --git a/src/vdisk/vdi.h b/src/vdisk/vdi.h index 1584c22..20ad12f 100644 --- a/src/vdisk/vdi.h +++ b/src/vdisk/vdi.h @@ -96,11 +96,21 @@ typedef struct { uint32_t *offsets; // Offset table - uint32_t bmask; // Block bit mask - uint32_t bshift; // Block shift positions + uint32_t mask; // Block bit mask + uint32_t shift; // Block shift positions + uint16_t majorver; } VDI_INTERNALS; -static const uint32_t VDI_HDR_ALLOC = 8192; // 8 KiB +typedef struct { + VDI_HDR hdr; + union { + VDI_HEADERv0 v0; + VDI_HEADERv1 v1; + }; + VDI_INTERNALS in; +} VDI_META; + +static const uint32_t VDI_META_ALLOC = sizeof(VDI_META); struct VDISK; diff --git a/src/vdisk/vhd.c b/src/vdisk/vhd.c index 8657365..c11c13a 100644 --- a/src/vdisk/vhd.c +++ b/src/vdisk/vhd.c @@ -12,26 +12,31 @@ // int vdisk_vhd_open(VDISK *vd, uint32_t flags, uint32_t internal) { - - if (internal & 2) - goto L_VHD_MAGICOK; + if ((vd->vmdk = malloc(VHD_META_ALLOC)) == NULL) + return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - if (os_fread(vd->fd, &vd->vhdhdr, sizeof(VHD_HDR))) + if (internal & 2) { + if (os_fseek(vd->fd, -512, SEEK_END)) + return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); + } + + if (os_fread(vd->fd, &vd->vhd->hdr, sizeof(VHD_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhdhdr.magic != VHD_MAGIC) + if (vd->vhd->hdr.magic != VHD_MAGIC) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); -L_VHD_MAGICOK: #if ENDIAN_LITTLE - vd->vhdhdr.major = bswap16(vd->vhdhdr.major); + vd->vhd->hdr.major = bswap16(vd->vhd->hdr.major); #endif - if (vd->vhdhdr.major != 1) + + if (vd->vhd->hdr.major != 1) return vdisk_i_err(vd, VVD_EVDVERSION, __LINE__, __func__); - + #if ENDIAN_LITTLE - vd->vhdhdr.type = bswap32(vd->vhdhdr.type); + vd->vhd->hdr.type = bswap32(vd->vhd->hdr.type); #endif - switch (vd->vhdhdr.type) { + + switch (vd->vhd->hdr.type) { case VHD_DISK_DIFF: case VHD_DISK_DYN: case VHD_DISK_FIXED: break; @@ -40,80 +45,78 @@ } #if ENDIAN_LITTLE - vd->vhdhdr.features = bswap32(vd->vhdhdr.features); - vd->vhdhdr.minor = bswap16(vd->vhdhdr.minor); - vd->vhdhdr.offset = bswap64(vd->vhdhdr.offset); - vd->vhdhdr.timestamp = bswap32(vd->vhdhdr.timestamp); - vd->vhdhdr.creator_major = bswap16(vd->vhdhdr.creator_major); - vd->vhdhdr.creator_minor = bswap16(vd->vhdhdr.creator_minor); -// vd->vhd.creator_os = bswap32(vd->vhd.creator_os); - vd->vhdhdr.size_original = bswap64(vd->vhdhdr.size_original); - vd->vhdhdr.size_current = bswap64(vd->vhdhdr.size_current); - vd->vhdhdr.cylinders = bswap16(vd->vhdhdr.cylinders); - vd->vhdhdr.checksum = bswap32(vd->vhdhdr.checksum); - uid_swap(&vd->vhdhdr.uuid); + vd->vhd->hdr.features = bswap32(vd->vhd->hdr.features); + vd->vhd->hdr.minor = bswap16(vd->vhd->hdr.minor); + vd->vhd->hdr.offset = bswap64(vd->vhd->hdr.offset); + vd->vhd->hdr.timestamp = bswap32(vd->vhd->hdr.timestamp); + vd->vhd->hdr.creator_major = bswap16(vd->vhd->hdr.creator_major); + vd->vhd->hdr.creator_minor = bswap16(vd->vhd->hdr.creator_minor); +// vd->vhd->creator_os = bswap32(vd->vhd->creator_os); + vd->vhd->hdr.size_original = bswap64(vd->vhd->hdr.size_original); + vd->vhd->hdr.size_current = bswap64(vd->vhd->hdr.size_current); + vd->vhd->hdr.cylinders = bswap16(vd->vhd->hdr.cylinders); + vd->vhd->hdr.checksum = bswap32(vd->vhd->hdr.checksum); + uid_swap(&vd->vhd->hdr.uuid); #endif - if (vd->vhdhdr.type != VHD_DISK_FIXED) { - if (os_fseek(vd->fd, vd->vhdhdr.offset, SEEK_SET)) + if (vd->vhd->hdr.type != VHD_DISK_FIXED) { + if (os_fseek(vd->fd, vd->vhd->hdr.offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, &vd->vhddyn, sizeof(VHD_DYN_HDR))) + if (os_fread(vd->fd, &vd->vhd->dyn, sizeof(VHD_DYN_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhddyn.magic != VHD_DYN_MAGIC) + if (vd->vhd->dyn.magic != VHD_DYN_MAGIC) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); #if ENDIAN_LITTLE - vd->vhddyn.data_offset = bswap64(vd->vhddyn.data_offset); - vd->vhddyn.table_offset = bswap64(vd->vhddyn.table_offset); - vd->vhddyn.minor = bswap16(vd->vhddyn.minor); - vd->vhddyn.major = bswap16(vd->vhddyn.major); - vd->vhddyn.max_entries = bswap32(vd->vhddyn.max_entries); - vd->vhddyn.blocksize = bswap32(vd->vhddyn.blocksize); - vd->vhddyn.checksum = bswap32(vd->vhddyn.checksum); - vd->vhddyn.parent_timestamp = bswap32(vd->vhddyn.parent_timestamp); - uid_swap(&vd->vhddyn.parent_uuid); + vd->vhd->dyn.data_offset = bswap64(vd->vhd->dyn.data_offset); + vd->vhd->dyn.table_offset = bswap64(vd->vhd->dyn.table_offset); + vd->vhd->dyn.minor = bswap16(vd->vhd->dyn.minor); + vd->vhd->dyn.major = bswap16(vd->vhd->dyn.major); + vd->vhd->dyn.max_entries = bswap32(vd->vhd->dyn.max_entries); + vd->vhd->dyn.blocksize = bswap32(vd->vhd->dyn.blocksize); + vd->vhd->dyn.checksum = bswap32(vd->vhd->dyn.checksum); + vd->vhd->dyn.parent_timestamp = bswap32(vd->vhd->dyn.parent_timestamp); + uid_swap(&vd->vhd->dyn.parent_uuid); for (size_t i = 0; i < 8; ++i) { - vd->vhddyn.parent_locator[i].code = bswap32( - vd->vhddyn.parent_locator[i].code); - vd->vhddyn.parent_locator[i].datasize = bswap32( - vd->vhddyn.parent_locator[i].datasize); - vd->vhddyn.parent_locator[i].dataspace = bswap32( - vd->vhddyn.parent_locator[i].dataspace); - vd->vhddyn.parent_locator[i].offset = bswap64( - vd->vhddyn.parent_locator[i].offset); + vd->vhd->dyn.parent_locator[i].code = + bswap32(vd->vhd->dyn.parent_locator[i].code); + vd->vhd->dyn.parent_locator[i].datasize = + bswap32(vd->vhd->dyn.parent_locator[i].datasize); + vd->vhd->dyn.parent_locator[i].dataspace = + bswap32(vd->vhd->dyn.parent_locator[i].dataspace); + vd->vhd->dyn.parent_locator[i].offset = + bswap64(vd->vhd->dyn.parent_locator[i].offset); } #endif - if (pow2(vd->vhddyn.blocksize) == 0 || - vd->vhddyn.max_entries != vd->vhdhdr.size_original / vd->vhddyn.blocksize) + if (pow2(vd->vhd->dyn.blocksize) == 0 || + vd->vhd->dyn.max_entries != vd->vhd->hdr.size_original / vd->vhd->dyn.blocksize) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - vd->u32blockcount = vd->vhddyn.max_entries; - vd->vhd_blockmask = vd->vhddyn.blocksize - 1; - vd->vhd_blockshift = fpow2(vd->vhddyn.blocksize); + vd->vhd->in.mask = vd->vhd->dyn.blocksize - 1; + vd->vhd->in.shift = fpow2(vd->vhd->dyn.blocksize); - if (vd->u32blockcount == 0) + if (vd->vhd->dyn.max_entries == 0) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); - if (os_fseek(vd->fd, vd->vhddyn.table_offset, SEEK_SET)) + if (os_fseek(vd->fd, vd->vhd->dyn.table_offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - int batsize = vd->u32blockcount << 2; // "* 4" - if ((vd->u32block = malloc(batsize)) == NULL) + int batsize = vd->vhd->dyn.max_entries << 2; // "* 4" + if ((vd->vhd->in.offsets = malloc(batsize)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - if (os_fread(vd->fd, vd->u32block, batsize)) + if (os_fread(vd->fd, vd->vhd->in.offsets, batsize)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); #if ENDIAN_LITTLE - for (size_t i = 0; i < vd->u32blockcount; ++i) - vd->u32block[i] = bswap32(vd->u32block[i]); + for (size_t i = 0; i < vd->vhd->dyn.max_entries; ++i) + vd->vhd->in.offsets[i] = bswap32(vd->vhd->in.offsets[i]); #endif vd->cb.lba_read = vdisk_vhd_dyn_read_lba; } else { // Fixed vd->cb.lba_read = vdisk_vhd_fixed_read_lba; } - vd->offset = 0; - vd->capacity = vd->vhdhdr.size_original; + vd->capacity = vd->vhd->hdr.size_original; return 0; } @@ -122,7 +125,6 @@ // int vdisk_vhd_fixed_read_lba(VDISK *vd, void *buffer, uint64_t index) { - uint64_t offset = SECTOR_TO_BYTE(index); // Byte offset if (os_fseek(vd->fd, offset, SEEK_SET)) @@ -138,21 +140,20 @@ // int vdisk_vhd_dyn_read_lba(VDISK *vd, void *buffer, uint64_t index) { - uint64_t offset = SECTOR_TO_BYTE(index); - uint32_t bi = (uint32_t)(offset >> vd->vhd_blockshift); + uint32_t bi = (uint32_t)(offset >> vd->vhd->in.shift); #ifdef TRACE printf("%s: bi=%u\n", __func__, bi); #endif - if (bi >= vd->u32blockcount) + if (bi >= vd->vhd->dyn.max_entries) return vdisk_i_err(vd, VVD_EVDBOUND, __LINE__, __func__); - uint32_t block = vd->u32block[bi]; + uint32_t block = vd->vhd->in.offsets[bi]; if (block == VHD_BLOCK_UNALLOC) // Unallocated return vdisk_i_err(vd, VVD_EVDUNALLOC, __LINE__, __func__); uint64_t base = SECTOR_TO_BYTE(block) + 512; - offset = base + (offset & vd->vhd_blockmask); + offset = base + (offset & vd->vhd->in.mask); #ifdef TRACE printf("%s: block=%u offset=%" PRIu64 "\n", __func__, block, offset); #endif diff --git a/src/vdisk/vhd.h b/src/vdisk/vhd.h index b91eae9..8d1addf 100644 --- a/src/vdisk/vhd.h +++ b/src/vdisk/vhd.h @@ -9,6 +9,7 @@ #define VHD_DYN_MAGIC 0x6573726170737863 // "cxsparse" #define VHD_OS_WIN 0x6B326957 // "Wi2k" #define VHD_OS_MAC 0x2063614D // "Mac " + enum { VHD_DISK_NONE = 0, VHD_DISK_RES1 = 1, @@ -18,6 +19,7 @@ VHD_DISK_RES2 = 5, VHD_DISK_RES3 = 6 }; + enum { VHD_BLOCK_UNALLOC = -1, // Block not allocated on disk VHD_FEAT_TEMP = 1, @@ -73,9 +75,19 @@ } VHD_DYN_HDR; typedef struct { - + uint32_t *offsets; + uint32_t mask; + uint32_t shift; } VHD_INTERNALS; +typedef struct { + VHD_HDR hdr; + VHD_DYN_HDR dyn; + VHD_INTERNALS in; +} VHD_META; + +static const uint32_t VHD_META_ALLOC = sizeof(VHD_META); + struct VDISK; int vdisk_vhd_open(struct VDISK *vd, uint32_t flags, uint32_t internal); diff --git a/src/vdisk/vhdx.c b/src/vdisk/vhdx.c index ac6ba16..65bdb6f 100644 --- a/src/vdisk/vhdx.c +++ b/src/vdisk/vhdx.c @@ -4,7 +4,10 @@ #include int vdisk_vhdx_open(VDISK *vd, uint32_t flags, uint32_t internal) { - assert(0); + assert(0); //TODO: Continue VHDX + + if ((vd->meta = malloc(VHDX_META_ALLOC)) == NULL) + return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); //TODO: Check both headers and regions before doing an error @@ -12,17 +15,25 @@ // Headers // - if (os_fread(vd->fd, &vd->vhdxhdr, sizeof(VHDX_HDR))) + if (os_fread(vd->fd, &vd->vhdx->hdr, sizeof(VHDX_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhdxhdr.magic != VHDX_MAGIC) + if (vd->vhdx->hdr.magic != VHDX_MAGIC) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); if (os_fseek(vd->fd, VHDX_HEADER1_LOC, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, &vd->vhdxhdr, sizeof(VHDX_HEADER1))) + if (os_fread(vd->fd, &vd->vhdx->v1, sizeof(VHDX_HEADER1))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhdxhdr.magic != VHDX_HDR1_MAGIC) + + if (os_fseek(vd->fd, VHDX_HEADER2_LOC, SEEK_SET)) + return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); + if (os_fread(vd->fd, &vd->vhdx->v1_2, sizeof(VHDX_HEADER1))) + return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); + + if (vd->vhdx->v1.magic != VHDX_HDR1_MAGIC || vd->vhdx->v1_2.magic != VHDX_HDR1_MAGIC) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); + if (vd->vhdx->v1.version != 1 || vd->vhdx->v1_2.version != 1) + return vdisk_i_err(vd, VVD_EVDVERSION, __LINE__, __func__); // // Regions @@ -30,9 +41,9 @@ if (os_fseek(vd->fd, VHDX_REGION1_LOC, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (os_fread(vd->fd, &vd->vhdxreg, sizeof(VHDX_REGION_HDR))) + if (os_fread(vd->fd, &vd->vhdx->reg, sizeof(VHDX_REGION_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vhdxreg.magic != VHDX_REGION_MAGIC) + if (vd->vhdx->reg.magic != VHDX_REGION_MAGIC) return vdisk_i_err(vd, VVD_EVDMAGIC, __LINE__, __func__); // diff --git a/src/vdisk/vhdx.h b/src/vdisk/vhdx.h index cf3cff9..e089421 100644 --- a/src/vdisk/vhdx.h +++ b/src/vdisk/vhdx.h @@ -1,22 +1,22 @@ /** * VHDX: (Microsoft) Virtual Hard Disk eXtended * - * MS-VHDX v20160714 + * Little Endian * - * BAT entry 8-Byte + * Source: MS-VHDX v20160714 */ #include #include "uid.h" -#define VHDX_MAGIC 0x656C696678646876 // "vhdxfile" -#define VHDX_HDR1_MAGIC 0x64616568 // "head" -#define VHDX_REGION_MAGIC 0x69676572 // "regi" -#define VHDX_LOG_HDR_MAGIC 0x65676F6C // "loge" -#define VHDX_LOG_ZERO_MAGIC 0x6F72657A // "zero" -#define VHDX_LOG_DESC_MAGIC 0x63736564 // "desc" -#define VHDX_LOG_DATA_MAGIC 0x61746164 // "data" -#define VHDX_METADATA_MAGIC 0x617461646174656D // "metadata" +static const uint64_t VHDX_MAGIC = 0x656C696678646876; // "vhdxfile" +static const uint32_t VHDX_HDR1_MAGIC = 0x64616568; // "head" +static const uint32_t VHDX_REGION_MAGIC = 0x69676572; // "regi" +static const uint32_t VHDX_LOG_HDR_MAGIC = 0x65676F6C; // "loge" +static const uint32_t VHDX_LOG_ZERO_MAGIC = 0x6F72657A; // "zero" +static const uint32_t VHDX_LOG_DESC_MAGIC = 0x63736564; // "desc" +static const uint32_t VHDX_LOG_DATA_MAGIC = 0x61746164; // "data" +static const uint64_t VHDX_METADATA_MAGIC = 0x617461646174656D; // "metadata" enum { VHDX_HEADER1_LOC = 64 * 1024, // 64 KiB @@ -28,7 +28,10 @@ typedef struct { uint64_t magic; - uint16_t creator[256]; + union { + uint8_t u8creator[512]; + uint16_t u16creator[256]; + }; } VHDX_HDR; typedef struct { @@ -42,8 +45,6 @@ uint16_t version; uint32_t logsize; uint64_t logoffset; - // Rest is reserved (4016 Bytes) - // It is not defined to avoid reading what we don't need } VHDX_HEADER1; typedef struct { @@ -116,16 +117,29 @@ // Logical Sector Size 8141BF1D-A96F-4709-BA47-F233A8FAAB5F // Logical Sector Size CDA348C7-445D-4471-9CC9-E9885251C556 // Parent Locator A8D35F2D-B30B-454D-ABF7-D3D84834AB0C - UID type; // itemID GUID + UID type; // itemID GUID uint32_t offset; uint32_t length; - uint32_t flags; // ...plus 2 bits? what the hell? + uint32_t flags; // ...plus 2 bits? what the hell? } VHDX_METADATA_ENTRY; typedef struct { } VHDX_INTERNALS; +typedef struct { + VHDX_HDR hdr; + VHDX_HEADER1 v1; + VHDX_HEADER1 v1_2; + VHDX_REGION_HDR reg; + VHDX_REGION_HDR reg2; + VHDX_LOG_HDR log; + VHDX_METADATA_HDR meta; + VHDX_INTERNALS in; +} VHDX_META; + +static const uint32_t VHDX_META_ALLOC = sizeof(VHDX_META); + struct VDISK; int vdisk_vhdx_open(struct VDISK *vd, uint32_t flags, uint32_t internal); diff --git a/src/vdisk/vmdk.c b/src/vdisk/vmdk.c index 3d8dff0..4a5ebf5 100644 --- a/src/vdisk/vmdk.c +++ b/src/vdisk/vmdk.c @@ -3,27 +3,23 @@ #include "platform.h" int vdisk_vmdk_open(VDISK *vd, uint32_t flags, uint32_t internal) { - - if ((vd->buffer_headers = malloc(VMDK_HDR_ALLOC)) == NULL) + if ((vd->vmdk = malloc(VMDK_META_ALLOC)) == NULL) return vdisk_i_err(vd, VVD_ENOMEM, __LINE__, __func__); - vd->vmdk.hdr = vd->buffer_headers; - vd->vmdk.in = (void*)vd->vmdk.hdr + sizeof(VMDK_HDR); - - if (os_fread(vd->fd, vd->vmdk.hdr, sizeof(VMDK_HDR))) + if (os_fread(vd->fd, &vd->vmdk->hdr, sizeof(VMDK_HDR))) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); - if (vd->vmdk.hdr->version != 1) + if (vd->vmdk->hdr.version != 1) return vdisk_i_err(vd, VVD_EVDVERSION, __LINE__, __func__); - if (vd->vmdk.hdr->grainSize < 8 || // < 4KiB - vd->vmdk.hdr->grainSize > 128 || // > 64KiB - pow2(vd->vmdk.hdr->grainSize) == 0) + if (vd->vmdk->hdr.grainSize < 8 || // < 4KiB + vd->vmdk->hdr.grainSize > 128 || // > 64KiB + pow2(vd->vmdk->hdr.grainSize) == 0) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - vd->capacity = SECTOR_TO_BYTE(vd->vmdk.hdr->capacity); + vd->capacity = SECTOR_TO_BYTE(vd->vmdk->hdr.capacity); - vd->vmdk.in->bmask = vd->vmdk.hdr->grainSize - 1; - vd->vmdk.in->bshift = fpow2((uint32_t)vd->vmdk.hdr->grainSize); - vd->vmdk.in->overhead = SECTOR_TO_BYTE(vd->vmdk.hdr->overHead); + vd->vmdk->in.mask = vd->vmdk->hdr.grainSize - 1; + vd->vmdk->in.shift = fpow2((uint32_t)vd->vmdk->hdr.grainSize); + vd->vmdk->in.overhead = SECTOR_TO_BYTE(vd->vmdk->hdr.overHead); vd->cb.lba_read = vdisk_vmdk_sparse_read_lba; @@ -37,9 +33,9 @@ if (offset >= vd->capacity) return vdisk_i_err(vd, VVD_EVDMISC, __LINE__, __func__); - //bi = offset / SECTOR_TO_BYTE(vd->vmdk.grainSize); + //bi = offset / SECTOR_TO_BYTE(vd->vmdkold.grainSize); //TODO: Work with the grainSize - offset += vd->vmdk.in->overhead; + offset += vd->vmdk->in.overhead; if (os_fseek(vd->fd, offset, SEEK_SET)) return vdisk_i_err(vd, VVD_EOS, __LINE__, __func__); diff --git a/src/vdisk/vmdk.h b/src/vdisk/vmdk.h index 4561116..9a081f0 100644 --- a/src/vdisk/vmdk.h +++ b/src/vdisk/vmdk.h @@ -72,12 +72,17 @@ typedef struct { uint32_t *l0_offsets; // Grain Directory offsets uint32_t *l1_offsets; // Grain Table offsets - uint32_t bmask; // Bit offset mask - uint32_t bshift; // Bit offset shift + uint32_t mask; // Bit offset mask + uint32_t shift; // Bit offset shift uint64_t overhead; // data overhead in bytes } VMDK_INTERNALS; -static const uint32_t VMDK_HDR_ALLOC = 4096; // 4 KiB +typedef struct { + VMDK_HDR hdr; + VMDK_INTERNALS in; +} VMDK_META; + +static const uint32_t VMDK_META_ALLOC = sizeof(VMDK_META); struct VDISK; diff --git a/src/vvd.c b/src/vvd.c index 448ecfe..3ac4f9a 100644 --- a/src/vvd.c +++ b/src/vvd.c @@ -270,7 +270,7 @@ // VDI // case VDISK_FORMAT_VDI: { - switch (vd->vdi.v1->type) { + switch (vd->vdi->v1.type) { case VDI_DISK_DYN: type = "dynamic"; break; case VDI_DISK_FIXED: type = "fixed"; break; case VDI_DISK_UNDO: type = "undo"; break; @@ -278,17 +278,17 @@ default: type = "type?"; } - bintostr(disksize, vd->vdi.v1->capacity); + bintostr(disksize, vd->vdi->v1.capacity); if (flags & VVD_INFO_RAW) { char create_uuid[UID_LENGTH], modify_uuid[UID_LENGTH], link_uuid[UID_LENGTH], parent_uuid[UID_LENGTH]; - bintostr(blocksize, vd->vdi.v1->blk_size); - uid_str(uid1, &vd->vdi.v1->uuidCreate, UID_UUID); - uid_str(uid2, &vd->vdi.v1->uuidModify, UID_UUID); - uid_str(uid3, &vd->vdi.v1->uuidLinkage, UID_UUID); - uid_str(uid4, &vd->vdi.v1->uuidParentModify, UID_UUID); + bintostr(blocksize, vd->vdi->v1.blk_size); + uid_str(uid1, &vd->vdi->v1.uuidCreate, UID_UUID); + uid_str(uid2, &vd->vdi->v1.uuidModify, UID_UUID); + uid_str(uid3, &vd->vdi->v1.uuidLinkage, UID_UUID); + uid_str(uid4, &vd->vdi->v1.uuidParentModify, UID_UUID); printf( "disk format : VDI\n" @@ -312,32 +312,32 @@ "modify uuid : %s\n" "link uuid : %s\n" "parent uuid : %s\n", - vd->vdi.hdr->majorver, vd->vdi.hdr->minorver, + vd->vdi->hdr.majorver, vd->vdi->hdr.minorver, type, - disksize, vd->vdi.v1->capacity, - vd->vdi.v1->hdrsize, - vd->vdi.v1->fFlags, - vd->vdi.v1->u32Dummy, - blocksize, vd->vdi.v1->blk_size, - vd->vdi.v1->blk_total, - vd->vdi.v1->blk_alloc, - vd->vdi.v1->blk_extra, - vd->vdi.v1->offBlocks, - vd->vdi.v1->offData, - vd->vdi.v1->cCylinders, - vd->vdi.v1->cHeads, - vd->vdi.v1->cSectors, - vd->vdi.v1->LegacyGeometry.cCylinders, - vd->vdi.v1->LegacyGeometry.cHeads, - vd->vdi.v1->LegacyGeometry.cSectors, - vd->vdi.v1->cbSector, - vd->vdi.v1->LegacyGeometry.cbSector, + disksize, vd->vdi->v1.capacity, + vd->vdi->v1.hdrsize, + vd->vdi->v1.fFlags, + vd->vdi->v1.u32Dummy, + blocksize, vd->vdi->v1.blk_size, + vd->vdi->v1.blk_total, + vd->vdi->v1.blk_alloc, + vd->vdi->v1.blk_extra, + vd->vdi->v1.offBlocks, + vd->vdi->v1.offData, + vd->vdi->v1.cCylinders, + vd->vdi->v1.cHeads, + vd->vdi->v1.cSectors, + vd->vdi->v1.LegacyGeometry.cCylinders, + vd->vdi->v1.LegacyGeometry.cHeads, + vd->vdi->v1.LegacyGeometry.cSectors, + vd->vdi->v1.cbSector, + vd->vdi->v1.LegacyGeometry.cbSector, uid1, uid2, uid3, uid4 ); } else { printf( "VirtualBox VDI %s disk v%u.%u, %s\n", - type, vd->vdi.hdr->majorver, vd->vdi.hdr->minorver, disksize + type, vd->vdi->hdr.majorver, vd->vdi->hdr.minorver, disksize ); //TODO: Interpret flags } @@ -349,7 +349,7 @@ case VDISK_FORMAT_VMDK: { const char *comp; // compression //if (h.flags & COMPRESSED) - switch (vd->vmdk.hdr->compressAlgorithm) { + switch (vd->vmdk->hdr.compressAlgorithm) { case 0: comp = "no"; break; case 1: comp = "DEFLATE"; break; default: comp = "?"; @@ -375,42 +375,42 @@ "double nl char 1 : 0x%02X\n" "double nl char 2 : 0x%02X\n" "compression : 0x%02X\n", - vd->vmdk.hdr->version, - vd->vmdk.hdr->flags, - vd->vmdk.hdr->capacity, - vd->vmdk.hdr->overHead, - vd->vmdk.hdr->grainSize, - vd->vmdk.hdr->descriptorOffset, - vd->vmdk.hdr->descriptorSize, - vd->vmdk.hdr->numGTEsPerGT, - vd->vmdk.hdr->rgdOffset, - vd->vmdk.hdr->gdOffset, - vd->vmdk.hdr->overHead, - vd->vmdk.hdr->uncleanShutdown, - vd->vmdk.hdr->singleEndLineChar, - vd->vmdk.hdr->nonEndLineChar, - vd->vmdk.hdr->doubleEndLineChar1, - vd->vmdk.hdr->doubleEndLineChar2, - vd->vmdk.hdr->compressAlgorithm + vd->vmdk->hdr.version, + vd->vmdk->hdr.flags, + vd->vmdk->hdr.capacity, + vd->vmdk->hdr.overHead, + vd->vmdk->hdr.grainSize, + vd->vmdk->hdr.descriptorOffset, + vd->vmdk->hdr.descriptorSize, + vd->vmdk->hdr.numGTEsPerGT, + vd->vmdk->hdr.rgdOffset, + vd->vmdk->hdr.gdOffset, + vd->vmdk->hdr.overHead, + vd->vmdk->hdr.uncleanShutdown, + vd->vmdk->hdr.singleEndLineChar, + vd->vmdk->hdr.nonEndLineChar, + vd->vmdk->hdr.doubleEndLineChar1, + vd->vmdk->hdr.doubleEndLineChar2, + vd->vmdk->hdr.compressAlgorithm ); } else { bintostr(disksize, vd->capacity); printf( "VMware VMDK disk v%u, %s compression, %s\n", - vd->vmdk.hdr->version, comp, disksize + vd->vmdk->hdr.version, comp, disksize ); - if (vd->vmdk.hdr->flags & VMDK_F_VALID_NL) + if (vd->vmdk->hdr.flags & VMDK_F_VALID_NL) puts("+ Valid newline detection"); - if (vd->vmdk.hdr->flags & VMDK_F_REDUNDANT_TABLE) + if (vd->vmdk->hdr.flags & VMDK_F_REDUNDANT_TABLE) puts("+ Redundant grain table used"); - if (vd->vmdk.hdr->flags & VMDK_F_ZEROED_GTE) + if (vd->vmdk->hdr.flags & VMDK_F_ZEROED_GTE) puts("+ Zeroed-grain GTE used"); - if (vd->vmdk.hdr->flags & VDMK_F_COMPRESSED) + if (vd->vmdk->hdr.flags & VDMK_F_COMPRESSED) puts("+ Grains are compressed"); - if (vd->vmdk.hdr->flags & VMDK_F_MARKERS) + if (vd->vmdk->hdr.flags & VMDK_F_MARKERS) puts("+ Markers used"); - if (vd->vmdk.hdr->uncleanShutdown) + if (vd->vmdk->hdr.uncleanShutdown) puts("+ Unclean shutdown"); } } @@ -422,22 +422,22 @@ char sizecur[BINSTR_LENGTH]; const char *byos; - switch (vd->vhdhdr.type) { + switch (vd->vhd->hdr.type) { case VHD_DISK_FIXED: type = "fixed"; break; case VHD_DISK_DYN: type = "dynamic"; break; case VHD_DISK_DIFF: type = "differencing"; break; default: - type = vd->vhdhdr.type <= 6 ? "reserved (deprecated)" : "unknown"; + type = vd->vhd->hdr.type <= 6 ? "reserved (deprecated)" : "unknown"; } - switch (vd->vhdhdr.creator_os) { + switch (vd->vhd->hdr.creator_os) { case VHD_OS_WIN: byos = "Windows"; break; case VHD_OS_MAC: byos = "macOS"; break; default: byos = "unknown"; break; } - uid_str(uid1, &vd->vhdhdr.uuid, UID_ASIS); - str_s(vd->vhdhdr.creator_app, 4); + uid_str(uid1, &vd->vhd->hdr.uuid, UID_ASIS); + str_s(vd->vhd->hdr.creator_app, 4); if (flags & VVD_INFO_RAW) { printf( @@ -452,20 +452,20 @@ "chs : %u/%u/%u\n" "checksum : 0x%08X\n" "uuid : %s\n", - vd->vhdhdr.major, vd->vhdhdr.minor, + vd->vhd->hdr.major, vd->vhd->hdr.minor, type, - vd->vhdhdr.size_current, - vd->vhdhdr.size_original, - vd->vhdhdr.creator_app, - vd->vhdhdr.creator_major, vd->vhdhdr.creator_minor, + vd->vhd->hdr.size_current, + vd->vhd->hdr.size_original, + vd->vhd->hdr.creator_app, + vd->vhd->hdr.creator_major, vd->vhd->hdr.creator_minor, byos, - vd->vhdhdr.cylinders, vd->vhdhdr.heads, vd->vhdhdr.sectors, - vd->vhdhdr.checksum, + vd->vhd->hdr.cylinders, vd->vhd->hdr.heads, vd->vhd->hdr.sectors, + vd->vhd->hdr.checksum, uid1 ); - if (vd->vhdhdr.type != VHD_DISK_FIXED) { + if (vd->vhd->hdr.type != VHD_DISK_FIXED) { char paruuid[UID_LENGTH]; - uid_str(paruuid, &vd->vhddyn.parent_uuid, UID_ASIS); + uid_str(paruuid, &vd->vhd->dyn.parent_uuid, UID_ASIS); printf( "dyn. header ver. : %u.%u\n" "offset table : %" PRIu64 "\n" @@ -474,29 +474,28 @@ "dyn. checksum : 0x%08X\n" "parent uuid : %s\n" "parent timestamp : %u\n" - "bat entries : %u\n" - , - vd->vhddyn.minor, vd->vhddyn.major, - vd->vhddyn.table_offset, - vd->vhddyn.data_offset, - vd->vhddyn.blocksize, - vd->vhddyn.checksum, + "bat entries : %u\n", + vd->vhd->dyn.minor, vd->vhd->dyn.major, + vd->vhd->dyn.table_offset, + vd->vhd->dyn.data_offset, + vd->vhd->dyn.blocksize, + vd->vhd->dyn.checksum, paruuid, - vd->vhddyn.parent_timestamp, - vd->vhddyn.max_entries + vd->vhd->dyn.parent_timestamp, + vd->vhd->dyn.max_entries ); } } else { - bintostr(sizecur, vd->vhdhdr.size_current); - bintostr(disksize, vd->vhdhdr.size_original); + bintostr(sizecur, vd->vhd->hdr.size_current); + bintostr(disksize, vd->vhd->hdr.size_original); printf( "Connectix/Microsoft VHD %s disk v%u.%u, %s/%s\n", - type, vd->vhdhdr.major, vd->vhdhdr.minor, sizecur, disksize + type, vd->vhd->hdr.major, vd->vhd->hdr.minor, sizecur, disksize ); } - if (vd->vhdhdr.savedState) + if (vd->vhd->hdr.savedState) puts("+ Saved state"); } break; @@ -512,20 +511,20 @@ "compact features : 0x%" PRIX64 "\n" "autoclear features : 0x%" PRIX64 "\n" "L1 offset : 0x%" PRIX64 "\n", - vd->qedhdr.cluster_size, - vd->qedhdr.table_size, - vd->qedhdr.header_size, - vd->qedhdr.features, - vd->qedhdr.compat_features, - vd->qedhdr.autoclear_features, - vd->qedhdr.l1_offset + vd->qed->hdr.cluster_size, + vd->qed->hdr.table_size, + vd->qed->hdr.header_size, + vd->qed->hdr.features, + vd->qed->hdr.compat_features, + vd->qed->hdr.autoclear_features, + vd->qed->hdr.l1_offset ); - if (vd->qedhdr.features & QED_F_BACKING_FILE) { + if (vd->qed->hdr.features & QED_F_BACKING_FILE) { printf( "back. name offset : %u\n" "back. name size : %u\n", - vd->qedhdr.backup_name_offset, - vd->qedhdr.backup_name_size + vd->qed->hdr.backup_name_offset, + vd->qed->hdr.backup_name_size ); } } else {