Category : Utilities for DOS and Windows Machines
Archive   : ZFMAT.ZIP
Filename : ZFMAT.C

 
Output of file : ZFMAT.C contained in archive : ZFMAT.ZIP
/* ----------------------------------------------------------------
Copyright 1988 by Edward V. Dong, All Rights Reserved.

This source code is placed into the public domain. However,
contributions are always welcome. This is a modified form of the
source code used in the author's ZIP program.

Edward V Dong's Floppy Formattor is a Turbo C program to format
floppy diskettes, based on earlier work by Frank Nystrom
(COPYIT.C;CIS 71631,355), Kim Kokkonen (FMAT.PAS; Compuserve
72457,2131), and Peter Norton (BOOT.ASM). This programs formats,
accurately, 360K diskettes in either standard 360K drives or 1.2M
drives.

Essentially, formatting is all performed by the BIOS, through calls
to Turbo C's biosdisk() routine. To format a disk, the tracks are
first formatted, then boot record, two copies of the file allocation
table (FAT), and the root directory are written to the diskette.
This program then verifies each track, again via the BIOS. The
basic formatting and verification routines are derived from
Nystrom's COPYIT.C; the boot record used is a custom one, based on
Norton's BOOT.ASM. The FAT and root directory routines are rehosted
versions based on Kokkonen's FMAT.PAS.

To format 360K diskettes in 1.2 megabyte drives, the DASD must be
set - this is only possible for DOS 3.0 or higher and for AT class
machines. The routines here are based on Kokkonen's Turbo Pascal
work, ported to Turbo C. Through some experimentation and analysis,
the only difference with running on an AT machine is to use a delay
of about 0.3 seconds between biosdisk calls to allow the disk heads
to settle.

Quick disk reformat is here done as a rewrite of the diskette's boot
sector, FAT, and root directory. A "quick" reformat ASSUMES that the
diskette has no bad sectors at all. Depending on configuration,
DOS retains a copy of the old FAT which shows the old free space,
even though the directory has been cleared. This is only true for
AT's and 1.2 meg drives; as a workaround, one track is formatted,
which seem to force AT floppy disk controller to recognize that the
disk has been changed; and therefore DOS will read the diskette to
acquire the new FAT and directory information.

Programming Note: Character bytes are set as unsigned. This was
compiled using the Large Model, but is essentially independent of
C memory model.

Edward V. Dong, 12205 Alexandria Pl, Chino, CA 91710. 18 May 1988
Change History
--------------
08 Jun 88 - Add check for type of drive (360K or 1.2Meg)
04 Jun 88 - set up logical disk sectoring -
01 Jun 88 - fix message on disk space -
18 May 88 - original issue
----------------------------------------------------------------*/

#include
#include
#include
#include
#include
#include
#include /* bioskey() */
#include /* getch() */
#include /* farcoreleft() */

/* defines for readability */

#define YES 1
#define ERR -1
#define NO_ERR 0
#define NO 0
#define VIDEO 16 /* BIOS interrupt number */

/* Disk Constants...*/

#define BYTES_PER_SECTOR 512
#define SECTORS_PER_TRACK 9
#define SD_PER_DSK 2
#define TR_PER_DSK 40

/* biosdisk() BIOS function cmd calls */

#define READ_TRK 2
#define WRITE_TRK 3
#define VERIFY_TRK 4
#define FORMAT_TRK 5

/* When you initialize the disk you need to pass the bios some things.
*/

struct {
struct {
struct {
char cyl,
head,
rec,
num;
} format_record[SECTORS_PER_TRACK];
} side[SD_PER_DSK];
} trk_fmt[TR_PER_DSK];


typedef struct {
struct {
char data[BYTES_PER_SECTOR * SECTORS_PER_TRACK];
}head[ SD_PER_DSK];
}TRACK;

char buffer[BYTES_PER_SECTOR * SECTORS_PER_TRACK];

/* The following is a custom boot record created using Peter Norton's
BOOT.ASM, modified for DSDD 9-sector disks. */

char boot_rec[] = { /* custom boot record */
0xEB,0x2A,0x90,0x20,0x45,0x2E,0x44,0x6F,0x6E,0x67,0x20,0,0x02,0x02,0x01,0,
0x02,0x70,0,0xD0,0x02,0xFD,0x02,0,0x09,0,0x02,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0xB8,0xC0,0x07,0x50,
0x1F,0xBB,0x56,0,0x90,0xB9,0x49,0x01,0x90,0xB4,0x0E,0x8A,0x07,0x1E,0x51,0x53,
0xCD,0x10,0x5B,0x59,0x1F,0x43,0xE2,0xF1,0xB4,0,0xCD,0x16,0xB4,0x0F,0xCD,0x10,
0xB4,0,0xCD,0x10,0xCD,0x19,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x20,0x20,
0x20,0x20,0x20,0x53,0x74,0x61,0x72,0x74,0x20,0x79,0x6F,0x75,0x72,0x20,0x63,0x6F,
0x6D,0x70,0x75,0x74,0x65,0x72,0x20,0x77,0x69,0x74,0x68,0x0D,0x0A,0x20,0x20,0x20,
0x20,0x20,0x61,0x20,0x44,0x4F,0x53,0x20,0x73,0x79,0x73,0x74,0x65,0x6D,0x20,0x64,
0x69,0x73,0x6B,0x65,0x74,0x74,0x65,0x2E,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,0x20,0x20,
0x20,0x20,0x20,0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x0D,0x0A,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x44,0x72,0x61,0x67,0x6F,0x6E,0x57,0x61,0x72,0x65,
0x20,0x53,0x6F,0x66,0x74,0x77,0x61,0x72,0x65,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x56,0x65,0x72,0x73,0x69,0x6F,0x6E,0x20,
0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20,0x0D,0x0A,0x0D,0x0A,0x20,0x20,0x20,0x20,
0x20,0x66,0x72,0x6F,0x6D,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,0x45,0x64,0x77,0x61,
0x72,0x64,0x20,0x56,0x2E,0x20,0x44,0x6F,0x6E,0x67,0x0D,0x0A,0x20,0x20,0x20,0x20,
0x20,0x31,0x32,0x32,0x30,0x35,0x20,0x41,0x6C,0x65,0x78,0x61,0x6E,0x64,0x72,0x69,
0x61,0x20,0x50,0x6C,0x61,0x63,0x65,0x0D,0x0A,0x20,0x20,0x20,0x20,0x20,0x43,0x68,
0x69,0x6E,0x6F,0x2C,0x20,0x43,0x41,0x20,0x39,0x31,0x37,0x31,0x30,0x0D,0x0A,0x0D,
0x0A,0x5A,0x49,0x50,0x3A,0x20,0x54,0x68,0x65,0x20,0x55,0x6C,0x74,0x69,0x6D,0x61,
0x74,0x65,0x20,0x55,0x74,0x69,0x6C,0x69,0x74,0x79,0x0D,0x0A,0x0D,0x0A,0x0D,0x0A,
0x0D,0x0A,0x20,0x20,0x20,0x20,0x49,0x6E,0x73,0x65,0x72,0x74,0x20,0x61,0x20,0x44,
0x4F,0x53,0x20,0x64,0x69,0x73,0x6B,0x65,0x74,0x74,0x65,0x0D,0x0A,0x20,0x20,0x20,
0x20,0x70,0x72,0x65,0x73,0x73,0x20,0x61,0x6E,0x79,0x20,0x6B,0x65,0x79,0x20,0x74,
0x6F,0x20,0x73,0x74,0x61,0x72,0x74,0x20,0x44,0x4F,0x53,0x2E,0x2E,0x2E,0x20,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x55,0xAA
};

/* ----------------------------------------------------------------- */
/* setDASD is used to command a 1.2M drive to format for 360K disks */
/* ----------------------------------------------------------------- */

int setDASD(int drive,char dType) /* set DASD to format 360K floppies */
{
union REGS inregs;
union REGS outregs;
int i;
char drive2;
drive2 = (drive); /* cast operation */
i = 0;
while ((i<3) && (!outregs.x.cflag))
{ inregs.h.ah = 0x17;
inregs.h.al = dType;
inregs.h.dl = drive2;
int86(0x13,&inregs,&outregs);
i++;
}
if (outregs.x.cflag) return(-1);
return(0);
}

/* -----------------------------------------------------------------
The following routine inserts a delay of 0.3 seconds between calls
to biosdisk(), to provide for disk head settling for AT class
machines. Delay is not needed for standard PC's or XT's. A delay
might be needed for Turbo PC/XT's, however.

FLOPPY is the Turbo C "direct BIOS" call, with the embedded delay.
DISKOP calls FLOPPY, but uses DOS logical sector number (0==boot
sector, etc.). This simplifies the programming for writing the
boot sector (0), FAT sectors (1-4), and root directory sectors
(5-12).

DOS logical sector numbers sequences through physical disk sectors
by first using head 0, track 0, then physical sectors 1 through
maximum sectors per track; then head 1, track 0, then sectors again;
then back to head 0, etc.
----------------------------------------------------------------- */

int DISKOP(int cmd,int drive,int sect,int nsects,void *buffer,int sect_per_trk)
{
return(FLOPPY(cmd,drive,(sect/sect_per_trk) % 2,
(sect/sect_per_trk) % sect_per_trk,
(sect % sect_per_trk) + 1,nsects,buffer));
}

int FLOPPY(int cmd,int drive,int head,int track,int sector,int nsects,
void *buffer)
{
int value;
char MachineType;
MachineType = peekb(0xf000,0xfffe);
value = biosdisk(cmd,drive,head,track,sector,nsects,buffer);
if (MachineType == 0x0fc) delay(300);
return(value);
}

/* ---------------------------------------------------------------------
The theory in chk_disk is that the first two sectors aren't formatted,
if the disk is not formatted. Generally, if these sectors aren't
formatted (or readable), the diskette needs formatting anyway.
--------------------------------------------------------------------- */

int chk_dsk(int drive,int *quick) /* check if disk already formatted */
{
*quick = 0;
if( (FLOPPY(READ_TRK, drive, 0, 0, 1, 9, buffer) == 0) &&
(FLOPPY(READ_TRK, drive, 1, 0, 1, 9, buffer) == 0))
{ printf("Disk in %c: already formatted...Reformat? [y/N]",
drive+'A');
if (toupper(getch()) != 'Y')
return(ERR);
printf("\nQuick reformat (IF diskette has NO bad sectors) [y/N]");
if (toupper(getch()) == 'Y')
*quick = 1;
}
return(NO_ERR); /* not formatted */
}

int verify_error(int drive,int sd,int tr,char FAT[])
{
int iptr, cluster, topcluster;
if (FLOPPY(VERIFY_TRK,drive,sd,tr,1,9,buffer))
{ cluster = ((9*(sd+2*tr)) >> 1) - 4;
topcluster = cluster + 5;
while (cluster < topcluster)
{ iptr = (3 * cluster) >> 1;
if ((cluster & 1)==1)
FAT[iptr] |= 0xff70;
else FAT[iptr] |= 0x0ff7;
cluster++;
}
return(ERR);
}
return(NO_ERR);
}

int disk_format(int drive,int verify) /* this does the formatting */
{
register int loop, tr, sd;
int iptr, cluster, topcluster, i, s, tries, success, quick;
char dType, NoOfCyl;
char DirSector[512], FAT[1024];
char MachineType;
union REGS inregs,outregs;
struct SREGS sregs;

/* initialize file allocation table (FAT) */
setmem(FAT,1024,0); /* fill fat with all zeroes */
/* fill in the ID bytes */
FAT[0] = 0xfd; /* 9 sector DSDD drive */
FAT[1] = 0xff; /* boilerplate */
FAT[2] = 0xff;

/* check machine type & DOS version, to handle 1.2meg drives */
MachineType = peekb(0xf000,0xfffe);
printf("\nFormatting Drive %c: \n", drive+'A');
if ((MachineType == 0x0fc) && ((_version & 0x00ff) == 3))
{ /* get drive type */
tries = 0;

/* call BIOS to determine number of cylinders formattable by drive */
inregs.h.ah = 8; /* call needed */
inregs.h.dl = drive;
int86(0x13,&inregs,&outregs); /* call BIOS */
NoOfCyl = outregs.h.ch;

/* if NoOfCyl = 79, then it's a 1.2 meg drive; else if 39, then it's a
360K drive; anything else is not supported! */
if (NoOfCyl == 79) /* 1.2 meg drive */
{ inregs.x.ax = drive;
inregs.h.ah = 0x15;
int86(0x13,&inregs,&outregs); /* invoke BIOS */
dType = outregs.h.ah; /* see if 360k supported */
if ((dType==0) || (dType==3))
{ printf("ERROR: Invalid drive %c (dType=%d)\n",
drive+'A',dType);
if (getch()==0) getch();
return(ERR);
}
if (dType==2)
setDASD(drive,dType); /* set DASD type */
}
else if (NoOfCyl != 39) /* not 1.2M or 360K drive! */
{ printf("Drive Type Not Supported: #%d\n",
NoOfCyl+1);
return(ERR);
}

}

/* see if disk already formatted */
if (chk_dsk(drive,&quick)) return(ERR);

/* use BIOS to format a track & format 40 tracks */
for(tr = 0; tr < TR_PER_DSK; tr++)
for(sd = 0; sd < SD_PER_DSK; sd++)
{ for(s = 0; s < SECTORS_PER_TRACK; s++)
{ trk_fmt[tr].side[sd].format_record[s].cyl = tr;
trk_fmt[tr].side[sd].format_record[s].head = sd;
trk_fmt[tr].side[sd].format_record[s].rec = s +1;
trk_fmt[tr].side[sd].format_record[s].num = 2;
}
success = tries = 0;
while (!success && (tries < 3))
{ if (!FLOPPY(FORMAT_TRK, drive, sd, tr, 1, 9,
&(trk_fmt[tr].side[sd].format_record[0])))
success = 1;
else tries++;
}
if (success)
{ if (quick) goto WriteBOOT;
printf("Head %d, Cyl %d(F)\r",sd,tr);
if (verify)
{ if (verify_error(drive,sd,tr,FAT))
printf("Head %d, Cyl %d(E)\r",sd,tr);
else printf("Head %d, Cyl %d(V)\r",sd,tr);
}
}
else
{ printf("Format Error - aborting...\n");
return(ERR);
}
}

WriteBOOT: /* create boot record on the floppy */
printf("DiskFormat: Writing BOOT record\r");
DISKOP(WRITE_TRK,drive,0,1,boot_rec,9);

/* create 2 copies of file allocation table (FAT) on the floppy */
printf("DiskFormat: Writing FAT blocks\r");
for (i=1; i<3; i++)
if (DISKOP(WRITE_TRK,drive,2*i-1,2,FAT,9))
printf("Error writing FAT #%d\n",i);

/* create root directory on the floppy */
printf("DiskFormat: Writing root directory\r");
setmem(DirSector,512,0xf6); /* fill with format bytes */
for (i=0;i<481;i++) /* mark each directory entry as avail */
if ((i % 32) == 0)

DirSector[i] = 0;
for (i=5; i<12; i++) /* 7 sectors */
DISKOP(WRITE_TRK,drive,i,1,DirSector,9);

/* all done */
return(NO_ERR);
}

void DiskFormat(void)
{
int drive, verify;
drive = 2;
while ((drive!=0)&&(drive!=1))
{ printf("Enter drive to format [A,B]:");
drive = toupper(getch());
if (drive==27) return;
drive -= 'A';
}
printf("\rVerify during formatting? [Y/n]: ");
if (toupper(getch())=='N')
verify = 0;
else verify = 1;
if (disk_format(drive,verify) == 0)
printf("Format [%c] Complete: \n",drive+'A');
}

main(void)
{
DiskFormat();
}


  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : ZFMAT.ZIP
Filename : ZFMAT.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/