/* 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;
}