home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Supreme Volume 6 #1
/
swsii.zip
/
swsii
/
167
/
BADCLU.ZIP
/
BADCLU.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-24
|
12KB
|
450 lines
/**********************************************************************
*
* 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);
}