diff --git a/src/emu/romload.c b/src/emu/romload.c index 6b7877e5d44..5faec25cfe5 100644 --- a/src/emu/romload.c +++ b/src/emu/romload.c @@ -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)); diff --git a/src/lib/util/chd.c b/src/lib/util/chd.c index 973b8ebb5cd..2902bf9bb86 100644 --- a/src/lib/util/chd.c +++ b/src/lib/util/chd.c @@ -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); - - /* iterate over the metadata */ - for (metaindex = 0; ; metaindex++) + /* loop until we run out of data */ + for (offset = chd->header.metaoffset; offset != 0; offset = next) { - /* 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; - break; - } + UINT8 raw_meta_header[METADATA_HEADER_SIZE]; + UINT32 count, metalength, metatag; + UINT8 *tempbuffer; + UINT8 metaflags; - /* if this entry doesn't participate, continue */ + /* 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; + + /* 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 + + /* allocate memory */ + tempbuffer = malloc(metalength); + if (tempbuffer == NULL) { - UINT8 *allocbuffer = (UINT8 *)malloc(metasize); - if (allocbuffer == NULL) + err = CHDERR_OUT_OF_MEMORY; + goto cleanup; + } + + /* 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(tempbuffer); + err = CHDERR_READ_ERROR; + goto cleanup; + } + + /* compute this entry's hash */ + sha1_init(&sha1); + sha1_update(&sha1, metalength, tempbuffer); + sha1_final(&sha1); + free(tempbuffer); + + /* 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; - 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) - { - free(allocbuffer); - break; - } - - /* compute the sum over that */ - sha1_update(&sha1, metasize, allocbuffer); - free(allocbuffer); } - } - - /* finish the sum */ - if (err == CHDERR_NONE) - { - 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); + /* 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); + +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 diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h index 6ea7b44d9a2..d0434c21ecd 100644 --- a/src/lib/util/chd.h +++ b/src/lib/util/chd.h @@ -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! */ diff --git a/src/tools/chdman.c b/src/tools/chdman.c index dc9ab490232..155ff38700f 100644 --- a/src/tools/chdman.c +++ b/src/tools/chdman.c @@ -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) {