mirror of
https://github.com/holub/mame
synced 2025-05-22 13:48:55 +03:00
Redid metadata hashing. A digest of tags and hashes for each
piece of metadata along with the hash for the raw data is then hashed to produce the final SHA1. Updated romload to skip the obsolete MD5 field.
This commit is contained in:
parent
20d7fc9d6e
commit
d2d22a19af
@ -1195,10 +1195,9 @@ static void process_disk_entries(rom_load_data *romdata, const char *regiontag,
|
||||
/* get the header and extract the MD5/SHA1 */
|
||||
header = *chd_get_header(chd.origchd);
|
||||
hash_data_clear(acthash);
|
||||
hash_data_insert_binary_checksum(acthash, HASH_MD5, header.md5);
|
||||
hash_data_insert_binary_checksum(acthash, HASH_SHA1, header.sha1);
|
||||
|
||||
/* verify the MD5 */
|
||||
/* verify the hash */
|
||||
if (!hash_data_is_equal(ROM_GETHASHDATA(romp), acthash, 0))
|
||||
{
|
||||
astring_catprintf(romdata->errorstring, "%s WRONG CHECKSUMS:\n", astring_c(filename));
|
||||
|
@ -184,6 +184,15 @@ struct _av_codec_data
|
||||
};
|
||||
|
||||
|
||||
/* a single metadata hash entry */
|
||||
typedef struct _metadata_hash metadata_hash;
|
||||
struct _metadata_hash
|
||||
{
|
||||
UINT8 tag[4]; /* tag of the metadata in big-endian */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* hash */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
GLOBAL VARIABLES
|
||||
@ -225,7 +234,8 @@ static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const
|
||||
static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
|
||||
static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset);
|
||||
static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length);
|
||||
static chd_error metadata_compute_hash(chd_file *chd, UINT8 *finalsha1);
|
||||
static chd_error metadata_compute_hash(chd_file *chd, const UINT8 *rawsha1, UINT8 *finalsha1);
|
||||
static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2);
|
||||
|
||||
/* zlib compression codec */
|
||||
static chd_error zlib_codec_init(chd_file *chd);
|
||||
@ -432,20 +442,6 @@ INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbyte
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
compute_overall_sum - compute an overall
|
||||
checksum from the raw + meta hashes
|
||||
-------------------------------------------------*/
|
||||
|
||||
INLINE void compute_overall_sum(UINT8 *sha1, const UINT8 *rawsha1, const UINT8 *metasha1)
|
||||
{
|
||||
int hashindex;
|
||||
|
||||
for (hashindex = 0; hashindex < CHD_SHA1_BYTES; hashindex++)
|
||||
sha1[hashindex] = rawsha1[hashindex] ^ metasha1[hashindex];
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
queue_async_operation - queue a new work
|
||||
item
|
||||
@ -1280,11 +1276,8 @@ chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, cons
|
||||
|
||||
update:
|
||||
/* update the hash */
|
||||
if (metadata_compute_hash(chd, chd->header.metasha1) == CHDERR_NONE)
|
||||
{
|
||||
compute_overall_sum(chd->header.sha1, chd->header.rawsha1, chd->header.metasha1);
|
||||
if (metadata_compute_hash(chd, chd->header.rawsha1, chd->header.sha1) == CHDERR_NONE)
|
||||
err = header_write(chd->file, &chd->header);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -1474,7 +1467,7 @@ chd_error chd_compress_finish(chd_file *chd)
|
||||
MD5Final(chd->header.md5, &chd->compmd5);
|
||||
sha1_final(&chd->compsha1);
|
||||
sha1_digest(&chd->compsha1, SHA1_DIGEST_SIZE, chd->header.rawsha1);
|
||||
compute_overall_sum(chd->header.sha1, chd->header.rawsha1, chd->header.metasha1);
|
||||
metadata_compute_hash(chd, chd->header.rawsha1, chd->header.sha1);
|
||||
|
||||
/* turn off the writeable flag and re-write the header */
|
||||
chd->header.flags &= ~CHDFLAGS_IS_WRITEABLE;
|
||||
@ -1575,11 +1568,8 @@ chd_error chd_verify_finish(chd_file *chd, chd_verify_result *result)
|
||||
sha1_final(&chd->versha1);
|
||||
sha1_digest(&chd->versha1, SHA1_DIGEST_SIZE, result->rawsha1);
|
||||
|
||||
/* compute the metadata hash as well */
|
||||
metadata_compute_hash(chd, result->metasha1);
|
||||
|
||||
/* and the overall sum */
|
||||
compute_overall_sum(result->sha1, result->rawsha1, result->metasha1);
|
||||
/* compute the overall hash including metadata */
|
||||
metadata_compute_hash(chd, result->rawsha1, result->sha1);
|
||||
|
||||
/* return an error */
|
||||
chd->verifying = FALSE;
|
||||
@ -1820,7 +1810,6 @@ static chd_error header_read(core_file *file, chd_header *header)
|
||||
memcpy(header->sha1, &rawheader[48], CHD_SHA1_BYTES);
|
||||
memcpy(header->parentsha1, &rawheader[68], CHD_SHA1_BYTES);
|
||||
memcpy(header->rawsha1, &rawheader[88], CHD_SHA1_BYTES);
|
||||
memcpy(header->metasha1, &rawheader[108], CHD_SHA1_BYTES);
|
||||
}
|
||||
|
||||
/* guess it worked */
|
||||
@ -1865,7 +1854,6 @@ static chd_error header_write(core_file *file, const chd_header *header)
|
||||
memcpy(&rawheader[48], header->sha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[68], header->parentsha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[88], header->rawsha1, CHD_SHA1_BYTES);
|
||||
memcpy(&rawheader[108], header->metasha1, CHD_SHA1_BYTES);
|
||||
|
||||
/* seek and write */
|
||||
core_fseek(file, 0, SEEK_SET);
|
||||
@ -2526,84 +2514,119 @@ static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length
|
||||
hash of all metadata that requests it
|
||||
-------------------------------------------------*/
|
||||
|
||||
static chd_error metadata_compute_hash(chd_file *chd, UINT8 *finalsha1)
|
||||
static chd_error metadata_compute_hash(chd_file *chd, const UINT8 *rawsha1, UINT8 *finalsha1)
|
||||
{
|
||||
UINT32 metatag, metasize, metaindex;
|
||||
UINT8 metabuffer[1024];
|
||||
metadata_hash *hasharray = NULL;
|
||||
chd_error err = CHDERR_NONE;
|
||||
struct sha1_ctx sha1;
|
||||
UINT8 metaflags;
|
||||
chd_error err;
|
||||
int count = 0;
|
||||
UINT32 hashindex = 0;
|
||||
UINT32 hashalloc = 0;
|
||||
UINT64 offset, next;
|
||||
|
||||
/* only works for V4 and above */
|
||||
if (chd->header.version < 4)
|
||||
{
|
||||
memset(finalsha1, 0, SHA1_DIGEST_SIZE);
|
||||
memcpy(finalsha1, rawsha1, SHA1_DIGEST_SIZE);
|
||||
return CHDERR_NONE;
|
||||
}
|
||||
|
||||
/* initialize the hash computation */
|
||||
sha1_init(&sha1);
|
||||
/* loop until we run out of data */
|
||||
for (offset = chd->header.metaoffset; offset != 0; offset = next)
|
||||
{
|
||||
UINT8 raw_meta_header[METADATA_HEADER_SIZE];
|
||||
UINT32 count, metalength, metatag;
|
||||
UINT8 *tempbuffer;
|
||||
UINT8 metaflags;
|
||||
|
||||
/* iterate over the metadata */
|
||||
for (metaindex = 0; ; metaindex++)
|
||||
{
|
||||
/* fetch the next piece of metadata */
|
||||
err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, metaindex, metabuffer, sizeof(metabuffer), &metasize, &metatag, &metaflags);
|
||||
if (err != CHDERR_NONE)
|
||||
{
|
||||
if (err == CHDERR_METADATA_NOT_FOUND)
|
||||
err = CHDERR_NONE;
|
||||
/* read the raw header */
|
||||
core_fseek(chd->file, offset, SEEK_SET);
|
||||
count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
|
||||
if (count != sizeof(raw_meta_header))
|
||||
break;
|
||||
}
|
||||
|
||||
/* if this entry doesn't participate, continue */
|
||||
/* extract the data */
|
||||
metatag = get_bigendian_uint32(&raw_meta_header[0]);
|
||||
metalength = get_bigendian_uint32(&raw_meta_header[4]);
|
||||
next = get_bigendian_uint64(&raw_meta_header[8]);
|
||||
|
||||
/* flags are encoded in the high byte of length */
|
||||
metaflags = metalength >> 24;
|
||||
metalength &= 0x00ffffff;
|
||||
|
||||
/* if not checksumming, continue */
|
||||
if (!(metaflags & CHD_MDFLAGS_CHECKSUM))
|
||||
continue;
|
||||
count++;
|
||||
|
||||
/* if that fit, compute the sum from the temporary buffer */
|
||||
if (metasize <= sizeof(metabuffer))
|
||||
sha1_update(&sha1, metasize, metabuffer);
|
||||
|
||||
/* otherwise, allocate a bigger temporary buffer */
|
||||
else
|
||||
{
|
||||
UINT8 *allocbuffer = (UINT8 *)malloc(metasize);
|
||||
if (allocbuffer == NULL)
|
||||
/* allocate memory */
|
||||
tempbuffer = malloc(metalength);
|
||||
if (tempbuffer == NULL)
|
||||
{
|
||||
err = CHDERR_OUT_OF_MEMORY;
|
||||
break;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* re-read the whole thing */
|
||||
err = chd_get_metadata(chd, CHDMETATAG_WILDCARD, metaindex, allocbuffer, metasize, &metasize, &metatag, &metaflags);
|
||||
if (err != CHDERR_NONE)
|
||||
/* seek and read the metadata */
|
||||
core_fseek(chd->file, offset + METADATA_HEADER_SIZE, SEEK_SET);
|
||||
count = core_fread(chd->file, tempbuffer, metalength);
|
||||
if (count != metalength)
|
||||
{
|
||||
free(allocbuffer);
|
||||
break;
|
||||
free(tempbuffer);
|
||||
err = CHDERR_READ_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* compute the sum over that */
|
||||
sha1_update(&sha1, metasize, allocbuffer);
|
||||
free(allocbuffer);
|
||||
}
|
||||
}
|
||||
/* compute this entry's hash */
|
||||
sha1_init(&sha1);
|
||||
sha1_update(&sha1, metalength, tempbuffer);
|
||||
sha1_final(&sha1);
|
||||
free(tempbuffer);
|
||||
|
||||
/* finish the sum */
|
||||
if (err == CHDERR_NONE)
|
||||
/* expand the hasharray if necessary */
|
||||
if (hashindex >= hashalloc)
|
||||
{
|
||||
hashalloc += 256;
|
||||
hasharray = realloc(hasharray, hashalloc * sizeof(hasharray[0]));
|
||||
if (hasharray == NULL)
|
||||
{
|
||||
err = CHDERR_OUT_OF_MEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* fill in the entry */
|
||||
put_bigendian_uint32(hasharray[hashindex].tag, metatag);
|
||||
sha1_digest(&sha1, SHA1_DIGEST_SIZE, hasharray[hashindex].sha1);
|
||||
hashindex++;
|
||||
}
|
||||
|
||||
/* sort the array */
|
||||
qsort(hasharray, hashindex, sizeof(hasharray[0]), metadata_hash_compare);
|
||||
|
||||
/* compute the SHA1 of the raw plus the various metadata */
|
||||
sha1_init(&sha1);
|
||||
sha1_update(&sha1, CHD_SHA1_BYTES, rawsha1);
|
||||
sha1_update(&sha1, hashindex * sizeof(hasharray[0]), (void *)hasharray);
|
||||
sha1_final(&sha1);
|
||||
sha1_digest(&sha1, SHA1_DIGEST_SIZE, finalsha1);
|
||||
|
||||
/* special case: if no entries, zero the sum */
|
||||
if (count == 0)
|
||||
memset(finalsha1, 0, SHA1_DIGEST_SIZE);
|
||||
}
|
||||
cleanup:
|
||||
if (hasharray != NULL)
|
||||
free(hasharray);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------
|
||||
metadata_hash_compare - compare two hash
|
||||
entries
|
||||
-------------------------------------------------*/
|
||||
|
||||
static int CLIB_DECL metadata_hash_compare(const void *elem1, const void *elem2)
|
||||
{
|
||||
return memcmp(elem1, elem2, sizeof(metadata_hash));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
ZLIB COMPRESSION CODEC
|
||||
|
@ -90,8 +90,7 @@
|
||||
[ 48] UINT8 sha1[20]; // combined raw+meta SHA1
|
||||
[ 68] UINT8 parentsha1[20];// combined raw+meta SHA1 of parent
|
||||
[ 88] UINT8 rawsha1[20]; // raw data SHA1
|
||||
[108] UINT8 metasha1[20]; // metadata SHA1
|
||||
[128] (V4 header length)
|
||||
[108] (V4 header length)
|
||||
|
||||
Flags:
|
||||
0x00000001 - set if this drive has a parent
|
||||
@ -109,7 +108,7 @@
|
||||
#define CHD_V1_HEADER_SIZE 76
|
||||
#define CHD_V2_HEADER_SIZE 80
|
||||
#define CHD_V3_HEADER_SIZE 120
|
||||
#define CHD_V4_HEADER_SIZE 128
|
||||
#define CHD_V4_HEADER_SIZE 108
|
||||
#define CHD_MAX_HEADER_SIZE CHD_V4_HEADER_SIZE
|
||||
|
||||
/* checksumming information */
|
||||
@ -218,7 +217,6 @@ struct _chd_header
|
||||
UINT8 parentmd5[CHD_MD5_BYTES]; /* overall MD5 checksum of parent */
|
||||
UINT8 sha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum */
|
||||
UINT8 rawsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
|
||||
UINT8 metasha1[CHD_SHA1_BYTES]; /* SHA1 checksum of metadata */
|
||||
UINT8 parentsha1[CHD_SHA1_BYTES]; /* overall SHA1 checksum of parent */
|
||||
|
||||
UINT32 obsolete_cylinders; /* obsolete field -- do not use! */
|
||||
|
@ -1764,25 +1764,6 @@ static int do_verify(int argc, char *argv[], int param)
|
||||
fixed = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(header.rawsha1, verify.metasha1, sizeof(header.metasha1)) != 0)
|
||||
{
|
||||
fprintf(stderr, "Error: metadata SHA1 in header = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", header.metasha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, " actual metadata SHA1 = ");
|
||||
for (i = 0; i < CHD_SHA1_BYTES; i++)
|
||||
fprintf(stderr, "%02x", verify.metasha1[i]);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
/* fix it */
|
||||
if (param)
|
||||
{
|
||||
memcpy(header.metasha1, verify.metasha1, sizeof(header.metasha1));
|
||||
fixed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2103,12 +2084,6 @@ static int do_info(int argc, char *argv[], int param)
|
||||
header.rawsha1[8], header.rawsha1[9], header.rawsha1[10], header.rawsha1[11],
|
||||
header.rawsha1[12], header.rawsha1[13], header.rawsha1[14], header.rawsha1[15],
|
||||
header.rawsha1[16], header.rawsha1[17], header.rawsha1[18], header.rawsha1[19]);
|
||||
printf("Metadata SHA1:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||
header.metasha1[0], header.metasha1[1], header.metasha1[2], header.metasha1[3],
|
||||
header.metasha1[4], header.metasha1[5], header.metasha1[6], header.metasha1[7],
|
||||
header.metasha1[8], header.metasha1[9], header.metasha1[10], header.metasha1[11],
|
||||
header.metasha1[12], header.metasha1[13], header.metasha1[14], header.metasha1[15],
|
||||
header.metasha1[16], header.metasha1[17], header.metasha1[18], header.metasha1[19]);
|
||||
}
|
||||
if (header.flags & CHDFLAGS_HAS_PARENT)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user