summaryrefslogtreecommitdiffstatshomepage
path: root/src/tools
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2009-03-09 16:49:56 +0000
committer Aaron Giles <aaron@aarongiles.com>2009-03-09 16:49:56 +0000
commit21b5f272248b8b86af006c559d54b9acb326ba9a (patch)
tree035f35331039afe4d361d8750cd32df5bd0c90be /src/tools
parentb91848413da43c35225c700ed52091471c5deba8 (diff)
NOTE: With the change, all existing CHD diff files are invalid.
Updated CHD format to version 4. Checksums are now computed and stored separately for raw data and metadata, and metadata is now checksummed by default. We will need to go through all existing CHDs, run a chdman -update on them, and update the SHA1s stored in the drivers to accommodate this (MD5s should be removed). Updated chdman to support a generic metadata addition system: chdman -addmeta <chdfile> <tag> [<index>] <sourcefile> The <sourcefile> is examined and if it appears to be strictly text, any EOFs and trailing EOLs are stripped, and the result is NULL- terminated to match the behavior of existing metadata. Updated chdman to report and fix errors in the raw and metadata SHA1s. Changed the CHD verify interfaces to pass back a structure containing all the necessary data for verification and fixing.
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/chdman.c315
1 files changed, 278 insertions, 37 deletions
diff --git a/src/tools/chdman.c b/src/tools/chdman.c
index b1662debb6f..dc9ab490232 100644
--- a/src/tools/chdman.c
+++ b/src/tools/chdman.c
@@ -166,6 +166,7 @@ static int usage(void)
printf(" or: chdman -diff parent.chd compare.chd diff.chd\n");
printf(" or: chdman -setchs inout.chd cylinders heads sectors\n");
printf(" or: chdman -fixavdata inout.chd\n");
+ printf(" or: chdman -addmeta inout.chd tag [index] sourcefile\n");
return 1;
}
@@ -309,7 +310,7 @@ static int do_createhd(int argc, char *argv[], int param)
/* write the metadata */
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
- err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
+ err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
@@ -480,7 +481,7 @@ static int do_createcd(int argc, char *argv[], int param)
sprintf(metadata, CDROM_TRACK_METADATA_FORMAT, i + 1, cdrom_get_type_string(&toc.tracks[i]),
cdrom_get_subtype_string(&toc.tracks[i]), toc.tracks[i].frames);
- err = chd_set_metadata(chd, CDROM_TRACK_METADATA_TAG, i, metadata, strlen(metadata) + 1, 0);
+ err = chd_set_metadata(chd, CDROM_TRACK_METADATA_TAG, i, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding CD-ROM metadata: %s\n", chd_error_string(err));
@@ -902,7 +903,7 @@ static int do_createav(int argc, char *argv[], int param)
/* write the metadata */
sprintf(metadata, AV_METADATA_FORMAT, fps_times_1million / 1000000, fps_times_1million % 1000000, width, height, interlaced, channels, rate);
- err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
+ err = chd_set_metadata(chd, AV_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding AV metadata: %s\n", chd_error_string(err));
@@ -959,7 +960,7 @@ static int do_createav(int argc, char *argv[], int param)
/* write the final metadata */
if (ldframedata != NULL)
{
- err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES, 0);
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, ldframedata, numframes * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
@@ -1048,7 +1049,7 @@ static int do_createblankhd(int argc, char *argv[], int param)
/* write the metadata */
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cylinders, heads, sectors, sectorsize);
- err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
+ err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding hard disk metadata: %s\n", chd_error_string(err));
@@ -1636,7 +1637,7 @@ cleanup:
static int do_verify(int argc, char *argv[], int param)
{
- UINT8 actualmd5[CHD_MD5_BYTES], actualsha1[CHD_SHA1_BYTES];
+ chd_verify_result verify;
const char *inputfile;
chd_file *chd = NULL;
chd_header header;
@@ -1681,7 +1682,7 @@ static int do_verify(int argc, char *argv[], int param)
/* finish it */
if (err == CHDERR_NONE)
- err = chd_verify_finish(chd, actualmd5, actualsha1);
+ err = chd_verify_finish(chd, &verify);
}
/* handle errors */
@@ -1695,31 +1696,34 @@ static int do_verify(int argc, char *argv[], int param)
}
/* verify the MD5 */
- if (memcmp(header.md5, actualmd5, sizeof(header.md5)) == 0)
- printf("MD5 verification successful!\n");
- else
+ if (header.version <= 3)
{
- fprintf(stderr, "Error: MD5 in header = ");
- for (i = 0; i < CHD_MD5_BYTES; i++)
- fprintf(stderr, "%02x", header.md5[i]);
- fprintf(stderr, "\n");
- fprintf(stderr, " actual MD5 = ");
- for (i = 0; i < CHD_MD5_BYTES; i++)
- fprintf(stderr, "%02x", actualmd5[i]);
- fprintf(stderr, "\n");
-
- /* fix it */
- if (param)
+ if (memcmp(header.md5, verify.md5, sizeof(header.md5)) == 0)
+ printf("MD5 verification successful!\n");
+ else
{
- memcpy(header.md5, actualmd5, sizeof(header.md5));
- fixed = TRUE;
+ fprintf(stderr, "Error: MD5 in header = ");
+ for (i = 0; i < CHD_MD5_BYTES; i++)
+ fprintf(stderr, "%02x", header.md5[i]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " actual MD5 = ");
+ for (i = 0; i < CHD_MD5_BYTES; i++)
+ fprintf(stderr, "%02x", verify.md5[i]);
+ fprintf(stderr, "\n");
+
+ /* fix it */
+ if (param)
+ {
+ memcpy(header.md5, verify.md5, sizeof(header.md5));
+ fixed = TRUE;
+ }
}
}
/* verify the SHA1 */
if (header.version >= 3)
{
- if (memcmp(header.sha1, actualsha1, sizeof(header.sha1)) == 0)
+ if (memcmp(header.sha1, verify.sha1, sizeof(header.sha1)) == 0)
printf("SHA1 verification successful!\n");
else
{
@@ -1729,15 +1733,57 @@ static int do_verify(int argc, char *argv[], int param)
fprintf(stderr, "\n");
fprintf(stderr, " actual SHA1 = ");
for (i = 0; i < CHD_SHA1_BYTES; i++)
- fprintf(stderr, "%02x", actualsha1[i]);
+ fprintf(stderr, "%02x", verify.sha1[i]);
fprintf(stderr, "\n");
/* fix it */
if (param)
{
- memcpy(header.sha1, actualsha1, sizeof(header.sha1));
+ memcpy(header.sha1, verify.sha1, sizeof(header.sha1));
fixed = TRUE;
}
+
+ /* verify the raw SHA1 */
+ if (header.version >= 4)
+ {
+ if (memcmp(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1)) != 0)
+ {
+ fprintf(stderr, "Error: raw SHA1 in header = ");
+ for (i = 0; i < CHD_SHA1_BYTES; i++)
+ fprintf(stderr, "%02x", header.rawsha1[i]);
+ fprintf(stderr, "\n");
+ fprintf(stderr, " actual raw SHA1 = ");
+ for (i = 0; i < CHD_SHA1_BYTES; i++)
+ fprintf(stderr, "%02x", verify.rawsha1[i]);
+ fprintf(stderr, "\n");
+
+ /* fix it */
+ if (param)
+ {
+ memcpy(header.rawsha1, verify.rawsha1, sizeof(header.rawsha1));
+ 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;
+ }
+ }
+ }
}
}
@@ -1967,7 +2013,7 @@ static int do_fixavdata(int argc, char *argv[], int param)
}
/* write new metadata */
- err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, 0);
+ err = chd_set_metadata(chd, AV_LD_METADATA_TAG, 0, vbidata, header.totalhunks * VBI_PACKED_BYTES, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error adding AVLD metadata: %s\n", chd_error_string(err));
@@ -2036,7 +2082,7 @@ static int do_info(int argc, char *argv[], int param)
printf("Hunk Size: %d bytes\n", header.hunkbytes);
printf("Total Hunks: %d\n", header.totalhunks);
printf("Logical size: %s bytes\n", big_int_string(header.logicalbytes));
- if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
+ if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version <= 3)
printf("MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
header.md5[0], header.md5[1], header.md5[2], header.md5[3],
header.md5[4], header.md5[5], header.md5[6], header.md5[7],
@@ -2049,6 +2095,21 @@ static int do_info(int argc, char *argv[], int param)
header.sha1[8], header.sha1[9], header.sha1[10], header.sha1[11],
header.sha1[12], header.sha1[13], header.sha1[14], header.sha1[15],
header.sha1[16], header.sha1[17], header.sha1[18], header.sha1[19]);
+ if (!(header.flags & CHDFLAGS_IS_WRITEABLE) && header.version >= 4)
+ {
+ printf("Raw SHA1: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+ header.rawsha1[0], header.rawsha1[1], header.rawsha1[2], header.rawsha1[3],
+ header.rawsha1[4], header.rawsha1[5], header.rawsha1[6], header.rawsha1[7],
+ 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)
{
printf("Parent MD5: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
@@ -2494,7 +2555,7 @@ static int do_setchs(int argc, char *argv[], int param)
/* write our own */
sprintf(metadata, HARD_DISK_METADATA_FORMAT, cyls, hds, secs, oldsecsize);
- err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, 0);
+ err = chd_set_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, strlen(metadata) + 1, CHD_MDFLAGS_CHECKSUM);
if (err != CHDERR_NONE)
{
fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
@@ -2541,6 +2602,186 @@ cleanup:
/*-------------------------------------------------
+ do_addmeta - add metadata to a CHD from a
+ file
+-------------------------------------------------*/
+
+static int do_addmeta(int argc, char *argv[], int param)
+{
+ const char *inoutfile, *srcfile, *tagstring;
+ UINT8 was_readonly = FALSE;
+ core_file *sourcefile = NULL;
+ UINT8 *metadata = NULL;
+ chd_file *chd = NULL;
+ chd_header header;
+ file_error filerr;
+ UINT32 metalength;
+ UINT32 metaindex;
+ UINT32 metatag;
+ UINT32 chindex;
+ chd_error err;
+ int istext;
+
+ /* require 5 or 6 args total */
+ if (argc != 5 && argc != 6)
+ return usage();
+
+ /* extract the data */
+ inoutfile = argv[2];
+ tagstring = argv[3];
+ if (argc == 5)
+ {
+ metaindex = 0;
+ srcfile = argv[4];
+ }
+ else
+ {
+ metaindex = atoi(argv[4]);
+ srcfile = argv[5];
+ }
+
+ /* verify the tag */
+ if (strlen(tagstring) > 4)
+ {
+ fprintf(stderr, "Invalid tag '%s'; must be 4 characters or less\n", tagstring);
+ return CHDERR_INVALID_PARAMETER;
+ }
+ metatag = ((tagstring[0] == 0) ? ' ' : tagstring[0]) << 24;
+ metatag |= ((tagstring[1] == 0) ? ' ' : tagstring[1]) << 16;
+ metatag |= ((tagstring[2] == 0) ? ' ' : tagstring[2]) << 8;
+ metatag |= ((tagstring[3] == 0) ? ' ' : tagstring[3]) << 0;
+
+ /* print some info */
+ printf("Input file: %s\n", inoutfile);
+ printf("Tag: '%c%c%c%c'\n", (metatag >> 24) & 0xff, (metatag >> 16) & 0xff, (metatag >> 8) & 0xff, metatag & 0xff);
+ printf("Index: %d\n", metaindex);
+ printf("Source file: %s\n", srcfile);
+
+ /* open the file read-only and get the header */
+ err = chd_open(inoutfile, CHD_OPEN_READ, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s' read-only: %s\n", inoutfile, chd_error_string(err));
+ goto cleanup;
+ }
+ header = *chd_get_header(chd);
+ chd_close(chd);
+ chd = NULL;
+
+ /* if the drive is not writeable, note that, and make it so */
+ if (!(header.flags & CHDFLAGS_IS_WRITEABLE))
+ {
+ was_readonly = TRUE;
+ header.flags |= CHDFLAGS_IS_WRITEABLE;
+
+ /* write the new header */
+ err = chd_set_header(inoutfile, &header);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error making CHD file writeable: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ }
+
+ /* open the file read/write */
+ err = chd_open(inoutfile, CHD_OPEN_READWRITE, NULL, &chd);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error opening CHD file '%s' read/write: %s\n", inoutfile, chd_error_string(err));
+ goto cleanup;
+ }
+
+ /* attempt to open the source file */
+ filerr = core_fopen(srcfile, OPEN_FLAG_READ, &sourcefile);
+ if (filerr != FILERR_NONE)
+ {
+ fprintf(stderr, "Error opening source file '%s'\n", srcfile);
+ err = CHDERR_FILE_NOT_FOUND;
+ goto cleanup;
+ }
+
+ /* allocate memory */
+ metalength = core_fsize(sourcefile);
+ if (metalength == 0 || metalength >= 16 * 1024 * 1024)
+ {
+ fprintf(stderr, "Source file '%s' is either 0-length or too large (must be under 16MB)\n", srcfile);
+ err = CHDERR_INVALID_PARAMETER;
+ goto cleanup;
+ }
+ metadata = malloc(metalength + 1);
+ if (metadata == NULL)
+ {
+ fprintf(stderr, "Out of memory allocating source file buffer\n");
+ err = CHDERR_OUT_OF_MEMORY;
+ goto cleanup;
+ }
+
+ /* read in the data */
+ if (core_fread(sourcefile, metadata, metalength) != metalength)
+ {
+ fprintf(stderr, "Error reading source file\n");
+ err = CHDERR_READ_ERROR;
+ goto cleanup;
+ }
+
+ /* analyze the data */
+ istext = FALSE;
+ for (chindex = 0; chindex < metalength; chindex++)
+ if (metadata[chindex] != 0x0d && metadata[chindex] != 0x0a && metadata[chindex] != 0x09 &&
+ (metadata[chindex] < ' ' || metadata[chindex] >= 0x7f))
+ break;
+
+ /* if it's text, strip any trailing Ctrl-Z and CR/LF and add a trailing NULL */
+ if (chindex == metalength || (chindex == metalength - 1 && metadata[chindex] == 0x1a))
+ {
+ istext = TRUE;
+ metalength = chindex + 1;
+ metadata[metalength - 1] = 0;
+ while (metalength > 0 && (metadata[metalength - 2] == 0x0a || metadata[metalength - 2] == 0x0d || metadata[metalength - 2] == 0x1a))
+ metadata[--metalength] = 0;
+ }
+
+ /* write the new metadata */
+ err = chd_set_metadata(chd, metatag, metaindex, metadata, metalength, CHD_MDFLAGS_CHECKSUM);
+ if (err != CHDERR_NONE)
+ {
+ fprintf(stderr, "Error writing new metadata to CHD file: %s\n", chd_error_string(err));
+ goto cleanup;
+ }
+ header = *chd_get_header(chd);
+
+ /* close the file */
+ chd_close(chd);
+ chd = NULL;
+
+ /* restore the read-only state */
+ if (was_readonly)
+ {
+ header.flags &= ~CHDFLAGS_IS_WRITEABLE;
+ err = chd_set_header(inoutfile, &header);
+ if (err != CHDERR_NONE)
+ fprintf(stderr, "Error writing new header to CHD file: %s\n", chd_error_string(err));
+ }
+ if (err == CHDERR_NONE)
+ printf("Metadata added successfully as %s\n", istext ? "text" : "binary");
+
+cleanup:
+ if (metadata != NULL)
+ free(metadata);
+ if (sourcefile != NULL)
+ core_fclose(sourcefile);
+ if (chd != NULL)
+ chd_close(chd);
+ if (err != CHDERR_NONE && was_readonly)
+ {
+ header.flags &= ~CHDFLAGS_IS_WRITEABLE;
+ chd_set_header(inoutfile, &header);
+ }
+ return (err != CHDERR_NONE);
+}
+
+
+/*-------------------------------------------------
chdman_compress_file - compress a regular
file via the compression interfaces
-------------------------------------------------*/
@@ -2713,17 +2954,16 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
if (verifyerr == CHDERR_NONE && source_offset >= source_header->logicalbytes)
{
static const UINT8 empty_checksum[CHD_SHA1_BYTES] = { 0 };
- UINT8 md5[CHD_MD5_BYTES];
- UINT8 sha1[CHD_SHA1_BYTES];
+ chd_verify_result verify;
int i;
/* get the final values */
- err = chd_verify_finish(source, md5, sha1);
+ err = chd_verify_finish(source, &verify);
/* check the MD5 */
if (memcmp(source_header->md5, empty_checksum, CHD_MD5_BYTES) != 0)
{
- if (memcmp(source_header->md5, md5, CHD_MD5_BYTES) != 0)
+ if (memcmp(source_header->md5, verify.md5, CHD_MD5_BYTES) != 0)
{
progress(TRUE, "WARNING: expected input MD5 = ");
for (i = 0; i < CHD_MD5_BYTES; i++)
@@ -2732,7 +2972,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
progress(TRUE, " actual MD5 = ");
for (i = 0; i < CHD_MD5_BYTES; i++)
- progress(TRUE, "%02x", md5[i]);
+ progress(TRUE, "%02x", verify.md5[i]);
progress(TRUE, "\n");
}
else
@@ -2742,7 +2982,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
/* check the SHA1 */
if (memcmp(source_header->sha1, empty_checksum, CHD_SHA1_BYTES) != 0)
{
- if (memcmp(source_header->sha1, sha1, CHD_SHA1_BYTES) != 0)
+ if (memcmp(source_header->sha1, verify.sha1, CHD_SHA1_BYTES) != 0)
{
progress(TRUE, "WARNING: expected input SHA1 = ");
for (i = 0; i < CHD_SHA1_BYTES; i++)
@@ -2751,7 +2991,7 @@ static chd_error chdman_compress_chd(chd_file *chd, chd_file *source, UINT32 tot
progress(TRUE, " actual SHA1 = ");
for (i = 0; i < CHD_SHA1_BYTES; i++)
- progress(TRUE, "%02x", sha1[i]);
+ progress(TRUE, "%02x", verify.sha1[i]);
progress(TRUE, "\n");
}
else
@@ -2806,7 +3046,8 @@ int CLIB_DECL main(int argc, char **argv)
{ "-merge", do_merge_update_chomp, OPERATION_MERGE },
{ "-diff", do_diff, 0 },
{ "-setchs", do_setchs, 0 },
- { "-fixavdata", do_fixavdata, 0 }
+ { "-fixavdata", do_fixavdata, 0 },
+ { "-addmeta", do_addmeta, 0 },
};
extern char build_version[];
int i;