home *** CD-ROM | disk | FTP | other *** search
- /* program to manipulate partitions on a fixed disk.
- * Written by Scott E. Garfinkle, July 1986. All rights reserved.
- *
- * This program will examine the partition table of a fixed disk. It will
- * probably only run under a close PC XT or AT compatible running PC-DOS.
- *
- * usage: part [drive_number]
- * where drive_number can be either 1 or 2. Default is 1.
- */
- #include "part.h"
- #include <errno.h>
- #include <ctype.h>
-
- #define ESC 27
-
- extern BOOT *master_boot_rec, /* master boot record of currently selected disk */
- *part_boot_rec[4]; /* boot record of each (active) logical partition */
- extern DISK_TABLE far * fd_tbl;
- extern PARTDATA part_data[4];
- extern byte fixed_disk, /* BIOS "address" of currently selected fixed disk */
- num_disks; /* number of drives attached to controller */
- word sector_size; /* aka bytes per sector */
- word lineno; /* current screen line */
-
- /* 16x16 bit unsigned multiply w/32 bit result */
- extern dword umul1632(word,word);
-
- char *version="Part v2.01 11 Jan 89";
- /* 2.01 -- allowed creating non-DOS partitions without formatting.
- */
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- int i, c;
-
- if(argc > 2 || (argc>1 && argv[1][0] != '0' && argv[1][0] != '1')) {
- fprintf(stderr,"Usage: part [0|1]\n");
- exit(-1);
- /* NOTREACHED */
- }
- fixed_disk = argc==1 ? DISK0 : (argv[1][0] == '0' ? DISK0 : DISK1);
- erase_eos(0);
- scr_pos(22,0);
- printf("Partition table editor, Copyright(C) 1986, 1988 S. E. Garfinkle.");
- scr_pos(23,0);
- printf("All rights reserved.");
- do {
- sector_size = get_scr_val(14,"Enter sector size (256,512,1024,etc.):",512,256,16*1024);
- } while (sector_size != 256 && (sector_size & 0x1ff));
- init(); /* Will exit from init if no disks are attached */
- while(1) {
- scr_pos(3,0);
- erase_eos(0);
- pr_head();
- for(i=0; i<4; i++)
- if(part_data[i].sys_ind)
- pr_part(i+1,master_boot_rec->ptable+i);
- else
- printf("%d Not active\n",i+1);
- lineno = (scr_rpos() >> 8) + 1;
- scr_pos(lineno+1,0);
- puts(" 1. Add Partition");
- puts(" 2. Change Partition");
- puts(" 3. Delete Partition");
- puts(" 4. Change Current Disk Parameters");
- if(num_disks>1) {
- i = '5';
- puts(" 5. Switch Drive");
- }
- else
- i = '4';
- c=(int) get_scr_char(lineno,"Select: 0. Exit ",'0',i);
- lineno += i-'0';
- switch(c) {
- case '.':
- case '0':
- clean_quit();
- /* NOTREACHED */
- case '1':
- add_part();
- break;
- case '2':
- mod_part();
- break;
- case '3':
- del_part();
- break;
- case '4':
- change_parms();
- break;
- case '5':
- do {
- sector_size = get_scr_val(14,"Enter sector size (256,512,1024,etc.):",512,256,16*1024);
- } while (sector_size != 256 && (sector_size & 0x1ff));
- fixed_disk = fixed_disk==DISK0 ? DISK1 : DISK0;
- init();
- break;
- }
- }
- /* NOTREACHED */
- }
-
- void
- add_part()
- {
- int i, j, k, save_line, partno, sysno, fat_size, flag, bootable;
- word start, end, minstart, maxend, temp, fats_in_sector;
- word uns, nsects, nheads, maxcyls, csize;
- PARTITION *part;
- BPB *bptr;
- extern word bcode_len, _shprod;
- extern char boot_code[];
-
- maxcyls = fd_tbl->fd_ncyls-1;
- nsects = fd_tbl->fd_sec_per_track;
- nheads = fd_tbl->fd_heads;
- _shprod = nsects * nheads;
- erase_eos(lineno -= 4);
- printf("Maximum cylinder number is %d.\n",maxcyls);
- save_line = lineno+2;
- do {
- erase_eos(lineno = save_line);
- partno = get_scr_char(lineno++,"Add which partition (0 to exit):",'0','4');
- if(partno <'1') {
- return;
- /* NOTREACHED */
- }
- if(part_data[partno -= '1'].sys_ind) {
- scr_pos(13,0);
- message("Partition already active.");
- continue;
- /* NOTREACHED */
- }
- minstart = 0; /* lowest possible starting cylinder */
- do {
- flag = 0;
- for(i=0; i<4; i++) {
- PARTDATA ptemp;
-
- ptemp = part_data[i];
- if( ptemp.sys_ind &&
- (ptemp.s_cylinder >= minstart && ptemp.s_cylinder-minstart < 3)
- ) {
- minstart = ptemp.e_cylinder + 1;
- flag = 1;
- }
- }
- } while (flag);
- if(minstart > maxcyls) {
- scr_pos(lineno+1,0);
- message("No room for a new partition on disk.");
- return;
- /* NOTREACHED */
- }
- start = get_scr_val(lineno++,"Enter starting cylinder number:",minstart,minstart,maxcyls-2);
- i = (int) (0xffff/_shprod) + start - 1;
- maxend = min(maxcyls,i);
- do {
- flag = 0;
- for(i=0; i<4; i++)
- if(part_data[i].sys_ind && part_data[i].e_cylinder == maxend) {
- maxend = part_data[i].s_cylinder-1;
- flag = 1;
- }
- } while (flag);
- if(maxend <= minstart || maxend == -1) {
- scr_pos(lineno+1,0);
- message("No room for partition at selected start position.");
- flag = 1;
- continue;
- /* NOTREACHED */
- }
- end = get_scr_val(lineno++,"Enter ending cylinder number:",maxend,start+2,maxend);
- #ifdef DEBUG
- printf("secs_per_track %u, nheads %u ", nsects, nheads);
- printf(" start %d, end %d\n",start,end);
- fflush(stdout);(void) getch();
- #endif
- for(i=flag=0; i<4; i++) {
- if(!part_data[i].sys_ind)
- continue;
- j = part_data[i].s_cylinder;
- k = part_data[i].e_cylinder;
- if(start <= k && end >= j) {
- flag = 1; /* blew it on this partition */
- break;
- }
- }
- if(flag) {
- scr_pos(lineno+1,0);
- message("New partition overlaps an old partition");
- }
- } while (flag);
- part = &master_boot_rec->ptable[partno];
- bptr = &part_boot_rec[partno]->bpb;
- scr_pos(lineno+1,0);
- puts(" 1. Additional DOS Volume");
- puts(" 2. DOS");
- puts(" 3. Extended DOS Partition");
- puts(" 4. XENIX");
- puts(" 5. Other");
- sysno = get_scr_char(lineno," 0. Exit ",'0','4');
- lineno += 6;
- switch(sysno) {
- case '0':
- return;
- /* NOTREACHED */
- case '4':
- sysno = XENIX_PART;
- break;
- case '1':
- sysno = EDOS_PART;
- break;
- case '2':
- sysno = DOS_PART;
- break;
- case '3':
- sysno = XDOS_PART;
- break;
- case '5':
- sysno = get_scr_val(lineno++,"Enter system ID byte:",0,0,255);
- break;
- }
- bootable = 0;
- if(sysno != EDOS_PART && sysno != XDOS_PART)
- if(get_scr_char(lineno++,"Make this partition bootable? (1=yes)",'0','1') == '1')
- bootable = 1;
- part_data[partno].s_cylinder = start;
- part_data[partno].e_cylinder = end;
- part_data[partno].sys_ind = part->sys_ind = (byte) sysno;
- if(bootable) {
- part->boot_ind = 0x80;
- for(i=0;i<4;i++)
- if (i==partno)
- continue;
- else
- if(master_boot_rec->ptable[i].boot_ind) {
- master_boot_rec->ptable[i].boot_ind = 0;
- boot_transfer(0,WRITE);
- break;
- }
- }
- else
- part->boot_ind = 0;
- part->s_head = 0;
- part->e_head = nheads-1; /* and end on the last head */
- uns = start ? 1 : 2; /* if first partition, save extra sec for master boot rec */
- part->s_sec_cyl = put_sec_cyl(uns, start); /* sector 1 */
- part->e_sec_cyl = put_sec_cyl(nsects, end);
- #ifdef DEBUG
- printf("\nuns %u, start %d, end %u, nsects %u, s_sec_cyl 0x%x, e_sec_cyl 0x%x\n",
- uns,start,end,nsects,part->s_sec_cyl, part->e_sec_cyl);
- #endif
- part->rel_sect = start ? umul1632(start,_shprod) : 1L;
- bptr->bytes_per_sec = sector_size;
- bptr->res_sectors = 1;
- bptr->nfats = 2;
- bptr->media_des = 0xf8;
- uns = (word) (end-start+1) * _shprod;
- if(!start) /* adjust for master boot rec */
- uns--;
- bptr->nsectors = uns;
- part->num_sects = (dword) uns;
- if(sysno != EDOS_PART) {
- /* that's it. write the boot records and return */
- boot_transfer(0,WRITE);
- boot_transfer(partno+1,WRITE);
- scr_pos(lineno+2,0);
- puts("Partition established. Use appropriate format utility to prep");
- puts("for files.");
- fflush(stdout);
- sleep(5000L);
- return;
- /* NOTREACHED */
- }
- /* make an estimate of parameters to use for number of root entries, fat
- * fat sectors and cluster size to use. We are somewhat somewhat conservative
- * on the # of fat sectors.
- */
- if(uns <= 2400) { /* "uns" is # of sectors in partition */
- i = 2; /* default cluster size */
- bptr->nroot_ents = 0xe0;
- }
- else {
- i = 4;
- bptr->nroot_ents = 0x200;
- }
- csize = get_scr_val(lineno++,"Enter number of sectors per cluster",i,1,16);
- if(get_scr_char(lineno++,"Make paritition with given parameters? (1=yes)",'0','1') == '0') {
- memset(part,'\0',sizeof(PARTITION));
- memset(part_boot_rec[partno],'\0',sizeof(BOOT));
- memset(&part_data[partno],'\0',sizeof(PARTDATA));
- return;
- /* NOTREACHED */
- }
- bptr->secs_per_au = csize;
- uns = (uns+csize-1)/csize; /* now uns is number of clusters */
- /* if DOS v2.x or clusters<4086 (magic #), must use 12 bit FAT entries */
- if(uns < 4086 || _osmajor < 3) {
- fats_in_sector = sector_size*3/4; /* fats_in_sector is # of FAT entries
- * in a fat sector
- */
- fat_size=12;
- }
- else {
- fats_in_sector = sector_size/2;
- fat_size=16;
- }
- /* i = number of sectors in fat */
- i = (uns+fats_in_sector-1)/fats_in_sector;
- /* set temp = secs_in_fat % cluster_size */
- if((temp = i % csize) != 0)
- bptr->secs_in_fat = i + csize-temp;
- else
- bptr->secs_in_fat = i;
- #ifdef DEBUG
- printf("nsects 0x%lxL, relsect 0x%lxL, root ents %d, cluster size %d, secs_in_fat %d\n",
- part->num_sects, part->rel_sect,bptr->nroot_ents,bptr->secs_per_au,bptr->secs_in_fat);
- printf("# of clusters %u, fat size %d, partno %d, sysno %d\n",
- uns, fat_size,partno,sysno);fflush(stdout);
- (void) getch();
- #endif
- puts("\nFormatting partition, standby....");
- i = make_rdir(partno); /* returns number of sectors in root dir */
- if(!i || !make_fat(partno, fat_size, i)) {
- scr_pos(lineno+2,0);
- if(errno == ENOMEM) {
- puts("Not enough memory. If partition is large and cluster size is small,");
- puts("try a larger cluster size.\nAlso try running without print spoolers, etc., in memory.");
- }
- else {
- puts("Error in creating FAT or root directory for partition.");
- puts("Try either relocating partition or changing FAT size");
- }
- fflush(stdout);
- memset(part,'\0',sizeof(PARTITION));
- memset(part_boot_rec[partno],'\0',sizeof(BOOT));
- memset(&part_data[partno],'\0',sizeof(PARTDATA));
- sleep(5000L);
- }
- else {
- /* now tidy up four fields that are not used by DOS, but are at
- * least reported by Norton Utilities, e.g. The definition I
- * use of "hidden sectors" is somewhat arbitrary ("hidden sectors
- * is identically zero), but Microsoft specifically says that this
- * field is not used by DOS. Kinda stupid, no?
- */
- memcpy(part_boot_rec[partno]->oem_name,"SEGpdisk",8); /* that's me! */
- part_boot_rec[partno]->secs_per_track = nsects;
- part_boot_rec[partno]->nheads = nheads;
- part_boot_rec[partno]->nhidden = 0;
- boot_transfer(WRITE,partno+1);
- if(master_boot_rec->signature != 0xaa55) { /* need to init master boot record */
- master_boot_rec->signature = 0xaa55;
- memcpy((char *)master_boot_rec,boot_code,bcode_len);
- }
- boot_transfer(WRITE,0);
- }
- }
-
- void
- del_part()
- {
- int partno;
- PARTITION *part;
-
- erase_eos(11);
- partno = get_scr_char(11,"Delete which partition (0 to exit):",'0','4');
- if(partno <'1') {
- return;
- /* NOTREACHED */
- }
- partno -= '1';
- if(!part_data[partno].sys_ind) {
- scr_pos(13,0);
- message("Partition not active.");
- return;
- /* NOTREACHED */
- }
- else {
- int ans = get_scr_char(14,"Are your REALLY sure?",'N','y');
- if(tolower(ans) != 'y') {
- return;
- /* NOTREACHED */
- }
- }
- part_data[partno].s_cylinder = part_data[partno].e_cylinder = 0;
- part_data[partno].sys_ind = 0;
- part = &master_boot_rec->ptable[partno];
- part->boot_ind = part->sys_ind = part->e_head = part->s_head = 0;
- part->s_sec_cyl = part->e_sec_cyl = 0;
- part->rel_sect = part->num_sects = 0L;
- boot_transfer(WRITE,0);
- }
-
- void
- mod_part()
- {
- int partno, i;
- PARTITION *part;
-
- erase_eos(11);
- partno = get_scr_char(11,"Modify which partition (0 to exit):",'0','4');
- if(partno <'1') {
- return;
- /* NOTREACHED */
- }
- partno -= '1';
- if(!part_data[partno].sys_ind) {
- scr_pos(13,0);
- message("Partition not active.");
- return;
- /* NOTREACHED */
- }
- part = &master_boot_rec->ptable[partno];
- scr_pos(12,0);
- puts(" 0. Exit");
- puts(" 1. Change Boot status");
- if((i = get_scr_char(14," 2. Change OS ID",'0','2')) == '1')
- part->boot_ind = !part->boot_ind ? 0x80 : 0;
- else if(i == '2') {
- int sysno;
-
- scr_pos(17,0);
- puts("System type: 1. Additional DOS Volume");
- puts("System type: 2. DOS");
- puts("System type: 3. Extended DOS Partition");
- puts("System type: 4. XENIX");
- sysno = get_scr_char(21,"System type: 5. Other ",'1','4');
- switch(sysno) {
- case '1':
- sysno = EDOS_PART;
- break;
- case '2':
- sysno = DOS_PART;
- break;
- case '3':
- sysno = XDOS_PART;
- break;
- case '4':
- sysno = XENIX_PART;
- break;
- case '5':
- sysno = get_scr_val(21,"Enter system ID byte:",0,0,255);
- break;
- }
- part->sys_ind = part_data[partno].sys_ind = sysno;
- }
- else
- return;
- boot_transfer(WRITE,0);
- }
-
- #include <bios.h>
-
- void
- change_parms()
- {
- extern byte _numsecs, changed_parms;
- extern word _shprod;
- extern DISK_TABLE far * save_tbl;
- static DISK_TABLE new_table;
- struct diskinfo_t diskinfo;
-
- erase_eos(11);
- if(!changed_parms) {
- changed_parms = fixed_disk;
- save_tbl = fd_tbl;
- new_table = *fd_tbl;
- }
- new_table.fd_ncyls = get_scr_val(11,"Number of cylinders on drive",
- new_table.fd_ncyls, 1, 1024);
- new_table.fd_heads = get_scr_val(12,"Number of heads on drive",
- new_table.fd_heads, 1, 40);
- new_table.fd_sec_per_track = get_scr_val(13,"Number of sectors per track",
- new_table.fd_sec_per_track, 1, 40);
- _numsecs = new_table.fd_sec_per_track;
- _shprod = _numsecs * new_table.fd_heads;
- fd_tbl = (DISK_TABLE far *) &new_table;
- /* we cast the table vector as a pointer to a far interrupt handler
- * function returning void, since that is what _dos_setvect expects.
- */
- _dos_setvect(fixed_disk==DISK1 ? 0x46 : 0x41, (void (interrupt far *)()) fd_tbl);
- diskinfo.drive = fixed_disk;
- _bios_disk(9, &diskinfo); /* reset drive pair characteristics */
- diskinfo.drive = fixed_disk;
- _bios_disk(0, &diskinfo); /* reset drive */
- }
-