/* mas.c vi:se ts=8 sw=8: */ /* mas--A disk image archiver * Copyright (C) 2001 Peter Backes * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include /* fopen(), ... */ #include /* memcpy(), memset() */ #include /* EXIT_FAILURE, EXIT_SUCCESS */ /* Disk parameter block */ struct diskpb { /* Archive info */ char name[8]; char padding[24]; /* Null bytes */ short recs; /* Count of tracks actually saved */ char resvd[8]; /* Null bytes */ /* Disk format */ short nsid; /* Sides */ short nsecpt; /* Sectors per track */ short ntrkps; /* Tracks per side */ }; #define DPBSIZE 48 /* Size of disk parameter block on disk */ #define SECSIZE 512 /* Sector size */ const char *prgnam; unsigned char buffer[SECSIZE]; static void (*action)(FILE *af, const char *bn, int cks, struct diskpb *hdr); int getdpb(struct diskpb *dstdpb, unsigned char *srcbuf) { unsigned char *src, *dst, *bot; int cks = 0; /* Padding checksum */ memcpy(dstdpb->name, srcbuf, 8); for (src = bot = srcbuf + 8, bot += 24, dst = dstdpb->padding; src < bot; cks += (*dst++ = *src++) != 0x00); for (src = bot = srcbuf + 34, bot += 8, dst = dstdpb->resvd; src < bot; cks += (*dst++ = *src++) != 0x00); dstdpb->recs = srcbuf[32] << 8; dstdpb->recs |= srcbuf[33]; dstdpb->nsid = srcbuf[42] << 8; dstdpb->nsid |= srcbuf[43]; dstdpb->nsecpt = srcbuf[44] << 8; dstdpb->nsecpt |= srcbuf[45]; dstdpb->ntrkps = srcbuf[46] << 8; dstdpb->ntrkps |= srcbuf[47]; return cks; } static void extract(FILE *af, const char *bn, int cks, struct diskpb *hdr) { FILE *of; /* Output file */ char filename[13]; /* FILENAME.EXT\0*/ /* count of specified and unspecified tracks */ int nst = hdr->recs * hdr->nsecpt, nut = hdr->nsid * hdr->ntrkps * hdr->nsecpt - nst; sprintf(filename, "%.8s.IMG", hdr->name); if ((of = fopen(filename, "wb")) == NULL) { fprintf(stderr, "%s: Unable to open %s for output\n", prgnam, filename); return; } printf("x %s %d+%d\n", filename, nst, nut); while (nst-- > 0) fwrite(buffer, SECSIZE, fread(buffer, SECSIZE, 1, af), of); if (nut > 0) memset(buffer, 0x00, SECSIZE); while (nut-- > 0) fwrite(buffer, SECSIZE, 1, of); fclose(of); } static void list1(FILE *af, const char *bn, int cks, struct diskpb *hdr) { int nst = hdr->recs * hdr->nsecpt; printf("%16s %-8.8s /%02X/ %-5d %-5d %-5d %-5d \n", bn, hdr->name, cks, hdr->recs, hdr->nsid, hdr->nsecpt, hdr->ntrkps); /* If you know only one file is in the archive then the * header integrity can be verified as follows. * (long) nst * SECSIZE + DPBSIZE == st.st_size */ fseek(af, (long) nst * SECSIZE, SEEK_CUR); /* See NINJA.DRAFT.NOTE1 for the casting style used here. */ } static void list0(FILE *af, const char *bn, int cks, struct diskpb *hdr) { printf(" filename ident ERR Len Sides Sect " "Tps \n"); action = list1; list1(af, bn, cks, hdr); } int main(int argc, char *argv[]) { FILE *af; /* Archive file */ int i; struct diskpb hdr; const char *basename; prgnam = *argv; if (argc < 2) { fprintf(stderr, "%s: not enough arguments\n", prgnam); return EXIT_FAILURE; } else if (!strcmp(argv[1], "-x")) action = extract; else if (!strcmp(argv[1], "-l")) action = list0; else { fprintf(stderr, "Usage: %s -xl file [...]\n", prgnam); return EXIT_FAILURE; } for (i = 2; i < argc; i++) { if ((af = fopen(argv[i], "rb")) == NULL) { fprintf(stderr, "%s: Could not open %s for input\n", prgnam, argv[i]); continue; } if ((basename = strrchr(argv[i], '/')) == 0) basename = argv[i]; else basename++; while (fread(buffer, DPBSIZE, 1, af) == 1) action(af, basename, getdpb(&hdr, buffer), &hdr); fclose(af); } return EXIT_SUCCESS; }