home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
118.lha
/
bformat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-20
|
11KB
|
469 lines
/* bformat.c */
/* simple program to format drive df0:, creating a bitmap which marks
bad tracks as 'in use'. Should work for any 3.5" floppy which can hold
a format on track 0 and 80 (Dos minimum requirements).. I never could
figure out why Dos didn't do this all by itself.. Should you really have
to throw out a disk that has one or two lousy tracks? */
/* I've been meaning to write this program for quite a long while but never
took the time to figure out how AmigaDos stores/manipulates the block
allocation map (aka bitmap). Well, finally took an evening and threw this
together. To the best of my determination here is a description of
the block allocation scheme (for 3.5" floppies anyway..) :
When you format a diskette dos grabs 2 blocks for its own use.
Block 880 is the Root block. Block 881 (normally on a fresh format) is
the bitmap which in itself indicates the blocks that are available for use
or currently in use. Generally, a '1' bit means the corresponding block
is available. A '0' bit means that the block is in use. This sounds
relatively simple but the AmigaDos implementation needs some
explanation.
AmigaDos Block Allocation Map (512 bytes -or- 128 longwords)
------------------------------------------------------------
LongWord Usage
-------- -----
0 location of the block checksum
1 first bitmap allocation longword, which breaks down as follows:
hi-order bit (31) lo-order bit (0)
/ /
| |
11111111111111111111111111111111 (32 bit longword)
\\ \\\
\\_block #32 \\\_block #2
\_block #33 \\_block #3
\_block #4
(The above example indicates that blocks 2 thru 33 are available for use)
You might wonder why the bitmap starts at block #2 and not block #0?
I suppose since the first 2 blocks of every disk are not available for
file storage, AmigaDos simply chooses to ignore the fact that they exist.
Another reason could be that if the bitmap included blocks zero and one,
it might be too easy to figure out.. Hmmmmm..
Actually I think it corresponds to the well documented (ha) Mountlist
parameter named 'Reserved' which can be used to segment a hard disk into
more than one logical drive. If you look at it in that light, the first
bit in the bitmap corresponds to a block number which is the same as the
number of 'Reserved' blocks in the Mountlist file.. Have yet to verify
this on my hard disk but it sounds logical..
In any case, the remainder of the bitmap looks the same e.g. the next
longword (lo order bit) starts the map for block #34 -- and so on, until
the map terminates at block #1760...
With the above info, you should be able to figure out how this program
works.
*/
/* Bob Bush cpu-73105,1332
compiled with Lattice 4.0 28-Mar-88 */
#include "stdio.h"
#include "string.h"
#include "exec/types.h"
#include "exec/nodes.h"
#include "exec/lists.h"
#include "exec/memory.h"
#include "exec/interrupts.h"
#include "exec/ports.h"
#include "exec/libraries.h"
#include "exec/io.h"
#include "exec/tasks.h"
#include "exec/execbase.h"
#include "exec/devices.h"
#include "devices/trackdisk.h"
#include "libraries/dosextens.h"
struct IOStdReq *mreq = NULL;
struct MsgPort *mport,*dosport = NULL;
struct StandardPacket *dpacket ; /* packet for dos */
#define DEVICE_NAME "trackdisk.device"
long *buffer,*bitmap,*track = NULL;
BOOL formatting = FALSE;
BOOL correct = FALSE;
/* handle ctrl-c, ctrl-d aborts */
brk()
{
int c; char buf[20];
printf("\n** BREAK **\n");
if(formatting) {
printf("Do you really want to abort? (y/n) ");
gets(buf); c = buf[0];
if(c == 'y' || c == 'Y') {
cleanup(999);
printf("Warning! disk may be un-useable..\n");
return(1); }
else
return(0);
}
return(1);
}
main(argc,argv)
int argc;
char *argv[];
{
static int error,fstat,j,c,err,badcount;
err = onbreak(&brk);
badcount = 0;
if(argc < 2)
usage_err(0);
if(!strcmp(argv[1],"?"))
usage_err(1);
if(argc == 3) {
fix(argv[2]);
if(!strcmp(argv[2],"-C"))
correct = TRUE;
else
usage_err(1);
}
if(correct)
printf("Insert Disk to be corrected in drive 'DF0:'.\n");
else
printf("Insert Disk to be formatted in drive 'DF0:'.\n");
printf("Press Return when ready: ");
c = getchar();
chkabort();
if(!(mport = (struct MsgPort *)CreatePort("FLOPPY0",0)))
cleanup(100);
if(!(dosport = (struct MsgPort *)CreatePort("DOSPORT",0)))
cleanup(100);
if(!(mreq = (struct IOStdReq *)CreateStdIO(mport)))
cleanup(100);
if(!(dpacket=(struct StandardPacket *)AllocMem(sizeof(struct StandardPacket),
MEMF_PUBLIC|MEMF_CLEAR)))
cleanup(100);
if(error = OpenDevice(DEVICE_NAME,0,mreq,0))
cleanup(1);
inhibit(TRUE) ;
if(!(bitmap = (long *)AllocMem(512,MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
if(!(buffer = (long *)AllocMem(512,MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
if(!(track = (long *)AllocMem(512 * 11,MEMF_CLEAR | MEMF_CHIP)))
cleanup(8);
formatting = TRUE;
if(!correct)
validate_required();
/* format entire disk, building bitmap as we go.. */
if(correct) {
for(j = 0; j < 160; j++) {
printf("\rVerify Track # %3ld",j);
if(!(fstat = verify_track(j))) {
printf(" -- Bad Track! allocated as used..\n");
badcount += 11;
}
else
set_track(j);
}
}
else {
for(j = 0; j < 160; j++) {
printf("\rFormat Track # %3ld",j);
format_track(j);
printf("\rVerify Track # %3ld",j);
if(!(fstat = verify_track(j))) {
printf(" -- Bad Track! allocated as used..\n");
badcount += 11;
}
else
set_track(j);
}
}
/* init root/bitmap blocks and write to disk.. */
init_root(buffer,argv[1]);
write_block(880,buffer);
init_bitmap(bitmap);
write_block(881,bitmap);
Update();
Clear();
mreq->io_Length = 0;
mreq->io_Command = TD_MOTOR; /* turn off motor */
DoIO(mreq);
printf("\n** Program Completed **\n");
printf("%ld Bad blocks allocated as used\n",badcount);
cleanup(0);
}
fix(s)
char *s;
{
s++;
*s = toupper(*s);
}
validate_required()
{
int fstat;
/* try formatting block 0 */
set_fbuff(track);
format_track(0);
formatting = TRUE;
if(!(fstat = verify_track(0))) {
printf("\nUnable to format track #0..disk not useable..\n\n");
cleanup(100);
}
/* try formatting root block next */
format_track(80);
if(!(fstat = verify_track(80))) {
printf("\nUnable to format root block..disk not useable..\n\n");
cleanup(100);
}
}
usage_err(b)
int b;
{
if(b)
printf("Command Error\n");
printf("Usage: bformat volume_name <-c> (assumes df0:)\n");
exit(0);
}
/* mark track as available */
set_track(tnum)
int tnum;
{
int j;
for(j = (tnum * 11); j < (tnum * 11 + 11);j++)
set_bitmap(j);
}
/* mark block as available for use */
set_bitmap(block)
int block;
{
int lindex;
if((block - 2) > -1) {
lindex = (block - 2) / 32 + 1;
bitmap[lindex] = bitmap[lindex] | (1 << ((block-2) % 32));
}
}
/* mark block as allocated (in use) */
clear_bitmap(block)
int block;
{
int lindex;
if((block - 2) > -1) {
lindex = (block - 2) / 32 + 1;
bitmap[lindex] = bitmap[lindex] & (~(1 << ((block-2) % 32)));
}
}
format_track(tnum)
int tnum;
{
mreq->io_Length = 512 * 11;
mreq->io_Data = (APTR)track;
mreq->io_Command = TD_FORMAT;
mreq->io_Offset = tnum * 11 * 512;
DoIO(mreq);
}
/* verify track with abort on critical tracks */
verify_track(tnum)
int tnum;
{
mreq->io_Length = 512;
mreq->io_Data = (APTR)buffer;
mreq->io_Command = CMD_READ;
mreq->io_Offset = tnum * 11 * 512;
DoIO(mreq);
if(mreq->io_Error) {
if((tnum == 80) || (tnum == 0)) {
printf("\nUnable to verify critical track # %d \n Aborted..\n");
exit(100);
}
else
return(0);
}
else
return(1);
}
write_block(block,buff)
int block;
long *buff;
{
mreq->io_Length = 512;
mreq->io_Data = (APTR)buff;
mreq->io_Command = CMD_WRITE;
mreq->io_Offset = block * 512;
DoIO(mreq);
}
Update()
{
mreq->io_Length = 1;
mreq->io_Command = CMD_UPDATE;
DoIO(mreq);
}
Clear()
{
mreq->io_Length = 0;
mreq->io_Command = CMD_CLEAR;
DoIO(mreq);
return(0);
}
set_fbuff(buff)
ULONG buff[];
{
static int j;
for(j = 0; j < 128;j++)
buff[j] = 0x444f5300; /* fill buffer with ascii 'DOS' */
}
init_root(wp,vname) /* build initialized root block */
ULONG wp[];
char *vname;
{
ULONG check_sum();
static ULONG temp;
temp = 0;
zblock(wp);
wp[0] = 0x02; /* type */
wp[3] = 0x48; /* hashtable size */
wp[78] = 0xffffffff; /* 'true' bitmap flag */
wp[79] = 0x371; /* block # of bitmap */
DateStamp(&wp[105]); /* datestamp */
set_name(&wp[108],vname); /* disk name (BCPL) string */
DateStamp(&wp[121]); /* datestamp */
wp[127] = 0x01; /* secondary type = root */
wp[5] = check_sum(wp); /* create root block checksum */
}
/* set volume name into root block (BCPL string) */
set_name(dest,vname)
char *dest,*vname;
{
*dest = (char)strlen(vname);
dest++;
while(*vname) {
*dest = *vname;
dest++; vname++;
}
}
zblock(wp) /* clear buffer to zeros */
ULONG wp[];
{
static int j;
for(j = 0; j < 128; j++)
wp[j] = 0;
}
ULONG check_sum(buff) /* checksum= 2's complement of sum of all words in block */
ULONG buff[];
{
static int j;
static ULONG cksum;
cksum = 0;
for(j = 0; j < 128; j++)
cksum += buff[j]; /* sum all words in block */
return(-cksum);
}
init_bitmap(wp)
ULONG wp[];
{
ULONG check_sum();
clear_bitmap(880); /* set as allocated block 880 (root) and */
clear_bitmap(881); /* block 881 (bitmap) */
wp[0] = check_sum(wp); /* calculate checksum and insert */
}
/* Inhibits dos from trying to access drive while we have control. Also puts
up DF0:BUSY message, causes dos to re-read disk info on termination.. */
inhibit(t)
long t ; /* true -or - false */
{
struct MsgPort *handler ;
struct StandardPacket *packet = dpacket ;
handler = (struct MsgPort *)DeviceProc("DF0:") ;
if (handler == NULL || dosport == NULL)
return ;
packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt) ;
packet->sp_Pkt.dp_Link = &(packet->sp_Msg) ;
packet->sp_Pkt.dp_Port = dosport ;
packet->sp_Pkt.dp_Type = ACTION_INHIBIT ;
packet->sp_Pkt.dp_Arg1 = t ;
PutMsg(handler, packet) ;
WaitPort(dosport) ;
GetMsg(dosport) ;
}
cleanup(err)
int err;
{
inhibit(FALSE);
if(mreq) {
CloseDevice(mreq);
DeleteStdIO(mreq);
}
if(mport)
DeletePort(mport);
if(dosport)
DeletePort(dosport);
if(dpacket)
FreeMem(dpacket,sizeof(struct StandardPacket));
if(bitmap)
FreeMem(bitmap,512);
if(buffer)
FreeMem(buffer,512);
if(track)
FreeMem(track,512 * 11);
if(err == 999)
return(0);
exit(0);
}