/* $Revision Header * Header built automatically - do not edit! *************
 *
 *	(C) Copyright 1990 by MXM
 *
 *	Name .....: LockDevice-Handler.c
 *	Created ..: Tuesday 26-Jun-90 14:19
 *	Revision .: 1
 *
 *	Date            Author          Comment
 *	=========       ========        ====================
 *	26-Jun-90       Olsen           Created this file!
 *
 * $Revision Header ********************************************************/

	/* Global lock segment. */

struct LockSeg			*LSeg;

	/* Prototypes. */

BYTE				StrCmp(char *a,char *b);
struct FileSysStartupMsg *	FindDevice(char *DevName);
BYTE				CreatePatch(char *DeviceName,char *PassWord);
extern VOID			NewBeginIO(VOID);
VOID *				PatchedBeginIO(struct IOExtTD *Request);
LONG				_main(VOID);

	/* StrCmp(char *a,char *b):
	 *
	 *	Do a string comparison ignoring case.
	 */

BYTE
StrCmp(char *a,char *b)
{
	for( ; toupper(*a) == toupper(*b) ; a++, b++)
	{
		if(!(*a))
			return(0);
	}

	return(1);
}

	/* FindDevice(char *DevName):
	 *
	 *	Find the environment data for filing system device.
	 */

struct FileSysStartupMsg *
FindDevice(char *DevName)
{
	char			*Pointer,Name[257];
	struct DeviceNode	*DevInfo;
	SHORT			 i;

	Forbid();

	DevInfo = (struct DeviceNode *)BADDR(((struct DosInfo *)BADDR(((struct RootNode *)DOSBase -> dl_Root) -> rn_Info)) -> di_DevInfo);

	while(DevInfo)
	{
		if(DevInfo -> dn_Type == DLT_DEVICE && DevInfo -> dn_Task && !DevInfo -> dn_Handler)
		{
			Pointer = (char *)BADDR(DevInfo -> dn_Name);

			for(i = 0 ; i < Pointer[0] ; i++)
				Name[i] = Pointer[i + 1];

			Name[Pointer[0]    ] = ':';
			Name[Pointer[0] + 1] = 0;

			if(!StrCmp(Name,DevName))
			{
				Permit();
				return(BADDR(DevInfo -> dn_Startup));
			}
		}

		DevInfo = (struct DeviceNode *)BADDR(DevInfo -> dn_Next);
	}

	Permit();

	return(NULL);
}

	/* CreatePatch(char *DeviceName,char *PassWord):
	 *
	 *	Create a BeginIO patch for a given filing device.
	 */

BYTE
CreatePatch(char *DeviceName,char *PassWord)
{
	struct Patch			*NewPatch,*TempPatch = LSeg -> RootPatch;
	struct FileSysStartupMsg	*Startup;
	char				*DriverName;

		/* Try to find the environment vector. */

	if(Startup = FindDevice(DeviceName))
	{
			/* Allocate memory for the patch. */

		if(NewPatch = (struct Patch *)AllocMem(sizeof(struct Patch),MEMF_PUBLIC | MEMF_CLEAR))
		{
				/* Allocate memory for the IORequest. */

			if(NewPatch -> Request = (struct IOExtTD *)AllocMem(sizeof(struct IOExtTD),MEMF_PUBLIC | MEMF_CLEAR))
			{
				NewPatch -> Request -> iotd_Req . io_Message . mn_Node . ln_Type	= NT_MESSAGE;
				NewPatch -> Request -> iotd_Req . io_Message . mn_Length		= sizeof(struct IOExtTD);

					/* Remember the name of the device driver. */

				DriverName = (char *)((ULONG)BADDR(Startup -> fssm_Device) + 1);

					/* Open the device driver. */

				if(!OpenDevice(DriverName,Startup -> fssm_Unit,NewPatch -> Request,Startup -> fssm_Flags))
				{
						/* Remember the device pointer. */

					NewPatch -> Device = NewPatch -> Request -> iotd_Req . io_Device;

						/* Copy the password. */

					if(PassWord)
						strcpy(NewPatch -> PassWord,PassWord);

						/* Copy the name of the filing device. */

					strcpy(NewPatch -> UnitName,DeviceName);

						/* Copy the name of the device driver. */

					strcpy(NewPatch -> DriverName,DriverName);

					Disable();

						/* Remember old BeginIO vector. */

					NewPatch -> OldBeginIO = (VOID *)SetFunction((struct Library *)NewPatch -> Device,DEV_BEGINIO,NewBeginIO);

						/* Add the patch to the patch list. */

					while(TempPatch)
					{
						if(!TempPatch -> NextPatch)
						{
							TempPatch -> NextPatch = NewPatch;

							Enable();

							return(TRUE);
						}

						TempPatch = TempPatch -> NextPatch;
					}

					LSeg -> RootPatch = NewPatch;

					Enable();

					return(TRUE);
				}

				FreeMem(NewPatch -> Request,sizeof(struct IOExtTD));
			}

			FreeMem(NewPatch,sizeof(struct Patch));
		}
	}

	return(FALSE);
}

	/* PatchedBeginIO(struct IOExtTD *Request):
	 *
	 *	Our patched BeginIO routine. Note: this code is
	 *	shared between a number of calling tasks and has
	 *	to be reentrant.
	 */

VOID *
PatchedBeginIO(struct IOExtTD *Request)
{
	struct Patch	*Patch		= LSeg -> RootPatch;
	VOID		*JumpAddress	= NULL;

	Disable();

		/* Find the patch for this device. */

	while(Patch)
	{
		if(Patch -> Device == Request -> iotd_Req . io_Device)
			break;

		Patch = Patch -> NextPatch;
	}

		/* Got it! Remember the old BeginIO vector. */

	if(Patch)
		JumpAddress = Patch -> OldBeginIO;

	Enable();

	if(!Patch)
		Request -> iotd_Req . io_Error = TDERR_NotSpecified;
	else
	{
		switch(Request -> iotd_Req . io_Command & ~TDF_EXTCOM)
		{
				/* Reject illegal commands. */

			case CMD_WRITE:
			case TD_FORMAT:
			case TD_RAWWRITE:	Request -> iotd_Req . io_Error	= TDERR_WriteProt;
						return(NULL);

				/* Disk is write protected. */

			case TD_PROTSTATUS:	Request -> iotd_Req . io_Error	= 0;
						Request -> iotd_Req . io_Actual	= ~0;
						return(NULL);

			default:		break;
		}
	}

		/* Return to the interface code. */

	return(JumpAddress);
}

	/* _main():
	 *
	 *	Handler entry point.
	 */

LONG
_main()
{
	struct Process		*ThisProcess = (struct Process *)SysBase -> ThisTask;
	ULONG			 SignalSet;

		/* Called from shell? */

	if(ThisProcess -> pr_CLI || !(LSeg = (struct LockSeg *)FindPort(PORTNAME)))
		return(-1);

		/* Initialize the global MsgPort. */

	LSeg -> SignalPort . mp_SigBit	= SIGBREAKB_CTRL_E;
	LSeg -> SignalPort . mp_SigTask	= ThisProcess;
	LSeg -> SignalPort . mp_Flags	= PA_SIGNAL;

		/* Add the child entry and ring back. */

	LSeg -> Child = (struct Task *)ThisProcess;

	Signal(LSeg -> Father,LSeg -> HandShake);

	for(;;)
	{
		SignalSet = Wait(SIG_PORT | SIG_QUIT);

			/* A new patch request came in. */

		if(SignalSet & SIG_PORT)
		{
			struct LockMsg *Message;

			while(Message = (struct LockMsg *)GetMsg(&LSeg -> SignalPort))
			{
				Message -> Success = CreatePatch(Message -> DeviceName,Message -> PassWord);

				ReplyMsg((struct Message *)Message);
			}
		}

			/* Deallocate the handler. */

		if(SignalSet & SIG_QUIT)
		{
			LSeg -> Child = NULL;

			Forbid();

			Signal(LSeg -> Father,LSeg -> HandShake);

			return(0);
		}
	}
}
