/* mpcimg.c vi: se ts=8 sw=8: */ /* Written by Peter Backes. * * Copyright abandoned. */ #include #include /* strpcy(), strcmp() */ #include /* strtoul(), #EXIT_FAILURE, #EXIT_SUCCESS */ #define MPCIMG_MAGIC 0x7f309ac5UL /* MPC image header magic. */ /* MPC image header structure. * * If you input the drive size in megabytes on creating the image, * then hdrsiz is initialized with 64, imgsiz with * drive size in megabytes times 1024000, secsiz with 512, * nsecs with drive size in megabytes times 2000 and resvd all with * zero. */ struct mpchdr { unsigned long magic, /* MPCI_MAGIC */ hdrsiz, /* Size of the header in bytes, usually 64. */ imgsiz, /* Size of the image behind the header. */ secsiz, /* Sector size in bytes, usually 512. */ nsecs, /* Total sector count. */ resvd[11]; /* Reserved. */ }; #if BUFSIZ < 64 #error BUFSIZ must be at least 64. #endif /* Intel pop */ #define popi32b(d, s) (d = *s++, d |= *s++ << 8, \ d |= *s++ << 16, d |= *s++ << 24) /* Intel push */ #define pushi32b(d, s) (*d++ = s & 0xFFUL, *d++ = (s & 0xFF00UL) >> 8, \ *d++ = (s & 0xFF0000UL) >> 16, *d++ = (s & 0xFF000000UL) >> 24); int fcopy(unsigned char *buf, FILE *is, FILE *os, unsigned long s, unsigned long n) { while (n-- > 0) if (fread(buf, s, 1, is) != 1 || fwrite(buf, s, 1, os) != 1) return 1; return 0; } int extract(FILE *is, FILE *os, unsigned long s, unsigned long n) { unsigned char buf[BUFSIZ], *t = buf; struct mpchdr h; if (fread(buf, 64, 1, is) != 1) return 1; popi32b(h.magic, t); popi32b(h.hdrsiz, t); popi32b(h.imgsiz, t); popi32b(h.secsiz, t); popi32b(h.nsecs, t); popi32b(h.resvd[0], t); popi32b(h.resvd[1], t); popi32b(h.resvd[2], t); popi32b(h.resvd[3], t); popi32b(h.resvd[4], t); popi32b(h.resvd[5], t); popi32b(h.resvd[6], t); popi32b(h.resvd[7], t); popi32b(h.resvd[8], t); popi32b(h.resvd[9], t); popi32b(h.resvd[10], t); if (h.magic != MPCIMG_MAGIC || h.hdrsiz != 64 || h.secsiz > BUFSIZ || !h.secsiz) return 1; return fcopy(buf, is, os, h.secsiz, h.nsecs); } int store(FILE *is, FILE *os, unsigned long s, unsigned long n) { unsigned char buf[BUFSIZ], *t = buf; struct mpchdr h = {MPCIMG_MAGIC, 64UL, 0UL, 0UL, 0UL, {0UL}}; if (s > BUFSIZ) return 0; if (!n) { long len; if (fseek(is, 0, SEEK_END) == -1 || (len = ftell(is)) == -1 || len % s) return 1; rewind(is); n = len / s; } h.secsiz = s; h.imgsiz = n * s; h.nsecs = n; pushi32b(t, h.magic); pushi32b(t, h.hdrsiz); pushi32b(t, h.imgsiz); pushi32b(t, h.secsiz); pushi32b(t, h.nsecs); pushi32b(t, h.resvd[0]); pushi32b(t, h.resvd[1]); pushi32b(t, h.resvd[2]); pushi32b(t, h.resvd[3]); pushi32b(t, h.resvd[4]); pushi32b(t, h.resvd[5]); pushi32b(t, h.resvd[6]); pushi32b(t, h.resvd[7]); pushi32b(t, h.resvd[8]); pushi32b(t, h.resvd[9]); pushi32b(t, h.resvd[10]); if (fwrite(buf, 64, 1, os) != 1) return 1; return fcopy(buf, is, os, s, n); } int main(int argc, char *argv[]) { unsigned long s = 512, n = 0; FILE *is, *os; int optind; for (optind = 1; optind < argc; optind++) { int (*f)(FILE *, FILE *, unsigned long, unsigned long); char *ep, *suf; int err; if (*argv[optind] == '-') switch (argv[optind][1]) { char *optarg; case 's': /* Set sector size */ if (!(optarg = argv[++optind])) return EXIT_FAILURE; s = strtoul(optarg, NULL, 10); continue; case 'n': /* Set sector count */ if (!(optarg = argv[++optind])) return EXIT_FAILURE; n = strtoul(optarg, NULL, 10); continue; default: return EXIT_FAILURE; } if (!(ep = strrchr(argv[optind], '.'))) { fprintf(stderr, "Unidentifiable suffix on %s.\n", argv[optind]); return EXIT_FAILURE; } if (!strcmp(ep, ".img")) { suf = ".mpc"; f = &store; } else if (!strcmp(ep, ".mpc")) { suf = ".img"; f = &extract; } else { fprintf(stderr, "Unrecognized suffix on %s.\n", argv[optind]); return EXIT_FAILURE; } if (!(is = fopen(argv[optind], "rb"))) { fprintf(stderr, "Coudln't open %s.\n", argv[optind]); return EXIT_FAILURE; } strcpy(ep, suf); if (!(os = fopen(argv[optind], "wb"))) { fclose(is); fprintf(stderr, "Couldn't open %s.\n", argv[optind]); return EXIT_FAILURE; } err = f(is, os, s, n); fclose(os); fclose(is); if (err) { fprintf(stderr, "Processing error.\n"); return EXIT_FAILURE; } } return EXIT_SUCCESS; }