938 lines
22 KiB
C
938 lines
22 KiB
C
static char sccsid[] = "@(#)69 1.6 src/bos/usr/bin/dosformat/dosformat.c, cmdpcdos, bos411, 9428A410j 7/7/94 13:56:00";
|
|
/*
|
|
* COMPONENT_NAME: CMDDOS routines to read dos floppies
|
|
*
|
|
* FUNCTIONS: dosformat
|
|
*
|
|
* ORIGINS: 10,27
|
|
*
|
|
* IBM CONFIDENTIAL -- (IBM Confidential Restricted when
|
|
* combined with the aggregated modules for this product)
|
|
* SOURCE MATERIALS
|
|
* (C) COPYRIGHT International Business Machines Corp. 1985, 1994
|
|
* All Rights Reserved
|
|
*
|
|
* US Government Users Restricted Rights - Use, duplication or
|
|
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <dos.h>
|
|
#include <fcntl.h>
|
|
#include <sys/devinfo.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/fd.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <locale.h>
|
|
|
|
/****************************************************
|
|
GENERAL PURPOSE DEFS
|
|
****************************************************/
|
|
|
|
/*
|
|
|
|
/* Disk parameters
|
|
*/
|
|
struct dkparm {
|
|
int devtype; /* drive type (hard disk or floppy) */
|
|
int bytpsec; /* bytes per sector */
|
|
int secptrk; /* sectors per track */
|
|
int trkpcyl; /* tracks per cylinder */
|
|
int secpclu; /* sectors per cluster */
|
|
int numcyls; /* total number of cylinders */
|
|
int fattype; /* FAT type: 12 or 16 bit */
|
|
int fatcode; /* device code in FAT table */
|
|
int secpfat; /* number of sectors in FAT table */
|
|
int rootsiz; /* number of sectors in root directory */
|
|
int bootoff; /* sector offset to boot sector */
|
|
char *bootsec; /* contents of boot sector */
|
|
int numsecs; /* total number of sectors */
|
|
int badclus; /* number of bad clusters */
|
|
int fat1off; /* sector offset to first FAT */
|
|
int fat2off; /* sector offset to second FAT */
|
|
int rootoff; /* sector offset to root directory */
|
|
int dataoff; /* sector offset to data area */
|
|
};
|
|
#define BOOT_SEC_SIZE 32
|
|
|
|
char boot80[BOOT_SEC_SIZE]={ /* boot sector for 5 1/4 1.2 meg disk */
|
|
0353, 0052, 0220, 0111, 0102, 0115, 0040, 0101,
|
|
0111, 0130, 0063, 0000, 0002, 0001, 0001, 0000,
|
|
0002, 0340, 0000, 0140, 0011, 0371, 0007, 0000,
|
|
0017, 0000, 0002, 0000, 0000, 0000, 0000, 0000
|
|
};
|
|
|
|
|
|
char boot40_9_2[BOOT_SEC_SIZE]={ /* boot sector for 5 1/4 360k disk */
|
|
0xEB,0x2A,0x90,0x49,0x42,0x4D,0x20,0x41,
|
|
0x49,0x58,0x33,0x00,0x02,0x02,0x01,0x00,
|
|
0x02,0x70,0x00,0xD0,0x02,0xFD,0x02,0x00,
|
|
0x09,0x00,0x02,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
|
|
char boot80_3_3[BOOT_SEC_SIZE]={ /* boot sector for 3 1/2 2.88 meg disk */
|
|
0xEB,0x3C,0x90,0x49,0x42,0x4D,0x20,0x41,
|
|
0x49,0x58,0x33,0x00,0x02,0x02,0x01,0x00,
|
|
0x02,0xF0,0x00,0x80,0x16,0xF0,0x09,0x00,
|
|
0x24,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
|
|
};
|
|
|
|
char boot80_3_2[BOOT_SEC_SIZE]={ /* boot sector for 3 1/2 1.44 meg disk */
|
|
0xEB,0x34,0x90,0x49,0x42,0x4D,0x20,0x41,
|
|
0x49,0x58,0x33,0x00,0x02,0x01,0x01,0x00,
|
|
0x02,0xE0,0x00,0x40,0x0B,0xF0,0x09,0x00,
|
|
0x12,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
|
|
};
|
|
|
|
char boot80_3_1[BOOT_SEC_SIZE]={ /* boot sector for 3 1/2 720k disk */
|
|
0xEB,0x3C,0x90,0x49,0x42,0x4D,0x20,0x41,
|
|
0x49,0x58,0x33,0x00,0x02,0x02,0x01,0x00,
|
|
0x02,0x70,0x00,0xA0,0x05,0xF9,0x03,0x00,
|
|
0x09,0x00,0x02,0x00,0x00,0x00,0x00,0x00,
|
|
};
|
|
|
|
/* Device types
|
|
*/
|
|
#define FLOPPY80 1 /* floppy, 5 1/4 hi-density */
|
|
#define FLOPPY40_9_2 2 /* floppy, 5 1/4 lo-density */
|
|
#define FLOPPY80_3_3 3 /* floppy, 3 1/2 extended-density 2.88M */
|
|
#define FLOPPY80_3_2 4 /* floppy, 3 1/2 hi-density */
|
|
#define FLOPPY80_3_1 5 /* floppy, 3 1/2 low-denisty */
|
|
|
|
/*
|
|
* FAT info
|
|
*/
|
|
#define FAT12 1 /* FAT has 12 bit entries */
|
|
#define FAT16 4 /* FAT has 16 bit entries */
|
|
#define FAT12SIZE 1.5 /* size of 12-bit FAT entry (in bytes) */
|
|
#define FAT16SIZE 2 /* size of 16-bit FAT entry (in bytes) */
|
|
#define BAD_CLUSTER 0xfff7 /* FAT code for bad cluster */
|
|
#define MAX_FATSIZE 64 /* max # sectors in a FAT */
|
|
|
|
#define DOS_DIRSIZ 32 /* # bytes in DOS directory entry */
|
|
|
|
/*
|
|
* Error codes
|
|
*/
|
|
#define ERR_BAD_TRACK0 (-1) /* unable to read/write track 0 */
|
|
#define ERR_DRIVE_BUSY (-2) /* non-sharable device already in use */
|
|
#define ERR_DRIVE_INVAL (-3) /* drive specification invalid */
|
|
#define ERR_GENERIC (-4) /* generic error */
|
|
/*#define ERR_INCOMPAT (-5) /* cmd line arg not applicable to hard disk */
|
|
#define ERR_INVAL_PARM (-6) /* unknown command line arg */
|
|
#define ERR_NOMEM (-7) /* 'malloc' failed */
|
|
#define ERR_NOSUPPORT (-8) /* command line option not supported */
|
|
#define ERR_NOT_READY (-9) /* no diskette in device; door not closed */
|
|
#define ERR_WRPROTECT (-10) /* write-protected diskette */
|
|
|
|
|
|
/*
|
|
* Miscellaneous
|
|
*/
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
#define EVEN(x) ((x) % 2 == 0)
|
|
char *sect_alloc(), _doscdisk();
|
|
|
|
/****************************************************
|
|
FLOPPY - SPECIFIC DEFS
|
|
****************************************************/
|
|
|
|
#define FDFILLER 0xF6 /* filler byte output by format operation */
|
|
#define FD_SECTSIZE 2 /* FDIOCFORMAT code for sector size *
|
|
|
|
/*
|
|
* Debugging defs
|
|
*/
|
|
#ifdef DEBUG
|
|
#undef TRACE
|
|
int dostrace;
|
|
#define TRACE(expr) if (dostrace) expr
|
|
#else
|
|
#define TRACE(expr) if (0) expr
|
|
#endif DEBUG
|
|
|
|
/****************************************************
|
|
GLOBALS
|
|
****************************************************/
|
|
|
|
|
|
|
|
char *sectbuf, *fatbuf;
|
|
char *label;
|
|
char vollabel, lowdensity;
|
|
struct dkparm *dkp;
|
|
char *devname;
|
|
int devfd;
|
|
|
|
/****************************************************
|
|
FLOPPY & HARD DISK PARAMETER TABLE
|
|
(from DOS technical reference manual)
|
|
****************************************************/
|
|
struct dkparm dktbl[] =
|
|
{
|
|
{ 0 , -1, -1,-1,-1, -1, -1, 0xF8, -1, -1, -1, 0, },
|
|
/* 5.25 inch 1.2meg floppy */
|
|
{ FLOPPY80, 512, 15, 2, 1, 80, FAT12, 0xF9, 7, 14, 0, boot80},
|
|
/* 5.25 inch 360k floppy */
|
|
{ FLOPPY40_9_2, 512, 9, 2, 2, 40, FAT12, 0xFD, 2, 7, 0, boot40_9_2},
|
|
/* 3.5 inch 2.88meg floppy */
|
|
{ FLOPPY80_3_3, 512, 36, 2, 2, 80, FAT12, 0xF0, 9, 15, 0, boot80_3_3,},
|
|
/* 3.5 inch 1.44meg floppy */
|
|
{ FLOPPY80_3_2, 512, 18, 2, 1, 80, FAT12, 0xF0, 9, 14, 0, boot80_3_2,},
|
|
/* 3.5 inch 720k floppy */
|
|
{ FLOPPY80_3_1, 512, 9, 2, 2, 80, FAT12, 0xF9, 3, 7, 0, boot80_3_1,}
|
|
};
|
|
|
|
/****************************************************
|
|
MAIN
|
|
****************************************************/
|
|
|
|
main(argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
|
|
|
|
int another = TRUE;
|
|
|
|
setlocale( LC_ALL, "");
|
|
|
|
if (get_args(argc, argv) != 0)
|
|
exit(1);
|
|
|
|
while (another == TRUE)
|
|
{
|
|
|
|
if ( open_drive() == 0)
|
|
exit(1);
|
|
|
|
if (get_drive_parms() != 0)
|
|
exit(1);
|
|
|
|
sectbuf = sect_alloc(1); /* allocate a sector */
|
|
|
|
printf("Insert new diskette for %s\n", devname);
|
|
printf("and strike ENTER when ready");
|
|
fflush(stdout);
|
|
while (getchar() != '\n')
|
|
;
|
|
printf("\nFormatting...");
|
|
fflush(stdout);
|
|
|
|
if (FDreset() == 0 )
|
|
{
|
|
if ( format() == 0)
|
|
{
|
|
printf("Format complete\n");
|
|
disk_space();
|
|
if (get_response("Format another (Y/N)?") == 'Y')
|
|
{
|
|
printf("\n");
|
|
close(devfd);
|
|
}
|
|
else
|
|
another = FALSE;
|
|
}
|
|
}
|
|
else
|
|
printf("Format failure\n\n");
|
|
}
|
|
|
|
exit(0);
|
|
}
|
|
|
|
/****************************************************
|
|
DEVICE-INDEPENDENT ROUTINES
|
|
****************************************************/
|
|
|
|
/* Format disk.
|
|
*/
|
|
format()
|
|
{
|
|
TRACE(printf("format\n"));
|
|
|
|
if (FDsoft_sector() != 0)
|
|
return(-1);
|
|
|
|
if (setup_FAT() != 0)
|
|
return(-1);
|
|
|
|
if (FDverify() != 0)
|
|
return(-1);
|
|
|
|
if (write_boot_sector() != 0)
|
|
return(-1);
|
|
|
|
if (write_root_dir() != 0)
|
|
return(-1);
|
|
|
|
if (write_FATs() != 0)
|
|
return(-1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Process command line arguments.
|
|
*/
|
|
get_args(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
int opt;
|
|
int gotdrive = FALSE;
|
|
extern char *optarg; /* option's argument */
|
|
|
|
vollabel = lowdensity = FALSE;
|
|
devname = "/dev/fd0";
|
|
|
|
while ((opt = getopt(argc, argv, "18V:4D:$")) != EOF)
|
|
{
|
|
switch (opt)
|
|
{
|
|
case 'V': /* give disk a volume label */
|
|
vollabel = TRUE;
|
|
label = optarg;
|
|
break;
|
|
case '4': /* 360K diskette in hi density drive */
|
|
lowdensity = TRUE;
|
|
break;
|
|
case 'D': /* which unix device to format */
|
|
if ( optarg[0] != '/') {
|
|
usage();
|
|
return( errmsg( ERR_DRIVE_INVAL));
|
|
}
|
|
devname = optarg;
|
|
break;
|
|
case '$': /* turn off trace feature */
|
|
#ifdef DEBUG
|
|
dostrace = TRUE;
|
|
#endif DEBUG
|
|
break;
|
|
|
|
case '?':
|
|
default:
|
|
usage();
|
|
return(errmsg(ERR_INVAL_PARM));
|
|
}
|
|
}
|
|
if (optind != argc) {
|
|
usage();
|
|
return(-1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
usage()
|
|
{
|
|
fprintf( stderr, "dosformat [-V label] [-D /dev/<floppy device>] [-4]\n");
|
|
fprintf( stderr, " -V label, label not to exceed 11 characters\n");
|
|
fprintf( stderr, " -D /dev/<fd> specify which floppy drive to format\n");
|
|
fprintf( stderr, " -4 format to the low density for this type of drive\n");
|
|
}
|
|
|
|
open_drive()
|
|
{
|
|
struct devinfo info;
|
|
|
|
TRACE(printf("open_drive\n"));
|
|
|
|
/* Try to open raw device first.
|
|
* Floppy I/O is lots faster on the raw device
|
|
* (and hard disk I/O is fast either way).
|
|
* 020 indicates synchronous I/O. (FSYNC)
|
|
* O_NDELAY tells the floppy driver NOT (O_NONBLOCK)
|
|
* to try to determine floppy's format.
|
|
*/
|
|
if ((devfd = open(devname, O_RDWR | O_NDELAY | 020)) < 0) {
|
|
perror( "dosformat");
|
|
return( 0);
|
|
}
|
|
if (ioctl(devfd, IOCINFO, (char*)&info) < 0)
|
|
{
|
|
TRACE(perror("get_drive_info (IOCINFO)"));
|
|
errmsg(ERR_DRIVE_INVAL);
|
|
return( 0);
|
|
}
|
|
return( devfd);
|
|
|
|
}
|
|
|
|
|
|
/* Determine drive parameters.
|
|
*/
|
|
get_drive_parms()
|
|
{
|
|
struct devinfo info;
|
|
|
|
if (ioctl(devfd, IOCINFO, (char*)&info) < 0)
|
|
{
|
|
TRACE(perror("get_drive_info (IOCINFO)"));
|
|
return(errmsg(ERR_DRIVE_INVAL));
|
|
}
|
|
|
|
else if (info.devtype != DD_DISK)
|
|
{
|
|
TRACE(printf("bad devtype: %c\n", info.devtype));
|
|
return(errmsg(ERR_DRIVE_INVAL));
|
|
}
|
|
else
|
|
{
|
|
if (FDparms(info) != 0)
|
|
return(-1);
|
|
}
|
|
|
|
dkp->fat1off = dkp->bootoff + 1;
|
|
dkp->fat2off = dkp->fat1off + dkp->secpfat;
|
|
dkp->rootoff = dkp->fat2off + dkp->secpfat;
|
|
dkp->dataoff = dkp->rootoff + dkp->rootsiz;
|
|
dkp->numsecs = dkp->numcyls * dkp->trkpcyl * dkp->secptrk;
|
|
|
|
TRACE(printf("*** devtype=%5d; bytpsec=%5d; secptrk=%5d; trkpcyl=%5d\n",
|
|
dkp->devtype,dkp->bytpsec,dkp->secptrk,dkp->trkpcyl));
|
|
TRACE(printf("*** secpclu=%5d; numcyls=%5d; numsecs=%5d; fattype=%5d\n",
|
|
dkp->secpclu,dkp->numcyls,dkp->numsecs,dkp->fattype));
|
|
TRACE(printf("*** fatcode=%5X; secpfat=%5d; rootsiz=%5d; bootoff=%5d\n",
|
|
dkp->fatcode,dkp->secpfat,dkp->rootsiz,dkp->bootoff));
|
|
TRACE(printf("*** fat1off=%5d; fat2off=%5d; rootoff=%5d; dataoff=%5d\n",
|
|
dkp->fat1off,dkp->fat2off,dkp->rootoff,dkp->dataoff));
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Write out boot sector.
|
|
*/
|
|
|
|
#define PT_SIGa 0x55 /* magic number at end of table (lo byte) */
|
|
#define PT_SIGb 0xAA /* magic number at end of table (hi byte) */
|
|
|
|
write_boot_sector()
|
|
{
|
|
char boot_sec[512];
|
|
int i;
|
|
|
|
TRACE(printf("*** writing out boot sector (sect #%d)\n", dkp->bootoff));
|
|
|
|
for ( i = 0; i < 512; i++) boot_sec[i] = 0;
|
|
memcpy( boot_sec, dkp->bootsec, BOOT_SEC_SIZE);
|
|
boot_sec[510] = PT_SIGa;
|
|
boot_sec[511] = PT_SIGb;
|
|
return( write_sector(dkp->bootoff, boot_sec) );
|
|
}
|
|
|
|
/*
|
|
* Set up in-core FAT table.
|
|
*/
|
|
|
|
setup_FAT()
|
|
{
|
|
TRACE(printf("*** setting up in-core FAT (size=%d)\n", dkp->secpfat));
|
|
|
|
if (fatbuf == NULL)
|
|
fatbuf = sect_alloc(dkp->secpfat);
|
|
|
|
sect_zero(fatbuf, 0x0, dkp->secpfat);
|
|
|
|
fatbuf[0] = dkp->fatcode;
|
|
fatbuf[1] = 0xFF;
|
|
fatbuf[2] = 0xFF;
|
|
if (dkp->fattype == FAT16)
|
|
fatbuf[3] = 0xFF;
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Write both FATs to disk.
|
|
*/
|
|
write_FATs()
|
|
{
|
|
int sect;
|
|
char *fatp;
|
|
|
|
|
|
/* Write out first FAT.
|
|
*/
|
|
fatp = fatbuf;
|
|
TRACE(printf("*** writing out first FAT (sect #%d)\n", dkp->fat1off));
|
|
for (sect=0; sect<dkp->secpfat; sect++)
|
|
{
|
|
if (write_sector(sect + dkp->fat1off, fatp) != 0)
|
|
return(-1);
|
|
fatp += dkp->bytpsec;
|
|
}
|
|
|
|
/* Write out second FAT.
|
|
*/
|
|
fatp = fatbuf;
|
|
TRACE(printf("*** writing out second FAT (sect #%d)\n", dkp->fat2off));
|
|
for (sect=0; sect<dkp->secpfat; sect++)
|
|
{
|
|
if (write_sector(sect + dkp->fat2off, fatp) != 0)
|
|
return(-1);
|
|
fatp += dkp->bytpsec;
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* Set up root directory.
|
|
*/
|
|
#define MAX_LABEL_LEN 11
|
|
#define OFFSET_TO_ATTRIBUTE_BYTE 11
|
|
#define VOL_ATTRIBUTE 0x08
|
|
#define DATE_TIME_INDEX 22
|
|
|
|
write_root_dir()
|
|
{
|
|
register int i;
|
|
|
|
|
|
TRACE(printf("*** writing out root dir (%d sects, sect #%d)\n",
|
|
dkp->rootsiz, dkp->rootoff));
|
|
|
|
sect_zero(sectbuf, FDFILLER, 1);
|
|
|
|
for (i=0; i<dkp->bytpsec; i+=DOS_DIRSIZ)
|
|
sectbuf[i] = 0;
|
|
|
|
if (vollabel) {
|
|
struct tm *tm;
|
|
long clock;
|
|
register int timefield,
|
|
datefield;
|
|
register uchar *stamp;
|
|
|
|
strncpy( sectbuf, label, MAX_LABEL_LEN);
|
|
sectbuf[ OFFSET_TO_ATTRIBUTE_BYTE] = VOL_ATTRIBUTE;
|
|
clock = time(0);
|
|
tm = localtime( &clock);
|
|
timefield = (((tm->tm_hour << 11) & 0xf800)
|
|
| ((tm->tm_min << 5) & 0x07e0)
|
|
| ((tm->tm_sec >> 1) & 0x001f));
|
|
|
|
datefield = ((((tm->tm_year - 80) << 9) & 0xfe00)
|
|
| (((tm->tm_mon + 1) << 5) & 0x01e0)
|
|
| (tm->tm_mday & 0x001f));
|
|
|
|
stamp =(uchar *)§buf[ DATE_TIME_INDEX];
|
|
|
|
*stamp++ = timefield & 0xff;
|
|
*stamp++ = (timefield >> 8) & 0xff;
|
|
*stamp++ = datefield & 0xff;
|
|
*stamp = (datefield >> 8) & 0xff;
|
|
}
|
|
|
|
for (i=0; i<dkp->rootsiz; i++)
|
|
if (write_sector(dkp->rootoff + i, sectbuf) != 0)
|
|
return(-1);
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Check floppy for bad sectors.
|
|
* (We're assuming hard disk already has
|
|
* its bad sectors mapped out).
|
|
*/
|
|
FDverify()
|
|
{
|
|
int sect, trk; /* sector, track counters */
|
|
int ntrks; /* number of tracks on diskette */
|
|
int badtrk; /* TRUE if entire track is bad */
|
|
int trksize; /* # bytes in a track */
|
|
int thiscluster, lastcluster = -1; /* which cluster a sector belongs to */
|
|
static char *trkbuf=NULL; /* for reading in track */
|
|
register char *s;
|
|
register int i;
|
|
|
|
TRACE(printf("*** verifying disk (%d sects)\n", dkp->numsecs));
|
|
|
|
if (trkbuf == NULL)
|
|
trkbuf = sect_alloc(dkp->secptrk);
|
|
ntrks = dkp->trkpcyl * dkp->numcyls;
|
|
trksize = dkp->secptrk * dkp->bytpsec;
|
|
|
|
/* Process floppy a track at a time for efficiency's sake.
|
|
*/
|
|
for (trk=0; trk<ntrks; trk++)
|
|
{
|
|
/* Read track.
|
|
*/
|
|
badtrk = FALSE;
|
|
if (lseek(devfd, trk*(long)trksize, 0) < 0
|
|
|| read(devfd, trkbuf, trksize) != trksize)
|
|
{
|
|
TRACE(perror("*** FDverify (lseek/read)"));
|
|
if (errno == ENOTREADY)
|
|
return(errmsg(ERR_NOT_READY));
|
|
badtrk = TRUE;
|
|
}
|
|
|
|
/* Check each sector of track for errors.
|
|
* When floppy was soft-sectored, each byte
|
|
* of the sector was initialized to a filler
|
|
* value. If it doesn't have that value now,
|
|
* the sector is bad.
|
|
*/
|
|
for (sect=0; sect<dkp->secptrk; sect++)
|
|
{
|
|
if (badtrk) /* the whole track is bad */
|
|
goto badsect;
|
|
s = &trkbuf[ sect*dkp->bytpsec ];
|
|
for (i=0; i<dkp->bytpsec; i++) /* check each byte */
|
|
if (s[i] != FDFILLER)
|
|
goto badsect;
|
|
continue;
|
|
|
|
badsect: /* Sector is bad.
|
|
* Find out what cluster sector is in.
|
|
* If cluster precedes data area on the diskette,
|
|
* diskette is unusable. Otherwise, mark the cluster as bad.
|
|
*/
|
|
thiscluster = sect2cluster(trk*dkp->secptrk + sect);
|
|
TRACE(printf("*** sec %d, trk %d (clu %d) bad\n",
|
|
sect, trk, thiscluster));
|
|
if (thiscluster < 2)
|
|
return(errmsg(ERR_BAD_TRACK0));
|
|
else if (thiscluster != lastcluster)
|
|
{
|
|
++dkp->badclus;
|
|
update_FAT(thiscluster, BAD_CLUSTER);
|
|
lastcluster = thiscluster;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Output a sector to disk.
|
|
*/
|
|
write_sector(n, buf)
|
|
int n;
|
|
register char *buf;
|
|
{
|
|
long offset;
|
|
|
|
offset = n * (long) dkp->bytpsec;
|
|
|
|
if (lseek(devfd, offset, 0) < 0)
|
|
{
|
|
TRACE(perror("*** write_sector (lseek)"));
|
|
return(errmsg(ERR_BAD_TRACK0));
|
|
}
|
|
if (write(devfd, buf, dkp->bytpsec) != dkp->bytpsec)
|
|
{
|
|
TRACE(perror("*** write_sector (write)"));
|
|
switch (errno)
|
|
{
|
|
case EWRPROTECT:
|
|
return(errmsg(ERR_WRPROTECT));
|
|
case EBUSY:
|
|
return(errmsg(ERR_DRIVE_BUSY));
|
|
case ENOTREADY:
|
|
return(errmsg(ERR_NOT_READY));
|
|
default:
|
|
return(errmsg(ERR_BAD_TRACK0));
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Convert disk sector number to DOS cluster number.
|
|
* Clusters are the units of allocation in the disk's data area
|
|
* and are numbered starting at '2'.
|
|
*/
|
|
sect2cluster(n)
|
|
register int n;
|
|
{
|
|
n -= dkp->dataoff;
|
|
n /= dkp->secpclu;
|
|
n += 2;
|
|
|
|
return(n);
|
|
}
|
|
|
|
/* Update the entry for cluster 'n'
|
|
* in the (in-core) FAT table.
|
|
*/
|
|
update_FAT(n, val)
|
|
int n;
|
|
unsigned val;
|
|
{
|
|
register char *fatp; /* pointer into in-core FAT table */
|
|
|
|
/* 16-bit FAT entries.
|
|
*/
|
|
if (dkp->fattype == FAT16)
|
|
{
|
|
/* Find the entry in FAT table.
|
|
*/
|
|
fatp = fatbuf + (int) (n * FAT16SIZE);
|
|
|
|
fatp[0] = val & 0xFF;
|
|
fatp[1] = val>>8 & 0xFF;
|
|
}
|
|
|
|
/* 12-bit (1.5 byte) FAT entries.
|
|
* These guys are a bit more complicated to handle than
|
|
* the 16 bit (2 byte) FAT entries since they must share
|
|
* a half byte with an adjacent entry.
|
|
*/
|
|
else
|
|
{
|
|
/* Find the entry in FAT table (to the nearest whole byte).
|
|
*/
|
|
fatp = fatbuf + (int) (n * FAT12SIZE);
|
|
|
|
if (EVEN(n))
|
|
{
|
|
fatp[0] = val & 0xFF;
|
|
fatp[1] &= 0xF0;
|
|
fatp[1] |= val>>8 & 0x0F;
|
|
}
|
|
else
|
|
{
|
|
fatp[0] &= 0x0F;
|
|
fatp[0] |= val<<4 & 0xF0;
|
|
fatp[1] = val>>4 & 0xFF;
|
|
}
|
|
}
|
|
|
|
TRACE(printf("*** updating FAT for cluster %d (off=%d)\n", n, fatp-fatbuf));
|
|
}
|
|
|
|
disk_space()
|
|
{
|
|
int totalbytes, badbytes;
|
|
|
|
TRACE(printf("*** printing diskspace\n"));
|
|
totalbytes = (dkp->numsecs - dkp->dataoff) * dkp->bytpsec;
|
|
badbytes = dkp->badclus * dkp->secpclu * dkp->bytpsec;
|
|
|
|
printf("\n%10d bytes total disk space", totalbytes);
|
|
if (badbytes)
|
|
printf("\n%10d bytes in bad sectors", badbytes);
|
|
printf("\n%10d bytes available on disk\n\n", totalbytes - badbytes);
|
|
}
|
|
|
|
get_response(prompt)
|
|
char *prompt;
|
|
{
|
|
int response;
|
|
int c;
|
|
|
|
do {
|
|
printf("%s", prompt);
|
|
fflush(stdout);
|
|
|
|
c = response = getchar();
|
|
while (c != '\n')
|
|
c = getchar();
|
|
response = toupper(response);
|
|
} while (response != 'N' && response != 'Y');
|
|
|
|
return(response);
|
|
}
|
|
|
|
errmsg(errcode)
|
|
int errcode;
|
|
{
|
|
switch (errcode)
|
|
{
|
|
default:
|
|
TRACE(printf("*** [UNKNOWN ERROR: %d]\n", errcode));
|
|
case ERR_GENERIC:
|
|
printf("\nFormat Failure\n");
|
|
break;
|
|
case ERR_DRIVE_INVAL:
|
|
printf("Invalid drive specification\n");
|
|
break;
|
|
case ERR_BAD_TRACK0:
|
|
printf("Invalid media or Track 0 bad - disk unusable\n");
|
|
break;
|
|
case ERR_INVAL_PARM:
|
|
printf("Invalid parameter\n");
|
|
break;
|
|
case ERR_NOMEM:
|
|
printf("Out of memory\n");
|
|
break;
|
|
case ERR_NOSUPPORT:
|
|
printf("Unsupported parameter\n");
|
|
break;
|
|
case ERR_DRIVE_BUSY:
|
|
printf("\nDrive busy\n");
|
|
break;
|
|
case ERR_WRPROTECT:
|
|
printf("\nAttempted write-protect violation\n");
|
|
break;
|
|
case ERR_NOT_READY:
|
|
printf("\nDrive not ready\n");
|
|
break;
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/* Zero out a sector buffer.
|
|
*/
|
|
sect_zero(buf, x, n)
|
|
register char *buf;
|
|
uchar x;
|
|
int n;
|
|
{
|
|
register int i, count;
|
|
|
|
count = n * dkp->bytpsec;
|
|
|
|
for (i=0; i<count; i++)
|
|
buf[i] = x;
|
|
}
|
|
|
|
/* Allocate 'n' sectors worth of memory.
|
|
*/
|
|
char *sect_alloc(n)
|
|
int n;
|
|
{
|
|
char *s;
|
|
char *malloc();
|
|
|
|
if ((s = malloc((unsigned)(n * dkp->bytpsec))) == NULL)
|
|
{
|
|
errmsg(ERR_NOMEM);
|
|
exit(1);
|
|
}
|
|
|
|
return(s);
|
|
}
|
|
|
|
/****************************************************
|
|
FLOPPY - SPECIFIC ROUTINES
|
|
****************************************************/
|
|
|
|
/* Do soft-sector formatting of floppy
|
|
* (lay out track headers, etc.)
|
|
* using the FDIOCFORMAT ioctl.
|
|
*/
|
|
FDsoft_sector()
|
|
{
|
|
register sect, cyl, track;
|
|
char data[1000];
|
|
register char *p;
|
|
|
|
TRACE(printf("FDsoft_sector: numcyls = %d, tracks = %d,secptrk = %d\n",
|
|
dkp->numcyls, dkp->trkpcyl,dkp->secptrk));
|
|
|
|
for (cyl=0; cyl<dkp->numcyls; ++cyl)
|
|
{
|
|
for (track=0; track<dkp->trkpcyl; ++track)
|
|
{
|
|
p = data;
|
|
for (sect=0; sect<dkp->secptrk; ++sect)
|
|
{
|
|
*p++ = cyl;
|
|
*p++ = track;
|
|
*p++ = sect + 1;
|
|
*p++ = FD_SECTSIZE;
|
|
}
|
|
if (ioctl(devfd, FDIOCFORMAT, data) != 0)
|
|
{
|
|
TRACE(perror("FDIOCFORMAT"));
|
|
if (errno == EWRPROTECT)
|
|
return(errmsg(ERR_WRPROTECT));
|
|
else if (errno == ENOTREADY)
|
|
return(errmsg(ERR_NOT_READY));
|
|
else
|
|
return(errmsg(ERR_GENERIC));
|
|
}
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Get/set floppy size parameters.
|
|
*/
|
|
FDparms(info)
|
|
struct devinfo info;
|
|
{
|
|
int type;
|
|
|
|
if ( info.un.dk.secptrk == 36)
|
|
type = FLOPPY80_3_3; /* 3 1/2 2.88 meg floppy */
|
|
else if ( info.un.dk.secptrk == 18)
|
|
type = FLOPPY80_3_2; /* 3 1/2 1.44 meg floppy */
|
|
else if ( info.un.dk.secptrk == 9) {
|
|
if ( info.un.dk.numblks == 720)
|
|
type = FLOPPY40_9_2; /* 5 1/4 360k floppy */
|
|
else
|
|
type = FLOPPY80_3_1; /* 3 1/2 720k floppy */
|
|
} else
|
|
type = FLOPPY80; /* 5 1/4 1.2 meg floppy */
|
|
|
|
if ( lowdensity) {
|
|
switch(type) {
|
|
case FLOPPY80_3_1:
|
|
case FLOPPY80_3_2:
|
|
case FLOPPY80_3_3:
|
|
type = FLOPPY80_3_1; /* format a 720k in a 1.44m drive */
|
|
break;
|
|
case FLOPPY40_9_2:
|
|
case FLOPPY80:
|
|
type = FLOPPY40_9_2; /* format a 360k in a 1.2m drive */
|
|
break;
|
|
}
|
|
}
|
|
|
|
dkp = &dktbl[type];
|
|
|
|
return(FDinit_drive());
|
|
}
|
|
|
|
/* Initialize floppy drive.
|
|
*/
|
|
FDinit_drive()
|
|
{
|
|
struct fdinfo fdinfo;
|
|
|
|
if (ioctl(devfd, FDIOCGINFO, (char*)&fdinfo) < 0)
|
|
{
|
|
TRACE(perror("get_drive_info (FDIOCGINFO)"));
|
|
return(errmsg(ERR_GENERIC));
|
|
}
|
|
|
|
fdinfo.nsects = dkp->secptrk;
|
|
fdinfo.sides = dkp->trkpcyl;
|
|
fdinfo.ncyls = dkp->numcyls;
|
|
|
|
if (ioctl(devfd, FDIOCSINFO, (char*)&fdinfo) < 0)
|
|
{
|
|
TRACE(perror("get_drive_info (FDIOCSINFO)"));
|
|
return(errmsg(ERR_GENERIC));
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
/* Reset floppy drive.
|
|
* This must be done if floppy was removed from the drive
|
|
* while we had the drive open.
|
|
*/
|
|
FDreset()
|
|
{
|
|
TRACE(printf("*** Resetting floppy drive\n"));
|
|
|
|
if (ioctl(devfd, FDIOCRESET, (char*)0) != 0)
|
|
{
|
|
TRACE(perror("DIOCERESET"));
|
|
return(errmsg(ERR_GENERIC));
|
|
}
|
|
|
|
dkp->badclus = 0;
|
|
|
|
return(0);
|
|
}
|