home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / HARDDISK / BADCLU.ZIP / HDIO.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-25  |  15.7 KB  |  576 lines

  1. /**********************************************************************
  2.  *  
  3.  *  NAME:           hdio.c
  4.  *  
  5.  *  DESCRIPTION:    hard disk i/o (int 13h)
  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/24/90    J. Alan Eldridge    created from badclu.c
  12.  *
  13.  *********************************************************************/
  14.  
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include <bios.h>
  18.  
  19. #include "hdio.h"
  20.  
  21. /**********************************************************************
  22.  *  some static vars used to keep status info
  23.  *********************************************************************/
  24.  
  25. static int      Drive       =   0,
  26.                 Partition   =   0,
  27.                 fatdirty    =   0;
  28.  
  29. /**********************************************************************
  30.  *  the File Allocation Table storage pointer
  31.  *********************************************************************/
  32.  
  33. static UINT     *fat        =   NULL;
  34.  
  35. /**********************************************************************
  36.  *  the biosdisk() function gives us drive info like this
  37.  *********************************************************************/
  38.  
  39. typedef struct {
  40.     UCHAR   max_secs;
  41.     UCHAR   max_cyls;
  42.     UCHAR   num_drvs;
  43.     UCHAR   max_hds;
  44. } DISK_PARMS;
  45.  
  46. /**********************************************************************
  47.  *  static work areas
  48.  *********************************************************************/
  49.  
  50. static DISK_PARMS       diskparms;
  51. static PART_TBL         part_tbl;
  52. static BOOT_SEC         boot_sector;
  53. static PARTITION        curr_part;
  54. static DISK_INFO        diskinfo;
  55. static DOS_PARTITION    curr_DOS;
  56.  
  57. /**********************************************************************
  58.  *  select disk & partition to use
  59.  *********************************************************************/
  60.  
  61. void
  62. hdSelDiskPart(
  63.     int d,
  64.     int p)
  65. {
  66.     Drive = d;
  67.     Partition = p;
  68. }    
  69.  
  70. /**********************************************************************
  71.  *  internal use:
  72.  *  DOS stores the 2 high order bits of the cylinder number
  73.  *  in the 2 top bits of the sector number. this is inconvenient.
  74.  *********************************************************************/
  75.  
  76. static void
  77. getCylSec(
  78.     UCHAR   cyl,
  79.     UCHAR   sec,
  80.     UINT    *cylw,
  81.     UINT    *secw)
  82. {
  83.     *cylw = cyl | ((sec << 2) & 0x300);
  84.     *secw = sec & 0x3f;
  85. }    
  86.  
  87. /**********************************************************************
  88.  *  if we have a DOS partition, calculate the extra info
  89.  *  using the boot sector and fill in a DOS partition structure
  90.  *********************************************************************/
  91.  
  92. static void
  93. parttoDOS(
  94.     PARTITION       *part,
  95.     BOOT_SEC        *boot,
  96.     DOS_PARTITION   *dos)
  97. {
  98.     dos->part = *part;
  99.     dos->dir0 = boot->num_fats * boot->sec_per_fat + 1;
  100.     dos->dsec = (boot->num_root_ent * 32) / boot->bytes_per_sec;
  101.     dos->dat0 = dos->dir0 + dos->dsec;
  102.     dos->nclu = (boot->num_sec - dos->dat0) / boot->sec_per_clust;
  103. }
  104.         
  105. /**********************************************************************
  106.  *  convert a partition table entry in disk form to a partition
  107.  *  structure that we can use more readily
  108.  *********************************************************************/
  109.  
  110. static void
  111. PEtoPart(
  112.     PART_ENT    *pent,
  113.     PARTITION   *part)
  114. {    
  115.     part->boot = pent->boot;
  116.     part->type = pent->type;
  117.     part->rel_sec = pent->rel_sec;
  118.     part->num_sec = pent->num_sec;
  119.     part->beg.hd = pent->beg.hd;
  120.     part->end.hd = pent->end.hd;
  121.     getCylSec(pent->beg.cyl,pent->beg.sec,
  122.         &part->beg.cyl, &part->beg.sec);                    
  123.     getCylSec(pent->end.cyl,pent->end.sec,
  124.         &part->end.cyl, &part->end.sec);
  125. }
  126.  
  127. /**********************************************************************
  128.  *  get the indicated partition # and set up the static partition
  129.  *  structure; if the # is -1, use the value of Partition
  130.  *********************************************************************/
  131.  
  132. int
  133. hdGetPart(int pn)
  134. {
  135.     int n, p;
  136.  
  137.     if (pn == -1)
  138.         pn = Partition;
  139.     for (p = n = 0; n < 4; n++) {
  140.         UCHAR ptype = part_tbl.part_ents[n].type;
  141.  
  142.         if (ptype == PRI_DOS_12 || ptype == PRI_DOS_16 || ptype == EXT_DOS)
  143.             if (p++ == pn) {
  144.                 PEtoPart(part_tbl.part_ents + n, &curr_part);
  145.                 Partition = p-1;
  146.                 return 0;
  147.             }
  148.     }
  149.     return -1;
  150. }
  151.  
  152. /**********************************************************************
  153.  *  set up the static structure for the primary DOS partition.
  154.  *  this sets the static var Partition to the index in the table.
  155.  *********************************************************************/
  156.  
  157. int
  158. hdGetPriDOS(void)
  159. {
  160.     int n;
  161.      
  162.     for ( n = 0; n < 4; n++) {
  163.         UCHAR ptype = part_tbl.part_ents[n].type;
  164.  
  165.         if (ptype == PRI_DOS_12 || ptype == PRI_DOS_16) {
  166.             PEtoPart(part_tbl.part_ents + n, &curr_part);
  167.             Partition = n;
  168.             return 0;
  169.         }
  170.     }
  171.     return -1;
  172. }
  173.  
  174. /**********************************************************************
  175.  *  set up the static structure for the extended DOS partition.
  176.  *  this sets the static var Partition to the index in the table.
  177.  *********************************************************************/
  178.  
  179. int
  180. hdGetExtDOS(void)
  181. {
  182.     int n;
  183.     
  184.     for ( n = 0; n < 4; n++) {
  185.         if (part_tbl.part_ents[n].type == EXT_DOS) {
  186.             PEtoPart(part_tbl.part_ents + n, &curr_part);
  187.             Partition = n;
  188.             return 0;
  189.         }
  190.     }
  191.     return -1;
  192. }
  193.  
  194. /**********************************************************************
  195.  *  return a pointer to the current partition, copying the 
  196.  *  structure to a user area if pointer is not NULL
  197.  *********************************************************************/
  198.  
  199. PARTITION *
  200. hdCurrPart(PARTITION *p)
  201. {
  202.     if (p) {
  203.         *p = curr_part;
  204.         return p;
  205.     } else
  206.         return &curr_part;
  207. }
  208.  
  209. /**********************************************************************
  210.  *  convert a cluster # for the current partition to an absolute (0 based)
  211.  *  sector # (from the start of the partition) 
  212.  *********************************************************************/
  213.  
  214. UINT
  215. hdClutoSec(UINT clu)
  216. {
  217.     if (clu >= curr_DOS.nclu) 
  218.         return 0;
  219.     return clu * boot_sector.sec_per_clust + curr_DOS.dat0;
  220. }    
  221.     
  222. /**********************************************************************
  223.  *  if the current partition structure is a DOS partiton, fill in
  224.  *  the static DOS partition structure
  225.  *********************************************************************/
  226.  
  227. int
  228. hdGetDOSPart(void)
  229. {
  230.     if (curr_part.type == PRI_DOS_12 || curr_part.type == PRI_DOS_16) {
  231.         parttoDOS(&curr_part, &boot_sector, &curr_DOS);
  232.         return 0;
  233.     } else
  234.         return -1;
  235. }        
  236.  
  237. /**********************************************************************
  238.  *  return a pointer to the current DOS partition, copying the 
  239.  *  structure to a user area if pointer is not NULL
  240.  *********************************************************************/
  241.  
  242. DOS_PARTITION *
  243. hdCurrDOS(DOS_PARTITION *dp)
  244. {
  245.     if (dp) {
  246.         *dp = curr_DOS;
  247.         return dp;
  248.     } else
  249.         return &curr_DOS;
  250. }
  251.         
  252. /**********************************************************************
  253.  *  convert an absolute sector # to cyl, hd, sec form
  254.  *********************************************************************/
  255.  
  256. static void
  257. calcCHS(
  258.     UINT    sector,
  259.     UINT    *cyl,
  260.     UINT    *sec,
  261.     UINT    *head)
  262. {
  263.     UINT            hcnt, 
  264.                     scnt;
  265.         
  266.     ULONG           lsec;
  267.         
  268.     hcnt = diskinfo.hds;
  269.     scnt = diskinfo.sec;
  270.     
  271.     lsec = (ULONG)sector + curr_part.rel_sec;
  272.  
  273.     *cyl = lsec / (hcnt*scnt);
  274.     *head = (lsec / scnt) % hcnt;
  275.     *sec = 1 + (lsec % scnt);
  276. }
  277.  
  278. /**********************************************************************
  279.  *  read/write/verify an absolute sector
  280.  *********************************************************************/
  281.  
  282. int
  283. hdRWVSector(
  284.     UINT    rwv,
  285.     UINT    sector,
  286.     UINT    cnt,
  287.     void    *buffer)
  288. {
  289.     UINT    hd, 
  290.             cyl, 
  291.             sec;
  292.  
  293.     calcCHS(sector, &cyl, &sec, &hd);
  294.  
  295.     return biosdisk(rwv, Drive|0x80, hd, cyl, sec, cnt, buffer) & 0xff;
  296. }
  297.  
  298. /**********************************************************************
  299.  *  fill in static diskinfo structure with BIOS call
  300.  *********************************************************************/
  301.  
  302. int
  303. hdGetDiskInfo(void)
  304. {
  305.     int ret;
  306.         
  307.     ret = biosdisk(8,Drive|0x80,0,0,0,0,&diskparms) & 0xff;
  308.     if (ret == 0) {
  309.         diskinfo.drv = diskparms.num_drvs;
  310.         diskinfo.hds = diskparms.max_hds + 1;
  311.         getCylSec(diskparms.max_cyls, diskparms.max_secs,
  312.           &diskinfo.cyl, &diskinfo.sec);
  313.     }
  314.     return ret;
  315. }
  316.  
  317. /**********************************************************************
  318.  *  return a pointer to the current disk info, copying the 
  319.  *  structure to a user area if pointer is not NULL
  320.  *********************************************************************/
  321.  
  322. DISK_INFO *
  323. hdDiskInfo(DISK_INFO *di)
  324. {
  325.     if (di) {
  326.         *di = diskinfo;
  327.         return di;
  328.     } else
  329.         return &diskinfo;
  330. }  
  331.  
  332. /**********************************************************************
  333.  *  reset disk system with BIOS call
  334.  *********************************************************************/
  335.  
  336. int
  337. hdDiskReset(void)
  338. {
  339.     return biosdisk(0,Drive|0x80,0,0,0,0,NULL) & 0xff;
  340. }
  341.     
  342. /**********************************************************************
  343.  *  read partition table into static work area with BIOS call
  344.  *********************************************************************/
  345.  
  346. int
  347. hdGetPartTbl(void)
  348. {
  349.     return biosdisk(2,Drive|0x80,0,0,1,1,&part_tbl) & 0xff;
  350. }
  351.  
  352. /**********************************************************************
  353.  *  return a pointer to the current partition table, copying the 
  354.  *  structure to a user area if pointer is not NULL
  355.  *********************************************************************/
  356.  
  357. PART_TBL *
  358. hdPartTbl(PART_TBL *pt)
  359. {
  360.     if (pt) {
  361.         *pt = part_tbl;
  362.         return pt;
  363.     } else
  364.         return &part_tbl;
  365. }
  366.  
  367. /**********************************************************************
  368.  *  get boot sector for current partition into static boot sector area
  369.  *********************************************************************/
  370.  
  371. int
  372. hdGetBootSec(void)
  373. {    
  374.     return hdRWSector(SEC_READ,0,1,&boot_sector) & 0xff;
  375. }    
  376.  
  377. /**********************************************************************
  378.  *  get boot sector for current partition:
  379.  *  if extended partition, get boot sector for first DOS partition
  380.  *  in the extended partition
  381.  *  NOTE: this only works one level deep; you CAN'T follow extended
  382.  *  partitions down the disk with this call. it's only good when called
  383.  *  on a partition in the real physical partition table!
  384.  *********************************************************************/
  385.  
  386. int
  387. hdGetXBootSec(void)
  388. {
  389.     int ret;
  390.  
  391.     ret = hdGetBootSec();
  392.     if (ret != 0)
  393.         return ret;
  394.     if (curr_part.type == EXT_DOS) {
  395.         ULONG   rel;
  396.  
  397.         rel = curr_part.rel_sec;
  398.         memcpy(&part_tbl, &boot_sector, 512);
  399.         ret = hdGetPriDOS();
  400.         if (ret != 0)
  401.             return ret;
  402.         curr_part.rel_sec += rel;
  403.         hdGetBootSec();
  404.     }
  405.     hdGetDOSPart();
  406.     return 0;
  407. }
  408.  
  409. /**********************************************************************
  410.  *  return a pointer to the current boot sector, copying the 
  411.  *  structure to a user area if pointer is not NULL
  412.  *********************************************************************/
  413.  
  414. BOOT_SEC *
  415. hdBootSec(BOOT_SEC *bs)
  416. {
  417.     if (bs) {
  418.         *bs = boot_sector;
  419.         return bs;
  420.     } else
  421.         return &boot_sector;
  422. }
  423.  
  424. /**********************************************************************
  425.  *  allocate a static area to hold a copy of the FAT
  426.  *********************************************************************/
  427.  
  428. int
  429. hdAllocFAT(void)
  430. {
  431.     if (fat)
  432.         free(fat);
  433.     fat = calloc(boot_sector.sec_per_fat + 1, boot_sector.bytes_per_sec);
  434.     return -(fat == NULL);
  435. }    
  436.  
  437. /**********************************************************************
  438.  *  free the static FAT storage area
  439.  *********************************************************************/
  440.  
  441. void
  442. hdFreeFAT(void)
  443. {
  444.     if (fat) {
  445.         free(fat);
  446.         fat = NULL;
  447.     }
  448. }        
  449.  
  450. /**********************************************************************
  451.  *  read the FAT for the current parition into the static storage area
  452.  *********************************************************************/
  453.  
  454. int
  455. hdGetFAT(void)
  456. {
  457.     fatdirty = 0;
  458.     return hdRWSector(SEC_READ,1,boot_sector.sec_per_fat,fat);
  459. }
  460.  
  461. /**********************************************************************
  462.  *  write the disk copy or copies of the FAT from the work area
  463.  *********************************************************************/
  464.  
  465. int
  466. hdPutFAT(void)
  467. {
  468.     int ret = 0;
  469.     
  470.     if (fatdirty) {
  471.         int start,
  472.             nfats;
  473.     
  474.         for (start = 1, nfats = 0; nfats < boot_sector.num_fats; nfats++, 
  475.             start += boot_sector.sec_per_fat) {
  476.             int err;
  477.  
  478.             err = hdRWSector(SEC_WRITE,start,boot_sector.sec_per_fat,fat);
  479.             if (err)
  480.                 ret = err;
  481.         }
  482.         fatdirty = 0;
  483.     }
  484.     return ret;
  485. }
  486.  
  487. /**********************************************************************
  488.  *  given a cluster # (0 based) get the FAT entry
  489.  *********************************************************************/
  490.  
  491. UINT
  492. hdGetFATEnt(UINT n)
  493. {
  494.     UINT    fatent;
  495.     
  496.     n += 2;
  497.     
  498.     if (curr_part.type == PRI_DOS_12) {
  499.         UINT    byteoffs;
  500.     
  501.         byteoffs = n * 3;
  502.         byteoffs /= 2;
  503.             
  504.         fatent = *(UINT *)&(((UCHAR *)fat)[byteoffs]);
  505.         if (n & 1)
  506.             fatent >>= 4;
  507.         else
  508.             fatent &= 0xFFF;
  509.         
  510.         if (fatent >= 0xFF7)
  511.             fatent |= 0xF000;
  512.     } else
  513.         fatent = fat[n];
  514.                 
  515.     return fatent;
  516. }
  517.  
  518. /**********************************************************************
  519.  *  given a cluster # (0 based), set the FAT entry
  520.  *********************************************************************/
  521.  
  522. void
  523. hdPutFATEnt(
  524.     UINT    n,
  525.     UINT    v)
  526. {
  527.     n += 2;
  528.     
  529.     if (curr_part.type == PRI_DOS_12) {
  530.         UINT    fatent,
  531.                 byteoffs,
  532.                 mask;
  533.     
  534.         fatdirty = 1;
  535.     
  536.         byteoffs = n * 3;
  537.         byteoffs /= 2;
  538.             
  539.         fatent = *(UINT *)&(((UCHAR *)fat)[byteoffs]);
  540.         v &= 0xFFF;
  541.         if (n & 1) {
  542.             v <<= 4;
  543.             mask = 0x000F;
  544.         } else {
  545.             mask = 0xF000;
  546.         }        
  547.  
  548.         fatent &= mask;
  549.         fatent |= v;
  550.         *(UINT *)&(((UCHAR *)fat)[byteoffs]) = fatent;
  551.     } else
  552.         fat[n] = v;
  553. }
  554.  
  555. /**********************************************************************
  556.  *  given a cluster # (0 based) mark it as bad
  557.  *********************************************************************/
  558.  
  559. void
  560. hdMarkBadClu(UINT n)
  561. {
  562.    hdPutFATEnt(n,CLUST_BAD);
  563. }
  564.  
  565. /**********************************************************************
  566.  *  return the size in bytes of a sector and cluster
  567.  *********************************************************************/
  568.  
  569. void
  570. hdSecCluSize(UINT *sec, UINT *clu)
  571. {
  572.     *clu = boot_sector.sec_per_clust * (*sec = boot_sector.bytes_per_sec);
  573. }
  574.  
  575.  
  576.