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