home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 May / Chip_2000-05_cd2.bin / dosutils / partprog / pdisk.arc / PART.C < prev    next >
C/C++ Source or Header  |  1989-01-12  |  14KB  |  491 lines

  1. /* program to manipulate partitions on a fixed disk.
  2.  * Written by Scott E. Garfinkle, July 1986.  All rights reserved.
  3.  *
  4.  * This program will examine the partition table of a fixed disk.  It will
  5.  * probably only run under a close PC XT or AT compatible running PC-DOS.
  6.  *
  7.  * usage: part [drive_number]
  8.  *  where drive_number can be either 1 or 2.  Default is 1.
  9. */
  10. #include "part.h"
  11. #include <errno.h>
  12. #include <ctype.h>
  13.  
  14. #define ESC 27
  15.  
  16. extern BOOT *master_boot_rec,    /* master boot record of currently selected disk */
  17.             *part_boot_rec[4];    /* boot record of each (active) logical partition */
  18. extern DISK_TABLE far * fd_tbl;
  19. extern PARTDATA part_data[4];
  20. extern byte fixed_disk,    /* BIOS "address" of currently selected fixed disk */
  21.             num_disks;    /* number of drives attached to controller */
  22. word sector_size;    /* aka bytes per sector */
  23. word lineno;    /* current screen line */
  24.  
  25. /* 16x16 bit unsigned multiply w/32 bit result */
  26. extern dword umul1632(word,word);
  27.  
  28. char *version="Part v2.01 11 Jan 89";
  29. /* 2.01 -- allowed creating non-DOS partitions without formatting.
  30.  */
  31.  
  32. main(argc,argv)
  33. int argc;
  34. char **argv;
  35. {
  36.     int i, c;
  37.  
  38.     if(argc > 2 || (argc>1 && argv[1][0] != '0' && argv[1][0] != '1')) {
  39.         fprintf(stderr,"Usage: part [0|1]\n");
  40.         exit(-1);
  41.         /* NOTREACHED */
  42.     }
  43.     fixed_disk = argc==1 ? DISK0 : (argv[1][0] == '0' ? DISK0 : DISK1);
  44.     erase_eos(0);
  45.     scr_pos(22,0);
  46.     printf("Partition table editor, Copyright(C) 1986, 1988 S. E. Garfinkle.");
  47.     scr_pos(23,0);
  48.     printf("All rights reserved.");
  49.     do {
  50.         sector_size = get_scr_val(14,"Enter sector size (256,512,1024,etc.):",512,256,16*1024);
  51.     } while (sector_size != 256 && (sector_size & 0x1ff));
  52.     init();    /* Will exit from init if no disks are attached */
  53.     while(1) {
  54.         scr_pos(3,0);
  55.         erase_eos(0);
  56.         pr_head();
  57.         for(i=0; i<4; i++)
  58.             if(part_data[i].sys_ind)
  59.                 pr_part(i+1,master_boot_rec->ptable+i);
  60.             else
  61.                 printf("%d  Not active\n",i+1);
  62.         lineno = (scr_rpos() >> 8) + 1;
  63.         scr_pos(lineno+1,0);
  64.         puts("         1. Add Partition");
  65.         puts("         2. Change Partition");
  66.         puts("         3. Delete Partition");
  67.         puts("         4. Change Current Disk Parameters");
  68.         if(num_disks>1) {
  69.             i = '5';
  70.             puts("         5. Switch Drive");
  71.         }
  72.         else
  73.             i = '4';
  74.         c=(int) get_scr_char(lineno,"Select:  0. Exit            ",'0',i);
  75.         lineno += i-'0';
  76.         switch(c) {
  77.         case '.':
  78.         case '0':
  79.             clean_quit();
  80.             /* NOTREACHED */
  81.         case '1':
  82.             add_part();
  83.             break;
  84.         case '2':
  85.             mod_part();
  86.             break;
  87.         case '3':
  88.             del_part();
  89.             break;
  90.         case '4':
  91.             change_parms();
  92.             break;
  93.         case '5':
  94.             do {
  95.                 sector_size = get_scr_val(14,"Enter sector size (256,512,1024,etc.):",512,256,16*1024);
  96.             } while (sector_size != 256 && (sector_size & 0x1ff));
  97.             fixed_disk = fixed_disk==DISK0 ? DISK1 : DISK0;
  98.             init();
  99.             break;
  100.         }
  101.     }
  102.     /* NOTREACHED */
  103. }
  104.  
  105. void
  106. add_part()
  107. {
  108.     int i, j, k, save_line, partno, sysno, fat_size, flag, bootable;
  109.     word start, end, minstart, maxend, temp, fats_in_sector;
  110.     word uns, nsects, nheads, maxcyls, csize;
  111.     PARTITION *part;
  112.     BPB *bptr;
  113.     extern word bcode_len, _shprod;
  114.     extern char boot_code[];
  115.  
  116.     maxcyls = fd_tbl->fd_ncyls-1;
  117.     nsects = fd_tbl->fd_sec_per_track;
  118.     nheads = fd_tbl->fd_heads;
  119.     _shprod = nsects * nheads;
  120.     erase_eos(lineno -= 4);
  121.     printf("Maximum cylinder number is %d.\n",maxcyls);
  122.     save_line = lineno+2;
  123.     do {
  124.         erase_eos(lineno = save_line);
  125.         partno = get_scr_char(lineno++,"Add which partition (0 to exit):",'0','4');
  126.         if(partno <'1') {
  127.             return;
  128.             /* NOTREACHED */
  129.         }
  130.         if(part_data[partno -= '1'].sys_ind) {
  131.             scr_pos(13,0);
  132.             message("Partition already active.");
  133.             continue;
  134.             /* NOTREACHED */
  135.         }
  136.         minstart = 0;        /* lowest possible starting cylinder */
  137.         do {
  138.             flag = 0;
  139.             for(i=0; i<4; i++) {
  140.                 PARTDATA ptemp;
  141.                 
  142.                 ptemp = part_data[i];
  143.                 if(    ptemp.sys_ind &&
  144.                     (ptemp.s_cylinder >= minstart && ptemp.s_cylinder-minstart < 3)
  145.                 ) {
  146.                     minstart = ptemp.e_cylinder + 1;
  147.                     flag = 1;
  148.                 }
  149.             }
  150.         } while (flag);
  151.         if(minstart > maxcyls) {
  152.             scr_pos(lineno+1,0);
  153.             message("No room for a new partition on disk.");
  154.             return;
  155.             /* NOTREACHED */
  156.         }
  157.         start = get_scr_val(lineno++,"Enter starting cylinder number:",minstart,minstart,maxcyls-2);
  158.         i = (int) (0xffff/_shprod) + start - 1;
  159.         maxend = min(maxcyls,i);
  160.         do {
  161.             flag = 0;
  162.             for(i=0; i<4; i++)
  163.                 if(part_data[i].sys_ind && part_data[i].e_cylinder == maxend) {
  164.                     maxend = part_data[i].s_cylinder-1;
  165.                     flag = 1;
  166.                 }
  167.         } while (flag);
  168.         if(maxend <= minstart || maxend == -1) {
  169.             scr_pos(lineno+1,0);
  170.             message("No room for partition at selected start position.");
  171.             flag = 1;
  172.             continue;
  173.             /* NOTREACHED */
  174.         }
  175.         end = get_scr_val(lineno++,"Enter ending cylinder number:",maxend,start+2,maxend);
  176. #ifdef DEBUG
  177.     printf("secs_per_track %u, nheads %u ", nsects, nheads);
  178.     printf(" start %d, end %d\n",start,end);
  179.     fflush(stdout);(void) getch();
  180. #endif
  181.         for(i=flag=0; i<4; i++) {
  182.             if(!part_data[i].sys_ind)
  183.                 continue;
  184.             j = part_data[i].s_cylinder;
  185.             k = part_data[i].e_cylinder;
  186.             if(start <= k && end >= j) {
  187.                 flag = 1;    /* blew it on this partition */
  188.                 break;
  189.             }
  190.         }
  191.         if(flag) {
  192.             scr_pos(lineno+1,0);
  193.             message("New partition overlaps an old partition");
  194.         }
  195.     } while (flag);
  196.     part = &master_boot_rec->ptable[partno];
  197.     bptr = &part_boot_rec[partno]->bpb;
  198.     scr_pos(lineno+1,0);
  199.     puts("              1.  Additional DOS Volume");
  200.     puts("              2.  DOS");
  201.     puts("              3.  Extended DOS Partition");
  202.     puts("              4.  XENIX");
  203.     puts("              5.  Other");
  204.     sysno = get_scr_char(lineno,"              0.  Exit                 ",'0','4');
  205.     lineno += 6;
  206.     switch(sysno) {
  207.     case '0':
  208.         return;
  209.         /* NOTREACHED */
  210.     case '4':
  211.         sysno = XENIX_PART;
  212.         break;
  213.     case '1':
  214.         sysno = EDOS_PART;
  215.         break;
  216.     case '2':
  217.         sysno = DOS_PART;
  218.         break;
  219.     case '3':
  220.         sysno = XDOS_PART;
  221.         break;
  222.     case '5':
  223.         sysno = get_scr_val(lineno++,"Enter system ID byte:",0,0,255);
  224.         break;
  225.     }
  226.     bootable = 0;
  227.     if(sysno != EDOS_PART && sysno != XDOS_PART)
  228.         if(get_scr_char(lineno++,"Make this partition bootable? (1=yes)",'0','1') == '1')
  229.             bootable = 1;
  230.     part_data[partno].s_cylinder = start;
  231.     part_data[partno].e_cylinder = end;
  232.     part_data[partno].sys_ind = part->sys_ind = (byte) sysno;
  233.     if(bootable) {
  234.         part->boot_ind = 0x80;
  235.         for(i=0;i<4;i++)
  236.             if (i==partno)
  237.                 continue;
  238.             else
  239.                 if(master_boot_rec->ptable[i].boot_ind) {
  240.                     master_boot_rec->ptable[i].boot_ind = 0;
  241.                     boot_transfer(0,WRITE);
  242.                     break;
  243.                 }
  244.     }
  245.     else
  246.         part->boot_ind = 0;
  247.     part->s_head = 0;
  248.     part->e_head = nheads-1;         /* and end on the last head */
  249.     uns = start ? 1 : 2;    /* if first partition, save extra sec for master boot rec */
  250.     part->s_sec_cyl = put_sec_cyl(uns, start); /* sector 1 */
  251.     part->e_sec_cyl = put_sec_cyl(nsects, end);
  252. #ifdef DEBUG
  253.     printf("\nuns %u, start %d, end %u, nsects %u, s_sec_cyl 0x%x, e_sec_cyl 0x%x\n",
  254.             uns,start,end,nsects,part->s_sec_cyl, part->e_sec_cyl);
  255. #endif
  256.     part->rel_sect = start ? umul1632(start,_shprod) : 1L;
  257.     bptr->bytes_per_sec = sector_size;
  258.     bptr->res_sectors = 1;
  259.     bptr->nfats = 2;
  260.     bptr->media_des = 0xf8;
  261.     uns = (word) (end-start+1) * _shprod; 
  262.     if(!start)    /* adjust for master boot rec */
  263.         uns--;
  264.     bptr->nsectors = uns;
  265.     part->num_sects = (dword) uns;
  266.     if(sysno != EDOS_PART) {
  267.         /* that's it.  write the boot records and return */
  268.         boot_transfer(0,WRITE);
  269.         boot_transfer(partno+1,WRITE);
  270.         scr_pos(lineno+2,0);
  271.         puts("Partition established.  Use appropriate format utility to prep");
  272.         puts("for files.");
  273.         fflush(stdout);
  274.         sleep(5000L);
  275.         return;
  276.         /* NOTREACHED */
  277.     }
  278.     /* make an estimate of parameters to use for number of root entries, fat
  279.      * fat sectors and cluster size to use.  We are somewhat somewhat conservative
  280.      * on the # of fat sectors.
  281.      */
  282.     if(uns <= 2400) {    /* "uns" is # of sectors in partition */
  283.         i = 2;    /* default cluster size */
  284.         bptr->nroot_ents = 0xe0;
  285.     }
  286.     else {
  287.         i = 4;
  288.         bptr->nroot_ents = 0x200;
  289.     }
  290.     csize = get_scr_val(lineno++,"Enter number of sectors per cluster",i,1,16);
  291.     if(get_scr_char(lineno++,"Make paritition with given parameters? (1=yes)",'0','1') == '0') {
  292.         memset(part,'\0',sizeof(PARTITION));
  293.         memset(part_boot_rec[partno],'\0',sizeof(BOOT));
  294.         memset(&part_data[partno],'\0',sizeof(PARTDATA));
  295.         return;
  296.         /* NOTREACHED */
  297.     }
  298.     bptr->secs_per_au = csize;
  299.     uns = (uns+csize-1)/csize;    /* now uns is number of clusters */
  300.     /* if DOS v2.x or clusters<4086 (magic #), must use 12 bit FAT entries */
  301.     if(uns < 4086 || _osmajor < 3) {
  302.         fats_in_sector = sector_size*3/4; /* fats_in_sector is # of FAT entries
  303.                                            * in a fat sector
  304.                                            */
  305.         fat_size=12;
  306.     }
  307.     else {
  308.         fats_in_sector = sector_size/2;
  309.         fat_size=16;
  310.     }
  311.     /* i = number of sectors in fat */
  312.     i = (uns+fats_in_sector-1)/fats_in_sector;
  313.     /* set temp = secs_in_fat % cluster_size */
  314.     if((temp = i % csize) != 0)
  315.         bptr->secs_in_fat = i + csize-temp;
  316.     else
  317.         bptr->secs_in_fat = i;
  318. #ifdef DEBUG
  319.     printf("nsects 0x%lxL, relsect 0x%lxL, root ents %d, cluster size %d, secs_in_fat %d\n",
  320.            part->num_sects, part->rel_sect,bptr->nroot_ents,bptr->secs_per_au,bptr->secs_in_fat);
  321.     printf("# of clusters %u, fat size %d, partno %d, sysno %d\n",
  322.         uns, fat_size,partno,sysno);fflush(stdout);
  323.     (void) getch();
  324. #endif
  325.     puts("\nFormatting partition, standby....");
  326.     i = make_rdir(partno);        /* returns number of sectors in root dir */
  327.     if(!i || !make_fat(partno, fat_size, i)) {
  328.         scr_pos(lineno+2,0);
  329.         if(errno == ENOMEM) {
  330.             puts("Not enough memory.  If partition is large and cluster size is small,");
  331.             puts("try a larger cluster size.\nAlso try running without print spoolers, etc., in memory.");
  332.         }
  333.         else {
  334.             puts("Error in creating FAT or root directory for partition.");
  335.             puts("Try either relocating partition or changing FAT size");
  336.         }
  337.         fflush(stdout);
  338.         memset(part,'\0',sizeof(PARTITION));
  339.         memset(part_boot_rec[partno],'\0',sizeof(BOOT));
  340.         memset(&part_data[partno],'\0',sizeof(PARTDATA));
  341.         sleep(5000L);
  342.     }
  343.     else {
  344.         /* now tidy up four fields that are not used by DOS, but are at
  345.          * least reported by Norton Utilities, e.g.  The definition I
  346.          * use of "hidden sectors" is somewhat arbitrary ("hidden sectors
  347.          * is identically zero), but Microsoft specifically says that this
  348.          * field is not used by DOS.  Kinda stupid, no?
  349.          */
  350.         memcpy(part_boot_rec[partno]->oem_name,"SEGpdisk",8);  /* that's me! */
  351.         part_boot_rec[partno]->secs_per_track = nsects;
  352.         part_boot_rec[partno]->nheads = nheads;
  353.         part_boot_rec[partno]->nhidden = 0;
  354.         boot_transfer(WRITE,partno+1);
  355.         if(master_boot_rec->signature != 0xaa55) { /* need to init master boot record */
  356.             master_boot_rec->signature = 0xaa55;
  357.             memcpy((char *)master_boot_rec,boot_code,bcode_len);
  358.         }
  359.         boot_transfer(WRITE,0);
  360.     }
  361. }
  362.  
  363. void
  364. del_part()
  365. {
  366.     int partno;
  367.     PARTITION *part;
  368.  
  369.     erase_eos(11);
  370.     partno = get_scr_char(11,"Delete which partition (0 to exit):",'0','4');
  371.     if(partno <'1') {
  372.         return;
  373.         /* NOTREACHED */
  374.     }
  375.     partno -= '1';
  376.     if(!part_data[partno].sys_ind) {
  377.         scr_pos(13,0);
  378.         message("Partition not active.");
  379.         return;
  380.         /* NOTREACHED */
  381.     }
  382.     else {
  383.         int ans = get_scr_char(14,"Are your REALLY sure?",'N','y');
  384.         if(tolower(ans) != 'y') {
  385.             return;
  386.             /* NOTREACHED */
  387.         }
  388.     }
  389.     part_data[partno].s_cylinder = part_data[partno].e_cylinder = 0;
  390.     part_data[partno].sys_ind = 0;
  391.     part = &master_boot_rec->ptable[partno];
  392.     part->boot_ind = part->sys_ind = part->e_head = part->s_head = 0;
  393.     part->s_sec_cyl = part->e_sec_cyl = 0;
  394.     part->rel_sect = part->num_sects = 0L;
  395.     boot_transfer(WRITE,0);
  396. }
  397.  
  398. void
  399. mod_part()
  400. {
  401.     int partno, i;
  402.     PARTITION *part;
  403.  
  404.     erase_eos(11);
  405.     partno = get_scr_char(11,"Modify which partition (0 to exit):",'0','4');
  406.     if(partno <'1') {
  407.         return;
  408.         /* NOTREACHED */
  409.     }
  410.     partno -= '1';
  411.     if(!part_data[partno].sys_ind) {
  412.         scr_pos(13,0);
  413.         message("Partition not active.");
  414.         return;
  415.         /* NOTREACHED */
  416.     }
  417.     part = &master_boot_rec->ptable[partno];
  418.     scr_pos(12,0);
  419.     puts("         0. Exit");
  420.     puts("         1. Change Boot status");
  421.     if((i = get_scr_char(14,"         2. Change OS ID",'0','2')) == '1')
  422.         part->boot_ind = !part->boot_ind ? 0x80 : 0;
  423.     else if(i == '2') {
  424.         int sysno;
  425.  
  426.         scr_pos(17,0);
  427.         puts("System type:  1.  Additional DOS Volume");
  428.         puts("System type:  2.  DOS");
  429.         puts("System type:  3.  Extended DOS Partition");
  430.         puts("System type:  4.  XENIX");
  431.         sysno = get_scr_char(21,"System type:  5.  Other            ",'1','4');
  432.         switch(sysno) {
  433.         case '1':
  434.             sysno = EDOS_PART;
  435.             break;
  436.         case '2':
  437.             sysno = DOS_PART;
  438.             break;
  439.         case '3':
  440.             sysno = XDOS_PART;
  441.             break;
  442.         case '4':
  443.             sysno = XENIX_PART;
  444.             break;
  445.         case '5':
  446.             sysno = get_scr_val(21,"Enter system ID byte:",0,0,255);
  447.             break;
  448.         }
  449.         part->sys_ind = part_data[partno].sys_ind = sysno;
  450.     }
  451.     else
  452.         return;
  453.     boot_transfer(WRITE,0);
  454. }
  455.  
  456. #include <bios.h>
  457.  
  458. void
  459. change_parms()
  460. {
  461.     extern byte _numsecs, changed_parms;
  462.     extern word _shprod;
  463.     extern DISK_TABLE far * save_tbl;
  464.     static DISK_TABLE new_table;
  465.     struct diskinfo_t diskinfo;
  466.  
  467.     erase_eos(11);
  468.     if(!changed_parms) {
  469.         changed_parms = fixed_disk;
  470.         save_tbl = fd_tbl;
  471.         new_table = *fd_tbl;
  472.     }
  473.     new_table.fd_ncyls = get_scr_val(11,"Number of cylinders on drive",
  474.                         new_table.fd_ncyls, 1, 1024);
  475.     new_table.fd_heads = get_scr_val(12,"Number of heads on drive",
  476.                         new_table.fd_heads, 1, 40);
  477.     new_table.fd_sec_per_track = get_scr_val(13,"Number of sectors per track",
  478.                         new_table.fd_sec_per_track, 1, 40);
  479.     _numsecs = new_table.fd_sec_per_track;
  480.     _shprod = _numsecs * new_table.fd_heads;
  481.     fd_tbl = (DISK_TABLE far *) &new_table;
  482.     /* we cast the table vector as a pointer to a far interrupt handler
  483.      * function returning void, since that is what _dos_setvect expects.
  484.      */
  485.     _dos_setvect(fixed_disk==DISK1 ? 0x46 : 0x41, (void (interrupt far *)()) fd_tbl);
  486.     diskinfo.drive = fixed_disk;
  487.     _bios_disk(9, &diskinfo);    /* reset drive pair characteristics */
  488.     diskinfo.drive = fixed_disk;
  489.     _bios_disk(0, &diskinfo);    /* reset drive */
  490. }
  491.