diff --git a/.vs/MiniVHD/v16/.suo b/.vs/MiniVHD/v16/.suo new file mode 100644 index 0000000..9254e15 Binary files /dev/null and b/.vs/MiniVHD/v16/.suo differ diff --git a/.vs/MiniVHD/v16/Browse.VC.db b/.vs/MiniVHD/v16/Browse.VC.db new file mode 100644 index 0000000..9a760c8 Binary files /dev/null and b/.vs/MiniVHD/v16/Browse.VC.db differ diff --git a/.vs/MiniVHD/v16/ipch/AutoPCH/aec064f3b1413ba4/MINIVHD_CREATE.ipch b/.vs/MiniVHD/v16/ipch/AutoPCH/aec064f3b1413ba4/MINIVHD_CREATE.ipch new file mode 100644 index 0000000..8c6c4a0 Binary files /dev/null and b/.vs/MiniVHD/v16/ipch/AutoPCH/aec064f3b1413ba4/MINIVHD_CREATE.ipch differ diff --git a/.vs/MiniVHD/v16/ipch/AutoPCH/bbb46fed585231f1/MINIVHD_CONVERT.ipch b/.vs/MiniVHD/v16/ipch/AutoPCH/bbb46fed585231f1/MINIVHD_CONVERT.ipch new file mode 100644 index 0000000..7459a46 Binary files /dev/null and b/.vs/MiniVHD/v16/ipch/AutoPCH/bbb46fed585231f1/MINIVHD_CONVERT.ipch differ diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..0cf5ea5 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": "No Configurations" +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..b439506 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,7 @@ +{ + "ExpandedNodes": [ + "" + ], + "SelectedNode": "\\CREDITS.md", + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..c9826c8 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/src/minivhd.h b/src/minivhd.h index 59dc838..d18bc64 100644 --- a/src/minivhd.h +++ b/src/minivhd.h @@ -21,20 +21,44 @@ typedef enum MVHDError { MVHD_ERR_PAR_NOT_FOUND, MVHD_ERR_INVALID_PAR_UUID, MVHD_ERR_INVALID_GEOM, - MVHD_ERR_INVALID_PARAMS, + MVHD_ERR_INVALID_SIZE, + MVHD_ERR_INVALID_BLOCK_SIZE, + MVHD_ERR_INVALID_PARAMS, MVHD_ERR_CONV_SIZE } MVHDError; +typedef enum MVHDType { + MVHD_TYPE_FIXED = 2, + MVHD_TYPE_DYNAMIC = 3, + MVHD_TYPE_DIFF = 4 +} MVHDType; + +typedef enum MVHDBlockSize { + MVHD_BLOCK_DEFAULT = 0, /**< 2 MB blocks */ + MVHD_BLOCK_SMALL = 1024, /**< 512 KB blocks */ + MVHD_BLOCK_LARGE = 4096 /**< 2 MB blocks */ +} MVHDBlockSize; + typedef struct MVHDGeom { uint16_t cyl; uint8_t heads; uint8_t spt; } MVHDGeom; -typedef struct MVHDMeta MVHDMeta; - typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors); +typedef struct MVHDCreationOptions { + int type; /** MVHD_TYPE_FIXED, MVHD_TYPE_DYNAMIC, or MVHD_TYPE_DIFF */ + char* path; /** Absolute path of the new VHD file */ + char* parent_path; /** For MVHD_TYPE_DIFF, this is the absolute path of the VHD's parent. For non-diff VHDs, this should be NULL. */ + uint64_t size_in_bytes; /** Total size of the VHD's virtual disk in bytes. Must be a multiple of 512. If 0, the size is auto-calculated from the geometry field. Ignored for MVHD_TYPE_DIFF. */ + MVHDGeom geometry; /** The geometry of the VHD. If set to 0, the geometry is auto-calculated from the size_in_bytes field. */ + uint32_t block_size_in_sectors; /** MVHD_BLOCK_LARGE or MVHD_BLOCK_SMALL, or 0 for the default value. The number of sectors per block. */ + mvhd_progress_callback progress_callback; /** Optional; if not NULL, gets called to indicate progress on the creation operation. Only applies to MVHD_TYPE_FIXED. */ +} MVHDCreationOptions; + +typedef struct MVHDMeta MVHDMeta; + /** * \brief Output a string from a MiniVHD error number * @@ -80,10 +104,9 @@ MVHDMeta* mvhd_open(const char* path, bool readonly, int* err); * \param [in] path is the absolute path to the image to create * \param [in] geom is the HDD geometry of the image to create. Determines final image size * \param [out] err indicates what error occurred, if any - * \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation + * \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation * - * \retval 0 if success - * \retval < 0 if an error occurrs. Check value of *err for actual error + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct */ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback); @@ -109,6 +132,18 @@ MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); */ MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err); +/** + * \brief Create a VHD using the provided options + * + * Use mvhd_create_ex if you want more control over the VHD's options. For quick creation, you can use mvhd_create_fixed, mvhd_create_sparse, or mvhd_create_diff. + * + * \param [in] options the VHD creation options. + * \param [out] err indicates what error occurred, if any + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err); + /** * \brief Safely close a VHD image * @@ -122,7 +157,9 @@ void mvhd_close(MVHDMeta* vhdm); * The VHD format uses Cylinder, Heads, Sectors per Track (CHS) when accessing the disk. * The size of the disk can be determined from C * H * S * sector_size. * - * Note, maximum VHD size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB + * Note, maximum geometry size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB. + * However, the maximum VHD size is 2040GB. For VHDs larger than 127GB, the geometry size will be + * smaller than the actual VHD size. * * This function determines the appropriate CHS geometry from a provided size in bytes. * The calculations used are those provided in "Appendix: CHS Calculation" from the document @@ -179,7 +216,7 @@ FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, * * \return the number of sectors that were not read, or zero */ -int mvhd_read_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff); +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); /** * \brief Write sectors to VHD file @@ -193,7 +230,7 @@ int mvhd_read_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buf * * \return the number of sectors that were not written, or zero */ -int mvhd_write_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff); +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); /** * \brief Write zeroed sectors to VHD file @@ -208,5 +245,5 @@ int mvhd_write_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buf * * \return the number of sectors that were not written, or zero */ -int mvhd_format_sectors(MVHDMeta* vhdm, int offset, int num_sectors); +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors); #endif \ No newline at end of file diff --git a/src/minivhd_convert.c b/src/minivhd_convert.c index 067863c..231e0f9 100644 --- a/src/minivhd_convert.c +++ b/src/minivhd_convert.c @@ -40,7 +40,8 @@ MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_ if (raw_img == NULL) { return NULL; } - MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, &geom, err, NULL); + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL); if (vhdm == NULL) { return NULL; } diff --git a/src/minivhd_create.c b/src/minivhd_create.c index 37b6715..5f68d3d 100644 --- a/src/minivhd_create.c +++ b/src/minivhd_create.c @@ -12,8 +12,8 @@ #include "minivhd_create.h" #include "minivhd.h" -static void mvhd_gen_footer(MVHDFooter* footer, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off); -static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset); +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off); +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors); static int mvhd_gen_par_loc(MVHDSparseHeader* header, const char* child_path, const char* par_path, @@ -21,17 +21,18 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, mvhd_utf16* w2ku_path_buff, mvhd_utf16* w2ru_path_buff, MVHDError* err); -static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, MVHDGeom* geom, int* err); +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err); /** * \brief Populate a VHD footer * * \param [in] footer to populate + * \param [in] size_in_bytes is the total size of the virtual hard disk in bytes * \param [in] geom to use * \param [in] type of HVD that is being created * \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images */ -static void mvhd_gen_footer(MVHDFooter* footer, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) { +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) { memcpy(footer->cookie, "conectix", sizeof footer->cookie); footer->features = 0x00000002; footer->fi_fmt_vers = 0x00010000; @@ -40,7 +41,7 @@ static void mvhd_gen_footer(MVHDFooter* footer, MVHDGeom* geom, MVHDType type, u memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app); footer->cr_vers = 0x000e0000; memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os); - footer->orig_sz = footer->curr_sz = mvhd_calc_size_bytes(geom); + footer->orig_sz = footer->curr_sz = size_in_bytes; footer->geom.cyl = geom->cyl; footer->geom.heads = geom->heads; footer->geom.spt = geom->spt; @@ -55,14 +56,15 @@ static void mvhd_gen_footer(MVHDFooter* footer, MVHDGeom* geom, MVHDType type, u * \param [in] header for sparse and differencing images * \param [in] num_blks is the number of data blocks that the image contains * \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table + * \param [in] block_size_in_sectors is the block size in sectors. */ -static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset) { +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) { memcpy(header->cookie, "cxsparse", sizeof header->cookie); header->data_offset = 0xffffffffffffffff; header->bat_offset = bat_offset; header->head_vers = 0x00010000; header->max_bat_ent = num_blks; - header->block_sz = (uint32_t)MVHD_SECT_PER_BLOCK * (uint32_t)MVHD_SECTOR_SIZE; + header->block_sz = block_size_in_sectors * (uint32_t)MVHD_SECTOR_SIZE; header->checksum = mvhd_gen_sparse_checksum(header); } @@ -165,7 +167,8 @@ end: } MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) { - return mvhd_create_fixed_raw(path, NULL, &geom, err, progress_callback); + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback); } /** @@ -176,7 +179,7 @@ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_prog * * \param [in] raw_image file handle to a raw disk image to populate VHD */ -MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) { +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) { uint8_t img_data[MVHD_SECTOR_SIZE] = {0}; uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; MVHDMeta* vhdm = calloc(1, sizeof *vhdm); @@ -197,7 +200,7 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, goto cleanup_vhdm; } mvhd_fseeko64(f, 0, SEEK_SET); - uint32_t size_sectors = mvhd_calc_size_sectors(geom); + uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); uint32_t s; if (progress_callback) progress_callback(0, size_sectors); @@ -209,7 +212,7 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, *err = MVHD_ERR_CONV_SIZE; goto cleanup_vhdm; } - mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_FIXED, 0); + mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0); mvhd_fseeko64(raw_img, 0, SEEK_SET); for (s = 0; s < size_sectors; s++) { fread(img_data, sizeof img_data, 1, raw_img); @@ -218,7 +221,7 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, progress_callback(s + 1, size_sectors); } } else { - mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_FIXED, 0); + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0); for (s = 0; s < size_sectors; s++) { fwrite(img_data, sizeof img_data, 1, f); if (progress_callback) @@ -245,12 +248,14 @@ end: * * \param [in] path is the absolute path to the VHD file to create * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [in] size_in_bytes is the total size in bytes of the virtual hard disk image * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [in] block_size_in_sectors is the block size in sectors * \param [out] err indicates what error occurred, if any * * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct */ -static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, MVHDGeom* geom, int* err) { +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) { uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0}; uint8_t bat_sect[MVHD_SECTOR_SIZE]; @@ -278,6 +283,7 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, par_geom.heads = par_vhdm->footer.geom.heads; par_geom.spt = par_vhdm->footer.geom.spt; geom = &par_geom; + size_in_bytes = par_vhdm->footer.curr_sz; } else if (geom != NULL && (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { *err = MVHD_ERR_INVALID_GEOM; goto cleanup_vhdm; @@ -293,21 +299,22 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, mvhd_fseeko64(f, 0, SEEK_SET); /* Note, the sparse header follows the footer copy at the beginning of the file */ if (par_path == NULL) { - mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE); + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE); } else { - mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE); + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE); } mvhd_footer_to_buffer(&vhdm->footer, footer_buff); /* As mentioned, start with a copy of the footer */ fwrite(footer_buff, sizeof footer_buff, 1, f); /** - * Calculate the number of (2MB) data blocks required to store the entire + * Calculate the number of (2MB or 512KB) data blocks required to store the entire * contents of the disk image, followed by the number of sectors the * BAT occupies in the image. Note, the BAT is sector aligned, and is padded * to the next sector boundary * */ - uint32_t num_blks = mvhd_calc_size_sectors(geom) / MVHD_SECT_PER_BLOCK; - if (mvhd_calc_size_sectors(geom) % MVHD_SECT_PER_BLOCK != 0) { + uint32_t size_in_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t num_blks = size_in_sectors / block_size_in_sectors; + if (size_in_sectors % block_size_in_sectors != 0) { num_blks += 1; } uint32_t num_bat_sect = num_blks / MVHD_BAT_ENT_PER_SECT; @@ -344,7 +351,7 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, goto cleanup_vhdm; } } - mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset); + mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors); mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); fwrite(sparse_buff, sizeof sparse_buff, 1, f); /* The BAT sectors need to be filled with 0xffffffff */ @@ -398,9 +405,80 @@ end: } MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) { - return mvhd_create_sparse_diff(path, NULL, &geom, err); + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err); } MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) { - return mvhd_create_sparse_diff(path, par_path, NULL, err); + return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) { + uint32_t geom_sector_size; + switch (options.type) + { + case MVHD_TYPE_FIXED: + case MVHD_TYPE_DYNAMIC: + geom_sector_size = mvhd_calc_size_sectors(&(options.geometry)); + if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0) + || (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES) + || (options.size_in_bytes == 0 && geom_sector_size == 0)) + { + *err = MVHD_ERR_INVALID_SIZE; + return NULL; + } + + if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes) + { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + + if (options.size_in_bytes == 0) + options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE; + + if (geom_sector_size == 0) + options.geometry = mvhd_calculate_geometry(options.size_in_bytes); + break; + case MVHD_TYPE_DIFF: + if (options.parent_path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + break; + default: + *err = MVHD_ERR_TYPE; + return NULL; + } + + if (options.path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + + if (options.type != MVHD_TYPE_FIXED) + { + if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT) + options.block_size_in_sectors = MVHD_BLOCK_LARGE; + + if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL) + { + *err = MVHD_ERR_INVALID_BLOCK_SIZE; + return NULL; + } + } + + switch (options.type) + { + case MVHD_TYPE_FIXED: + return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback); + case MVHD_TYPE_DYNAMIC: + return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err); + case MVHD_TYPE_DIFF: + return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err); + } + + return NULL; /* Make the compiler happy */ } \ No newline at end of file diff --git a/src/minivhd_create.h b/src/minivhd_create.h index 3db1f3f..9840d19 100644 --- a/src/minivhd_create.h +++ b/src/minivhd_create.h @@ -3,6 +3,6 @@ #include #include "minivhd.h" -MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback); +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback); #endif \ No newline at end of file diff --git a/src/minivhd_internal.h b/src/minivhd_internal.h index a0e795d..ea75284 100644 --- a/src/minivhd_internal.h +++ b/src/minivhd_internal.h @@ -8,9 +8,10 @@ #define MVHD_SPARSE_SIZE 1024 #define MVHD_SECTOR_SIZE 512 -#define MVHD_SECT_PER_BLOCK 4096 /* 2MB block size */ #define MVHD_BAT_ENT_PER_SECT 128 +#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000 + #define MVHD_SPARSE_BLK 0xffffffff /* For simplicity, we don't handle paths longer than this * Note, this is the max path in characters, as that is what @@ -22,12 +23,6 @@ #define MVHD_DIF_LOC_W2RU 0x57327275 #define MVHD_DIF_LOC_W2KU 0x57326B75 -typedef enum MVHDType { - MVHD_TYPE_FIXED = 2, - MVHD_TYPE_DYNAMIC = 3, - MVHD_TYPE_DIFF = 4 -} MVHDType; - typedef struct MVHDSectorBitmap { uint8_t* curr_bitmap; int sector_count; @@ -90,8 +85,8 @@ struct MVHDMeta { uint32_t* block_offset; int sect_per_block; MVHDSectorBitmap bitmap; - int (*read_sectors)(MVHDMeta*, int, int, void*); - int (*write_sectors)(MVHDMeta*, int, int, void*); + int (*read_sectors)(MVHDMeta*, uint32_t, int, void*); + int (*write_sectors)(MVHDMeta*, uint32_t, int, void*); struct { uint8_t* zero_data; int sector_count; diff --git a/src/minivhd_io.c b/src/minivhd_io.c index cd366a5..8e9172e 100644 --- a/src/minivhd_io.c +++ b/src/minivhd_io.c @@ -15,7 +15,7 @@ #define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) ) #define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) ) -static inline void mvhd_check_sectors(int offset, int num_sectors, int total_sectors, int* transfer_sect, int* trunc_sect); +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect); static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk); static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk); static void mvhd_create_block(MVHDMeta* vhdm, int blk); @@ -31,10 +31,10 @@ static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm); * This may be lower than num_sectors if offset + num_sectors >= total_sectors * \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors */ -static inline void mvhd_check_sectors(int offset, int num_sectors, int total_sectors, int* transfer_sect, int* trunc_sect) { +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) { *transfer_sect = num_sectors; *trunc_sect = 0; - if ((total_sectors - offset) < *transfer_sect) { + if ((total_sectors - offset) < (uint32_t)*transfer_sect) { *transfer_sect = total_sectors - offset; *trunc_sect = num_sectors - *transfer_sect; } @@ -128,7 +128,7 @@ static void mvhd_create_block(MVHDMeta* vhdm, int blk) { } abs_offset += padding_amount; } - int sect_offset = (int)(abs_offset / MVHD_SECTOR_SIZE); + uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE); int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors); /* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */ @@ -140,10 +140,10 @@ static void mvhd_create_block(MVHDMeta* vhdm, int blk) { mvhd_write_bat_entry(vhdm, blk); } -int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) { +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { int64_t addr; int transfer_sectors, truncated_sectors; - int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); addr = (int64_t)offset * MVHD_SECTOR_SIZE; mvhd_fseeko64(vhdm->f, addr, SEEK_SET); @@ -151,13 +151,14 @@ int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) return truncated_sectors; } -int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) { +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { int transfer_sectors, truncated_sectors; - int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); uint8_t* buff = (uint8_t*)out_buff; int64_t addr; - int s, ls, blk, prev_blk, sib; + uint32_t s, ls; + int blk, prev_blk, sib; ls = offset + transfer_sectors; prev_blk = -1; for (s = offset; s < ls; s++) { @@ -184,13 +185,14 @@ int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff return truncated_sectors; } -int mvhd_diff_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) { +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { int transfer_sectors, truncated_sectors; - int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); uint8_t* buff = (uint8_t*)out_buff; MVHDMeta* curr_vhdm = vhdm; - int s, ls, blk, sib; + uint32_t s, ls; + int blk, sib; ls = offset + transfer_sectors; for (s = offset; s < ls; s++) { while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) { @@ -216,10 +218,10 @@ int mvhd_diff_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) return truncated_sectors; } -int mvhd_fixed_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) { +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { int64_t addr; int transfer_sectors, truncated_sectors; - int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); addr = (int64_t)offset * MVHD_SECTOR_SIZE; mvhd_fseeko64(vhdm->f, addr, SEEK_SET); @@ -227,13 +229,14 @@ int mvhd_fixed_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) return truncated_sectors; } -int mvhd_sparse_diff_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) { +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { int transfer_sectors, truncated_sectors; - int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); uint8_t* buff = (uint8_t*)in_buff; int64_t addr; - int s, ls, blk, prev_blk, sib; + uint32_t s, ls; + int blk, prev_blk, sib; ls = offset + transfer_sectors; prev_blk = -1; for (s = offset; s < ls; s++) { @@ -268,6 +271,6 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in return truncated_sectors; } -int mvhd_noop_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) { +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { return 0; } \ No newline at end of file diff --git a/src/minivhd_io.h b/src/minivhd_io.h index 7301e72..cdbfa6d 100644 --- a/src/minivhd_io.h +++ b/src/minivhd_io.h @@ -28,7 +28,7 @@ void mvhd_write_empty_sectors(FILE* f, int sector_count); * \retval 0 num_sectors were read from file * \retval >0 < num_sectors were read from file */ -int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff); +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); /** * \brief Read a sparse VHD image @@ -48,7 +48,7 @@ int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) * \retval 0 num_sectors were read from file * \retval >0 < num_sectors were read from file */ -int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff); +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); /** * \brief Read a differencing VHD image @@ -71,7 +71,7 @@ int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff * \retval 0 num_sectors were read from file * \retval >0 < num_sectors were read from file */ -int mvhd_diff_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff); +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); /** * \brief Write to a fixed VHD image @@ -88,7 +88,7 @@ int mvhd_diff_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff); * \retval 0 num_sectors were written to file * \retval >0 < num_sectors were written to file */ -int mvhd_fixed_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff); +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); /** * \brief Write to a sparse or differencing VHD image @@ -113,7 +113,7 @@ int mvhd_fixed_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) * \retval 0 num_sectors were written to file * \retval >0 < num_sectors were written to file */ -int mvhd_sparse_diff_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff); +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); /** * \brief A no-op function to "write" to read-only VHD images @@ -127,6 +127,6 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in * \retval 0 num_sectors were written to file * \retval >0 < num_sectors were written to file */ -int mvhd_noop_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff); +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); #endif \ No newline at end of file diff --git a/src/minivhd_manage.c b/src/minivhd_manage.c index ed5e564..6c4384d 100644 --- a/src/minivhd_manage.c +++ b/src/minivhd_manage.c @@ -328,19 +328,18 @@ bool mvhd_file_is_vhd(FILE* f) { MVHDGeom mvhd_calculate_geometry(uint64_t size) { MVHDGeom chs; - uint64_t ts = size / MVHD_SECTOR_SIZE; + uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE); uint32_t spt, heads, cyl, cth; if (ts > 65535 * 16 * 255) { ts = 65535 * 16 * 255; } - if (ts >= 65535 * 16 * 63) { - ts = 65535 * 16 * 63; + if (ts >= 65535 * 16 * 63) { spt = 255; heads = 16; - cth = (uint32_t)ts / spt; + cth = ts / spt; } else { spt = 17; - cth = (uint32_t)ts / spt; + cth = ts / spt; heads = (cth + 1023) / 1024; if (heads < 4) { heads = 4; @@ -348,12 +347,12 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size) { if (cth >= (heads * 1024) || heads > 16) { spt = 31; heads = 16; - cth = (uint32_t)ts / spt; + cth = ts / spt; } if (cth >= (heads * 1024)) { spt = 63; heads = 16; - cth = (uint32_t)ts / spt; + cth = ts / spt; } } cyl = cth / heads; @@ -475,19 +474,20 @@ void mvhd_close(MVHDMeta* vhdm) { } } -int mvhd_read_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) { +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff); } -int mvhd_write_sectors(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) { +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff); } -int mvhd_format_sectors(MVHDMeta* vhdm, int offset, int num_sectors) { +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) { int num_full = num_sectors / vhdm->format_buffer.sector_count; int remain = num_sectors % vhdm->format_buffer.sector_count; for (int i = 0; i < num_full; i++) { vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data); + offset += vhdm->format_buffer.sector_count; } vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data); return 0; diff --git a/src/minivhd_util.c b/src/minivhd_util.c index 7fdfcda..5e1475e 100644 --- a/src/minivhd_util.c +++ b/src/minivhd_util.c @@ -225,6 +225,10 @@ const char* mvhd_strerr(MVHDError err) { return "UUID mismatch between child and parent VHD"; case MVHD_ERR_INVALID_GEOM: return "invalid geometry detected"; + case MVHD_ERR_INVALID_SIZE: + return "invalid size"; + case MVHD_ERR_INVALID_BLOCK_SIZE: + return "invalid block size"; case MVHD_ERR_INVALID_PARAMS: return "invalid parameters passed to function"; case MVHD_ERR_CONV_SIZE: