[comp.os.minix] DOS[READ\WRITE\DIR] on hard disk

Leisner.Henr@xerox.com (marty) (05/20/88)

I'm currently trying to do a rewrite of dos[dir/read/write] to handle hard
disks.

The first thing I did was have the argument specify the block special device
(/dev/fd0 instead of 0).

However, it seems hard disks are a major pain.  In order to compute the fat
size, there is this mega-equation in the DOS tech reference manual, based on
some generic system parameters and the number of sectors in the partition.  So I
need a way to determine sectors/partition.

The algorithm would have to look something like:
	if(floppy disk)
		if(360K floppy)
			do 360k floppy
		if(1.2 meg floppy)
			do 1.2 meg floppy
	else	/* hard disk */
		figure out sectors for this partitions (somehow)
		check first fat entry for hard disk partition ID
		do good stuff
	end

I suppose the  major device numbers could be examined to determine floppy/hard
disks.
But in multiple hard disk systems, how would the boot block be read in?  
Or is there a better way to determine number sectors/drive?  Seek off the end?
Then divide the offset by SECTOR_SIZE?

marty
ARPA:	leisner.henr@xerox.com
GV:  leisner.henr
NS:  martin leisner:henr801c:xerox
UUCP:  nsc!nscimg!amps!marty

rtregn@faui44.informatik.uni-erlangen.de (Robert Regn ) (05/31/88)

I've already tried to modify DOSxxx to handle hard disk's.
It uses the boot sector.  I made a link of /dev/hd<n> to /dev/at2,
so I need not remember which partition is dos.

The program - diff to 1.2 is included - works  (for 12 bit fats) ok as
dosdir and dosread, but as doswrite it destroys my dos partition (e.g.
root dir)!  Make a 100KB backup of the dos partition with dd if you
try doswrite.
I've put debug messages in "disk_io", but the behavior seems ok.
If i use doswrite on a file which contains a copy of the dos partitions
first MB, the program works! (Is the problem caused by the driver ??)

Can somebody send me the "mega-equation"  referenced by Marty ?
Can somebody say what hiddensec means ?

------------------------------ diff to dosread.c 1.2 ---------------
 20a21
 > #define HARDDISK	0xF8
 22,24c23,25
 < #define MAX_CLUSTER_SIZE	1024
 < #define MAX_FAT_SIZE		3584	/* 7 sectoren */
 < #define MAX_ROOT_ENTRIES	224	/* 14 sectoren */
 ---
 > #define MAX_CLUSTER_SIZE	4096
 > #define MAX_FAT_SIZE		6144
 > #define MAX_ROOT_ENTRIES	512
 89c90
 < short total_clusters, cluster_size, fat_size,
 ---
 > unsigned short total_clusters, cluster_size, fat_size,
 114a116,141
 > determine()
 > {
 > 		struct dosboot {
 > 			short   jump;
 > 			char    nop;
 > 			char    name[8];
 > 			char    byteps_1;       /* short wuerde um 1byte hochgeschoben */
 > 			char    byteps_2;
 > 			char    secpclus;
 > 			short   reservsec;
 > 			char    fats;
 > 			char    rooten_1;         /* Alignment    */
 > 			char	rooten_2;
 > 			char	totsec_1;
 > 			char	totsec_2;
 > 			char    media;
 > 			short   secpfat;
 > 			short   secptrack;
 > 			short   heads;
 > 			short   hiddensec;
 > 			/* char    fill[482]; */
 > 		}  boot;
 > 		unsigned int bytepers, dirents, totsec;
 > 		char stderr[100];
 > 			/* read Bios-Parameterblock */
 > 		disk_read(0L, &boot, sizeof boot);
 115a143,190
 > 		bytepers = ((int) boot.byteps_2) <<8 + boot.byteps_1;
 > 		dirents =  ((int) boot.rooten_2) <<8 + boot.rooten_1;
 > 		/*totsec  =  ((int) boot.totsec_2) <<8 + boot.totsec_1;*/
 > 		totsec  = boot.totsec_2 <<8;
 > 		totsec  +=  boot.totsec_1;
 >
 > 		total_clusters = totsec/boot.secpclus;
 > 		cluster_size = bytepers * boot.secpclus;
 > 		fat_size = boot.secpfat * bytepers;
 > 		data_start = bytepers + boot.fats* fat_size + dirents * 32;
 > 		root_entries = dirents;	
 > 		sub_entries = boot.secpclus * bytepers/32;
 >
 > #ifdef debug
 > 		sprintf(stderr, "fatsize: %u totclusters: %u totsec %u ( %x %x)\n",
 > 		fat_size,total_clusters, totsec, boot.totsec_2, boot.totsec_1);
 > 		write(2,stderr, strlen(stderr));
 > 		sprintf(stderr, "dirents %u bytepers %u\n", dirents, bytepers);
 > 		write(2,stderr, strlen(stderr));
 > #endif
 >
 > 		/* safety checking */
 > 		if ( boot.fats != 2 && dos_write)
 > 			{print_string (TRUE, "fats != 2 - Can't handle disk\n");
 > 			 leave (2);
 > 			}
 > 		if ( boot.reservsec != 1)
 > 			{print_string (TRUE, "reserved != 1 - Can't handle disk\n");
 > 			 leave (2);
 > 			}
 > 		if ( total_clusters > 4096)
 > 			{print_string (TRUE, "no 12 Bit fat - Can't handle disk\n");
 > 			 leave (2);
 > 			}
 > 		if (fat_size > MAX_FAT_SIZE)
 > 			{print_string (TRUE, "fatsize to big - Can't handle disk\n");
 > 			 leave (2);
 > 			}
 > 		if (cluster_size > MAX_CLUSTER_SIZE)
 > 			{print_string (TRUE, "clustersize to big - Can't handle disk\n");
 > 			 leave (2);
 > 			}
 > 		if ( boot.media &0xFF != HARDDISK)
 > 			{printf("improper media descriptor: %x\n", boot.media);
 > 			 leave (2);
 > 			}
 > }
 >
 184a260,261
 > 	else if (fat[0] == HARDDISK) 		/*Hard Disk*/
 > 		determine();
 199c276
 < 	if (dos_dir) {
 ---
 > 	if (dos_dir && Lflag) {
 211c288,289
 < 		print(STD_OUT, "Root directory:\n", 0);
 ---
 > 		if (Lflag)
 > 			print(STD_OUT, "Root directory:\n", 0);
 213c291,292
 < 		free_blocks();
 ---
 > 		if (Lflag)
 > 			free_blocks();
 229c308
 < 	if (dos_dir)
 ---
 > 	if (dos_dir && Lflag)
 236c315,316
 < 		free_blocks();
 ---
 > 		if (Lflag)
 > 			free_blocks();

------------------------------ end  diff to dosread.c 1.2 ---------------

					Robert Regn

mmdf@udel.UUCP (06/03/88)

There is a major bug/design flaw in the Minix winchester driver which is a
problem for reading the boot partition.  In kernel/wini/copy_prt, disk
partitions are rounded up to a block boundary and the size is rounded down to a
block boundary.  So if the first sector of a dos partition is odd, you can't
read the boot record.
Strange.....

I'm using the following code now:

#define PART_TABLE	0x1be	/* where partitoin table actually starts */
/* borrowed from block0.h of fdisk */
typedef struct {
	      unsigned char   blk0_boot;      /* boot partition    */
	      unsigned char   blk0_s_h;       /* starting head     */
	      unsigned char   blk0_s_s;       /* starting sector   */
	      unsigned char   blk0_s_c;       /* starting cylinder */
	      unsigned char   blk0_sys;       /* partition type    */
	      unsigned char   blk0_e_h;       /* ending head       */
	      unsigned char   blk0_e_s;       /* ending sector     */
	      unsigned char   blk0_e_c;       /* ending cylinder   */
	      long            blk0_start;     /* starting sector   */
	      long            blk0_size;      /* size in sectors   */
} PARTITION_INFO;

PRIVATE copy_prt(drive)
int drive;
{
	PARTITION_INFO *part_info;
	struct wini *wn;
	int part_num;
	
	for(part_num = 0, wn = &wini[drive + 1], part_info = (PARTITION_INFO *)
&buf[PART_TABLE];
		 part_num < 4; part_num++, wn++, part_info++  ) {
		 wn->wn_low = part_info->blk0_start;
		 wn->wn_size = part_info->blk0_size;
		 if(wn->wn_size % SECTORS_PER_BLOCK) 
		 	/* round down to even number of blocks */
		 	wn->wn_size = (wn->wn_size/SECTORS_PER_BLOCK - 1)*SECTORS_PER_BLOCK;
	}	       
}

Only problem is if you previously built a Minix partition on an odd sector
boundary -- you can't read it anymore.

The mega-equation is taken care of in the boot record -- DOS has an elaborate
equation  to figure out the number of fat sectors when the format is done.


marty
ARPA:	leisner.henr@xerox.com
GV:  leisner.henr
NS:  martin leisner:henr801c:xerox
UUCP:  nsc!nscimg!amps!marty