home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 28
/
amigaformatcd28.iso
/
-in_the_mag-
/
under_the_bonnet
/
misc
/
rigids
/
rigids.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-05-02
|
17KB
|
665 lines
/********************************************************************
**
** Rigids v1.0 beta © 1997 by Tadek Knapik. Freeware.
** Send comments, bug reports etc to
** <tadek@malenstwo.iinf.polsl.gliwice.pl>
**
** This piece of code is probably something I sould be ashame of.
** But it's my first "platform" C program, first disk access, first
** job I had deadline on (let's say so:) and... still I decided to
** show it. Comments appreciated, but please don't hurt me :)
**
********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <dos/dos.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <devices/hardblocks.h>
#include <devices/scsidisk.h>
#include <devices/trackdisk.h>
#include <proto/dos.h>
#include <proto/exec.h>
/*
#define DEBUG
*/
#define IDNAME_OLDRIGID 0xD2CFCCC4 /* 'ROLD' */
#define BYTESONBLOCK 512
struct RigidDiskBlock *memrdb = NULL;
struct FileInfoBlock *fib = NULL;
struct RDArgs *rdargs = NULL; /* for ReadArgs() */
struct MsgPort *ioport = NULL;
struct IOExtTD *ioreq = NULL;
long *buffer = NULL;
long *memdata = NULL;
long *iodata = NULL;
long theunit = NULL;
long theoffset = NULL;
long rdbstart = NULL;
long rdbsize = NULL;
long rdbshift = NULL;
long rdbblock = NULL;
long current = NULL;
int scsiok = NULL;
int writeok = NULL;
int rdbok = NULL;
long BytesPerBlock = BYTESONBLOCK; /* fixed as for now, but... */
char DevName[80] = "scsi.device";
char argstring[] = "D=DEVICE/K,U=UNIT/K/N,O=OFFSET/K/N,RDB=RDBONLY/S,WRITE/S,FORCE/S,F=FILE/A";
char verstring[] = "$VER: Rigids v1.0b (14.12.97) © 1997 by Tadek Knapik.";
enum {DEVNAME = 0, DEVUNIT, NOFFSET, RDBONLY, DEVWRITE, RDBFORCE, FILENAME};
long argarray[] = {0, 0, 0, 0, 0, 0, 0};
void ParseBBB(struct BadBlockBlock *BBB);
void ParsePB(struct PartitionBlock *PB);
void ParseFHB(struct FileSysHeaderBlock *FHB);
void ParseLSB(struct LoadSegBlock *LSB);
long CountChkSum(ULONG *data, ULONG nr);
int ChkRDBSum(struct RigidDiskBlock *RDB);
int ChkBBBSum(struct BadBlockBlock *BBB);
int ChkPBSum(struct PartitionBlock *PB);
int ChkFHBSum(struct FileSysHeaderBlock *FHB);
int ChkLSBSum(struct LoadSegBlock *LSB);
void OpenDev(void);
void CloseAll(void);
int scandev(long block, long *rdbfound);
int SumOK(ULONG *p);
void main(int argc, char **argv)
{
BPTR thefile; /* file pointer */
if(!(rdargs=ReadArgs(argstring, argarray, NULL)))
{
printf(" %s\n", &verstring[6]);
return;
}
if (argarray[DEVNAME])
strcpy(DevName, (STRPTR) argarray[DEVNAME]);
if (argarray[DEVUNIT])
theunit = * (ULONG *) argarray[DEVUNIT];
if (argarray[NOFFSET])
theoffset = * (ULONG *) argarray[NOFFSET];
if ((theoffset >= 0) && (theoffset < RDB_LOCATION_LIMIT))
{
#ifdef DEBUG
printf("* Device: %s\n", DevName);
printf("* Unit: %ld\n", theunit);
printf("* Offset: %ld\n", theoffset);
printf("* RDBOnly: %s\n", argarray[RDBONLY]? "Yes": "No");
printf("* Mode: %s\n", argarray[DEVWRITE]? "Write": "Read");
printf("* Force: %s\n", argarray[RDBFORCE]? "Yes": "No");
printf("* File: %s\n", argarray[FILENAME]);
printf("\n");
#endif
OpenDev();
#ifdef DEBUG
printf("* %s unit %ld %s\n", DevName, theunit, scsiok? "opened": "not opened");
#endif
if(scsiok)
{
if((buffer=malloc(BytesPerBlock))) /* buffer to read blocks into */
{
if(argarray[DEVWRITE]) /* write */
{
if(thefile=Open((STRPTR) argarray[FILENAME], MODE_OLDFILE))
{
if(fib=malloc(sizeof(struct FileInfoBlock)))
{
if(ExamineFH(thefile, fib))
{
if(memdata=malloc(fib->fib_Size))
{
if((fib->fib_Size) && !((fib->fib_Size)%BytesPerBlock))
{
if(FRead(thefile, (STRPTR) memdata, (ULONG) fib->fib_Size, (ULONG) 1))
{
current = 0;
memrdb = (struct RigidDiskBlock *) memdata;
while((current < (fib->fib_Size)/BytesPerBlock) && (current < RDB_LOCATION_LIMIT))
{
if(memrdb->rdb_ID==IDNAME_RIGIDDISK)
break;
/* to the next "block" */
memrdb += BytesPerBlock/sizeof(struct RigidDiskBlock);
++current;
}
if(memrdb->rdb_ID==IDNAME_RIGIDDISK)
{
#ifdef DEBUG
printf("* RDB found in the file on \"block\" %ld.\n", current);
#endif
/* to know when the user has specified offset 0, and when he/she did not */
if(!argarray[NOFFSET])
theoffset = -1;
if(argarray[RDBONLY] || (theoffset!=-1))
{
argarray[RDBONLY] = TRUE;
iodata = (long *) memrdb;
rdbsize = (fib->fib_Size)-(current*BytesPerBlock);
}
else
{
iodata = memdata;
rdbsize = (fib->fib_Size);
}
/* data write start is counted from HighRDSKBlock and RDB size, not in-file position */
/* rdbstart and rdbsize are start and size of all data, not RDB structure only! */
if((rdbstart=(memrdb->rdb_HighRDSKBlock)-(rdbsize/BytesPerBlock)+1) < 0)
rdbstart = 0;
/* real starting block of RDB, needed for checksum checking */
/* when OFFSET specified, fixed later */
rdbblock = ((UBYTE *)memrdb-(UBYTE*)memdata)/BytesPerBlock;
/* RDB shifting and checksumming all lists */
if(theoffset!=-1)
{
rdbshift = rdbstart-theoffset;
#ifdef DEBUG
printf("* Shift value is %ld\n", rdbshift);
#endif
if(memrdb->rdb_SummedLongs <= 555)
{
#ifdef DEBUG
printf("%ld longs to checksum in RDB.\n", memrdb->rdb_SummedLongs);
#endif
if(memrdb->rdb_BadBlockList != -1)
{
ParseBBB((struct BadBlockBlock *) &((UBYTE *)memrdb)[((memrdb->rdb_BadBlockList)-rdbstart)*BytesPerBlock]);
memrdb->rdb_BadBlockList -= rdbshift;
}
if(memrdb->rdb_PartitionList != -1)
{
ParsePB((struct PartitionBlock *) &((UBYTE *)memrdb)[((memrdb->rdb_PartitionList)-rdbstart)*BytesPerBlock]);
memrdb->rdb_PartitionList -= rdbshift;
}
if(memrdb->rdb_FileSysHeaderList != -1)
{
ParseFHB((struct FileSysHeaderBlock *) &((UBYTE *) memrdb)[((memrdb->rdb_FileSysHeaderList)-rdbstart)*BytesPerBlock]);
memrdb->rdb_FileSysHeaderList -= rdbshift;
}
if(memrdb->rdb_DriveInit != -1)
{
memrdb->rdb_DriveInit -= rdbshift;
}
memrdb->rdb_HighRDSKBlock -= rdbshift;
memrdb->rdb_ChkSum = 0;
memrdb->rdb_ChkSum = CountChkSum((ULONG *) memrdb, (ULONG) memrdb->rdb_SummedLongs);
rdbstart = theoffset;
rdbblock = theoffset;
}
else
printf("Can't calculate checksum.\n");
}
#ifdef DEBUG
printf("* Checksum is %s.\n", SumOK((ULONG *) memrdb)? "OK": "wrong");
printf("* Writing RDB at block %ld, size %ld\n", rdbstart, rdbsize);
#endif
if((ChkRDBSum(memrdb)) || argarray[RDBFORCE])
{
current=0;
while((scandev(current, &theoffset)) && (theoffset<rdbstart))
{
#ifdef DEBUG
printf("* Replacing old 'RDSK' with 'ROLD' at block %ld\n", theoffset);
#endif
buffer[0] = IDNAME_OLDRIGID;
ioreq->iotd_Req.io_Command = CMD_WRITE;
ioreq->iotd_Req.io_Flags = 0;
ioreq->iotd_Req.io_Data = buffer;
ioreq->iotd_Req.io_Length = BytesPerBlock;
ioreq->iotd_Req.io_Offset = theoffset * BytesPerBlock;
DoIO((struct IORequest *) ioreq);
current = theoffset+1;
}
ioreq->iotd_Req.io_Command = CMD_WRITE;
ioreq->iotd_Req.io_Flags = 0;
ioreq->iotd_Req.io_Data = iodata;
ioreq->iotd_Req.io_Length = rdbsize;
ioreq->iotd_Req.io_Offset = rdbstart * BytesPerBlock;
if(!rdbok)
printf("Checksum is corrupt. Forcing write...\n");
if(!DoIO((struct IORequest *) ioreq))
printf("%ld bytes%s written at block %ld\n", rdbsize, argarray[RDBONLY]? " (RDB only)": "", rdbstart);
else
printf("Device error. File not written.\n");
}
else
printf("Checksum is corrupt. RDB not written (you can use FORCE switch though).\n");
}
else
printf("RDB not found in file %s\n", (STRPTR) argarray[FILENAME]);
}
else
printf("Error reading from file %s\n", (STRPTR) argarray[FILENAME]);
}
else
printf("Error: size of %s is not a multipler of BytesPerBlock.\n", (STRPTR) argarray[FILENAME]);
free(memdata);
}
else
printf("Not enough memory.\n");
}
else
printf("Can't get file size.\n");
free(fib);
}
else
printf("Not enough memory.\n");
Close(thefile);
}
else
printf("Can't open file %s\n", (STRPTR) argarray[FILENAME]);
}
else /* read */
{
/* first we search for the start of RDB on the disk... and read its length */
if(scandev(theoffset, &rdbstart)) /* search for RDB on the disk */
{
/* remember the real offset of RDB structure */
rdbblock = rdbstart;
/* now we can open the file and fill it with the data */
if(thefile=Open((STRPTR) argarray[FILENAME], MODE_NEWFILE))
{
if(!argarray[RDBONLY])
rdbstart = theoffset;
rdbsize = ((((struct RigidDiskBlock *)buffer)->rdb_HighRDSKBlock)-rdbstart+1) * BytesPerBlock;
#ifdef DEBUG
printf("* RDB size is %ld bytes\n", rdbsize);
#endif
if(memdata=malloc(rdbsize))
{
ioreq->iotd_Req.io_Command = CMD_READ;
ioreq->iotd_Req.io_Flags = 0;
ioreq->iotd_Req.io_Data = memdata;
ioreq->iotd_Req.io_Length = rdbsize;
ioreq->iotd_Req.io_Offset = rdbstart * BytesPerBlock;
if(!DoIO((struct IORequest *) ioreq))
{
/* memrdb pointer for checksumming */
memrdb = (struct RigidDiskBlock *) &((UBYTE *)memdata)[(rdbblock-rdbstart)*BytesPerBlock];
if(ChkRDBSum(memrdb) || argarray[RDBFORCE])
{
if(!rdbok)
printf("Checksum is corrupt. Forcing read...\n");
if(writeok=FWrite(thefile, (STRPTR) memdata, (ULONG) rdbsize, (ULONG) 1))
printf("%ld bytes%s written to %s\n", rdbsize, argarray[RDBONLY]? " (RDB only)": "", (STRPTR) argarray[FILENAME]);
else
printf("Write error\n");
}
else
printf("RDB checksum is corrupt. Use FORCE to read it.\n");
}
else
printf("Device error. File not written.\n");
free(memdata);
}
else
printf("Not enough memory.\n");
Close(thefile);
if(!writeok)
DeleteFile((STRPTR) argarray[FILENAME]);
}
else
printf("Can't open file %s\n", argarray[FILENAME]);
}
else
printf("Can't find RDB on the disk.\n");
}
}
else
printf("Not enough memory.\n");
}
else
printf("Cant't open %s unit %ld\n", DevName, theunit);
CloseAll();
}
else
printf("Invalid offset value (must be from 0 to %ld).\n", RDB_LOCATION_LIMIT-1);
}
int scandev(long block, long *rdbfound)
{
while (block < RDB_LOCATION_LIMIT)
{
ioreq->iotd_Req.io_Command = CMD_READ;
ioreq->iotd_Req.io_Flags = 0;
ioreq->iotd_Req.io_Data = buffer;
ioreq->iotd_Req.io_Length = BytesPerBlock;
ioreq->iotd_Req.io_Offset = block * BytesPerBlock;
if(DoIO((struct IORequest *) ioreq))
{
#ifdef DEBUG
printf("* Error number %ld\n", ioreq->iotd_Req.io_Error);
#endif
printf("Disk error. ");
return FALSE;
}
else if (((struct RigidDiskBlock *)buffer)->rdb_ID==IDNAME_RIGIDDISK)
{
*rdbfound = block;
#ifdef DEBUG
printf("* RDB found on block %ld\n", block);
printf("* RDB last block is %ld\n", ((struct RigidDiskBlock *)buffer)->rdb_HighRDSKBlock);
#endif
return TRUE;
}
else
++block;
}
return FALSE;
}
/* list parsing... hope I didn't make a mistake here */
void ParseBBB(struct BadBlockBlock *BBB)
{
if((BBB->bbb_Next)!=-1)
{
ParseBBB((struct BadBlockBlock *) &((UBYTE *) memrdb)[((BBB->bbb_Next)-rdbstart)*BytesPerBlock]);
BBB->bbb_Next -= rdbshift;
BBB->bbb_ChkSum = 0;
BBB->bbb_ChkSum = CountChkSum((ULONG *) BBB, (ULONG) BBB->bbb_SummedLongs);
}
}
void ParsePB(struct PartitionBlock *PB)
{
if((PB->pb_Next)!=-1)
{
ParsePB((struct PartitionBlock *) &((UBYTE *) memrdb)[((PB->pb_Next)-rdbstart)*BytesPerBlock]);
PB->pb_Next -= rdbshift;
PB->pb_ChkSum = 0;
PB->pb_ChkSum = CountChkSum((ULONG *) PB, (ULONG) PB->pb_SummedLongs);
}
}
void ParseFHB(struct FileSysHeaderBlock *FHB)
{
if((FHB->fhb_Next)!=-1)
{
ParseFHB((struct FileSysHeaderBlock *) &((UBYTE *) memrdb)[((FHB->fhb_Next)-rdbstart)*BytesPerBlock]);
FHB->fhb_Next -= rdbshift;
}
if((FHB->fhb_SegListBlocks)!=-1)
{
ParseLSB((struct LoadSegBlock *) &((UBYTE *) memrdb)[((FHB->fhb_SegListBlocks)-rdbstart)*BytesPerBlock]);
FHB->fhb_SegListBlocks -= rdbshift;
}
FHB->fhb_ChkSum = 0;
FHB->fhb_ChkSum = CountChkSum((ULONG *) FHB, (ULONG) FHB->fhb_SummedLongs);
}
void ParseLSB(struct LoadSegBlock *LSB)
{
if((LSB->lsb_Next)!=-1)
{
ParseLSB((struct LoadSegBlock *) &((UBYTE *) memrdb)[((LSB->lsb_Next)-rdbstart)*BytesPerBlock]);
LSB->lsb_Next -= rdbshift;
LSB->lsb_ChkSum = 0;
LSB->lsb_ChkSum = CountChkSum((ULONG *) LSB, (ULONG) LSB->lsb_SummedLongs);
}
}
/* checksum checking for all RDB structures */
int ChkRDBSum(struct RigidDiskBlock *RDB)
{
rdbok = TRUE;
if(!SumOK((ULONG *) RDB))
{
rdbok = FALSE;
return FALSE;
}
if((RDB->rdb_BadBlockList) != -1)
ChkBBBSum((struct BadBlockBlock *) &((UBYTE *)memrdb)[((RDB->rdb_BadBlockList)-rdbblock)*BytesPerBlock]);
if((RDB->rdb_PartitionList) != -1)
ChkPBSum((struct PartitionBlock *) &((UBYTE *)memrdb)[((RDB->rdb_PartitionList)-rdbblock)*BytesPerBlock]);
if((RDB->rdb_FileSysHeaderList) != -1)
ChkFHBSum((struct FileSysHeaderBlock *) &((UBYTE *)memrdb)[((RDB->rdb_FileSysHeaderList)-rdbblock)*BytesPerBlock]);
return rdbok;
}
int ChkBBBSum(struct BadBlockBlock *BBB)
{
if(!rdbok)
return FALSE;
if(!SumOK((ULONG *) BBB))
rdbok = FALSE;
if((BBB->bbb_Next) != -1)
ChkBBBSum((struct BadBlockBlock *) &((UBYTE *)memrdb)[((BBB->bbb_Next)-rdbblock)*BytesPerBlock]);
return rdbok;
}
int ChkPBSum(struct PartitionBlock *PB)
{
if(!rdbok)
return FALSE;
if(!SumOK((ULONG *) PB))
rdbok = FALSE;
if((PB->pb_Next) != -1)
ChkPBSum((struct PartitionBlock *) &((UBYTE *)memrdb)[((PB->pb_Next)-rdbblock)*BytesPerBlock]);
return rdbok;
}
int ChkFHBSum(struct FileSysHeaderBlock *FHB)
{
if(!rdbok)
return FALSE;
if(!SumOK((ULONG *) FHB))
rdbok = FALSE;
if((FHB->fhb_Next) != -1)
ChkFHBSum((struct FileSysHeaderBlock *) &((UBYTE *)memrdb)[((FHB->fhb_Next)-rdbblock)*BytesPerBlock]);
if((FHB->fhb_SegListBlocks) != -1)
ChkLSBSum((struct LoadSegBlock *) &((UBYTE *)memrdb)[((FHB->fhb_SegListBlocks)-rdbblock)*BytesPerBlock]);
return rdbok;
}
int ChkLSBSum(struct LoadSegBlock *LSB)
{
if(!rdbok)
return FALSE;
if(!SumOK((ULONG *) LSB))
rdbok = FALSE;
if((LSB->lsb_Next) != -1)
ChkLSBSum((struct LoadSegBlock *) &((UBYTE *)memrdb)[((LSB->lsb_Next)-rdbblock)*BytesPerBlock]);
return rdbok;
}
/* Next two functions had been written looking at David Balazic's
RDBInformer v0.2. */
long CountChkSum(ULONG *data, ULONG nr)
{
long i;
long chksum = 0;
for(i=0; i<nr; i++)
chksum -= (*data++);
return chksum;
}
void CloseAll(void)
{
if(scsiok)
CloseDevice((struct IORequest *) ioreq);
if(ioreq)
DeleteIORequest(ioreq);
if(ioport)
DeleteMsgPort(ioport);
if (buffer)
free(buffer);
if (rdargs)
FreeArgs(rdargs);
}
/* The source below is took from David Balazic's RDBInformer v0.2 */
void OpenDev(void)
{
if (ioport=CreateMsgPort())
{
#ifdef DEBUG
printf("* MsgPort created\n");
#endif
if(ioreq=CreateIORequest(ioport,sizeof(struct IOExtTD)))
#ifdef DEBUG
printf("* IORequest created\n");
#endif
{
if(!OpenDevice(DevName, theunit, (struct IORequest *) ioreq, 0))
{
scsiok=TRUE;
return;
}
}
}
scsiok=FALSE;
}
int SumOK(ULONG *p)
{
int i;
LONG chk=0;
ULONG nr=((struct RigidDiskBlock *)p)->rdb_SummedLongs;
if(nr>555) return FALSE;
for(i=0;i<nr;i++)
chk+=(*p++);
if (chk) return FALSE;
return TRUE;
}