#define __USE_SYSBASE
#include <exec/memory.h>
#include <devices/hardblocks.h>
#include <dos/filehandler.h>
#include <proto/dos.h>
#include <proto/utility.h>
#include <proto/exec.h>

#define dol_Startup   dol_misc.dol_handler.dol_Startup

#include "rdb.h"
#include "disk.h"

static struct DosList *dos_node;

#define RDB(b)  ((struct RigidDiskBlock *)(b))
#define PART(b) ((struct PartitionBlock *)(b))

#define SUM_OK(b,n) (RDB(b)->rdb_SummedLongs*4 <= (n) && \
                   checkSum((ULONG *)b, RDB(b)->rdb_SummedLongs))
#define IS_RDB(b,n)  (RDB(b)->rdb_ID == IDNAME_RIGIDDISK && SUM_OK(b,n))
#define IS_PART(b,n) (PART(b)->pb_ID == IDNAME_PARTITION && SUM_OK(b,n))

static void EnvToInfo(struct DosEnvec *de, struct Partition *info)
{
	ULONG cluster, bpc;

	cluster = de->de_SectorPerBlock * de->de_SizeBlock / 128;
	bpc = de->de_Surfaces * de->de_BlocksPerTrack;

	info->block_size  = 512 * cluster;
	info->first_block = de->de_LowCyl * bpc;
	info->num_blocks  = (de->de_HighCyl-de->de_LowCyl+1) * bpc;
	info->res_blocks  = de->de_Reserved;
	info->pre_blocks  = de->de_PreAlloc;
	info->mem_type    = de->de_BufMemType;
	info->dos_type    = de->de_DosType;
}

static BOOL checkSum(ULONG *buf, LONG n)
{
	ULONG sum = 0;
	while (n-- > 0)
		sum += *buf++;
	return (BOOL)(sum == 0);
}

#define upper(x) ((x) >= 'a' && (x) <= 'z' ? (x) - ('a' - 'A') : (x))

static BOOL compName(STRPTR p, UBYTE *b)
{
	UBYTE len;
	UBYTE c1,c2;

	len = *b++;
	while (len > 0) {
		c1 = upper(*p); ++p;
		if (c1 == '\0')
			return FALSE;
		c2 = upper(*b); ++b;
		if (c1 != c2)
			return FALSE;
		--len;
	}
	if (*p != '\0')
		return FALSE;
	return TRUE;
}

BOOL getPartitionRDB(STRPTR name, struct Partition *info)
{
	ULONG i, maxkey, minkey;
	struct DosEnvec *de;
	UBYTE *buf;
	LONG bufsize;
	int n;

	bufsize = setMapping(0, 0);
	buf     = getBuffer(bufsize);
	if (!buf)
		return FALSE;

	for (i=0; i<RDB_LOCATION_LIMIT; ++i)
		if (readDisk(i, buf, bufsize) && IS_RDB(buf,bufsize))
			break;

	if (i >= RDB_LOCATION_LIMIT) {
		freeBuffer(buf);
		return FALSE;
	}

	minkey = RDB(buf)->rdb_RDBBlocksLo;
	maxkey = RDB(buf)->rdb_RDBBlocksHi;
	i = RDB(buf)->rdb_PartitionList;
	n = 0;
	while (n++ < 99 && i >= minkey && i <= maxkey) {
		if (readDisk(i, (UBYTE *)buf, bufsize) && IS_PART(buf,bufsize)) {
			if (compName(name, PART(buf)->pb_DriveName)) {
				de = (struct DosEnvec *)&PART(buf)->pb_Environment;
				/* info->device = */
				/* info->unit   = */
				info->flags  = PART(buf)->pb_DevFlags;
				EnvToInfo(de, info);
				freeBuffer(buf);
				return TRUE;
			}
			i = PART(buf)->pb_Next;
		} else
			break;
	}
	freeBuffer(buf);
	return FALSE;
}
