Fixed bug in mvhd_create_sparse_diff (w2ku_path and w2ru_path were NULL and never populated).

Fixed bug in mvhd_sparse_read (needed an fseek after doing memset(buff, 0, MVHD_SECTOR_SIZE)).
Added progress callbacks to the mvhd_create_* functions.
Converted all use of ftello64 and fseeko64 to new portable versions: mvhd_ftello64 and mvhd_fseeko64.
Addes some explicit casts and other fixes to remove compiler warnings.
This commit is contained in:
Stephen McKinney
2020-11-05 01:58:49 -06:00
parent 3c54ca311a
commit 83e8ff4eb7
8 changed files with 200 additions and 112 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -3,6 +3,6 @@
#include <stdio.h>
#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

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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;
}

View File

@@ -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