home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- *
- * NAME: badclu.c
- *
- * DESCRIPTION: search & mark bad clusters
- *
- * M O D I F I C A T I O N H I S T O R Y
- *
- * when who what
- * -------------------------------------------------------------------
- * 04/18/90 J. Alan Eldridge created
- * 04/23/90 JAE cleaned up a lot
- *
- * *** This program should be compiled with the HUGE memory model. ***
- * *** This program should be compiled with structure alignment off. ***
- *
- *********************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <alloc.h>
- #include <bios.h>
- #include <conio.h>
-
- #include "getargs.h"
-
- #define VERSION "badclu v. 0.12 by J. Alan Eldridge\n"
-
- #define BOOT_CODE_SIZE (512-0x01E)
-
- #define PRI_DOS_12 1
- #define PRI_DOS_16 4
- #define EXT_DOS 5
- #define BOOT_IND 0x80
-
- #define CLUST_BAD 0xFFF7
- #define IS_CLUST_FREE(x) ((x)==0x0000)
- #define IS_CLUST_RESV(x) ((x)<=0xFFF6&&(x)>=0xFFF0)
- #define IS_CLUST_BAD(x) ((x)==CLUST_BAD)
- #define IS_CLUST_LAST(x) ((x)<=0xFFFF&&(x)>=0xFFF8)
- #define IS_CLUST_INUSE(x) \
- (!IS_CLUST_FREE(x)&&!IS_CLUST_RESV(x)&&!IS_CLUST_BAD(x))
-
- #define SEC_READ 2
- #define SEC_WRITE 3
-
- typedef unsigned short UINT;
- typedef unsigned char UCHAR;
- typedef unsigned long ULONG;
-
- typedef struct {
- UCHAR max_secs;
- UCHAR max_cyls;
- UCHAR num_drvs;
- UCHAR max_hds;
- UINT max_cylinder;
- UINT max_sector;
- } DISK_PARMS;
-
- typedef struct {
- UCHAR hd;
- UCHAR cyl;
- UCHAR sec;
- } HCS_POS;
-
- typedef struct {
- UCHAR boot;
- HCS_POS beg;
- UCHAR type;
- HCS_POS end;
- ULONG rel_sec;
- ULONG num_sec;
- } PART_ENT;
-
- typedef struct {
- UCHAR reserved[0x1be];
- PART_ENT part_ents[4];
- UCHAR signature[2];
- } PART_TBL;
-
- typedef struct {
- UCHAR jmp_instr[3];
- UCHAR oem[8];
- UINT bytes_per_sec;
- UCHAR sec_per_clust;
- UINT rsv_sec_cnt;
- UCHAR num_fats;
- UINT num_root_ent;
- UINT num_sec;
- UCHAR media_desc;
- UINT sec_per_fat;
- UINT sec_per_trk;
- UINT num_heads;
- UINT num_hidden_sec;
- UCHAR boot_code[BOOT_CODE_SIZE];
- } BOOT_SEC;
-
- int retries = 0,
- drive = 0,
- part = 0,
- fatdirty = 0,
- nowrite = 0,
- markok = 0,
- writethru = 0;
-
- UCHAR *clubuf;
-
- UINT found_bad = 0,
- marked_bad = 0,
- *fat;
-
- DISK_PARMS diskparms;
- PART_TBL part_tbl;
- BOOT_SEC boot_sector;
- PART_ENT curr_part;
-
- int
- ckdrv(
- char *notused,
- int *val)
- {
- return -(*val != 0 && *val != 1);
- }
-
- CMD_ARG args[] = {
- "-d", ARG_INT|ARG_REQD, &drive, ckdrv,
- "-p", ARG_INT|ARG_REQD, &part, ckdrv,
- "-r", ARG_INT, &retries, ARG_NOFUNC,
- "-n", ARG_BOOL, &nowrite, ARG_NOFUNC,
- "-m", ARG_BOOL, &markok, ARG_NOFUNC,
- "-w", ARG_BOOL, &writethru, ARG_NOFUNC
- };
-
- char *umsg[] = {
- "scans hard disk partitions for bad clusters",
- "",
- "badclu -d drive -p partition [-r retries][-n|w][-m]",
- "",
- "-d\tdrive is the physical hard disk number (0 or 1)",
- "-p\tpartition is the logical partition number (0 or 1)",
- "-r\tretries is the number of retries to attempt before marking",
- "\ta cluster as bad (default is 0)",
- "-n\tdo NOT write the updated File Allocation Table (overrides -w)",
- "-w\twrite FAT each time an entry is changed",
- "-m\tallow marking most recent cluster by keypress during disk read",
- "",
- "this program is placed in the public domain",
- NULL
- };
-
- void
- fix_cyl_sec(
- UCHAR cyl,
- UCHAR sec,
- UINT *cylw,
- UINT *secw)
- {
- *cylw = cyl | ((sec << 2) & 0x300);
- *secw = sec & 0x3f;
- }
-
- void
- get_part_ent(void)
- {
- int n, p;
-
- for (p = n = 0; n < 4; n++) {
- UCHAR ptype = part_tbl.part_ents[n].type;
-
- if (ptype==PRI_DOS_12||ptype==PRI_DOS_16||ptype==EXT_DOS)
- if (p++ == part) {
- curr_part = part_tbl.part_ents[n];
- return;
- }
- }
-
- printf("partition %d on drive %d doesn't exist\n",part,drive);
- exit(1);
- }
-
- void
- calc_chs(
- UINT sector,
- UINT *cyl,
- UINT *sec,
- UINT *head)
- {
- UINT hcnt,
- scnt;
-
- ULONG lsec;
-
- hcnt = diskparms.max_hds + 1;
- scnt = diskparms.max_sector;
-
- lsec = sector;
- lsec += curr_part.rel_sec;
-
- *cyl = lsec / (hcnt*scnt);
- *head = (lsec / scnt) % hcnt;
- *sec = 1 + (lsec % scnt);
- }
-
- void
- get_disk_parms(void)
- {
- biosdisk(8,drive|0x80,0,0,0,0,&diskparms);
- fix_cyl_sec(diskparms.max_cyls, diskparms.max_secs,
- &diskparms.max_cylinder, &diskparms.max_sector);
- }
-
- #define diskreset() biosdisk(0,drive|0x80,0,0,0,0,NULL)
- #define get_part_tbl() biosdisk(2,drive|0x80,0,0,1,1,&part_tbl)
- #define get_boot_sector() rw_sector(SEC_READ,0,1,&boot_sector)
-
- int
- rw_sector(
- UINT rw,
- UINT sector,
- UINT cnt,
- void *buffer)
- {
- UINT hd,
- cyl,
- sec;
-
- calc_chs(sector, &cyl, &sec, &hd);
-
- printf("%s: c=%4d h=%2d s=%2d n=%2d\r",
- rw == SEC_READ ? "rd" : "wr", cyl, hd, sec, cnt);
-
- return biosdisk(rw, drive|0x80, hd, cyl, sec, cnt, buffer) & 0xff;
- }
-
- #define getFAT() \
- ((fatdirty = 0),rw_sector(SEC_READ,1,boot_sector.sec_per_fat,fat))
-
- void putFAT(void)
- {
- if (fatdirty && !nowrite) {
- int start,
- nfats;
-
- printf("\nwriting File Allocation Table...");
- for (start = 1, nfats = 0; nfats < boot_sector.num_fats; nfats++,
- start += boot_sector.sec_per_fat) {
- putchar('\n');
- if (rw_sector(SEC_WRITE,start,boot_sector.sec_per_fat,fat))
- printf("\n\007error writing FAT # %d\n", nfats);
- }
- fatdirty = 0;
- }
- putchar('\n');
- }
-
- UINT
- GET_FAT12_ENT(UINT n)
- {
- UINT fatent, byteoffs;
-
- byteoffs = n * 3;
- byteoffs /= 2;
-
- fatent = *(UINT*)&(((UCHAR*)fat)[byteoffs]);
- if (n & 1)
- fatent >>= 4;
- else
- fatent &= 0xFFF;
-
- if (fatent >= 0xFF7)
- fatent |= 0xF000;
- return fatent;
- }
-
- void
- PUT_FAT12_ENT(UINT n,UINT v)
- {
- UINT fatent, byteoffs, mask;
-
- fatdirty = 1;
-
- byteoffs = n * 3;
- byteoffs /= 2;
-
- fatent = *(UINT*)&(((UCHAR*)fat)[byteoffs]);
- v &= 0xFFF;
- if (n & 1) {
- v <<= 4;
- mask = 0x000F;
- } else {
- mask = 0xF000;
- }
-
- fatent &= mask;
- fatent |= v;
- *(UINT*)&(((UCHAR*)fat)[byteoffs]) = fatent;
- }
-
- #define GET_FAT_ENT(n) \
- (curr_part.type==PRI_DOS_12?GET_FAT12_ENT(n):GET_FAT16_ENT(n))
- #define PUT_FAT_ENT(n,v) \
- (curr_part.type==PRI_DOS_12?PUT_FAT12_ENT(n,v):PUT_FAT16_ENT(n,v))
-
- #define GET_FAT16_ENT(n) (fat[(n)])
- #define PUT_FAT16_ENT(n,v) ((fat[(n)]=v),fatdirty=1)
- #define MARK_BAD(n) PUT_FAT_ENT(n,CLUST_BAD)
-
- int
- makebad(UINT clust)
- {
- if (kbhit()) {
- getch();
- if (askyn(1,"\n*** Mark cluster %5u as bad", clust)) {
- if (IS_CLUST_INUSE(GET_FAT_ENT(clust+2)))
- printf(" Cluster %5u in use. sorry.\n", clust);
- else {
- printf(" Marking cluster %5u as bad\n",clust);
- MARK_BAD(clust + 2);
- if (writethru)
- putFAT();
- marked_bad++;
- }
- return 1;
- }
- }
- return 0;
- }
-
- void
- scan(void)
- {
- UINT dirsecs,
- clust,
- first_data_sec,
- first_dir_sec,
- last_cluster;
-
- putchar('\n');
- first_dir_sec = boot_sector.num_fats * boot_sector.sec_per_fat + 1;
- dirsecs = boot_sector.num_root_ent * 32;
- dirsecs /= boot_sector.bytes_per_sec;
- first_data_sec = first_dir_sec + dirsecs;
- last_cluster = ((boot_sector.num_sec - first_data_sec)
- / boot_sector.sec_per_clust) - 1;
-
- for (clust = 0; clust <= last_cluster; clust++) {
- int ret;
-
- printf("clu %5u of %5u: ", clust, last_cluster);
-
- if (IS_CLUST_BAD(GET_FAT_ENT(clust+2))) {
- printf("%-40s\n", "already marked bad");
- found_bad++;
- continue;
- }
-
- ret = rw_sector(SEC_READ, clust * boot_sector.sec_per_clust
- + first_data_sec, boot_sector.sec_per_clust, clubuf);
-
- if (markok && makebad(clust))
- continue;
-
- if (ret != 0 && ret != 0x11) {
- int forced = 0;
-
- printf("\n\007*** error reading cluster %5u: %02xH\n",
- clust, ret);
- for (ret = 0; ret < retries; ret++) {
- int r;
-
- printf("*** retry %d\n",ret+1);
- diskreset();
- r = rw_sector(SEC_READ, clust * boot_sector.sec_per_clust + first_data_sec,
- boot_sector.sec_per_clust, clubuf);
- if (markok && makebad(clust)) {
- forced = 1;
- break;
- }
- if (r == 0 || r == 0x11)
- break;
- putchar('\n');
- }
-
- if (forced)
- continue;
-
- if (ret == retries) {
- UINT fat_entry = GET_FAT_ENT(clust+2);
-
- printf("\007\007\007cluster %5u is dead: ",clust);
- if (IS_CLUST_INUSE(fat_entry))
- printf("cluster in use. sorry.\n");
- else {
- printf("marking as bad\n");
- MARK_BAD(clust + 2);
- if (writethru)
- putFAT();
- marked_bad++;
- }
- }
- }
- }
- }
-
- main(
- int ac,
- char **av)
- {
- puts(VERSION);
- if (!getargs(&ac, av, ARG_CNT(args), args)) {
- if (!askyn(1,"Scan disk %d partition %d for defects",drive,part))
- exit(0);
- putchar(7);
- diskreset();
- get_disk_parms();
- get_part_tbl();
- get_part_ent();
- if (!get_boot_sector()) {
- if (curr_part.type == EXT_DOS) {
- long relsec;
-
- relsec = curr_part.rel_sec;
- memcpy(&part_tbl,&boot_sector, 512);
- part = 0;
- get_part_ent();
- curr_part.rel_sec += relsec;
- if (curr_part.type == EXT_DOS) {
- printf("\n\007multiple logical drives in extended DOS "
- "partitions are not supported.\n");
- exit(1);
- }
- get_boot_sector();
- }
- fat = farcalloc((ULONG)(boot_sector.sec_per_fat+1),
- (ULONG)(boot_sector.bytes_per_sec));
- clubuf = calloc(boot_sector.bytes_per_sec,
- boot_sector.sec_per_clust);
- if (clubuf && fat && !getFAT()) {
- scan();
- putFAT();
- printf("found %4u bad clusters, marked %4u bad clusters\n",
- found_bad, marked_bad);
- }
- exit(0);
- }
- }
- usage(umsg, 20, 1);
- }
-