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

  1. /**********************************************************************
  2.  *  
  3.  *  NAME:           badclu.c
  4.  *  
  5.  *  DESCRIPTION:    search & mark bad clusters
  6.  *  
  7.  *  M O D I F I C A T I O N   H I S T O R Y
  8.  *
  9.  *  when        who                 what
  10.  *  -------------------------------------------------------------------
  11.  *  04/18/90    J. Alan Eldridge    created
  12.  *  04/23/90    JAE                 cleaned up a lot
  13.  *  
  14.  *  *** This program should be compiled with the HUGE memory model. ***
  15.  *  *** This program should be compiled with structure alignment off. ***
  16.  *
  17.  *********************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <alloc.h>
  23. #include <bios.h>
  24. #include <conio.h>
  25.  
  26. #include "getargs.h"
  27.  
  28. #define VERSION "badclu v. 0.12 by J. Alan Eldridge\n"
  29.  
  30. #define BOOT_CODE_SIZE  (512-0x01E)
  31.  
  32. #define PRI_DOS_12  1
  33. #define PRI_DOS_16  4
  34. #define EXT_DOS     5
  35. #define BOOT_IND    0x80
  36.  
  37. #define CLUST_BAD          0xFFF7
  38. #define IS_CLUST_FREE(x)   ((x)==0x0000)
  39. #define IS_CLUST_RESV(x)   ((x)<=0xFFF6&&(x)>=0xFFF0)
  40. #define IS_CLUST_BAD(x)    ((x)==CLUST_BAD)
  41. #define IS_CLUST_LAST(x)   ((x)<=0xFFFF&&(x)>=0xFFF8)
  42. #define IS_CLUST_INUSE(x)  \
  43.     (!IS_CLUST_FREE(x)&&!IS_CLUST_RESV(x)&&!IS_CLUST_BAD(x))
  44.  
  45. #define SEC_READ    2
  46. #define SEC_WRITE   3
  47.  
  48. typedef unsigned short  UINT;
  49. typedef unsigned char   UCHAR;
  50. typedef unsigned long   ULONG;
  51.  
  52. typedef struct {
  53.     UCHAR   max_secs;
  54.     UCHAR   max_cyls;
  55.     UCHAR   num_drvs;
  56.     UCHAR   max_hds;
  57.     UINT    max_cylinder;
  58.     UINT    max_sector;
  59. } DISK_PARMS;
  60.  
  61. typedef struct {
  62.     UCHAR   hd;
  63.     UCHAR   cyl;
  64.     UCHAR   sec;
  65. } HCS_POS;
  66.  
  67. typedef struct {
  68.     UCHAR       boot;
  69.     HCS_POS     beg;
  70.     UCHAR       type;
  71.     HCS_POS     end;
  72.     ULONG       rel_sec;
  73.     ULONG       num_sec;
  74. } PART_ENT;
  75.  
  76. typedef struct {
  77.     UCHAR       reserved[0x1be];
  78.     PART_ENT    part_ents[4];
  79.     UCHAR       signature[2];
  80. } PART_TBL;
  81.  
  82. typedef struct {
  83.     UCHAR   jmp_instr[3];
  84.     UCHAR   oem[8];
  85.     UINT    bytes_per_sec;
  86.     UCHAR   sec_per_clust;
  87.     UINT    rsv_sec_cnt;
  88.     UCHAR   num_fats;
  89.     UINT    num_root_ent;
  90.     UINT    num_sec;
  91.     UCHAR   media_desc;
  92.     UINT    sec_per_fat;
  93.     UINT    sec_per_trk;
  94.     UINT    num_heads;
  95.     UINT    num_hidden_sec;
  96.     UCHAR   boot_code[BOOT_CODE_SIZE];
  97. } BOOT_SEC;
  98.  
  99. int     retries     =   0,
  100.         drive       =   0,
  101.         part        =   0,
  102.         fatdirty    =   0,
  103.         nowrite     =   0,
  104.         markok      =   0,
  105.         writethru   =   0;
  106.  
  107. UCHAR   *clubuf;
  108.  
  109. UINT    found_bad   =   0,
  110.         marked_bad  =   0,
  111.         *fat;
  112.  
  113. DISK_PARMS      diskparms;
  114. PART_TBL        part_tbl;
  115. BOOT_SEC        boot_sector;
  116. PART_ENT        curr_part;
  117.  
  118. int
  119. ckdrv(
  120.     char    *notused,
  121.     int     *val)
  122. {
  123.     return -(*val != 0 && *val != 1);
  124. }    
  125.  
  126. CMD_ARG args[] = {
  127.     "-d",   ARG_INT|ARG_REQD,   &drive,     ckdrv,
  128.     "-p",   ARG_INT|ARG_REQD,   &part,      ckdrv,
  129.     "-r",   ARG_INT,            &retries,   ARG_NOFUNC,
  130.     "-n",   ARG_BOOL,           &nowrite,   ARG_NOFUNC,
  131.     "-m",   ARG_BOOL,           &markok,    ARG_NOFUNC,
  132.     "-w",   ARG_BOOL,           &writethru, ARG_NOFUNC
  133. };
  134.  
  135. char    *umsg[] = {
  136.     "scans hard disk partitions for bad clusters",
  137.     "",
  138.     "badclu -d drive -p partition [-r retries][-n|w][-m]",
  139.     "",
  140.     "-d\tdrive is the physical hard disk number (0 or 1)",
  141.     "-p\tpartition is the logical partition number (0 or 1)",
  142.     "-r\tretries is the number of retries to attempt before marking",
  143.     "\ta cluster as bad (default is 0)",
  144.     "-n\tdo NOT write the updated File Allocation Table (overrides -w)",
  145.     "-w\twrite FAT each time an entry is changed",
  146.     "-m\tallow marking most recent cluster by keypress during disk read",
  147.     "",
  148.     "this program is placed in the public domain",
  149.     NULL
  150. };
  151.  
  152. void
  153. fix_cyl_sec(
  154.     UCHAR   cyl,
  155.     UCHAR   sec,
  156.     UINT    *cylw,
  157.     UINT    *secw)
  158. {
  159.     *cylw = cyl | ((sec << 2) & 0x300);
  160.     *secw = sec & 0x3f;
  161. }    
  162.  
  163. void
  164. get_part_ent(void)
  165. {
  166.     int n, p;
  167.  
  168.     for (p = n = 0; n < 4; n++) {
  169.         UCHAR ptype = part_tbl.part_ents[n].type;
  170.  
  171.         if (ptype==PRI_DOS_12||ptype==PRI_DOS_16||ptype==EXT_DOS)
  172.             if (p++ == part) {
  173.                 curr_part = part_tbl.part_ents[n];
  174.                 return;
  175.             }
  176.     }
  177.  
  178.     printf("partition %d on drive %d doesn't exist\n",part,drive);
  179.     exit(1);    
  180. }
  181.  
  182. void
  183. calc_chs(
  184.     UINT    sector,
  185.     UINT    *cyl,
  186.     UINT    *sec,
  187.     UINT    *head)
  188. {
  189.     UINT            hcnt, 
  190.                     scnt;
  191.         
  192.     ULONG           lsec;
  193.         
  194.     hcnt = diskparms.max_hds + 1;
  195.     scnt = diskparms.max_sector;
  196.     
  197.     lsec = sector;
  198.     lsec += curr_part.rel_sec;
  199.  
  200.     *cyl = lsec / (hcnt*scnt);
  201.     *head = (lsec / scnt) % hcnt;
  202.     *sec = 1 + (lsec % scnt);
  203. }
  204.  
  205. void
  206. get_disk_parms(void)
  207. {
  208.     biosdisk(8,drive|0x80,0,0,0,0,&diskparms);
  209.     fix_cyl_sec(diskparms.max_cyls, diskparms.max_secs,
  210.       &diskparms.max_cylinder, &diskparms.max_sector);
  211. }
  212.  
  213. #define diskreset()         biosdisk(0,drive|0x80,0,0,0,0,NULL)
  214. #define get_part_tbl()      biosdisk(2,drive|0x80,0,0,1,1,&part_tbl)
  215. #define get_boot_sector()   rw_sector(SEC_READ,0,1,&boot_sector)
  216.  
  217. int
  218. rw_sector(
  219.     UINT    rw,
  220.     UINT    sector,
  221.     UINT    cnt,
  222.     void    *buffer)
  223. {
  224.     UINT    hd, 
  225.             cyl, 
  226.             sec;
  227.  
  228.     calc_chs(sector, &cyl, &sec, &hd);
  229.  
  230.     printf("%s: c=%4d h=%2d s=%2d n=%2d\r",
  231.         rw == SEC_READ ? "rd" : "wr", cyl, hd, sec, cnt);
  232.  
  233.     return biosdisk(rw, drive|0x80, hd, cyl, sec, cnt, buffer) & 0xff;
  234. }
  235.  
  236. #define getFAT()    \
  237.     ((fatdirty = 0),rw_sector(SEC_READ,1,boot_sector.sec_per_fat,fat))
  238.  
  239. void putFAT(void)
  240. {
  241.     if (fatdirty && !nowrite) {
  242.         int start,
  243.             nfats;
  244.     
  245.         printf("\nwriting File Allocation Table...");
  246.         for (start = 1, nfats = 0; nfats < boot_sector.num_fats; nfats++, 
  247.             start += boot_sector.sec_per_fat) {
  248.             putchar('\n');
  249.             if (rw_sector(SEC_WRITE,start,boot_sector.sec_per_fat,fat))
  250.                 printf("\n\007error writing FAT # %d\n", nfats);
  251.         }
  252.         fatdirty = 0;
  253.     }
  254.     putchar('\n');
  255. }
  256.  
  257. UINT
  258. GET_FAT12_ENT(UINT n)
  259. {
  260.     UINT fatent, byteoffs;
  261.     
  262.     byteoffs = n * 3;
  263.     byteoffs /= 2;
  264.             
  265.     fatent = *(UINT*)&(((UCHAR*)fat)[byteoffs]);
  266.     if (n & 1)
  267.         fatent >>= 4;
  268.     else
  269.         fatent &= 0xFFF;
  270.         
  271.     if (fatent >= 0xFF7)
  272.         fatent |= 0xF000;
  273.     return fatent;
  274. }
  275.  
  276. void
  277. PUT_FAT12_ENT(UINT n,UINT v)
  278. {
  279.     UINT fatent, byteoffs, mask;
  280.     
  281.     fatdirty = 1;
  282.     
  283.     byteoffs = n * 3;
  284.     byteoffs /= 2;
  285.             
  286.     fatent = *(UINT*)&(((UCHAR*)fat)[byteoffs]);
  287.     v &= 0xFFF;
  288.     if (n & 1) {
  289.         v <<= 4;
  290.         mask = 0x000F;
  291.     } else {
  292.         mask = 0xF000;
  293.     }        
  294.  
  295.     fatent &= mask;
  296.     fatent |= v;
  297.     *(UINT*)&(((UCHAR*)fat)[byteoffs]) = fatent;
  298. }
  299.  
  300. #define GET_FAT_ENT(n) \
  301.     (curr_part.type==PRI_DOS_12?GET_FAT12_ENT(n):GET_FAT16_ENT(n))
  302. #define PUT_FAT_ENT(n,v) \
  303.     (curr_part.type==PRI_DOS_12?PUT_FAT12_ENT(n,v):PUT_FAT16_ENT(n,v))
  304.  
  305. #define GET_FAT16_ENT(n)    (fat[(n)])
  306. #define PUT_FAT16_ENT(n,v)  ((fat[(n)]=v),fatdirty=1)
  307. #define MARK_BAD(n)         PUT_FAT_ENT(n,CLUST_BAD)
  308.  
  309. int
  310. makebad(UINT clust)
  311. {
  312.     if (kbhit()) {
  313.         getch();
  314.         if (askyn(1,"\n*** Mark cluster %5u as bad", clust)) {
  315.             if (IS_CLUST_INUSE(GET_FAT_ENT(clust+2)))
  316.                 printf("    Cluster %5u in use. sorry.\n", clust);
  317.             else {
  318.                 printf("    Marking cluster %5u as bad\n",clust);
  319.                 MARK_BAD(clust + 2);                
  320.                 if (writethru)
  321.                     putFAT();
  322.                 marked_bad++;
  323.             }
  324.             return 1;
  325.         }
  326.     }
  327.     return 0;
  328. }
  329.  
  330. void
  331. scan(void)
  332. {
  333.     UINT    dirsecs,
  334.             clust,
  335.             first_data_sec,
  336.             first_dir_sec,
  337.             last_cluster;
  338.  
  339.     putchar('\n');
  340.     first_dir_sec = boot_sector.num_fats * boot_sector.sec_per_fat + 1;
  341.     dirsecs = boot_sector.num_root_ent * 32;
  342.     dirsecs /= boot_sector.bytes_per_sec;
  343.     first_data_sec = first_dir_sec + dirsecs;
  344.     last_cluster = ((boot_sector.num_sec - first_data_sec) 
  345.         / boot_sector.sec_per_clust) - 1;
  346.  
  347.     for (clust = 0; clust <= last_cluster; clust++) {
  348.         int ret;
  349.         
  350.         printf("clu %5u of %5u: ", clust, last_cluster);
  351.  
  352.         if (IS_CLUST_BAD(GET_FAT_ENT(clust+2))) {
  353.             printf("%-40s\n", "already marked bad");
  354.             found_bad++;
  355.             continue;
  356.         }
  357.  
  358.         ret = rw_sector(SEC_READ, clust * boot_sector.sec_per_clust
  359.             + first_data_sec, boot_sector.sec_per_clust, clubuf);
  360.             
  361.         if (markok && makebad(clust))
  362.             continue;
  363.  
  364.         if (ret != 0 && ret != 0x11) {
  365.             int forced = 0;
  366.             
  367.             printf("\n\007*** error reading cluster %5u: %02xH\n", 
  368.                 clust, ret);
  369.             for (ret = 0; ret < retries; ret++) {
  370.                 int r;
  371.  
  372.                 printf("*** retry %d\n",ret+1);
  373.                 diskreset();
  374.                 r = rw_sector(SEC_READ, clust * boot_sector.sec_per_clust + first_data_sec,
  375.                     boot_sector.sec_per_clust, clubuf);
  376.                 if (markok && makebad(clust)) {
  377.                     forced = 1;
  378.                     break;
  379.                 }
  380.                 if (r == 0 || r == 0x11)
  381.                     break;
  382.                 putchar('\n');
  383.             }
  384.  
  385.             if (forced)
  386.                 continue;
  387.  
  388.             if (ret == retries) {
  389.                 UINT fat_entry = GET_FAT_ENT(clust+2);
  390.                     
  391.                 printf("\007\007\007cluster %5u is dead: ",clust);
  392.                 if (IS_CLUST_INUSE(fat_entry))
  393.                     printf("cluster in use. sorry.\n");
  394.                 else {
  395.                     printf("marking as bad\n");
  396.                     MARK_BAD(clust + 2);                
  397.                     if (writethru)
  398.                         putFAT();
  399.                     marked_bad++;
  400.                 }
  401.             }                
  402.         }
  403.     }
  404. }
  405.  
  406. main(
  407.     int     ac,
  408.     char    **av)
  409. {
  410.     puts(VERSION);    
  411.     if (!getargs(&ac, av, ARG_CNT(args), args)) {
  412.         if (!askyn(1,"Scan disk %d partition %d for defects",drive,part))
  413.             exit(0);
  414.         putchar(7);
  415.         diskreset();
  416.         get_disk_parms();
  417.         get_part_tbl();
  418.         get_part_ent();
  419.         if (!get_boot_sector()) {
  420.             if (curr_part.type == EXT_DOS) {
  421.                 long relsec;
  422.                 
  423.                 relsec = curr_part.rel_sec;
  424.                 memcpy(&part_tbl,&boot_sector, 512);
  425.                 part = 0;
  426.                 get_part_ent();
  427.                 curr_part.rel_sec += relsec;
  428.                 if (curr_part.type == EXT_DOS) {
  429.                     printf("\n\007multiple logical drives in extended DOS "
  430.                         "partitions are not supported.\n");
  431.                     exit(1);
  432.                 }
  433.                 get_boot_sector();
  434.             }
  435.             fat = farcalloc((ULONG)(boot_sector.sec_per_fat+1),
  436.                 (ULONG)(boot_sector.bytes_per_sec));
  437.             clubuf = calloc(boot_sector.bytes_per_sec,
  438.                 boot_sector.sec_per_clust);
  439.             if (clubuf && fat && !getFAT()) {
  440.                 scan();
  441.                 putFAT();
  442.                 printf("found %4u bad clusters, marked %4u bad clusters\n",
  443.                     found_bad, marked_bad);
  444.             }
  445.             exit(0);
  446.         }
  447.     }
  448.     usage(umsg, 20, 1);
  449. }    
  450.