From 0fe280bc5adc553ac6d3f81d9401a23d897a18b3 Mon Sep 17 00:00:00 2001 From: Christopher Kobayashi Date: Tue, 21 Apr 2020 15:32:19 +0900 Subject: [PATCH] Initial commit. --- Makefile | 10 +++ dc42cksm.c | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 Makefile create mode 100644 dc42cksm.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0171061 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +CFLAGS= -O2 -Wall -Werror + + +all: dc42cksm + +install: all + install -m755 dc42cksm /usr/local/bin/ + +clean: + rm -f dc42cksm *.o diff --git a/dc42cksm.c b/dc42cksm.c new file mode 100644 index 0000000..5a6a937 --- /dev/null +++ b/dc42cksm.c @@ -0,0 +1,220 @@ +/* dc42cksm + + A command-line program to view the checksums in a Macintosh Disk Copy 4.2 + disk image file, and optionally to update the checksums if they’re not + correct. + + Originally written by Steve Chamberlin + 64-bit-cleaned and lightly converted from C++ to C by Christopher RYU +*/ + +#include +#include +#include +#include + +u_int8_t Read8(FILE* file) +{ + u_int8_t b; + fread(&b, 1, 1, file); + return b; +} + +u_int16_t ReadBigEndian16(FILE* file) +{ + u_int8_t b[2]; + fread(&b, 1, 2, file); + return (((u_int16_t)b[0]) << 8) | b[1]; +} + +u_int32_t ReadBigEndian32(FILE* file) +{ + u_int8_t b[4]; + fread(&b, 1, 4, file); + return (((u_int32_t)b[0]) << 24) | (((u_int32_t)b[1]) << 16) | (((u_int32_t)b[2]) << 8) | b[3]; +} + +void SetBigEndian32(u_int8_t* pDest, u_int32_t value) +{ + pDest[0] = (value >> 24) & 0xFF; + pDest[1] = (value >> 16) & 0xFF; + pDest[2] = (value >> 8) & 0xFF; + pDest[3] = value & 0xFF; +} + +int main(int argc, char* argv[]) +{ + /* parse the command line */ + if (argc != 2) + { + printf("Disk Copy 4.2 checksum tool:\nVerifies and optionally updates checksums for DC42 disk image files.\n\n"); + printf("Usage: %s filename\n", argv[0]); + return -1; + } + + char *sourceFilename = argv[1]; + + printf("Verifying Disk Copy 4.2 disk image checksums for %s\n", sourceFilename); + + FILE *pFile = fopen(sourceFilename, "rb"); + if (!pFile) + { + printf("Could not open source file %s\n", sourceFilename); + return -1; + } + + /* check the DC42 signature bytes */ + fseek(pFile, 0x52, SEEK_SET); + u_int16_t magic0 = Read8(pFile); + u_int16_t magic1 = Read8(pFile); + + if (magic0 != 1 || magic1 != 0) + { + printf("This doesn't look like a valid DC42 disk image file. Aborting.\n"); + fclose(pFile); + return 0; + } + + /* return to start */ + fseek(pFile, 0, SEEK_SET); + + /* disk image name */ + u_int8_t nameLen = Read8(pFile); + unsigned char name[64]; + fread(name, 1, 63, pFile); + if (nameLen < 64) + name[nameLen] = 0; + else + name[63] = 0; + printf(" stored image name: %s\n", name); + + /* size of data and tag regions */ + u_int32_t dataSize = ReadBigEndian32(pFile); + printf(" data size: %08X\n", dataSize); + u_int32_t tagSize = ReadBigEndian32(pFile); + printf(" tag size: %08X\n", tagSize); + + /* stored checksums */ + u_int32_t storedDataChecksum = ReadBigEndian32(pFile); + u_int32_t storedTagChecksum = ReadBigEndian32(pFile); + + /* disk encoding */ + u_int8_t encoding = Read8(pFile); + switch (encoding) + { + case 0: + printf(" encoding: 00, GCR single-sided double density 400K\n"); + break; + case 1: + printf(" encoding: 01, GCR double-sided double density 800K\n"); + break; + case 2: + printf(" encoding: 02, MFM double-sided double density 720K\n"); + break; + case 3: + printf(" encoding: 03, MFM double-sided high density 1440K\n"); + break; + default: + printf(" encoding: %02X, unknown\n", encoding); + break; + } + + /* disk format */ + u_int8_t format = Read8(pFile); + switch (format) + { + case 0x02: + printf(" format: 02, Macintosh/Lisa 400K\n"); + break; + case 0x22: + printf(" format: 22, Macintosh 800K\n"); + break; + case 0x24: + printf(" format: 24, ProDOS 800K\n"); + break; + default: + printf(" format: %02X, unknown\n", format); + break; + } + + /* ignore the magic number */ + ReadBigEndian16(pFile); + + /* compute the data checksum */ + u_int32_t dataChecksum = 0; + for (u_int32_t i=0; i> 1) | ((dataChecksum & 1) << 31); + } + + /* compute the tag checksum */ + u_int32_t tagChecksum = 0; + if (tagSize > 12) + { + /* skip the first 12 tag bytes */ + for (int i=0; i<12; i++) + { + Read8(pFile); + } + + for (u_int32_t i=12; i> 1) | ((tagChecksum & 1) << 31); + } + } + + /* show the results */ + printf(" stored data checksum: %08X\n", storedDataChecksum); + printf("computed data checksum: %08X\n", dataChecksum); + printf(" stored tag checksum: %08X\n", storedTagChecksum); + printf(" computed tag checksum: %08X\n", tagChecksum); + + if (storedDataChecksum == dataChecksum && storedTagChecksum == tagChecksum) + { + printf("\nVerification succeeded, no errors.\n"); + } + else + { + printf("\nThe stored checksums do not match the computed checksums.\n"); + printf("\nUpdate the stored checksums? (Y/N) "); + u_int8_t a = getchar(); + if (a == 'y' || a =='Y') + { + /* read the whole file into memory */ + u_int32_t bufSize = 0x54 + dataSize + tagSize; + u_int8_t* pBuffer = (u_int8_t*)malloc(bufSize); + if (pBuffer == 0) + { + printf("error: couldn't allocate %u bytes\n", bufSize); + return -1; + } + fseek(pFile, 0, SEEK_SET); + fread(pBuffer, bufSize, 1, pFile); + fclose(pFile); + + /* modify the checksums */ + SetBigEndian32(&pBuffer[0x48], dataChecksum); + SetBigEndian32(&pBuffer[0x4C], tagChecksum); + + /* write the modified file */ + FILE *pFile = fopen(sourceFilename, "wb"); + if (!pFile) + { + printf("error: could not re-open file for writing\n"); + return -1; + } + fwrite(pBuffer, bufSize, 1, pFile); + + printf("%s was modified, checksums updated.\n", sourceFilename); + } + else + { + printf("%s was not modified.\n", sourceFilename); + } + } + + fclose(pFile); + return 0; +}