Basic VHD open functionality

This commit is contained in:
shermp
2019-06-09 12:55:45 +12:00
parent 3e7fd76684
commit 67bf1af5ae
6 changed files with 447 additions and 0 deletions

202
bswap.h Normal file
View File

@@ -0,0 +1,202 @@
#ifndef BSWAP_H
#define BSWAP_H
//#include "config-host.h"
#include <inttypes.h>
#ifdef HAVE_BYTESWAP_H
#include <byteswap.h>
#else
#define bswap_16(x) \
({ \
uint16_t __x = (x); \
((uint16_t)( \
(((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
})
#define bswap_32(x) \
({ \
uint32_t __x = (x); \
((uint32_t)( \
(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
})
#define bswap_64(x) \
({ \
uint64_t __x = (x); \
((uint64_t)( \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \
})
#endif /* !HAVE_BYTESWAP_H */
static inline uint16_t bswap16(uint16_t x)
{
return bswap_16(x);
}
static inline uint32_t bswap32(uint32_t x)
{
return bswap_32(x);
}
static inline uint64_t bswap64(uint64_t x)
{
return bswap_64(x);
}
static inline void bswap16s(uint16_t *s)
{
*s = bswap16(*s);
}
static inline void bswap32s(uint32_t *s)
{
*s = bswap32(*s);
}
static inline void bswap64s(uint64_t *s)
{
*s = bswap64(*s);
}
#if defined(WORDS_BIGENDIAN)
#define be_bswap(v, size) (v)
#define le_bswap(v, size) bswap ## size(v)
#define be_bswaps(v, size)
#define le_bswaps(p, size) *p = bswap ## size(*p);
#else
#define le_bswap(v, size) (v)
#define be_bswap(v, size) bswap ## size(v)
#define le_bswaps(v, size)
#define be_bswaps(p, size) *p = bswap ## size(*p);
#endif
#define CPU_CONVERT(endian, size, type)\
static inline type endian ## size ## _to_cpu(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline type cpu_to_ ## endian ## size(type v)\
{\
return endian ## _bswap(v, size);\
}\
\
static inline void endian ## size ## _to_cpus(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline void cpu_to_ ## endian ## size ## s(type *p)\
{\
endian ## _bswaps(p, size)\
}\
\
static inline type endian ## size ## _to_cpup(const type *p)\
{\
return endian ## size ## _to_cpu(*p);\
}\
\
static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
{\
*p = cpu_to_ ## endian ## size(v);\
}
CPU_CONVERT(be, 16, uint16_t)
CPU_CONVERT(be, 32, uint32_t)
CPU_CONVERT(be, 64, uint64_t)
CPU_CONVERT(le, 16, uint16_t)
CPU_CONVERT(le, 32, uint32_t)
CPU_CONVERT(le, 64, uint64_t)
/* unaligned versions (optimized for frequent unaligned accesses)*/
#if defined(__i386__) || defined(__powerpc__)
#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
#define le16_to_cpupu(p) le16_to_cpup(p)
#define le32_to_cpupu(p) le32_to_cpup(p)
#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
#else
static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
}
static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v;
p1[1] = v >> 8;
p1[2] = v >> 16;
p1[3] = v >> 24;
}
static inline uint16_t le16_to_cpupu(const uint16_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8);
}
static inline uint32_t le32_to_cpupu(const uint32_t *p)
{
const uint8_t *p1 = (const uint8_t *)p;
return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
}
static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 8;
p1[1] = v;
}
static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
{
uint8_t *p1 = (uint8_t *)p;
p1[0] = v >> 24;
p1[1] = v >> 16;
p1[2] = v >> 8;
p1[3] = v;
}
#endif
#ifdef WORDS_BIGENDIAN
#define cpu_to_32wu cpu_to_be32wu
#else
#define cpu_to_32wu cpu_to_le32wu
#endif
#undef le_bswap
#undef be_bswap
#undef le_bswaps
#undef be_bswaps
#endif /* BSWAP_H */

View File

@@ -3,6 +3,14 @@
#include <stdio.h>
#include "minivhd_internal.h"
typedef enum MVHDType
{
MVHD_TYPE_FIXED = 2,
MVHD_TYPE_DYNAMIC = 3,
MVHD_TYPE_DIFF = 4
} MVHDType;
typedef struct MVHDMeta {
FILE* f;
char* filename;

View File

@@ -1,6 +1,10 @@
#ifndef MINIVHD_INTERNAL_H
#define MINIVHD_INTERNAL_H
#include <stdint.h>
#include <stdbool.h>
#define MVHD_FOOTER_SIZE 512
#define MVHD_SPARSE_SIZE 1024
typedef struct MVHDFooter
{
@@ -49,4 +53,14 @@ typedef struct MVHDSparseHeader
uint8_t reserved_2[256];
} MVHDSparseHeader;
const char MVHD_CONECTIX_COOKIE[] = "conectix";
const char MVHD_CREATOR[] = "pcem";
const char MVHD_CREATOR_HOST_OS[] = "Wi2k";
const char MVHD_CXSPARSE_COOKIE[] = "cxsparse";
bool mvhd_is_conectix_str(const void* buffer);
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer);
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer);
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer);
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer);
#endif

71
minivhd_manage.c Normal file
View File

@@ -0,0 +1,71 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "bswap.h"
#include "minivhd_internal.h"
#include "minivhd.h"
static bool mvhd_file_is_vhd(FILE* f);
static void mvhd_read_footer(MVHDMeta* vhdm);
static void mvhd_read_sparse_header(MVHDMeta* vhdm);
static bool mvhd_file_is_vhd(FILE* f) {
if (f) {
uint8_t con_str[8];
fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END);
fread(con_str, sizeof con_str, 1, f);
return mvhd_is_conectix_str(con_str);
} else {
return false;
}
}
static void mvhd_read_footer(MVHDMeta* vhdm) {
uint8_t buffer[MVHD_FOOTER_SIZE];
fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END);
fread(buffer, sizeof buffer, 1, vhdm->f);
mvhd_buffer_to_footer(&vhdm->footer, buffer);
}
static void mvhd_read_sparse_header(MVHDMeta* vhdm) {
uint8_t buffer[MVHD_SPARSE_SIZE];
fseeko64(vhdm->f, -MVHD_SPARSE_SIZE, SEEK_END);
fread(buffer, sizeof buffer, 1, vhdm->f);
mvhd_buffer_to_header(&vhdm->sparse, buffer);
}
MVHDMeta* mvhd_open(const char* path, int* err) {
MVHDMeta *vhdm = calloc(sizeof *vhdm, 1);
if (vhdm == NULL) {
*err = -1;
goto end;
}
vhdm->f = fopen64(path, "r+");
if (vhdm->f == NULL) {
*err = -2;
goto cleanup_vhdm;
}
if (!mvhd_file_is_vhd(vhdm->f)) {
*err = -3;
goto cleanup_file;
}
mvhd_read_footer(vhdm);
if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) {
mvhd_read_sparse_header(vhdm);
} else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) {
*err = -4;
goto cleanup_file;
}
/* If we've reached this point, we are good to go, so skip the cleanup steps */
goto end;
cleanup_file:
fclose(vhdm->f);
vhdm->f = NULL;
cleanup_vhdm:
free(vhdm);
vhdm = NULL;
end:
return vhdm;
}

140
minivhd_struct_rw.c Normal file
View File

@@ -0,0 +1,140 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "bswap.h"
#include "minivhd_internal.h"
#include "minivhd.h"
/* Read data from footer into the struct members, swapping endian where necessary
Note: order matters here! We must read each field in the order the struct is in.
Doing this may be less elegant than performing a memcpy to a packed struct, but
it avoids potential data alignment issues, and the endian swapping allows us to
use the fields directly. */
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer);
static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
memcpy(struct_memb, *buffer, memb_size);
if (req_endian) {
switch (memb_size) {
case 2:
*(uint16_t*)(struct_memb) = be16_to_cpu(*(uint16_t*)(struct_memb));
break;
case 4:
*(uint32_t*)(struct_memb) = be32_to_cpu(*(uint32_t*)(struct_memb));
break;
case 8:
*(uint64_t*)(struct_memb) = be64_to_cpu(*(uint64_t*)(struct_memb));
break;
}
}
*buffer += memb_size;
}
static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) {
memcpy(*buffer, struct_memb, memb_size);
if (req_endian) {
switch (memb_size) {
case 2:
*(uint16_t*)(struct_memb) = cpu_to_be16(*(uint16_t*)(struct_memb));
break;
case 4:
*(uint32_t*)(struct_memb) = cpu_to_be32(*(uint32_t*)(struct_memb));
break;
case 8:
*(uint64_t*)(struct_memb) = cpu_to_be64(*(uint64_t*)(struct_memb));
break;
}
}
*buffer += memb_size;
}
void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) {
uint8_t* buff_ptr = buffer;
mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
}
void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) {
uint8_t* buff_ptr = buffer;
mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr);
mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr);
}
void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) {
uint8_t* buff_ptr = buffer;
mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr);
mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
for (int i = 0; i < 8; i++) {
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
}
mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
}
void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) {
uint8_t* buff_ptr = buffer;
mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr);
mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr);
for (int i = 0; i < 8; i++) {
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr);
mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr);
}
mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr);
}

12
minivhd_uitl.c Normal file
View File

@@ -0,0 +1,12 @@
#include <stdbool.h>
#include <string.h>
#include "minivhd_internal.h"
//#include "minivhd.h"
bool mvhd_is_conectix_str(const void* buffer) {
if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) {
return true;
} else {
return false;
}
}