Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!caip!topaz!uwvax!husc6!harvard!panda!genrad!decvax!tektronix!uw-beaver!cornell!batcomputer!braner From: braner@batcomputer.TN.CORNELL.EDU (braner) Newsgroups: net.micro.atari16 Subject: Re: Double-sided disk format and fonts Message-ID: <788@batcomputer.TN.CORNELL.EDU> Date: Wed, 30-Jul-86 13:58:00 EDT Article-I.D.: batcompu.788 Posted: Wed Jul 30 13:58:00 1986 Date-Received: Sat, 2-Aug-86 09:02:50 EDT References: <401@atari.UUcp> Reply-To: braner@batcomputer.UUCP (braner) Organization: Theory Center, Cornell University, Ithaca NY Lines: 318 Keywords: same as single-sided, ROM TOS [] It was bound to happen: a disk went bad on me and I did not have a backup. Using MUTIL I could see that the data was there but the second FAT was damaged. Using the "file attributes" option of MUTIL I wrote down the starting sector (or cluster) of each file I wanted to recover. (These cluster and sector are the two last columns in the directory-entry list of MUTIL). (I also wrote down the length of the file for later reference.) Then I used the following program to read each file and save it on a different drive (a RAMdisk, in my case). This program will work for MSDOS, by the way. Note that the program reads by clusters, so you will have some extra junk at the end of the file. If it is a text file, use a text editor to remove it. Then compare the length with the original length you wrote down. Some day I'll try to write a program that will intelligently search the disk for the required starting-sector information. (MUTIL did the job but is a PAIN.) Note: this program assumes a standard disk. If you have a damaged, "copy protected" disk, well, you get what you deserve for buying one of those things... ------------------------------------------------------------- /* * READFILE - a program to read a file from off a damaged disk. * Uses information in the FAT and the boot sector. * The first sector (or cluster) of the file must be known. * * By Moshe Braner, 860730. */ #include #include #define TRUE 1 #define FALSE 0 #define READ 2 /* ignore disk changes */ #define DRIVEA 0 /* always read drive A */ #define SECSIZE 1024 /* for up to 1K sectors */ /* read unsigned bytes and Intel-style integers */ #define US(p,o) (p[o]&0xFF) #define UI(p,o) (US(p,o)+256*US(p,o+1)) /* translate between sectors and clusters */ #define stc(s) ((s-fuds)/spc+2) #define cts(c) ((c-2)*spc+fuds) /* offsets into the boot sector */ #define BPS 11 #define SPC 13 #define RES 14 #define FAT 16 #define DIR 17 #define SPF 22 /* The CLUSTER data structure: a linked list */ typedef struct CLUSTER { struct CLUSTER *link; /* link to next */ char *data; /* pointer to data in cluster */ } CLUSTER; /*** GLOBALS ***/ int bps, spc, res, fat, dir, spf, bpc, bpf, fuds; char *fat1, *fat2; CLUSTER *clhead = NULL; error(msg) char msg[]; { printf(msg); Cconin(); exit(0); } /* Read the boot sector */ readboot() { register long status; register int c; char boot[SECSIZE]; printf("\nReading boot sector\n"); status = Rwabs (READ, boot, 1, 0, DRIVEA); if (status != 0) { printf("\nError reading boot sector!\n"); printf("Continue? (y/n) "); fflush(stdout); if ((c=(int)Cconin())!='y' && c!='Y') exit(0); /* else guess the parameters */ bps = 512; spc = 2; /* 1 for SS 5.25" disks */ res = 1; fat = 2; dir = 112; /* 64 for SS 5.25" disks */ spf = 5; /* 2 for 5.25" disks, incl DS */ } bps = UI(boot, BPS); /* bytes per sector */ spc = US(boot, SPC); /* sectors per cluster */ res = US(boot, RES); /* no. of reserved sec */ fat = US(boot, FAT); /* no. of FAT copies */ dir = UI(boot, DIR); /* no. of dir entries */ spf = US(boot, SPF); /* sectors per FAT */ bpc = bps * spc; /* bytes per cluster */ bpf = bps * spf; /* bytes per FAT */ fuds = dir * 32; /* length of directory in bytes */ fuds /= bps; /* in sectors */ fuds += res + fat*spf; /* first usable data sector */ } /* read (both) FAT areas */ readfat() { register long status; register int c; register int err1 = FALSE; register int err2 = FALSE; fat1 = malloc(spf*bps); if (fat1 == NULL) error("\nNot enough memory!\n"); printf("\nReading FAT (#1)\n"); status = Rwabs (READ, fat1, spf, res, DRIVEA); if (status != 0) { printf("\nError reading FAT #1.\n"); err1 = TRUE; } if (fat > 1) { fat2 = malloc(spf*bps); if (fat2 == NULL) error("\nNot enough memory!\n"); printf("\nReading FAT #2\n"); status = Rwabs (READ, fat2, spf, res+spf, DRIVEA); if (status != 0) { printf("\nError reading FAT #2.\n"); err2 = TRUE; fat2 = fat1; } } else { err2 = TRUE; fat2 = fat1; } if (err1==TRUE && err2==TRUE) error("\nCannot proceed without FAT!\n"); if (err1) fat1 = fat2; } /* compare the 2 FATs */ compfats() { register char *p1, *p2; register int i, c; if (fat1 == fat2) /* only one FAT */ return; p1 = fat1; p2 = fat2; for (i=0; i>= 1; /* offset into FAT = 3/2 * cluster */ next = UI(fat1, offset); if (cluster&0x01) /* if cluster no. odd */ next >>= 4; next &= 0xFFF; /* the 12-bit value of FAT entry */ return (next); } /* allocate memory for another cluster */ CLUSTER * clspace(clp) CLUSTER *clp; { register CLUSTER *ncp; register char *dp; dp = malloc(bpc); if (dp == NULL) return (NULL); ncp = (CLUSTER *) malloc(sizeof(CLUSTER)); if (ncp == NULL) { free(dp); return (NULL); } else { if (clp == NULL) clhead = ncp; else clp->link = ncp; ncp->link = NULL; ncp->data = dp; } return (ncp); } main() { register int i, c; register char *dp; int sknown, sector, cluster; long status; CLUSTER *clp; FILE *fp; char filename[80]; printf("\nREADFILE MB 8607\n\n"); printf("Insert disk in drive A, press return: "); fflush(stdout); while ((c=(int)Cconin())!='\n' && c!='\r'); readboot(); readfat(); compfats(); loop: printf("\nDo you know the cluster or sector number? (c/s) "); fflush(stdout); if (Cconis()) Crawcin(); if ((c=(int)Cconin())!='c' && c!='C') sknown = TRUE; else sknown = FALSE; printf("\nFirst cluster or sector of file: "); fflush(stdout); scanf("%d", §or); if (sknown) cluster = stc(sector); else { cluster = sector; sector = cts(cluster); } clp = NULL; do { /* while not EOF */ clp = clspace(clp); if (clp == NULL) error("\nNot enough memory!\n"); printf("reading cluster at logical sector #%d\n", sector); status = Rwabs(READ, clp->data, spc, sector, DRIVEA); if (status != 0) { printf("\nRead error on data cluster!\n"); printf("Continue? (y/n) "); fflush(stdout); if ((c=(int)Cconin())!='y' && c!='Y') exit(0); } cluster = nxtclus(cluster); sector = cts(cluster); } while (cluster < 0x0FF1); /* not EOF */ clp = clhead; if (clp == NULL) error("\nNothing read!\n"); printf("\nPathname to save as: "); fflush(stdout); scanf("%s", filename); fp = fopen(filename, "bw"); /* binary write (Megamax) */ if (fp == NULL) error("\nError opening file!\n"); while (clp != NULL) { dp = clp->data; for(i=0; ilink; } fclose(fp); printf("Read another file? (y/n) "); fflush(stdout); if ((c=(int)Cconin())=='y' || c=='Y') goto loop; } ------------------------------------------------------------ - Moshe Braner Corson Hall, Cornell University, Ithaca NY 14853 (607) 272-3487 For electronic mail, my address is: braner@amvax.tn.cornell.edu (ARPANET) braner%amvax.tn.cornell.edu@WISCVM.BITNET (Bitnet) {decvax,ihnp4,cmcl2,vax135}!cornell!amvax!braner (USENET)