diff --git a/src/minivhd.h b/src/minivhd.h index a3543ba..aee8d98 100644 --- a/src/minivhd.h +++ b/src/minivhd.h @@ -33,6 +33,8 @@ typedef struct MVHDGeom { typedef struct MVHDMeta MVHDMeta; +typedef void (*mvhd_progress_callback_t)(int64_t progress); + /** * \brief Output a string from a MiniVHD error number * @@ -79,11 +81,12 @@ MVHDMeta* mvhd_open(const char* path, bool readonly, int* err); * \param [in] geom is the HDD geometry of the image to create. Determines final image size * \param [out] pos stores the current sector being written to disk * \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 * * \retval 0 if success * \retval < 0 if an error occurrs. Check value of *err for actual error */ -MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err); +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err, mvhd_progress_callback_t progress_callback); /** * \brief Create sparse (dynamic) VHD image. @@ -91,10 +94,11 @@ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err) * \param [in] path is the absolute path to the VHD file 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 * * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct */ -MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback_t progress_callback); /** * \brief Create differencing VHD imagee. @@ -102,10 +106,11 @@ MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); * \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 [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 * * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct */ -MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err); +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err, mvhd_progress_callback_t progress_callback); /** * \brief Safely close a VHD image diff --git a/src/minivhd_convert.c b/src/minivhd_convert.c index bf621a9..24f3a43 100644 --- a/src/minivhd_convert.c +++ b/src/minivhd_convert.c @@ -20,8 +20,8 @@ static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geo *err = MVHD_ERR_INVALID_GEOM; return NULL; } - fseeko64(raw_img, 0, SEEK_END); - uint64_t size_bytes = (uint64_t)ftello64(raw_img); + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img); MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes); if (mvhd_calc_size_bytes(&new_geom) != size_bytes) { *err = MVHD_ERR_CONV_SIZE; @@ -30,7 +30,7 @@ static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geo geom->cyl = new_geom.cyl; geom->heads = new_geom.heads; geom->spt = new_geom.spt; - fseeko64(raw_img, 0, SEEK_SET); + mvhd_fseeko64(raw_img, 0, SEEK_SET); return raw_img; } @@ -41,7 +41,7 @@ MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_ return NULL; } int pos; - MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, &geom, &pos, err); + MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, &geom, &pos, err, NULL); if (vhdm == NULL) { return NULL; } @@ -54,7 +54,7 @@ MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8 if (raw_img == NULL) { return NULL; } - vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err); + vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err, NULL); if (vhdm == NULL) { goto end; } @@ -100,6 +100,6 @@ FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, fwrite(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); } mvhd_close(vhdm); - fseeko64(raw_img, 0, SEEK_SET); + mvhd_fseeko64(raw_img, 0, SEEK_SET); return raw_img; } \ No newline at end of file diff --git a/src/minivhd_create.c b/src/minivhd_create.c index f83e2c1..9696d81 100644 --- a/src/minivhd_create.c +++ b/src/minivhd_create.c @@ -18,10 +18,10 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, const char* child_path, const char* par_path, uint64_t start_offset, - void* w2ku_buff, - void* w2ru_buff, + mvhd_utf16* w2ku_path, + mvhd_utf16* w2ru_path, 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, MVHDGeom* geom, int* err, mvhd_progress_callback_t progress_callback); /** * \brief Populate a VHD footer @@ -84,8 +84,8 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, const char* child_path, const char* par_path, uint64_t start_offset, - void* w2ku_buff, - void* w2ru_buff, + mvhd_utf16* w2ku_path, + mvhd_utf16* w2ru_path, MVHDError* err) { /* Get our paths to store in the differencing VHD. We want both the absolute path to the parent, as well as the relative path from the child VHD */ @@ -96,7 +96,7 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, char child_dir[MVHD_MAX_PATH_BYTES] = {0}; size_t child_dir_len; if (strlen(child_path) < sizeof child_dir) { - strcpy(child_dir, child_path); + strcpy_s(child_dir, MVHD_MAX_PATH_BYTES, child_path); } else { *err = MVHD_ERR_PATH_LEN; rv = -1; @@ -116,43 +116,27 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, int utf_ret; utf_ret = UTF8ToUTF16BE((unsigned char*)header->par_utf16_name, &outlen, (const unsigned char*)par_filename, (int*)&par_fn_len); if (utf_ret < 0) { - mvhd_set_encoding_err(utf_ret, err); + mvhd_set_encoding_err(utf_ret, (int*)err); rv = -1; goto end; } - /** - * Create output buffers to encode paths into. - * The paths are not stored directly in the sparse header, hence the need to - * store them in buffers to be written to the VHD image later - */ - mvhd_utf16 *w2ku_path = calloc(MVHD_MAX_PATH_CHARS, sizeof *w2ku_path); - if (w2ku_path == NULL) { - *err = MVHD_ERR_MEM; - rv = -1; - goto end; - } - mvhd_utf16 *w2ru_path = calloc(MVHD_MAX_PATH_CHARS, sizeof *w2ru_path); - if (w2ru_path == NULL) { - *err = MVHD_ERR_MEM; - rv = -1; - goto cleanup_w2ku; - } + /* And encode the paths to UTF16-LE */ size_t par_path_len = strlen(par_path); outlen = sizeof *w2ku_path * MVHD_MAX_PATH_CHARS; utf_ret = UTF8ToUTF16LE((unsigned char*)w2ku_path, &outlen, (const unsigned char*)par_path, (int*)&par_path_len); if (utf_ret < 0) { - mvhd_set_encoding_err(utf_ret, err); + mvhd_set_encoding_err(utf_ret, (int*)err); rv = -1; - goto cleanup_w2ru; + goto end; } int w2ku_len = utf_ret; outlen = sizeof *w2ru_path * MVHD_MAX_PATH_CHARS; utf_ret = UTF8ToUTF16LE((unsigned char*)w2ru_path, &outlen, (const unsigned char*)rel_path, (int*)&rel_len); if (utf_ret < 0) { - mvhd_set_encoding_err(utf_ret, err); + mvhd_set_encoding_err(utf_ret, (int*)err); rv = -1; - goto cleanup_w2ru; + goto end; } int w2ru_len = utf_ret; /** @@ -170,16 +154,12 @@ static int mvhd_gen_par_loc(MVHDSparseHeader* header, header->par_loc_entry[1].plat_data_space = (header->par_loc_entry[1].plat_data_len / MVHD_SECTOR_SIZE) + 1; goto end; -cleanup_w2ru: - free(w2ru_path); -cleanup_w2ku: - free(w2ku_path); end: return rv; } -MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err) { - return mvhd_create_fixed_raw(path, NULL, &geom, pos, err); +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err, mvhd_progress_callback_t progress_callback) { + return mvhd_create_fixed_raw(path, NULL, &geom, pos, err, progress_callback); } /** @@ -190,7 +170,7 @@ MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* pos, int* err) * * \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* pos, int* err) { +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, int* pos, int* err, mvhd_progress_callback_t progress_callback) { uint8_t img_data[MVHD_SECTOR_SIZE] = {0}; uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; MVHDMeta* vhdm = calloc(1, sizeof *vhdm); @@ -210,11 +190,13 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, if (f == NULL) { goto cleanup_vhdm; } - fseeko64(f, 0, SEEK_SET); + mvhd_fseeko64(f, 0, SEEK_SET); uint32_t size_sectors, s; + if (progress_callback) + progress_callback(0); if (raw_img != NULL) { - fseeko64(raw_img, 0, SEEK_END); - uint64_t raw_size = (uint64_t)ftello64(raw_img); + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img); MVHDGeom raw_geom = mvhd_calculate_geometry(raw_size); if (mvhd_calc_size_bytes(&raw_geom) != raw_size) { *err = MVHD_ERR_CONV_SIZE; @@ -222,13 +204,15 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, } mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_FIXED, 0); size_sectors = mvhd_calc_size_sectors(geom); - fseeko64(raw_img, 0, SEEK_SET); + mvhd_fseeko64(raw_img, 0, SEEK_SET); for (s = 0; s < size_sectors; s++) { if (pos != NULL) { *pos = (int)s; } fread(img_data, sizeof img_data, 1, raw_img); fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s); } } else { mvhd_gen_footer(&vhdm->footer, geom, MVHD_TYPE_FIXED, 0); @@ -238,6 +222,8 @@ MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, *pos = (int)s; } fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s); } } mvhd_footer_to_buffer(&vhdm->footer, footer_buff); @@ -265,20 +251,24 @@ end: * * \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, MVHDGeom* geom, int* err, mvhd_progress_callback_t progress_callback) { uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0}; uint8_t bat_sect[MVHD_SECTOR_SIZE]; - MVHDGeom par_geom = {}; + MVHDGeom par_geom = {0}; memset(bat_sect, 0xffffffff, sizeof bat_sect); + MVHDMeta* vhdm = NULL; MVHDMeta* par_vhdm = NULL; + mvhd_utf16* w2ku_path = NULL; + mvhd_utf16* w2ru_path = NULL; + if (par_path != NULL) { par_vhdm = mvhd_open(par_path, true, err); if (par_vhdm == NULL) { goto end; } } - MVHDMeta* vhdm = calloc(1, sizeof *vhdm); + vhdm = calloc(1, sizeof *vhdm); if (vhdm == NULL) { *err = MVHD_ERR_MEM; goto cleanup_par_vhdm; @@ -296,11 +286,14 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, *err = MVHD_ERR_INVALID_GEOM; goto cleanup_vhdm; } + + if (progress_callback) + progress_callback(0); FILE* f = mvhd_fopen(path, "wb+", err); if (f == NULL) { goto cleanup_vhdm; } - fseeko64(f, 0, SEEK_SET); + 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); @@ -326,17 +319,31 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, } /* Storing the BAT directly following the footer and header */ uint64_t bat_offset = MVHD_FOOTER_SIZE + MVHD_SPARSE_SIZE; - uint64_t par_loc_offset = 0; - uint8_t *w2ku_path, *w2ru_path; - w2ku_path = w2ru_path = NULL; + uint64_t par_loc_offset = 0; + /** * If creating a differencing VHD, populate the sparse header with additional * data about the parent image, and where to find it * */ if (par_vhdm != NULL) { + /** + * Create output buffers to encode paths into. + * The paths are not stored directly in the sparse header, hence the need to + * store them in buffers to be written to the VHD image later + */ + w2ku_path = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ku_path); + if (w2ku_path == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + w2ru_path = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ru_path); + if (w2ru_path == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid); - par_loc_offset = bat_offset + (num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE); - if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path, w2ru_path, err) < 0) { + par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE); + if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path, w2ru_path, (MVHDError*)err) < 0) { goto cleanup_vhdm; } } @@ -353,23 +360,23 @@ static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, * tp the file. Both absolute and relative paths are written * */ if (par_vhdm != NULL) { - uint64_t curr_pos = (uint64_t)ftello64(f); + uint64_t curr_pos = (uint64_t)mvhd_ftello64(f); /* Double check my sums... */ assert(curr_pos == par_loc_offset); /* Fill the space required for location data with zero */ uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0}; for (int i = 0; i < 2; i++) { - for (int j = 0; j < vhdm->sparse.par_loc_entry[i].plat_data_space; j++) { + for (uint32_t j = 0; j < vhdm->sparse.par_loc_entry[i].plat_data_space; j++) { fwrite(empty_sect, sizeof empty_sect, 1, f); } } /* Now write the location entries */ - fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET); fwrite(w2ku_path, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f); - fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET); fwrite(w2ru_path, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f); /* and reset the file position to continue */ - fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + (vhdm->sparse.par_loc_entry[1].plat_data_space * MVHD_SECTOR_SIZE), SEEK_SET); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + ((uint64_t)(vhdm->sparse.par_loc_entry[1].plat_data_space) * MVHD_SECTOR_SIZE), SEEK_SET); mvhd_write_empty_sectors(f, 5); } /* And finish with the footer */ @@ -388,13 +395,19 @@ cleanup_par_vhdm: mvhd_close(par_vhdm); } end: + if (w2ku_path != NULL) + free(w2ku_path); + if (w2ru_path != NULL) + free(w2ru_path); + if (progress_callback) + progress_callback(mvhd_calc_size_sectors(geom) - 1); return vhdm; } -MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) { - return mvhd_create_sparse_diff(path, NULL, &geom, err); +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback_t progress_callback) { + return mvhd_create_sparse_diff(path, NULL, &geom, err, progress_callback); } -MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) { - return mvhd_create_sparse_diff(path, par_path, NULL, err); +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err, mvhd_progress_callback_t progress_callback) { + return mvhd_create_sparse_diff(path, par_path, NULL, err, progress_callback); } \ No newline at end of file diff --git a/src/minivhd_create.h b/src/minivhd_create.h index a767d44..f07520f 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* pos, int* err); +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, MVHDGeom* geom, int* pos, int* err, mvhd_progress_callback_t progress_callback); #endif \ No newline at end of file diff --git a/src/minivhd_io.c b/src/minivhd_io.c index 1a0acfb..cd366a5 100644 --- a/src/minivhd_io.c +++ b/src/minivhd_io.c @@ -58,7 +58,7 @@ void mvhd_write_empty_sectors(FILE* f, int sector_count) { */ static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) { if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) { - fseeko64(vhdm->f, vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET); + mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET); fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f); } else { memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE); @@ -73,8 +73,8 @@ static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) { */ static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) { if (vhdm->bitmap.curr_block >= 0) { - int64_t abs_offset = vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE; - fseeko64(vhdm->f, abs_offset, SEEK_SET); + int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET); fwrite(vhdm->bitmap.curr_bitmap, MVHD_SECTOR_SIZE, vhdm->bitmap.sector_count, vhdm->f); } } @@ -86,9 +86,9 @@ static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) { * \param [in] blk The block for which to write the offset for */ static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) { - uint64_t table_offset = vhdm->sparse.bat_offset + (blk * sizeof *vhdm->block_offset); + uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset); uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]); - fseeko64(vhdm->f, table_offset, SEEK_SET); + mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET); fwrite(&offset, sizeof offset, 1, vhdm->f); } @@ -109,16 +109,16 @@ static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) { static void mvhd_create_block(MVHDMeta* vhdm, int blk) { uint8_t footer[MVHD_FOOTER_SIZE]; /* Seek to where the footer SHOULD be */ - fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); fread(footer, sizeof footer, 1, vhdm->f); - fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); if (!mvhd_is_conectix_str(footer)) { /* Oh dear. We use the header instead, since something has gone wrong at the footer */ - fseeko64(vhdm->f, 0, SEEK_SET); + mvhd_fseeko64(vhdm->f, 0, SEEK_SET); fread(footer, sizeof footer, 1, vhdm->f); - fseeko64(vhdm->f, 0, SEEK_END); + mvhd_fseeko64(vhdm->f, 0, SEEK_END); } - int64_t abs_offset = ftello64(vhdm->f); + int64_t abs_offset = mvhd_ftello64(vhdm->f); if (abs_offset % MVHD_SECTOR_SIZE != 0) { /* Yikes! We're supposed to be on a sector boundary. Add some padding */ int64_t padding_amount = (int64_t)MVHD_SECTOR_SIZE - (abs_offset % MVHD_SECTOR_SIZE); @@ -146,7 +146,7 @@ int mvhd_fixed_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff) int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); addr = (int64_t)offset * MVHD_SECTOR_SIZE; - fseeko64(vhdm->f, addr, SEEK_SET); + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); return truncated_sectors; } @@ -167,16 +167,17 @@ int mvhd_sparse_read(MVHDMeta* vhdm, int offset, int num_sectors, void* out_buff prev_blk = blk; if (vhdm->bitmap.curr_block != blk) { mvhd_read_sect_bitmap(vhdm, blk); - fseeko64(vhdm->f, sib * MVHD_SECTOR_SIZE, SEEK_CUR); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); } else { - addr = (int64_t)(vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; - fseeko64(vhdm->f, addr, SEEK_SET); + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); } - } + } if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) { fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); } else { memset(buff, 0, MVHD_SECTOR_SIZE); + mvhd_fseeko64(vhdm->f, MVHD_SECTOR_SIZE, SEEK_CUR); } buff += MVHD_SECTOR_SIZE; } @@ -221,7 +222,7 @@ int mvhd_fixed_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in_buff) int total_sectors = vhdm->footer.geom.cyl * vhdm->footer.geom.heads * vhdm->footer.geom.spt; mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); addr = (int64_t)offset * MVHD_SECTOR_SIZE; - fseeko64(vhdm->f, addr, SEEK_SET); + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); return truncated_sectors; } @@ -251,10 +252,10 @@ int mvhd_sparse_diff_write(MVHDMeta* vhdm, int offset, int num_sectors, void* in mvhd_write_curr_sect_bitmap(vhdm); } mvhd_read_sect_bitmap(vhdm, blk); - fseeko64(vhdm->f, sib * MVHD_SECTOR_SIZE, SEEK_CUR); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); } else { - addr = (int64_t)(vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; - fseeko64(vhdm->f, addr, SEEK_SET); + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); } prev_blk = blk; } diff --git a/src/minivhd_manage.c b/src/minivhd_manage.c index 6c9429f..ed5e564 100644 --- a/src/minivhd_manage.c +++ b/src/minivhd_manage.c @@ -42,7 +42,7 @@ static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err); */ static void mvhd_read_footer(MVHDMeta* vhdm) { uint8_t buffer[MVHD_FOOTER_SIZE]; - fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); fread(buffer, sizeof buffer, 1, vhdm->f); mvhd_buffer_to_footer(&vhdm->footer, buffer); } @@ -54,7 +54,7 @@ static void mvhd_read_footer(MVHDMeta* vhdm) { */ static void mvhd_read_sparse_header(MVHDMeta* vhdm) { uint8_t buffer[MVHD_SPARSE_SIZE]; - fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET); + mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET); fread(buffer, sizeof buffer, 1, vhdm->f); mvhd_buffer_to_header(&vhdm->sparse, buffer); } @@ -100,7 +100,7 @@ static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) { *err = MVHD_ERR_MEM; return -1; } - fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET); + mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET); for (uint32_t i = 0; i < vhdm->sparse.max_bat_ent; i++) { fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f); vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]); @@ -171,7 +171,7 @@ static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) { cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path); } else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) { - strncpy(paths->joined_path, (const char*)paths->w2ku_path, sizeof paths->joined_path); + strncpy_s(paths->joined_path, sizeof paths->joined_path, (const char*)paths->w2ku_path, sizeof paths->joined_path); cwk_ret = 0; } else if (plat_code == 0) { cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->file_name, paths->joined_path, sizeof paths->joined_path); @@ -182,7 +182,7 @@ static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr); if (f != NULL) { /* We found a file at the requested path! */ - strncpy(tmp_open_path, paths->joined_path, sizeof tmp_open_path); + strncpy_s(tmp_open_path, sizeof tmp_open_path, paths->joined_path, sizeof tmp_open_path); fclose(f); return true; } else { @@ -225,7 +225,7 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) { *err = MVHD_ERR_PATH_LEN; goto paths_cleanup; } - strncpy(paths->dir_path, vhdm->filename, dirlen); + strncpy_s(paths->dir_path, sizeof paths->dir_path, vhdm->filename, dirlen); /* Get the filename field from the sparse header. */ utf_outlen = (int)sizeof paths->file_name; utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name; @@ -250,7 +250,7 @@ static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) { *err = MVHD_ERR_PATH_LEN; goto paths_cleanup; } - fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET); + mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET); fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f); /* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained, which is UTF-16BE */ @@ -318,7 +318,7 @@ static void mvhd_assign_io_funcs(MVHDMeta* vhdm) { bool mvhd_file_is_vhd(FILE* f) { if (f) { uint8_t con_str[8]; - fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END); + mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END); fread(con_str, sizeof con_str, 1, f); return mvhd_is_conectix_str(con_str); } else { @@ -328,7 +328,7 @@ bool mvhd_file_is_vhd(FILE* f) { MVHDGeom mvhd_calculate_geometry(uint64_t size) { MVHDGeom chs; - uint32_t ts = size / MVHD_SECTOR_SIZE; + uint64_t ts = size / MVHD_SECTOR_SIZE; uint32_t spt, heads, cyl, cth; if (ts > 65535 * 16 * 255) { ts = 65535 * 16 * 255; @@ -337,10 +337,10 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size) { ts = 65535 * 16 * 63; spt = 255; heads = 16; - cth = ts / spt; + cth = (uint32_t)ts / spt; } else { spt = 17; - cth = ts / spt; + cth = (uint32_t)ts / spt; heads = (cth + 1023) / 1024; if (heads < 4) { heads = 4; @@ -348,12 +348,12 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size) { if (cth >= (heads * 1024) || heads > 16) { spt = 31; heads = 16; - cth = ts / spt; + cth = (uint32_t)ts / spt; } if (cth >= (heads * 1024)) { spt = 63; heads = 16; - cth = ts / spt; + cth = (uint32_t)ts / spt; } } cyl = cth / heads; @@ -364,7 +364,7 @@ MVHDGeom mvhd_calculate_geometry(uint64_t size) { } MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) { - int open_err; + MVHDError open_err; MVHDMeta *vhdm = calloc(sizeof *vhdm, 1); if (vhdm == NULL) { *err = MVHD_ERR_MEM; @@ -374,7 +374,7 @@ MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) { *err = MVHD_ERR_PATH_LEN; goto cleanup_vhdm; } - strcpy(vhdm->filename, path); + strcpy_s(vhdm->filename, sizeof vhdm->filename, path); vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err); if (vhdm->f == NULL) { /* note, mvhd_fopen sets err for us */ diff --git a/src/minivhd_util.c b/src/minivhd_util.c index b05c9f7..7fdfcda 100644 --- a/src/minivhd_util.c +++ b/src/minivhd_util.c @@ -66,14 +66,14 @@ uint32_t mvhd_to_be32(uint32_t val) { uint64_t mvhd_to_be64(uint64_t val) { uint64_t ret = 0; uint8_t *tmp = (uint8_t*)&ret; - tmp[0] = (val & 0xff00000000000000) >> 56; - tmp[1] = (val & 0x00ff000000000000) >> 48; - tmp[2] = (val & 0x0000ff0000000000) >> 40; - tmp[3] = (val & 0x000000ff00000000) >> 32; - tmp[4] = (val & 0x00000000ff000000) >> 24; - tmp[5] = (val & 0x0000000000ff0000) >> 16; - tmp[6] = (val & 0x000000000000ff00) >> 8; - tmp[7] = (val & 0x00000000000000ff) >> 0; + tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56); + tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); + tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); + tmp[3] = (uint8_t)((val & 0x000000ff00000000) >> 32); + tmp[4] = (uint8_t)((val & 0x00000000ff000000) >> 24); + tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); + tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); + tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0); return ret; } @@ -88,7 +88,7 @@ bool mvhd_is_conectix_str(const void* buffer) { void mvhd_generate_uuid(uint8_t* uuid) { /* We aren't doing crypto here, so using system time as seed should be good enough */ - srand(time(0)); + srand((unsigned int)time(0)); for (int n = 0; n < 16; n++) { uuid[n] = rand(); } @@ -128,8 +128,8 @@ FILE* mvhd_fopen(const char* path, const char* mode, int* err) { int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len); if (path_res > 0 && mode_res > 0) { - f = _wfopen(new_path, mode_str); - if (f == NULL) { + errno_t wfopen_err = _wfopen_s(&f, new_path, mode_str); + if (wfopen_err != 0 || f == NULL) { mvhd_errno = errno; *err = MVHD_ERR_FILE; } @@ -168,6 +168,11 @@ uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) { return sector_size; } +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) { + MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt }; + return geometry; +} + uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) { uint32_t new_chk = 0; uint32_t orig_chk = footer->checksum; @@ -227,4 +232,41 @@ const char* mvhd_strerr(MVHDError err) { default: return "unknown error"; } +} + +int64_t mvhd_ftello64(FILE* stream) +{ +#ifdef _MSC_VER + return _ftelli64(stream); +#else + return ftello64(stream); +#endif +} + +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin) +{ +#ifdef _MSC_VER + return _fseeki64(stream, offset, origin); +#else + return fseeko64(stream, offset, origin); +#endif +} + +uint32_t mvhd_crc32_for_byte(uint32_t r) { + for (int j = 0; j < 8; ++j) + r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; + return r ^ (uint32_t)0xFF000000L; +} + +uint32_t mvhd_crc32(const void* data, size_t n_bytes) { + static uint32_t table[0x100]; + if (!*table) + for (size_t i = 0; i < 0x100; ++i) + table[i] = mvhd_crc32_for_byte(i); + + uint32_t crc = 0; + for (size_t i = 0; i < n_bytes; ++i) + crc = table[(uint8_t)crc ^ ((uint8_t*)data)[i]] ^ crc >> 8; + + return crc; } \ No newline at end of file diff --git a/src/minivhd_util.h b/src/minivhd_util.h index 62e172f..eabbf92 100644 --- a/src/minivhd_util.h +++ b/src/minivhd_util.h @@ -68,6 +68,7 @@ FILE* mvhd_fopen(const char* path, const char* mode, int* err); void mvhd_set_encoding_err(int encoding_retval, int* err); uint64_t mvhd_calc_size_bytes(MVHDGeom *geom); uint32_t mvhd_calc_size_sectors(MVHDGeom *geom); +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm); /** * \brief Generate VHD footer checksum @@ -82,4 +83,30 @@ uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer); * \param [in] vhdm MiniVHD data structure */ uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header); + +/** + * \brief Get current position in file stream + * + * This is a portable version of the POSIX ftello64(). * + */ +int64_t mvhd_ftello64(FILE* stream); + +/** + * \brief Reposition the file stream's position + * + * This is a portable version of the POSIX fseeko64(). * + */ +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin); + +/** + * \brief Calculate the CRC32 of a data buffer. + * + * This function can be used for verifying data integrity. + * + * \param [in] data The data buffer + * \param [in] n_bytes The size of the data buffer in bytes + * + * \return The CRC32 of the data buffer + */ +uint32_t mvhd_crc32(const void* data, size_t n_bytes); #endif \ No newline at end of file