#pragma once #include "os.h" #include "utils.h" #include "vdisk/raw.h" #include "vdisk/vdi.h" #include "vdisk/vmdk.h" #include "vdisk/vhd.h" #include "vdisk/vhdx.h" #include "vdisk/qed.h" #include "vdisk/qcow.h" #include "vdisk/phdd.h" #define LINE_BEFORE (__LINE__ - 1) // // Constants // #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ enum { // DISKFORMAT magical hints (LSB), used for VDISK.format VDISK_FORMAT_NONE = 0, // No formats has been specificied yet VDISK_FORMAT_RAW = 0xAAAAAAAA, // Raw files and devices VDISK_FORMAT_VDI = 0x203C3C3C, // "<<< " VirtualBox VDISK_FORMAT_VMDK = 0x564D444B, // "VMDK" VMware VDISK_FORMAT_VMDK_COW = 0x44574F43, // "COWD" VMware EXSi COW disk VDISK_FORMAT_VHD = 0x656E6F63, // "cone" VirtualPC/Hyper-V VDISK_FORMAT_VHDX = 0x78646876, // "vhdx" Hyper-V VDISK_FORMAT_QED = 0x00444551, // "QED\0" QEMU Enhanced Disk VDISK_FORMAT_QCOW = 0xFB494651, // "QFI\xFB" QEMU Copy-On-Write, v1/v2 VDISK_FORMAT_PHDD = 0x68746957, // "With" Parallels HDD VDISK_FORMAT_BOCHS = 0x68636F68, // "Boch" Bochs Virtual HD Image // VDISK_FORMAT_DMG = 0x, // "" Apple DMG }; #else #endif enum { // VDISK flags, the open/create flags may overlap VDISK_RAW = 0x1, // Open or create vdisk as raw // // vdisk_open flags // VDISK_OPEN_VDI_ONLY = 0x1000, //TODO: Only open successfully if VDISK is VDI VDISK_OPEN_VMDK_ONLY = 0x2000, //TODO: Only open successfully if VDISK is VMDK VDISK_OPEN_VHD_ONLY = 0x3000, //TODO: Only open successfully if VDISK is VHD VDISK_OPEN_VHDX_ONLY = 0x4000, //TODO: Only open successfully if VDISK is VHDX VDISK_OPEN_QED_ONLY = 0x5000, //TODO: Only open successfully if VDISK is QED VDISK_OPEN_QCOW_ONLY = 0x6000, //TODO: Only open successfully if VDISK is QCOW VDISK_OPEN_PHDD_ONLY = 0x7000, //TODO: Only open successfully if VDISK is Parallels HDD VDISK_OPEN_BOCHS_ONLY = 0x8000, //TODO: Only open successfully if VDISK is Parallels HDD // // vdisk_create flags // VDISK_CREATE_TEMP = 0x0100, //TODO: Create a temporary (random) vdisk file VDISK_CREATE_DYN = 0x1000, //TODO: Create a dynamic type VDISK VDISK_CREATE_FIXED = 0x2000, //TODO: Create a fixed type VDISK VDISK_CREATE_PARENT = 0x3000, //TODO: Create a parent of the VDISK VDISK_CREATE_SNAPSHOT = 0x4000, //TODO: Create a snapshot of the VDISK }; enum { // VDISK error codes VVD_EOK = 0, // VDISK OK VVD_EOS = -2, // OS/CRT related error VVD_ENULL = -3, // Input pointer is NULL VVD_ENOMEM = -4, // Could not allocate memory VVD_EVDFORMAT = -10, // Invalid VDISK format VVD_EVDMAGIC = -11, // Invalid VDISK magic signature VVD_EVDVERSION = -12, // Unsupported VDISK version (major) VVD_EVDTYPE = -13, // Unsupported VDISK type VVD_EVDFULL = -14, // VDISK is full and no more data can be allocated VVD_EVDUNALLOC = -15, // Block is unallocated VVD_EVDBOUND = -16, // Index was out of block index bounds VVD_EVDTODO = -254, // Currently unimplemented VVD_EVDMISC = -255, // Unknown }; enum { // Operation has completed successfully. // Parameter: NULL VVD_NOTIF_DONE, // VDISK was created with type // Parameter: const char* VVD_NOTIF_VDISK_CREATED_TYPE_NAME, // Total amount of blocks before processing // Parameter: uint32_t VVD_NOTIF_VDISK_TOTAL_BLOCKS, // Total amount of blocks before processing (64-bit indexes) // Parameter: uint64_t VVD_NOTIF_VDISK_TOTAL_BLOCKS64, // // Parameter: uint32_t VVD_NOTIF_VDISK_CURRENT_BLOCK, // // Parameter: uint64_t VVD_NOTIF_VDISK_CURRENT_BLOCK64, }; // // Structure definitions // // Defines a virtual disk. // All fields are more or less internal. typedef struct VDISK { // Defines the virtual disk format (e.g. VDI, VMDK, etc.). // See VDISKFORMAT enumeration. uint32_t format; // Flags. See VDISK_FLAG enumeration. uint32_t flags; // Calculated absolute offset to data. uint64_t offset; // (Internal) Location of new allocation block uint64_t nextblock; // Virtual disk capacity in bytes. For RAW files, it's the file size. For // RAW devices, it's the disk size. uint64_t capacity; // (Posix) File descriptor (Windows) File HANDLE __OSFILE fd; int errcode; // Error number int errline; // Error line const char *errfunc; // Function name // Function pointer: Read a sector with a LBA index int (*read_lba)(struct VDISK*, void*, uint64_t); // Function pointer: Read a dynamic block with a block index int (*read_block)(struct VDISK*, void*, uint64_t); // Function pointer: Read a sector with a LBA index int (*write_lba)(struct VDISK*, void*, uint64_t); // Function pointer: Read a sector with a LBA index int (*write_block)(struct VDISK*, void*, uint64_t); union { // Allocation table using 64-bit indexes uint64_t *u64block; // Allocation table using 32-bit indexes uint32_t *u32block; }; union { // Total amount of allocated blocks uint64_t u64blockcount; // Total amount of allocated blocks uint32_t u32blockcount; }; union { uint64_t blockmask64; uint32_t blockmask; }; uint32_t blockshift; //TODO: Consider allocating on open/create operations union { struct { VDI_HDR vdihdr; // pre-header VDIHEADER0 vdiv0; VDIHEADER1 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 vmdk; uint64_t vmdk_blockmask; uint32_t vmdk_blockshift; }; struct { VHD_HDR vhd; VHD_DYN_HDR vhddyn; uint32_t vhd_blockmask; uint32_t vhd_blockshift; }; struct { VHDX_HDR vhdx; VHDX_HEADER1 vhdxhdr; VHDX_REGION_HDR vhdxreg; }; struct { QED_HDR qed; 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; }; } VDISK; // // SECTION Internal functions // /** * (Internal) Set errcode and errline. * * \returns errcode */ int vdisk_i_err(VDISK *vd, int e, int l); // // SECTION Functions // /** * Open a VDISK. * * When opening a file, this function verifies the file path, VDISK format, * header structure, version, and other fields. * * When creating a file, the specified file at the file path is overwritten. * An empty, unallocated VDISK is created. If VDISK_CREATE_TEMP is defined, * path parameter can be NULL, since the function will create a random * filename (OS). * * \param vd VDISK structure * \param path OS string path * \param flags Opening flags * * \returns Exit status */ int vdisk_open(VDISK *vd, const oschar *path, uint32_t flags); /** * Create a VDISK. * * \param vd VDISK structure * \param path OS string path * \param format Virtual disk format * \param capacity Virtual disk capacity * \param flags Creation flags * * \returns Exit status */ int vdisk_create(VDISK *vd, const oschar *path, int format, uint64_t capacity, uint16_t flags); /** * Returns a string representation of the loaded virtual disk. If a format was * not found, a null pointer is returned. */ const char *vdisk_str(VDISK *vd); /** * Update header information and allocation tables into file or device. */ int vdisk_update(VDISK *vd); /** * Seek and read a sector-size (512 bytes) of data from a sector index (LBA). * * This function checks if sector exists on dynamic type disks, and index * tables such as the BAT on VHDs. * * Returns error code. Non-zero being an error. */ int vdisk_read_sector(VDISK *vd, void *buffer, uint64_t lba); /** * Seek to a block index and read it. The size of the block depends on the size * speicified in the VDISK structure. Only certain VDISK types are supported, * notably dynamic types. If unsupported, returns EVDFORMAT or EVDTYPE. */ int vdisk_read_block(VDISK *vd, void *buffer, uint64_t index); /** * */ int vdisk_write_lba(VDISK *vd, void *buffer, uint64_t lba); /** * */ int vdisk_write_block(VDISK *vd, void *buffer, uint64_t index); /** * */ int vdisk_write_block_at(VDISK *vd, void *buffer, uint64_t bindex, uint64_t dindex); // // SECTION // /** * */ int vdisk_op_compact(VDISK *vd, void(*cb)(uint32_t, void*)); /** * */ //int vdisk_op_resize(VDISK *vd, void(*cb_progress)(uint64_t block)); // // SECTION Error handling // /** * Returns an error message depending on the last value of vdisk_errno. If the * error is set to VVD_EOS, the error message will come from the OS (or CRT). */ const char* vdisk_error(VDISK *vd); /** * Print to stdout, with the name of the function, a message with the last * value set to vdisk_errno. */ void vdisk_perror(VDISK *vd);