
/**********************************************************************
**
**   Rigids v1.2 beta © 1997, 1998 by Tadek Knapik. Freeware.
**   Send comments, bug reports etc to  
**   <tadek@nautilus.uwoj.krakow.pl>
**
**   This piece of code is probably something I should 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 :)
**
**   1.0 (14.12.97) - as it says, the first version
**   1.1 (11.06.98) - added RAW writing to devices, RDB/MBR independent
**   1.2 (04.10.98) - added PAD switch (suggested by Henry Schimmer)
**                  - fixed RDBBlocksLo handling
**
**************************************************************************
* 
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*    
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*    
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*************************************************************************/


#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					/* fixed as for now */
#define DEF_RDBLOW	0						/* where to write by default */

/* The define below determines behaviour of Rigids concerning RDBBlocksLo.
   Defining STRICT_RDBLOW (recommended) means RDBBlocksLo is assumed to be
   correct, and so Rigids uses it to decide where to write if only RDB is
   to write, to calculate HighRDSKBlock etc. If undefined, it acts like old
   versions did.
   All of this is my fault, as I forgot to shift RDBBlocksLo when writing a
   RDB with an offset. Now I assume there are some backups with wrong value
   there. All what's needed is to reread them with v1.2, if it is possible,
   of course. Sorry :( */


#define STRICT_RDBLOW

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	thesize = NULL;
long	padding = NULL;
long	readsize = 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,RAW/S,S=SIZE/N,PAD/S";
char verstring[] = "$VER: Rigids v1.2b (04.10.98) Copyright (C) 1997, 1998 by Tadek Knapik.";

enum {DEVNAME = 0, DEVUNIT, NOFFSET, RDBONLY, DEVWRITE, RDBFORCE, FILENAME, RAW, NSIZE, NPAD};
long argarray[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void ParseBBB(struct BadBlockBlock *BBB, int startblock);
void ParsePB(struct PartitionBlock *PB, int startblock);
void ParseFHB(struct FileSysHeaderBlock *FHB, int startblock);
void ParseLSB(struct LoadSegBlock *LSB, int startblock);
long CountChkSum(ULONG *data, ULONG nr);
int ChkRDBSum(struct RigidDiskBlock *RDB, int startblock);
int ChkBBBSum(struct BadBlockBlock *BBB, int startblock);
int ChkPBSum(struct PartitionBlock *PB, int startblock);
int ChkFHBSum(struct FileSysHeaderBlock *FHB, int startblock);
int ChkLSBSum(struct LoadSegBlock *LSB, int startblock);

void OpenDev(void);
void CloseAll(void);
int scandev(long block, long *rdbfound);
void clearmem(char *mem, int size);
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]);
		printf(" This program is distributed under the GNU General Public Licence.\n");
		return;
	}

	if (argarray[DEVNAME])
		strcpy(DevName, (STRPTR) argarray[DEVNAME]);

	if (argarray[DEVUNIT])
		theunit = * (ULONG *) argarray[DEVUNIT];

	if (argarray[NSIZE])
		thesize = * (ULONG *) argarray[NSIZE];

	if (argarray[NOFFSET])
		theoffset = * (ULONG *) argarray[NOFFSET];

	if (((theoffset >= 0) && (theoffset < RDB_LOCATION_LIMIT)) || (argarray[RAW]))
	{

#ifdef DEBUG
	printf("* Device: %s\n", DevName);
	printf("* Unit: %ld\n", theunit);
	printf("* Offset: %ld\n", theoffset);
	printf("* Size: %ld\n", thesize);
	printf("* Padding: %s\n", argarray[NPAD]? "on": "off");
	printf("* RDBOnly: %s\n", argarray[RDBONLY]? "Yes": "No");
	printf("* Mode: %s\n", argarray[DEVWRITE]? "Write": "Read");
	printf("* Raw: %s\n", argarray[RAW]? "On": "Off");
	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(!argarray[RAW])
						{
							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;
#ifdef STRICT_RDBLOW
														rdbsize = (memrdb->rdb_HighRDSKBlock-memrdb->rdb_RDBBlocksLo+1)*BytesPerBlock;
														rdbstart = memrdb->rdb_RDBBlocksLo;	/* fixed later if OFFSSET given */
#else
														rdbsize = (fib->fib_Size)-(current*BytesPerBlock);
														rdbstart = (memrdb->rdb_HighRDSKBlock)-(rdbsize/BytesPerBlock)+1;
#endif


													}
													else
													{
														iodata = memdata;
														rdbsize = (fib->fib_Size);
														rdbstart = DEF_RDBLOW;
#ifdef STRICT_RDBLOW
														if((UBYTE *) memdata == (UBYTE *) memrdb)
														{
															rdbstart = memrdb->rdb_RDBBlocksLo;
															argarray[RDBONLY] = TRUE;		/* just for the record */
														}
#endif
													}

													if(rdbstart < 0)
														rdbstart = DEF_RDBLOW;

													writeok = TRUE;

/* check if the length is OK. might be too big only determining by High-Lo */

#ifdef STRICT_RDBLOW
													if((memrdb->rdb_HighRDSKBlock-memrdb->rdb_RDBBlocksLo+1)*BytesPerBlock > (fib->fib_Size)-(current*BytesPerBlock))
													{
														printf("The file seems to be too short");
														if(argarray[RDBFORCE])
														{
															printf(". Forcing write...\n");
															rdbsize = (fib->fib_Size)-(current*BytesPerBlock);
														}
														else
														{
														 printf(" (use FORCE if needed).\n");
															writeok = FALSE;
														}
#ifdef DEBUG
	printf("* Expected size is %ld, found %ld bytes\n", rdbsize, (fib->fib_Size)-(current*BytesPerBlock));
#endif
													}
#endif



/* future real starting block of RDB, needed for checksumming */
/* since v1.2 took from RDBBlocksLo, unless STRICT_RDBLOW undefined - then
   using position deducated from the file, as previous */
/* when OFFSET specified, fixed later */

#ifdef STRICT_RDBLOW
													rdbblock = memrdb->rdb_RDBBlocksLo;
#else
													rdbblock = ((UBYTE *)memrdb-(UBYTE*)memdata)/BytesPerBlock;
#endif

/* RDB shifting and checksumming all lists */

													if(theoffset!=-1)
#ifdef STRICT_RDBLOW
														rdbshift = memrdb->rdb_RDBBlocksLo-theoffset;
#else
														rdbshift = rdbstart-theoffset;
#endif

/* rdbok is a flag used to setting new rdbblock later */

													rdbok = TRUE;

#ifdef STRICT_RDBLOW
													if((memrdb->rdb_RDBBlocksLo != current+DEF_RDBLOW) && !argarray[RDBONLY])
													{
														rdbshift = memrdb->rdb_RDBBlocksLo-(current+DEF_RDBLOW);
														rdbok = FALSE;
													}
#endif


/* rdbblock is changed later, as it desribes a block, where RDB _used_to_
   start, and not the actual one */


													if(rdbshift)
													{

#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

/* fixing stuff, so it is correct for sure */

															memrdb->rdb_RDBBlocksLo -= rdbshift;
															memrdb->rdb_HighRDSKBlock -= rdbshift;

															if(memrdb->rdb_RDBBlocksHi < memrdb->rdb_HighRDSKBlock)
															{
																printf("Cant't shift beyond the highest block destined for RDB, aborting.\n");
																writeok = FALSE;
															}

#ifdef DEBUG
	printf("* RDBBlocksLo is %ld, HighRDSKBlock is %ld.\n", memrdb->rdb_RDBBlocksLo, memrdb->rdb_HighRDSKBlock);
#endif

															if(memrdb->rdb_BadBlockList != -1)
															{
																ParseBBB((struct BadBlockBlock *) &((UBYTE *)memrdb)[((memrdb->rdb_BadBlockList)-rdbblock)*BytesPerBlock], rdbblock);
																memrdb->rdb_BadBlockList -= rdbshift;
															}

															if(memrdb->rdb_PartitionList != -1)
															{
																ParsePB((struct PartitionBlock *) &((UBYTE *)memrdb)[((memrdb->rdb_PartitionList)-rdbblock)*BytesPerBlock], rdbblock);
																memrdb->rdb_PartitionList -= rdbshift;
															}

															if(memrdb->rdb_FileSysHeaderList != -1)
															{
																ParseFHB((struct FileSysHeaderBlock *) &((UBYTE *) memrdb)[((memrdb->rdb_FileSysHeaderList)-rdbblock)*BytesPerBlock], rdbblock);
																memrdb->rdb_FileSysHeaderList -= rdbshift;
															}

															if(memrdb->rdb_DriveInit != -1)
															{
																memrdb->rdb_DriveInit -= rdbshift;
															}

															memrdb->rdb_ChkSum = 0;
															memrdb->rdb_ChkSum = CountChkSum((ULONG *) memrdb, (ULONG) memrdb->rdb_SummedLongs);


														}
														else
														{
															printf("Can't calculate checksum, aborting.\n");
															writeok = FALSE;
														}


/* now, new rdbblock, as RDB is already "shifted" */

														if(theoffset!=-1)
														{
															rdbstart = theoffset;
															rdbblock = theoffset;
														}

														if(!rdbok)
															rdbblock -= rdbshift;

													}


#ifdef DEBUG
	printf("* Main checksum is %s.\n", SumOK((ULONG *) memrdb)? "OK": "wrong");
	printf("* Writing RDB at block %ld, size %ld\n", rdbstart, rdbsize);
#endif

													if(writeok)
													{

														if((ChkRDBSum(memrdb, rdbblock)) || argarray[RDBFORCE])
														{

															current=0;
															while((scandev(current, &theoffset)) && (theoffset<rdbstart))
															{
#ifdef DEBUG
	printf("* Replacing old 'RDSK' with 'ROLD' on 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. Data not written.\n");
														}
														else
														{
															printf("Checksum is corrupt. RDB not written (you can use FORCE switch though).\n");
														}

													}
													else
														;	/* error described earlier - checksum or RDBBlocksHi */

												}
												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
						{

/* RAW mode writing */

							if(fib=malloc(sizeof(struct FileInfoBlock)))
							{
								if(buffer=malloc(BytesPerBlock))
								{
									if(ExamineFH(thefile, fib))
									{
										if(fib->fib_Size)
										{

#ifdef DEBUG
	printf("* File size is %ld, requested block size is %ld\n", fib->fib_Size, thesize);
#endif

/* is the file size is OK? */

											if((fib->fib_Size)%BytesPerBlock)
											{
												current = FALSE;
#ifdef DEBUG
	printf("* File size is not multipler of BytesPerBlock.\n");
#endif

												if(argarray[NPAD])
												{
													padding = (fib->fib_Size)%BytesPerBlock;
#ifdef DEBUG
	printf("* PAD given while %ld bytes \"too much\".\n", padding);
#endif
												}
											}
											else
												current = TRUE;


/* do we have to, and if so, can we put it as write size? */

											if(thesize * BytesPerBlock <= fib->fib_Size)
											{
												if(argarray[NSIZE])		/* if size given */
												{
													current = TRUE;
#ifdef DEBUG
	printf("* Using valid SIZE given\n");
#endif
												}
												else
												{
													thesize = (fib->fib_Size)/BytesPerBlock;
#ifdef DEBUG
	printf("* No valid SIZE given, trying to use file size\n");
#endif
												}
											}
											else
											{
												thesize = (fib->fib_Size)/BytesPerBlock;
#ifdef DEBUG
	printf("* SIZE too big, trying to use file size\n");
#endif

											}

											if(padding)
												++thesize;

#ifdef DEBUG
	printf("* Final write size is %ld blocks\n", thesize);
#endif

											if(current || padding)
											{
												if(thesize)
												{
													writeok = TRUE;
													readsize = BytesPerBlock;

													for(current=theoffset; current != theoffset+thesize; ++current)
													{
														if((current == theoffset+thesize-1) && padding)
														{
															clearmem((char *) buffer, (int) BytesPerBlock);
															readsize = padding;
#ifdef DEBUG
	printf("* Reading last %ld bytes from file.\n", padding);
#endif
														}

														if(FRead(thefile, (STRPTR) buffer, (ULONG) readsize, (ULONG) 1))
														{
															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 =  current * BytesPerBlock;

															if(DoIO((struct IORequest *) ioreq))
															{
																printf("Device error. Data not written.\n");
																writeok = FALSE;
																break;
															}
														}
														else
														{
															printf("Error reading from file %s\n", (STRPTR) argarray[FILENAME]);
															writeok = FALSE;
															break;
														}

													}

													if(writeok)
														printf("%ld bytes written at block %ld.\n", thesize * BytesPerBlock, theoffset);
												}
												else
													printf("Writing 0 bytes is not what I'm made for.\n");
											}
											else
												printf("Error: size of %s is not a multipler of BytesPerBlock (maybe try PAD switch).\n", (STRPTR) argarray[FILENAME]);
										}
										else
											printf("The file is empty, null size, or in any other way contains no data.\n");
									}
									else
										printf("Can't get file size.\n");

									free(buffer);
									buffer = NULL;
								}
								else
									printf("Not enough memory.\n");

								free(fib);
							}
							else
								printf("Not enough memory.\n");

							Close(thefile);
						}

					}
					else
						printf("Can't open file %s\n", (STRPTR) argarray[FILENAME]);

				}
				else							/* read */
				{
					if(!argarray[RAW])
					{


/* 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%s size is %ld bytes\n", argarray[RDBONLY]? " (only)": "", 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];

/* fix RDBBlocksLo, if broken. Main structure summing only */

										if(memrdb->rdb_RDBBlocksLo != rdbblock)
										{
#ifdef DEBUG
	printf("* Fixing RDBBlocksLo, %ld changed to %ld.\n", memrdb->rdb_RDBBlocksLo, rdbblock);
#endif
											memrdb->rdb_RDBBlocksLo = rdbblock;
											memrdb->rdb_ChkSum = 0;
											memrdb->rdb_ChkSum = CountChkSum((ULONG *) memrdb, (ULONG) memrdb->rdb_SummedLongs);

										}

										if(ChkRDBSum(memrdb, rdbblock) || 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
					{

/* RAW mode reading */

						if(thesize)
						{
							if(buffer=malloc(BytesPerBlock))
							{
								if(thefile=Open((STRPTR) argarray[FILENAME], MODE_NEWFILE))
								{
									writeok = TRUE;

									for(current=theoffset; current != theoffset+thesize; ++current)
									{
										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 =  current * BytesPerBlock;

										if(DoIO((struct IORequest *) ioreq))
										{
											printf("Device error. File not written.\n");
											writeok = FALSE;
											break;
										}

										if(!(writeok=FWrite(thefile, (STRPTR) buffer, (ULONG) BytesPerBlock, (ULONG) 1)))
										{
											printf("Write error\n");
											break;
										}

									}

									Close(thefile);
									if(writeok)
										printf("%ld bytes written to %s\n", thesize * BytesPerBlock, (STRPTR) argarray[FILENAME]);
									else
										DeleteFile((STRPTR) argarray[FILENAME]);
								}
								else
									printf("Can't open file %s\n", argarray[FILENAME]);

								free(buffer);
								buffer = NULL;
							}
							else
								printf("Not enough memory.\n");
						}
						else
							printf("For reading 0 bytes I recommend using HDToolBox.\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 existed on disk block %ld, last block %ld\n", block, ((struct RigidDiskBlock *)buffer)->rdb_HighRDSKBlock);
#endif

			return TRUE;
		}
		else
			++block;

	}
	return FALSE;

}

/* clear buffer with nulls */

void clearmem(char *mem, int size)
{
	while(size)
		mem[--size] = '\0';

}

/* list parsing... hope I didn't make a mistake here */

void ParseBBB(struct BadBlockBlock *BBB, int startblock)
{
	if((BBB->bbb_Next)!=-1)
	{
		ParseBBB((struct BadBlockBlock *) &((UBYTE *) memrdb)[((BBB->bbb_Next)-startblock)*BytesPerBlock], startblock);
		BBB->bbb_Next -= rdbshift;

		BBB->bbb_ChkSum = 0;
 	 	BBB->bbb_ChkSum = CountChkSum((ULONG *) BBB, (ULONG) BBB->bbb_SummedLongs);
	}
}

void ParsePB(struct PartitionBlock *PB, int startblock)
{
	if((PB->pb_Next)!=-1)
	{
		ParsePB((struct PartitionBlock *) &((UBYTE *) memrdb)[((PB->pb_Next)-startblock)*BytesPerBlock], startblock);
		PB->pb_Next -= rdbshift;

		PB->pb_ChkSum = 0;
  	PB->pb_ChkSum = CountChkSum((ULONG *) PB, (ULONG) PB->pb_SummedLongs);
	}
}

void ParseFHB(struct FileSysHeaderBlock *FHB, int startblock)
{
	if((FHB->fhb_Next)!=-1)
	{
		ParseFHB((struct FileSysHeaderBlock *) &((UBYTE *) memrdb)[((FHB->fhb_Next)-startblock)*BytesPerBlock], startblock);
		FHB->fhb_Next -= rdbshift;
	}

	if((FHB->fhb_SegListBlocks)!=-1)
	{
		ParseLSB((struct LoadSegBlock *) &((UBYTE *) memrdb)[((FHB->fhb_SegListBlocks)-startblock)*BytesPerBlock], startblock);
		FHB->fhb_SegListBlocks -= rdbshift;
	}

	FHB->fhb_ChkSum = 0;
	FHB->fhb_ChkSum = CountChkSum((ULONG *) FHB, (ULONG) FHB->fhb_SummedLongs);

}

void ParseLSB(struct LoadSegBlock *LSB, int startblock)
{
	if((LSB->lsb_Next)!=-1)
	{
		ParseLSB((struct LoadSegBlock *) &((UBYTE *) memrdb)[((LSB->lsb_Next)-startblock)*BytesPerBlock], startblock);
		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, int startblock)
{
	rdbok = TRUE;

	if(!SumOK((ULONG *) RDB))
	{
#ifdef DEBUG
	printf("* Main RDB struct checksum error!\n");
#endif
		rdbok = FALSE;
		return FALSE;
	}

	if((RDB->rdb_BadBlockList) != -1)
		ChkBBBSum((struct BadBlockBlock *) &((UBYTE *)memrdb)[((RDB->rdb_BadBlockList)-startblock)*BytesPerBlock], startblock);

	if((RDB->rdb_PartitionList) != -1)
		ChkPBSum((struct PartitionBlock *) &((UBYTE *)memrdb)[((RDB->rdb_PartitionList)-startblock)*BytesPerBlock], startblock);

	if((RDB->rdb_FileSysHeaderList) != -1)
		ChkFHBSum((struct FileSysHeaderBlock *) &((UBYTE *)memrdb)[((RDB->rdb_FileSysHeaderList)-startblock)*BytesPerBlock], startblock);

	return rdbok;
}

int ChkBBBSum(struct BadBlockBlock *BBB, int startblock)
{
	if(!rdbok)
		return FALSE;

	if(!SumOK((ULONG *) BBB))
		rdbok = FALSE;

	if((BBB->bbb_Next) != -1)
		ChkBBBSum((struct BadBlockBlock *) &((UBYTE *)memrdb)[((BBB->bbb_Next)-startblock)*BytesPerBlock], startblock);

	return rdbok;
}


int ChkPBSum(struct PartitionBlock *PB, int startblock)
{
	if(!rdbok)
		return FALSE;

	if(!SumOK((ULONG *) PB))
		rdbok = FALSE;

	if((PB->pb_Next) != -1)
		ChkPBSum((struct PartitionBlock *) &((UBYTE *)memrdb)[((PB->pb_Next)-startblock)*BytesPerBlock], startblock);

	return rdbok;
}


int ChkFHBSum(struct FileSysHeaderBlock *FHB, int startblock)
{
	if(!rdbok)
		return FALSE;

	if(!SumOK((ULONG *) FHB))
		rdbok = FALSE;

	if((FHB->fhb_Next) != -1)
		ChkFHBSum((struct FileSysHeaderBlock *) &((UBYTE *)memrdb)[((FHB->fhb_Next)-startblock)*BytesPerBlock], startblock);

	if((FHB->fhb_SegListBlocks) != -1)
		ChkLSBSum((struct LoadSegBlock *) &((UBYTE *)memrdb)[((FHB->fhb_SegListBlocks)-startblock)*BytesPerBlock], startblock);

	return rdbok;
}

int ChkLSBSum(struct LoadSegBlock *LSB, int startblock)
{
	if(!rdbok)
		return FALSE;

	if(!SumOK((ULONG *) LSB))
		rdbok = FALSE;

	if((LSB->lsb_Next) != -1)
		ChkLSBSum((struct LoadSegBlock *) &((UBYTE *)memrdb)[((LSB->lsb_Next)-startblock)*BytesPerBlock], startblock);

	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;
}


