home *** CD-ROM | disk | FTP | other *** search
/ Borland Programmer's Resource / Borland_Programmers_Resource_CD_1995.iso / code / bcpp / file7 / cformat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-19  |  16.0 KB  |  677 lines

  1. /*
  2.    Program to format a floppy disk
  3.  
  4.    Tested with BC++ 3.1 (compilable as C or as C++)
  5.  
  6.    Compile: bcc -ms cformat.c
  7. */
  8.  
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <conio.h>
  12. #include <bios.h>
  13. #include <dos.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include <io.h>
  17. #include <fcntl.h>
  18. #include <ctype.h>
  19. #include <dir.h>
  20.  
  21. #include "cformat.h"
  22.  
  23. Byte far* far* disk_ptr = (Byte far* far*) MK_FP(0, 0x1e * 4);
  24. Byte far* old_value     = 0;
  25.  
  26. const int retries = 3;
  27. int   verify_flag = 0;  /* change to non-zero if you want to verify tracks */
  28. int   system_flag = 1;  /* change to zero if you don't want to write system files */
  29.  
  30. int main(void)
  31. {
  32.    int drive_type = -1;
  33.    int media_type = -1;
  34.  
  35.    int function_17_code;
  36.  
  37.    int drive;
  38.    int ntracks, nsects;
  39.    int track, head;
  40.    int status;
  41.  
  42.    /* floppy-specific data */
  43.    static struct disk_info info[] = {
  44.       { 512, 2, 1, 2, 112,  720, 0xfd, 2,  9, 2 },    /*  360K floppy */
  45.       { 512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2 },    /*  1.2M floppy */
  46.       { 512, 2, 1, 2, 112, 1440, 0xf9, 3,  9, 2 },    /*  720K floppy */
  47.       { 512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2 }     /* 1.44M floppy */
  48.    };
  49.  
  50.    /* rows: drive type  cols: media type */
  51.    static struct validity valid[4][4] = {
  52.       { {1, 1}, {0, 0}, {0, 0}, {0, 0} },
  53.       { {1, 2}, {1, 3}, {0, 0}, {0, 0} },
  54.       { {0, 0}, {0, 0}, {1, 4}, {0, 0} },
  55.       { {0, 0}, {0, 0}, {1, 4}, {1, 4} }
  56.    };
  57.  
  58.    static char* smedia[] = { "360K", "1.2M", "720K", "1.44M" };
  59.  
  60.    /* save original value of pointer to disk parameter table */
  61.    old_value     = *disk_ptr;
  62.  
  63.    atexit(cleanup);        /* insure restoration of pointer, cursor */
  64.    ctrlbrk(breakhandler);
  65.  
  66. #ifdef __cplusplus
  67.    harderr( (int (*)(int,int,int,int))errhandler );
  68. #else
  69.    harderr( errhandler );
  70. #endif
  71.  
  72.    /* get drive (A or B floppy) */
  73.    do
  74.       {
  75.       cprintf("Enter drive [A or B]: ");
  76.       drive = toupper(getche()) - 'A';
  77.       putch('\r');
  78.       putch('\n');
  79.       }
  80.    while(drive < 0  ||  drive > 1);
  81.  
  82.    /* get media type */
  83.    do
  84.       {
  85.       putch('\r');
  86.       putch('\n');
  87.  
  88.       cputs("Select media type:\r\n");
  89.       cputs(" 1)  360K floppy\r\n");
  90.       cputs(" 2)  1.2M floppy\r\n");
  91.       cputs(" 3)  720K floppy\r\n");
  92.       cputs(" 4) 1.44M floppy\r\n");
  93.       cputs(" 5) Exit program\r\n");
  94.       cputs("Select [1-5]: ");
  95.  
  96.       media_type = getche() - '1';
  97.  
  98.       putch('\r');
  99.       putch('\n');
  100.       }
  101.    while(media_type < 0  ||  media_type > 4);
  102.  
  103.    if(media_type == 4)
  104.       return 0;
  105.  
  106.    putch('\r');
  107.    putch('\n');
  108.  
  109.    /* reset the disk controller */
  110.    if( reset(drive) )
  111.       {
  112.       fputs("Unable to reset floppy controller\n", STDERR);
  113.       return 1;
  114.       }
  115.  
  116.    /* this may fail if not an AT-compatible machine */
  117.    drive_type = getdrivetype(drive);
  118.    if(drive_type < 0  ||  drive_type > 3)
  119.       {
  120.       fputs("No floppy drive or unable to determine drive type\n", STDERR);
  121.       return 1;
  122.       }
  123.  
  124.    if( !valid[drive_type][media_type].OK )
  125.       {
  126.       fputs("Unable to format floppy in specified drive\n", STDERR);
  127.       return 1;
  128.       }
  129.  
  130.    function_17_code = valid[drive_type][media_type].disk_type_code;
  131.  
  132.    /* this may fail if not an AT-compatible machine */
  133.    if( setdisktype(drive, function_17_code) )
  134.       {
  135.       fputs("Unable to set disk type\n", STDERR);
  136.       return 1;
  137.       }
  138.  
  139.    ntracks = info[media_type].total_sectors     /
  140.              info[media_type].sectors_per_track /
  141.              info[media_type].heads;
  142.    nsects  = info[media_type].sectors_per_track;
  143.  
  144.    /* this may fail if not an AT-compatible machine */
  145.    if( setmediatype(drive, ntracks, nsects) )
  146.       {
  147.       fputs("Unable to set media type\n", STDERR);
  148.       return 1;
  149.       }
  150.  
  151.    _setcursortype(_NOCURSOR);    /* turn off the cursor */
  152.  
  153.    cprintf("Formatting %s floppy in drive %c:\r\n", smedia[media_type], drive+'A');
  154.  
  155.    /* format the floppy tracks */
  156.    for(track=0; track<ntracks; track++)
  157.       {
  158.       for(head=0; head<2; head++)
  159.          {
  160.          cprintf("Track %2d   Head %2d\r", track, head);
  161.  
  162.          if( (status = format(drive, head, track, nsects, &info[media_type])) != 0 )
  163.             {
  164.             fprintf(STDERR, "Unable to format track %d.  Status: %d\n",
  165.                     track, status);
  166.             return 1;
  167.             }
  168.  
  169.          /* verify each track as it is formatted if verify_flag != 0 */
  170.          if(verify_flag)
  171.             if( (status = verify(drive, head, track, nsects)) != 0 )
  172.                {
  173.                fprintf(STDERR, "Unable to verify track %d.  Status: %d\n",
  174.                     track, status);
  175.                return 1;
  176.                }           
  177.          }
  178.       }
  179.  
  180.    putch('\r');
  181.    clreol();
  182.    gotoxy(1, wherey()-1);
  183.    clreol();
  184.  
  185.    /* write the boot sector to the floppy */
  186.    cputs("Writing boot sector.\r");
  187.    status = write_boot(drive, &info[media_type]);
  188.    if(status)
  189.       {
  190.       fprintf(STDERR, "Error writing boot sector: %d\n", status);
  191.       return 1;
  192.       }
  193.  
  194.    putch('\r');
  195.    clreol();
  196.  
  197.    /* clear out the FAT tables on the floppy */
  198.    cputs("Writing FAT tables.\r");
  199.    status = write_FATs(drive, &info[media_type]);
  200.    if(status)
  201.       {
  202.       fprintf(STDERR, "Error writing FAT tables: %d\n", status);
  203.       return 1;
  204.       }
  205.  
  206.    putch('\r');
  207.    clreol();
  208.  
  209.    /* clear out the directory entries on the floppy */
  210.    cputs("Writing root directory entries.\r");
  211.    status = write_root(drive, &info[media_type]);
  212.    if(status)
  213.       {
  214.       fprintf(STDERR, "Error writing root directory: %d\n", status);
  215.       return 1;
  216.       }
  217.  
  218.    putch('\r');
  219.    clreol();
  220.  
  221.    /* write the system files (MS-DOS): io.sys, msdos.sys, command.com */
  222.    if( system_flag )
  223.       {
  224.       cputs("Writing system files.\r");
  225.       status = write_system(drive);
  226.       if(status)
  227.          {
  228.          fputs("Error writing system files\n", STDERR);
  229.          return 1;
  230.          }
  231.       putch('\r');
  232.       clreol();
  233.       }
  234.  
  235.    return 0;
  236. }
  237.  
  238. int reset(int drive)
  239. {
  240.    int status;
  241.    int retry;
  242.  
  243.    for(retry=0; retry<retries; retry++)
  244.       {
  245.       if( (status = biosdisk(0, drive, 0, 0, 0, 0, 0)) == 0 )
  246.          break;
  247.       }
  248.  
  249.    if(retry == retries)
  250.       return status;
  251.  
  252.    return 0;
  253. }
  254.  
  255. int setdisktype(int drive, int type)
  256. {
  257.    union  REGS regs;
  258.    int    retry;
  259.  
  260.    for(retry=0; retry<retries; retry++)
  261.       {
  262.       regs.h.ah = 0x17;
  263.       regs.h.al = type;
  264.       regs.h.dl = drive;
  265.       int86(0x13, ®s, ®s);
  266.       if(!regs.x.cflag)
  267.          break;
  268.       biosdisk(0, drive, 0, 0, 0, 0, 0);
  269.       }
  270.  
  271.    if(retry == retries)
  272.       return regs.h.ah;
  273.  
  274.    return 0;
  275. }
  276.  
  277. int setmediatype(int drive, int ntracks, int nsects)
  278. {
  279.    union  REGS regs;
  280.    struct SREGS sregs;
  281.    int    retry;
  282.  
  283.    segread(&sregs);
  284.  
  285.    for(retry=0; retry<retries; retry++)
  286.       {
  287.       regs.h.ah = 0x18;
  288.       regs.h.ch = ntracks - 1;
  289.       regs.h.cl = nsects;
  290.       regs.h.dl = drive;
  291.       int86x(0x13, ®s, ®s, &sregs);
  292.       if(!regs.x.cflag)
  293.          break;
  294.       biosdisk(0, drive, 0, 0, 0, 0, 0);
  295.       }
  296.  
  297.    if(retry == retries)
  298.       return regs.h.ah;
  299.  
  300.    /* set pointer to disk para,meter table for this kind of floppy */
  301.    *disk_ptr = (Byte far *) MK_FP(sregs.es, regs.x.di);
  302.  
  303.    return 0;
  304. }
  305.  
  306. int format(int drive, int head, int track, int nsects, struct disk_info* info)
  307. {
  308.    int sects;
  309.    int status;
  310.    int retry;
  311.  
  312.    int sector_size_type = 0;
  313.    int bytes_per_sector = 128;
  314.  
  315.    Byte* tdata = (Byte*) malloc( nsects*4*sizeof(Byte) );
  316.    if(!tdata)
  317.       return -1;
  318.  
  319.    /* compute sector size type for BIOS table */
  320.    while(bytes_per_sector != info->bytes_per_sector  &&  sector_size_type < 4)
  321.       {
  322.       ++sector_size_type;
  323.       bytes_per_sector *= 2;
  324.       }
  325.  
  326.    for(sects=0; sects<nsects; sects++)
  327.       {
  328.       tdata[sects*4 + 0] = track;
  329.       tdata[sects*4 + 1] = head;
  330.       tdata[sects*4 + 2] = sects + 1;
  331.       tdata[sects*4 + 3] = sector_size_type;
  332.       }
  333.  
  334.    for(retry=0; retry<retries; retry++)
  335.       {
  336.       status = biosdisk(5, drive, head, track, 1, nsects, tdata);
  337.       if(!status)
  338.          break;
  339.       biosdisk(0, drive, 0, 0, 0, 0, 0);
  340.       }
  341.  
  342.    free(tdata);
  343.  
  344.    if(retry == retries)
  345.       return status;
  346.  
  347.    return 0;
  348. }
  349.  
  350. int write_hts(int drive, int head, int track, int sect, int nsects, Byte* buf)
  351. {
  352.    int status;
  353.    int retry;
  354.  
  355.    for(retry=0; retry<retries; retry++)
  356.       {
  357.       status = biosdisk(3, drive, head, track, sect, nsects, buf);
  358.       if(!status)
  359.          break;
  360.       biosdisk(0, drive, 0, 0, 0, 0, 0);
  361.       }
  362.  
  363.    if(retry == retries)
  364.       return status;
  365.  
  366.    return 0;
  367. }
  368.  
  369. int verify(int drive, int head, int track, int nsects)
  370. {
  371.    int status;
  372.    int retry;
  373.  
  374.    for(retry=0; retry<retries; retry++)
  375.       {
  376.       status = biosdisk(4, drive, head, track, 1, nsects, 0);
  377.       if(!status)
  378.          break;
  379.       biosdisk(0, drive, 0, 0, 0, 0, 0);
  380.       }
  381.  
  382.    if(retry == retries)
  383.       return status;
  384.  
  385.    return 0;
  386. }
  387.  
  388. int write_boot(int drive, struct disk_info* info)
  389. {
  390.    size_t result;
  391.  
  392.    /* memory is allocated for a full sector, */
  393.    /* not just sizeof(struct boot_sector)    */
  394.    struct boot_sector* buf = (struct boot_sector*)
  395.                                  malloc( info->bytes_per_sector );
  396.  
  397.    FILE* boot = fopen("boot.bin", "rb");
  398.  
  399.    if(!boot)
  400.       {
  401.       fputs("Unable to open file containing boot sector image\n", STDERR);
  402.       return -1;
  403.       }
  404.  
  405.    if(!buf)
  406.       {
  407.       fputs("Unable to allocate memory\n", STDERR);
  408.       return -2;
  409.       }
  410.  
  411.    /* read the boot sector image */
  412.    result = fread(buf, info->bytes_per_sector, 1, boot);
  413.    if( result != 1 )
  414.       {
  415.       fputs("Unable to read file containing boot sector image\n", STDERR);
  416.       free(buf);
  417.       return -3;
  418.       }
  419.  
  420.    /* copy the floppy-specific parameters to boot sector image */
  421.    memcpy((Byte*)buf + offsetof(struct boot_sector, parms),
  422.            info, sizeof(struct disk_info));
  423.  
  424.    /* compute a serial number */
  425.    buf->serial_number = serial_number();
  426.  
  427.    /* write data out to the floppy */
  428.    result = write_hts(drive, 0, 0, 1, 1, (Byte*)buf);
  429.  
  430.    free(buf);
  431.    return result;
  432. }
  433.  
  434. long serial_number()
  435. {
  436.    struct date d;
  437.    struct time t;
  438.  
  439.    union { long value;  size_t w[2]; } result;
  440.  
  441.    getdate(&d);
  442.    gettime(&t);
  443.  
  444.    result.w[0] = *(size_t*)&d.da_day  + *(size_t*)&t.ti_hund;
  445.    result.w[1] = *(size_t*)&d.da_year + *(size_t*)&t.ti_min;
  446.  
  447.    return result.value;
  448. }
  449.  
  450. int write_sector(int drive, int sector, Byte* buf, struct disk_info* info)
  451. {
  452.    /* translate logical sector to head, track, sector */
  453.    int head  = (sector / info->sectors_per_track) % info->heads;
  454.    int track = (sector / info->sectors_per_track) / info->heads;
  455.    sector    = (sector % info->sectors_per_track) + 1;
  456.  
  457.    return write_hts(drive, head, track, sector, 1, buf);
  458. }
  459.  
  460. int write_FATs(int drive, struct disk_info* info)
  461. {
  462.    int i, j;
  463.  
  464.    int sector;
  465.    int status;
  466.  
  467.    Byte* buf = (Byte*) malloc( info->bytes_per_sector );
  468.    if( !buf )
  469.       {
  470.       fputs("Unable to allocate memory\n", STDERR);
  471.       return -1;
  472.       }
  473.  
  474.    for(i=0; i<info->FATs; i++)                     /* for each FAT */
  475.       {
  476.       for(j=0; j<info->sectors_per_FAT; j++)       /* for each sector of FAT */
  477.          {
  478.          memset(buf, 0, info->bytes_per_sector);   /* clear it to 0 */
  479.          if(j == 0)                                /* first sector gets some data */
  480.             {
  481.             buf[0] = info->media_descriptor;
  482.             buf[1] = 0xff;
  483.             buf[2] = 0xff;
  484.             }
  485.          sector = info->reserved_sectors + i*info->sectors_per_FAT + j;
  486.          status = write_sector(drive, sector, buf, info);
  487.          if(status)
  488.             {
  489.             free(buf);
  490.             return status;
  491.             }
  492.          }
  493.       }
  494.  
  495.    free(buf);
  496.    return 0;
  497. }
  498.  
  499. int write_root(int drive, struct disk_info* info)
  500. {
  501.    int sector, status;
  502.  
  503.    /* root directory starts after the FATs */
  504.    int start_sector = info->FATs * info->sectors_per_FAT +
  505.                       info->reserved_sectors;
  506.  
  507.    /* number of sectors required by root directory entries */
  508.    int nsects = (info->root_directories * 32) / info->bytes_per_sector;
  509.  
  510.    Byte* buf = (Byte*) malloc( info->bytes_per_sector );
  511.    if( !buf )
  512.       {
  513.       fputs("Unable to allocate memory\n", STDERR);
  514.       return -1;
  515.       }
  516.  
  517.    /* clear 'em to 0 */
  518.    memset(buf, 0, info->bytes_per_sector);
  519.  
  520.    /* write 'em out */
  521.    for(sector=start_sector; sector<nsects+start_sector; sector++)
  522.       {
  523.       status = write_sector(drive, sector, buf, info);
  524.       if(status)
  525.          {
  526.          free(buf);
  527.          return status;
  528.          }
  529.       }
  530.  
  531.    free(buf);
  532.    return 0;
  533. }
  534.  
  535. int write_system(int drive)
  536. {
  537.    char* ifile1 = "\\io.sys";    /* these file names are MS-DOS specific */
  538.    char* ifile2 = "\\msdos.sys"; /*  and the files should be present in  */
  539.    char  ifile3[MAXPATH];        /*  the root directory (except for command.com) */
  540.  
  541.    char ofile1[13];
  542.    char ofile2[13];
  543.    char ofile3[] = "X:\\COMMAND.COM";
  544.  
  545.    /* make file name for io.sys on floppy */
  546.    ofile1[0] = drive + 'A';
  547.    ofile1[1] = ':';
  548.    ofile1[2] = '\0';
  549.    strcat(ofile1, ifile1);
  550.  
  551.    /* copy file to floppy */
  552.    if(copy_file(ofile1, ifile1))
  553.       return -1;
  554.  
  555.    /* make file name for msdos.sys on floppy */
  556.    ofile2[0] = drive + 'A';
  557.    ofile2[1] = ':';
  558.    ofile2[2] = '\0';
  559.    strcat(ofile2, ifile2);
  560.  
  561.    /* copy file to floppy */
  562.    if(copy_file(ofile2, ifile2))
  563.       return -1;
  564.  
  565.    /* get file name for current command processor */
  566.    strcpy( ifile3, getenv("COMSPEC") );
  567.  
  568.    /* only copy it to the floppy if it is MS-DOS's command.com */
  569.    if( strstr( strupr(ifile3), "COMMAND.COM") )
  570.       {
  571.       ofile3[0] = drive + 'A';         /* fill in drive letter */
  572.  
  573.       if(copy_file(ofile3, ifile3))    /* copy the file */
  574.          return -1;
  575.       }
  576.  
  577.    return 0;
  578. }
  579.  
  580. int copy_file(char* dest, char* src)
  581. {
  582.    int ihandle, ohandle;
  583.    int ibytes,  obytes;
  584.    int attrib;
  585.  
  586.    struct ftime t;
  587.  
  588.    const int bufsz = 50*1024;
  589.  
  590.    char* buf = (char*) malloc( bufsz );
  591.    if(!buf)
  592.       {
  593.       fputs("Unable to allocate memory\n", STDERR);
  594.       return -1;
  595.       }
  596.  
  597.    ihandle = _open(src, O_RDONLY);
  598.    if(ihandle < 0)
  599.       {
  600.       fprintf(STDERR, "Unable to open %s\n", src);
  601.       free(buf);
  602.       return -1;
  603.       }
  604.  
  605.    /* get attributes of source file */
  606.    attrib = _chmod(src, 0);
  607.  
  608.    /* creates new file with specified attributes */
  609.    ohandle = _creat(dest, attrib);
  610.    if(ohandle < 0)
  611.       {
  612.       fprintf(STDERR, "Unable to open %s\n", dest);
  613.       free(buf);
  614.       return -1;
  615.       }
  616.  
  617.    /* do the actual file copy */
  618.    while( (ibytes = _read(ihandle, buf, bufsz)) != 0 )
  619.       {
  620.       obytes = _write(ohandle, buf, ibytes);
  621.       if(obytes != ibytes)
  622.          {
  623.          fputs("Error copying file\n", STDERR);
  624.          free(buf);
  625.          return -1;
  626.          }
  627.       }
  628.  
  629.    /* it is assumed that the rest of this won't generate errors      */
  630.    /*  if something goes wrong -> if it does, the errors are ignored */
  631.  
  632.    getftime(ihandle, &t);     /* get original file time/date */
  633.    setftime(ohandle, &t);     /* set file time/date of file  */
  634.  
  635.    _close(ihandle);
  636.    _close(ohandle);
  637.  
  638.    free(buf);
  639.    return 0;
  640. }
  641.  
  642. void cleanup(void)
  643. {
  644.    *disk_ptr = old_value;           /* restore pointer to disk parameter table */
  645.    _setcursortype(_NORMALCURSOR);   /* restore cursor to normal */
  646. }
  647.  
  648. int breakhandler(void)
  649. {
  650.    cleanup();        /* do a little bit of clean up */
  651.    return 0;
  652. }
  653.  
  654. int errhandler(void)
  655. {
  656.    cleanup();        /* do a little bit of clean up */
  657.    hardresume(2);    /* abort */
  658.    return 0;         /* should never get here */
  659. }
  660.  
  661. int getdrivetype(int drive)
  662. {
  663.    union  REGS regs;
  664.    struct SREGS sregs;
  665.  
  666.    segread(&sregs);
  667.  
  668.    regs.h.ah = 8;
  669.    regs.h.dl = drive;
  670.    int86x(0x13, ®s, ®s, &sregs);
  671.  
  672.    if(regs.x.cflag)
  673.       return -1;
  674.    else
  675.       return regs.h.bl - 1;
  676. }
  677.