File:  [truecrypt] / truecrypt / driver vxd / tc9x.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:37:52 2018 UTC (8 years, 3 months ago) by root
Branches: drWhax, MAIN
CVS tags: v1_0, HEAD
1.0

/* Copyright (C) 2004 TrueCrypt Team, truecrypt.org
   This product uses components written by Paul Le Roux <[email protected]> 
   Majority of this code originally Copyright (C) 1998/9 by Aman. Used with
   permission. Other parts originally Copyright (C) 1995 by Walter Oney used
   with implied permission. */

#include "TCdefs.h"

#pragma VxD_LOCKED_CODE_SEG
#pragma VxD_LOCKED_DATA_SEG

#include "crypto.h"
#include "fat.h"
#include "volumes.h"
#include "cache.h"
#include "apidrvr.h"
#include "tc9x.h"
#include "queue.h"

#include "ifshook.h"
#include "ifsmgr.inc"


#define NUMSLOTS        8	/* Only up to 8 volumes at a time */
#define MAXBLOCK        128	/* 64k  was 256.... */

#define MAX_MESSAGES    8	/* Max number of queued driver messages */

#define DEVICE_TYPE     0	/* We are a fixed disk (even files on
				   removables) */

#ifdef DEBUG
#define EXTRA_INFO 1
#endif

int halfseccount=0xc9;

char *transferbuffer = NULL;	/* IO transfer buffer */
char *appaccessbuffer = NULL;	/* win32 GUI IO buffer */
char *partitiontestbuffer = NULL;	/* Buffer for the MBR */
int dcbcount = 0;		/* DCB hack */
PDCB dcblist[128];		/* DCB hack */

PDCB dcb_boot;			/* Boot device */

extern DRP theDRP;		/* Device registration packet */

int bAllowFastShutdown = 0;

cryptvol cv1 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv2 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv3 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv4 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv5 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv6 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv7 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol cv8 =
{0, 0, 0, 0, 0, 0, 0, 0};

cryptvol *cryptvols[]=
{
	&cv1,
	&cv2,
	&cv3,
	&cv4,
	&cv5,
	&cv6,
	&cv7,
	&cv8
};

typedef struct MessageBox_t
{
	char *MessageHdr;
	char *MessageBody;
	int PostPlease;
} MessageBox;

MessageBox Msgs[MAX_MESSAGES];


VOID
OnAsyncRequest (PAEP aep)
{
	typedef USHORT (*PEF) (PAEP);

	static PEF evproc[AEP_MAX_FUNC + 1] =
	{(PEF) OnInitialize	/* 0 AEP_INITIALIZE */
	 ,NULL			/* 1 AEP_SYSTEM_CRIT_SHUTDOWN */
	 ,(PEF) OnBootComplete	/* 2 AEP_BOOT_COMPLETE */
	 ,(PEF) OnConfigDcb	/* 3 AEP_CONFIG_DCB */
	 ,(PEF) OnUnconfigDcb	/* 4 AEP_UNCONFIG_DCB */
	 ,NULL			/* 5 AEP_IOP_TIMEOUT */
	 ,NULL			/* 6 AEP_DEVICE_INQUIRY */
	 ,(PEF) OnHalfSec	/* 7 AEP_HALF_SEC */
	 ,NULL			/* 8 AEP_1_SEC */
	 ,NULL			/* 9 AEP_2_SECS */
	 ,NULL			/* 10 AEP_4_SECS */
	 ,NULL			/* 11 AEP_DBG_DOT_CMD */
	 ,NULL			/* 12 AEP_ASSOCIATE_DCB */
	 ,NULL			/* 13 AEP_REAL_MODE_HANDOFF */
	 ,(PEF) OnSystemExit	/* 14 AEP_SYSTEM_SHUTDOWN */
	 ,(PEF) OnUninitialize	/* 15 AEP_UNINITIALIZE */
	 ,NULL			/* 16 AEP_DCB_LOCK */
	 ,NULL			/* 17 AEP_MOUNT_VERIFY */
	 ,NULL			/* 18 AEP_CREATE_VRP */
	 ,NULL			/* 19 AEP_DESTROY_VRP */
	 ,NULL			/* 20 AEP_REFRESH_DRIVE */
	 ,NULL			/* 21 AEP_PEND_UNCONFIG_DCB */
	 ,NULL			/* 22 AEP_1E_VEC_UPDATE */
	 ,NULL			/* 23 AEP_CHANGE_RPM */
	};
	PEF proc;

	if (aep->AEP_func < arraysize (evproc) && (proc = evproc[aep->AEP_func]))
		aep->AEP_result = proc (aep);
	else
		aep->AEP_result = (USHORT) AEP_FAILURE;
}


USHORT
OnInitialize (PAEP_bi_init aep)
{
	/* allocate our (smaller) memory buffer..... */

	static int initalready = 0;

	if (initalready)
		return AEP_SUCCESS;

	initalready++;

	transferbuffer = (char *) _PageAllocate (50, PG_SYS, 0, 0, 0, MBYTE16, NULL, PAGEZEROINIT | PAGEFIXED | PAGECONTIG | PAGEUSEALIGN);
	partitiontestbuffer = (char *) transferbuffer + (265 * 512);
	appaccessbuffer = transferbuffer + (265 * 512);


	if (transferbuffer)
		return AEP_SUCCESS;

	return (USHORT) AEP_FAILURE;
}

USHORT
OnUninitialize (PAEP_bi_uninit aep)
{
	return AEP_SUCCESS;
}

/* asks us if we want to stay loaded or not. */

USHORT
OnBootComplete (PAEP_boot_done aep)
{
	installhook ();
	return AEP_SUCCESS;
}

USHORT
OnConfigDcb (PAEP_dcb_config aep)
{
	PDCB dcb = (PDCB) aep->AEP_d_c_dcb;
	if (!(dcb->DCB_cmn.DCB_device_flags & DCB_DEV_PHYSICAL))
	{
		return AEP_SUCCESS;
	}

	/* Sadly for SCSI some port drivers have not set apparent_blk_shift
	   up at this point.. if  ((dcb->DCB_cmn.DCB_apparent_blk_shift!=9)
	   && (dcb->DCB_cmn.DCB_device_type!=DCB_type_cdrom) ) return
	   AEP_SUCCESS; */

	if (dcbcount < 100)
	{
		if ((dcb->DCB_cmn.DCB_device_type == 0) || (dcb->DCB_cmn.DCB_device_type == DCB_type_cdrom))
		{
			if (cmpvend ((char *) &dcb->DCB_vendor_id, "JETICO", 6) != 0)
			{
				if (CheckDcbAlready (dcb))
					return AEP_SUCCESS;
				dcblist[dcbcount] = dcb;
				dcblist[dcbcount + 1] = NULL;
				dcbcount++;
			}
		}
	}


	if (dcb->DCB_cmn.DCB_device_type == 0)
		((IspInsertCalldown (dcb, OnRequest, (PDDB) aep->AEP_d_c_hdr.AEP_ddb, 0,
		    dcb->DCB_cmn.DCB_dmd_flags, aep->AEP_d_c_hdr.AEP_lgn)));

	return AEP_SUCCESS;
}

/* AEP_UNCONFIG_DCB informs us that the physical device represented by a DCB
   is going away */

USHORT
OnUnconfigDcb (PAEP_dcb_unconfig aep)
{
	return AEP_SUCCESS;
}

VOID
OnRequest (PIOP iop)
{
	DoCallDown (iop);	/* do normal unencryped disk stuff... */
}

int
cmpvend (char *a, char *b, int len)
{
	int n;
	for (n = 0; n < len; n++)
		if (a[n] != b[n])
			return 1;
	return 0;
}


int
CheckDcbAlready (PDCB dcb)
{
	int n;
	/* sometimes the same dcb is passed more than once, on some drivers!! */
	if (!dcbcount)
		return 0;

	for (n = 0; n < dcbcount; n++)
		if (dcblist[n] == dcb)
			return 1;

	return 0;
}

/* DoCallDown passes a request to the next lower layer. Note that the
   documentation about how to do this is totally wrong: you don't just add
   sizeof(DCB_cd_entry) to the calldown pointer, you follow a linked list
   from one calldown entry to the next. */

void
DoCallDown (PIOP iop)
{
	_asm
	{			/* call down to next layer */
		pushfd
		pushad
		mov ecx,[iop]
		mov eax,[ecx] IOP.IOP_calldown_ptr
		  mov eax,[eax] DCB_cd_entry.DCB_cd_next
		  mov[ecx] IOP.IOP_calldown_ptr, eax
		  push ecx
		  call[eax] DCB_cd_entry.DCB_cd_io_address
		  add esp, 4
		  popad
		  popfd
	}
}

  BOOL
OnSysDynamicDeviceInit ()
{
	cv1.cryptsectorfirst = 0x7fffffff;
	cv1.cryptsectorlast = 0;

	cv2.cryptsectorfirst = 0x7fffffff;
	cv2.cryptsectorlast = 0;

	cv3.cryptsectorfirst = 0x7fffffff;
	cv3.cryptsectorlast = 0;

	cv4.cryptsectorfirst = 0x7fffffff;
	cv4.cryptsectorlast = 0;

	cv5.cryptsectorfirst = 0x7fffffff;
	cv5.cryptsectorlast = 0;

	cv6.cryptsectorfirst = 0x7fffffff;
	cv6.cryptsectorlast = 0;

	cv7.cryptsectorfirst = 0x7fffffff;
	cv7.cryptsectorlast = 0;

	cv8.cryptsectorfirst = 0x7fffffff;
	cv8.cryptsectorlast = 0;

	IOS_Register (&theDRP);
	return TRUE;		/* stay resident no matter what IOS says */
}

BOOL
OnSysDynamicDeviceExit ()
{
	return TRUE;
}

DWORD
OnDeviceIoControl (PDIOCPARAMETERS p)
{
	installhook ();		/* make sure hook is installed */
	InstallTCThread ();

	/* select on IOCTL code */
	switch (p->dwIoControlCode)
	{

	case 0:		/* VWIN32 pinging us during CreateFile */
	case -1:		/* CloseHandle */
		break;

	case ALLOW_FAST_SHUTDOWN:
		{
			bAllowFastShutdown = 1;
			break;
		}

	case DRIVER_VERSION:
		{
			LONG *tmp = (LONG *) p->lpvInBuffer;
			LONG tmp2 = VERSION_NUM;

			if (tmp == NULL)
				return ERROR_GEN_FAILURE;

			memcpy (tmp, &tmp2, 4);
			break;
		}

	case WIPE_CACHE:
		WipeCache ();
		break;

	case CACHE_STATUS:
		return cacheEmpty ? ERROR_GEN_FAILURE : 0;

	case DISKIO:		/* Call to read and write sectors from
				   application */
		{
			DISKIO_STRUCT *dio = (DISKIO_STRUCT *) p->lpvInBuffer;
			int s;

			if (dio == NULL)
				return ERROR_GEN_FAILURE;

			s = AppAccessBlockDevice (dio->devicenum, dio->sectorstart, dio->sectorlen, dio->bufferad, dio->mode);
			dio->nReturnCode = s;

			break;
		}

	case OPEN_TEST:
		{
			OPEN_TEST_STRUCT *item = (OPEN_TEST_STRUCT *) p->lpvInBuffer;
			unsigned long *tmp = (void *) partitiontestbuffer;
			MOUNT_STRUCT mount;

			if (item == NULL)
				return ERROR_GEN_FAILURE;

			strcpy ((char *) mount.wszVolume, (char *) item->wszFileName);

			item->nReturnCode = ERR_BAD_DRIVE_LETTER;

			readallpartitions (&mount, TRUE);

			item->nReturnCode = mount.nReturnCode;

			item->secstart = tmp[0];
			item->seclast = tmp[1];
			item->device = tmp[2];

			break;
		}

	case MOUNT_LIST_N:
		{
			MOUNT_LIST_N_STRUCT *item = (MOUNT_LIST_N_STRUCT *) p->lpvInBuffer;
			cryptvol *cv;
			int c;

			if (item == NULL)
				return ERROR_GEN_FAILURE;

			item->nReturnCode = ERR_BAD_DRIVE_LETTER;

			for (c = 0; c < NUMSLOTS; c++)
			{
				cv = cryptvols[c];

				if ((cv->booted == 0) && (cv->physdevDCB == 0))
					continue;

				if (item->nDosDriveNo == cv->drive)
				{
					/* 16/9/99 This is safe as
					   item->wszVolume is >
					   cv->mounted_file_name */
					strcpy ((char *) item->wszVolume, cv->mounted_file_name);
					item->nReturnCode = 0;
					break;
				}
			}

			break;
		}

	case RELEASE_TIME_SLICE:
		ReleaseTimeSlice ();
		break;

	case MOUNT:
		{
			MOUNT_STRUCT *mount = (MOUNT_STRUCT *) p->lpvInBuffer;
			char tmp[9];

			if (mount == NULL)
				return ERROR_GEN_FAILURE;

#if EXTRA_INFO
			_Debug_Printf_Service ("MOUNT\n");
#endif

			memcpy (tmp, (char *) mount->wszVolume, 8);
			tmp[8] = 0;

			if (strcmp (tmp, "\\Device\\") == 0)
				readallpartitions (mount, FALSE);
			else
				mountdiskfileR0 (mount);

            if (mount->nReturnCode == 0 &&  bAllowFastShutdown == 1)
            {
                IFSMgr_PNPEvent (DBT_DEVICEARRIVAL, mount->nDosDriveNo, PNPT_VOLUME | DBTF_MEDIA );
            }


#if EXTRA_INFO
			_Debug_Printf_Service ("MOUNT end\n");
#endif

			break;
		}

	case UNMOUNT:
	case UNMOUNT_PENDING:
		{
			UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) p->lpvInBuffer;
			cryptvol *cv;
			int c;

			if (unmount == NULL)
				return ERROR_GEN_FAILURE;

			unmount->nReturnCode = ERR_BAD_DRIVE_LETTER;

			for (c = 0; c < NUMSLOTS; c++)
			{
				cv = cryptvols[c];

				if ((cv->booted == 0) && (cv->physdevDCB == 0))
					continue;

				if (unmount->nDosDriveNo == cv->drive)
				{
					if (p->dwIoControlCode == UNMOUNT_PENDING)
					{
						if (closeCrDevice (cv, 0) != 0)
							unmount->nReturnCode = ERR_FILES_OPEN;
						else
							unmount->nReturnCode = 0;
					}
					else
					{
						if (closeCrDevice (cv, 1) != 0)
							unmount->nReturnCode = ERR_FILES_OPEN;
						else
							unmount->nReturnCode = 0;
					}

					break;
				}
			}

			break;
		}

	case MOUNT_LIST:
		{
			MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) p->lpvInBuffer;
			cryptvol *cv;
			int c;

			if (list == NULL)
				return ERROR_GEN_FAILURE;

			list->ulMountedDrives = 0;

			for (c = 0; c < NUMSLOTS; c++)
			{
				int nDosDriveNo;

				cv = cryptvols[c];

				if ((cv->booted == 0) && (cv->physdevDCB == 0))
					continue;

				nDosDriveNo = cv->drive;

				list->ulMountedDrives |= 1 << nDosDriveNo;

				if (strlen (cv->mounted_file_name) < 64)
				{
					strcpy ((char *) list->wszVolume[nDosDriveNo], cv->mounted_file_name);
				}
				else
				{
					memcpy ((char *) list->wszVolume[nDosDriveNo], cv->mounted_file_name, 60);
					((char *) list->wszVolume[nDosDriveNo])[60] = '.';
					((char *) list->wszVolume[nDosDriveNo])[61] = '.';
					((char *) list->wszVolume[nDosDriveNo])[62] = '.';
					((char *) list->wszVolume[nDosDriveNo])[63] = 0;
				}

				list->cipher[nDosDriveNo] = cv->cryptoInfo->cipher;

				if(!cv->mountfilehandle)
					list->diskLength[nDosDriveNo] = (cv->cryptsectorlast - cv->cryptsectorfirst) * 512I64;
				else
					list->diskLength[nDosDriveNo] = 0;

				list->cipher[nDosDriveNo] = cv->cryptoInfo->cipher;

			}

			break;
		}

	case VOLUME_PROPERTIES:
		{
			VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) p->lpvInBuffer;
			cryptvol *cv;
			int c;

			if (prop == NULL)
				return ERROR_GEN_FAILURE;

			for (c = 0; c < NUMSLOTS; c++)
			{
				int nDosDriveNo;

				cv = cryptvols[c];

				if ((cv->booted == 0) && (cv->physdevDCB == 0))
					continue;

				nDosDriveNo = cv->drive;

				if (nDosDriveNo != prop->driveNo)
					continue;

				if (strlen (cv->mounted_file_name) < 64)
				{
					strcpy ((char *) prop->wszVolume, cv->mounted_file_name);
				}
				else
				{
					memcpy ((char *) prop->wszVolume, cv->mounted_file_name, 60);
					((char *) prop->wszVolume)[60] = '.';
					((char *) prop->wszVolume)[61] = '.';
					((char *) prop->wszVolume)[62] = '.';
					((char *) prop->wszVolume)[63] = 0;
				}

				prop->cipher = cv->cryptoInfo->cipher;

				if(!cv->mountfilehandle)
					prop->diskLength = (cv->cryptsectorlast - cv->cryptsectorfirst) * 512I64;
				else
					prop->diskLength = 0;

				prop->cipher = cv->cryptoInfo->cipher;
				prop->pkcs5 = cv->cryptoInfo->pkcs5;
				prop->pkcs5Iterations = cv->cryptoInfo->noIterations;
				prop->volumeCreationTime = cv->cryptoInfo->volume_creation_time;
				prop->headerCreationTime = cv->cryptoInfo->header_creation_time;

				return 0;
			}

			return ERROR_GEN_FAILURE;
		}


	default:
		return ERROR_INVALID_FUNCTION;

	}

	return 0;
}

BOOL
Kill_Drive (cryptvol * cv)
{
	BOOL result = FALSE;

	if (cv->booted != 0 || cv->physdevDCB != 0)
	{
		if ((cv->drive >= 0) && (cv->drive < 26))
		{
			result = IspDisassociateDcb (cv->drive);
			if (cv->mountfilehandle)
				R0_CloseFile (cv->mountfilehandle);

			if (result == TRUE)
			{
				PDCB dcb;

				if (!cv->mountfilehandle)
					unlockdrive (cv);	/* files to be handled
								   by win32 app. */

				crypto_close (cv->cryptoInfo);

				dcb = cv->ldcb;
				dcb->DCB_Port_Specific = 0;
				memset (cv, 0, sizeof (cryptvol));
				cv->cryptsectorfirst = 0x7fffffff;
			}
		}
	}

	return result;
}

int
closeCrDevice (cryptvol * cv, int mode)
{
	if (mode == 0)		/* pre flush volume call..... */
	{
		if (cv->drive != 0)
		{
			if (cv->booted <= 2)
			{
				_VolFlush (cv->drive, 0);	/* flush stuff out
								   before the
								   dismount... */
				//%% NotifyVolumeRemoval (cv->drive);
			}
			return 0;
		}
		else
			return 1;
	}
	else
	{
		if (Kill_Drive (cv) == TRUE)
			return 0;
		else
			return 0x42424242;
	}
}

int
installthread (void *t)
{
	int id;
	_asm
	{
		mov ecx, 4096
		  mov edi, 0
		  mov ebx,[t];
		xor esi, esi
	}

	  VxDCall (_VWIN32_CreateRing0Thread)
	_asm mov[id], eax
	  return id;
}

void
sectorcopy (char *dest, char *source, int num)
{
	_asm
	{
		pushad
		mov edi,[dest]
		mov esi,[source]
		mov ecx,[num]
		shl ecx, 9	/* *512 */
		  sar ecx, 4	/* 16 in pass... */
		  cpylp:
		  mov eax,[esi]
		mov ebx,[esi + 4]
		  mov[edi], eax
		  mov[edi + 4], ebx
		  mov eax,[esi + 8]
		mov ebx,[esi + 12]
		  mov[edi + 8], eax
		  mov[edi + 12], ebx
		  add edi, 16
		  add esi, 16
		  dec ecx
		  jnz cpylp
		  popad
	}
}

void
cryptproc (PIOP iop, cryptvol * cv)
{
	PDCB dcbx;
	unsigned int buffernum, totalsectors;
	unsigned int sectorstart, sectorcount;
	char *outbuffer, *bufadr, *buffercopy;
	_BlockDev_Scatter_Gather *sgd;

	dcbx = (PDCB) iop->IOP_physical_dcb;
	ior.IOR_status = 0;
	if (ior.IOR_func == IOR_WRITEV)
	{
		ior.IOR_status = IORS_INVALID_COMMAND;
		return;
	}

	sectorcount = ior.IOR_xfer_count;

	if (!sectorcount)
	{
		ior.IOR_status = 0;
		return;
	}

	if ((ior.IOR_func == IOR_READ) || (ior.IOR_func == IOR_WRITE))
	{
		if (iop->IOP_ior.IOR_flags & IORF_CHAR_COMMAND)
		{
			ior.IOR_status = IORS_INVALID_COMMAND;
			return;	/* Char command NOT supported or needed.... */
		}
	}
	else
	{
		ior.IOR_status = 0;
		if (!cv->mountfilehandle)
			DoCallDown (iop);
		return;
	}

	if (ior.IOR_func == IOR_READ)
	{
		sectorstart = ior.IOR_start_addr[0];
		sectorcount = ior.IOR_xfer_count;
		outbuffer = (char *) ior.IOR_buffer_ptr;	/* may be scatter gather
								   pointer... */
		if (ior.IOR_flags & IORF_SCATTER_GATHER)
		{
			sgd = (_BlockDev_Scatter_Gather *) outbuffer;
			while ((sectorcount = sgd->BD_SG_Count))
			{
				outbuffer = (char *) sgd->BD_SG_Buffer_Ptr;
				inblock (iop, outbuffer, sectorstart, sectorcount, cv);

				if (sectorstart == 0)
				{
					(unsigned char) outbuffer[0] = 0xeb;
					outbuffer[1] = 0x3c;
					(unsigned char) outbuffer[2] = 0x90;

					outbuffer[510] = 0x55;	/* boot sector
								   bodge...... */
					(unsigned char) outbuffer[511] = 0xAA;
				}

				sectorstart += sectorcount;
				++sgd;
			}
		}
		else
			/* linear buffer     */
		{
			inblock (iop, outbuffer, sectorstart, sectorcount, cv);

			/* The following code LIES to win98, who won't
			   otherwise mount disks created by earlier versions,
			   because the boot sector had stuff missing.  (fixed
			   now...) */
			if (sectorstart == 0)
			{
				(unsigned char) outbuffer[0] = 0xeb;
				outbuffer[1] = 0x3c;
				(unsigned char) outbuffer[2] = 0x90;
				outbuffer[510] = 0x55;
				(unsigned char) outbuffer[511] = 0xAA;
			}
		}
	}			/* end read op */
	else if (ior.IOR_func == IOR_WRITE)
	{
		if (cv->booted == 0)
		{
			ior.IOR_status = 0;
			return;
		}

		buffernum = 0;

		bufadr = transferbuffer;
		bufadr += (buffernum * (MAXBLOCK * 512));
		sectorstart = ior.IOR_start_addr[0];
		sectorcount = ior.IOR_xfer_count;
		outbuffer = (char *) ior.IOR_buffer_ptr;	/* may be scatter gather
								   pointer...; */
		totalsectors = 0;
		buffercopy = bufadr;

		if (ior.IOR_flags & IORF_SCATTER_GATHER)
		{
			sgd = (_BlockDev_Scatter_Gather *) outbuffer;
			while ((sectorcount = sgd->BD_SG_Count))
			{
				outbuffer = (char *) sgd->BD_SG_Buffer_Ptr;
				if ((totalsectors + sectorcount) <= MAXBLOCK)
				{
					sectorcopy (buffercopy, outbuffer, sectorcount);
					totalsectors += sectorcount;
					buffercopy += sectorcount * 512;
				}
				else
					/* write any previous buffer..... */
				{
					if (totalsectors)	/* was it too big to
								   start with ? */
					{
						outblock (iop, bufadr, sectorstart, totalsectors, cv, NULL);

						buffernum = 0;

						bufadr = transferbuffer;
						bufadr += (buffernum * (MAXBLOCK * 512));
						sectorstart += totalsectors;
						totalsectors = 0;
						buffercopy = bufadr;
						--sgd;	/* back to previous for
							   next pass..... */
					}
					else
					{	/* initial buffer was too
						   big, to start with! */
						outblock (iop, outbuffer, sectorstart, sectorcount, cv, bufadr);

						buffernum = 0;

						bufadr = transferbuffer;
						bufadr += (buffernum * (MAXBLOCK * 512));
						sectorstart += sectorcount;
						buffercopy = bufadr;
					}

				}
				++sgd;
			}	/* end while  */

			if (totalsectors)
				outblock (iop, bufadr, sectorstart, totalsectors, cv, NULL);	/* last one ? */
		}		/* end if scatter gather */
		else
			/* not scatter gather but is linear buffer */
		{

			outblock (iop, outbuffer, sectorstart, sectorcount, cv, bufadr);	/* get it to copy and do
												   large bit... */
		}
	}			/* end write op */

}

/* DoCallBack handles completion of an I/O request by calling the previous
   level's callback routine. */

void
DoCallBack (PIOP iop)
{
	_asm
	{			/* call back to previous layer */
		pushfd
		pushad
		mov ecx,[iop]
		sub[ecx] IOP.IOP_callback_ptr, size IOP_callback_entry
		mov eax,[ecx] IOP.IOP_callback_ptr
		push ecx
		call[eax] IOP_callback_entry.IOP_CB_address
		add esp, 4
		popad
		popfd

	}
}

VOID
partfilerequest (PIOP iop)
{
	PDCB dcb;
	cryptvol *cv;

	dcb = (PDCB) iop->IOP_physical_dcb;
	cv = (cryptvol *) dcb->DCB_Port_Specific;


	if ((cv != &cv1) && (cv != &cv2) && (cv != &cv3) && (cv != &cv4) && (cv != &cv5) && (cv != &cv6) && (cv != &cv7) && (cv != &cv8))
	{
		DoCallDown (iop);
		return;
	}

	if (cv->booted > 2)
	{
		ior.IOR_status = IORS_NOT_READY;	/* HW_FAILURE; */
		DoCallBack (iop);
		return;
	}

	if (ior.IOR_func == IOR_COMPUTE_GEOM)
	{
		dcb->DCB_actual_sector_cnt[0] = cv->cryptsectorlast - cv->cryptsectorfirst;
		dcb->DCB_actual_sector_cnt[0]++;
		dcb->DCB_actual_sector_cnt[1] = 0;
		dcb->DCB_actual_blk_size = 512;
		dcb->DCB_actual_head_cnt = 1;	/* number of heads */
		dcb->DCB_actual_cyl_cnt = 1;	/* number of cylinders */
		dcb->DCB_cmn.DCB_apparent_blk_shift = 9;
		dcb->DCB_cmn.DCB_TSD_Flags |= DCB_TSD_ACTUAL_PRE_SET;
		ior.IOR_status = IORS_SUCCESS;
		DoCallBack (iop);
		return;
	}

	if (ior.IOR_func == IOR_GEN_IOCTL)
	{
		iop->IOP_ior.IOR_ioctl_return = 01;
		ior.IOR_status = IORS_INVALID_PARM;	/* All the time now....  */
		DoCallBack (iop);
		return;
	}

	if ((ior.IOR_func == IOR_READ) || (ior.IOR_func == IOR_WRITE))
	{
		dcb = (PDCB) iop->IOP_physical_dcb;
		ior.IOR_status = IORS_CMD_IN_PROGRESS;	/* 0     */

		dcb->DCB_cmn.DCB_device_flags |= DCB_DEV_IO_ACTIVE;
		QueueMyIop (iop);
		return;
	}

	if ((ior.IOR_func == IOR_MEDIA_CHECK) || (ior.IOR_func == IOR_MEDIA_CHECK_RESET))
	{
		dcb = (PDCB) iop->IOP_original_dcb;

		ior.IOR_status = IORS_UNCERTAIN_MEDIA;	/* IORS_SUCCESS; */
		DoCallBack (iop);
		return;
	}

	ior.IOR_status = IORS_INVALID_COMMAND;
	DoCallBack (iop);
	return;
}

int
Add_Drive (PDCB dcb, cryptvol * cv, int prefdrive)
{
	int md = 0;
	PDCB ldcb;
	unsigned int flags;
	unsigned int dmdbits;
	ldcb = &cv->logicaldcb;
	cv->ldcb = ldcb;

#if EXTRA_INFO
	_Debug_Printf_Service ("Add_Drive\n");
#endif

	if (1)
	{
		ldcb = &cv->logicaldcb;
		flags = ldcb->DCB_cmn.DCB_device_flags;

		if (dcb)
			memcpy ((char *) ldcb, (char *) dcb, sizeof (DCB));

		ldcb->DCB_cmn.DCB_device_flags = flags;
		flags = dcb->DCB_cmn.DCB_device_flags;
		dmdbits = dcb->DCB_cmn.DCB_dmd_flags;
		dmdbits &= ~DCB_dmd_phys_sgd;
		cv->ldcb = ldcb;
		if (!cv->mountfilehandle)
			IspInsertCalldown (ldcb, partfilerequest, (PDDB) & cv->addb,
				 (USHORT) dcb->DCB_cmn.DCB_expansion_length,
					   dmdbits, (UCHAR) DRP_VSD_3);
		else
			IspInsertCalldown (ldcb, partfilerequest, (PDDB) & cv->addb, 0,
					   0, (UCHAR) DRP_VSD_3);

		ldcb->DCB_Port_Specific = (ULONG) cv;
		ldcb->DCB_cmn.DCB_physical_dcb = (ULONG) ldcb;
		ldcb->DCB_max_xfer_len = MAXBLOCK * 512;	/* 256*512 */

		if ((dcb->DCB_max_xfer_len < MAXBLOCK * 512) && (cv->mountfilehandle == 0))
			ldcb->DCB_max_xfer_len = dcb->DCB_max_xfer_len;

		if (!cv->mountfilehandle)
		{
			ldcb->DCB_max_sg_elements = dcb->DCB_max_sg_elements;	/* 1; */
			ldcb->DCB_cmn.DCB_expansion_length = dcb->DCB_cmn.DCB_expansion_length;
			ldcb->DCB_cmn.DCB_dmd_flags = dmdbits;
		}
		else
			ldcb->DCB_max_sg_elements = 17;

		ldcb->DCB_cmn.DCB_device_flags |= DCB_DEV_PHYSICAL;
		ldcb->DCB_cmn.DCB_device_flags2 = 0;
		ldcb->DCB_cmn.DCB_device_flags &= ~DCB_DEV_REMOVABLE;	/* support removable as
									   fixed... */
		ldcb->DCB_cmn.DCB_device_type = DEVICE_TYPE;
		ldcb->DCB_cmn.DCB_user_drvlet = (USHORT) md;
		ldcb->DCB_cmn.DCB_partition_type = 0;
		ldcb->DCB_cmn.DCB_Sstor_Host = 0;
		ldcb->DCB_actual_sector_cnt[0] = 0;
		ldcb->DCB_actual_sector_cnt[0]++;
		ldcb->DCB_actual_sector_cnt[1] = 0;
		ldcb->DCB_actual_blk_size = 512;
		ldcb->DCB_actual_head_cnt = 1;	/* number of heads */
		ldcb->DCB_actual_cyl_cnt = 1;	/* number of cylinders */
		ldcb->DCB_cmn.DCB_apparent_blk_shift = 9;
		ldcb->DCB_actual_spt = ldcb->DCB_actual_sector_cnt[0];
		ldcb->DCB_bdd.DCB_apparent_sector_cnt[0] = ldcb->DCB_actual_sector_cnt[0];
		ldcb->DCB_bdd.DCB_apparent_sector_cnt[1] = 0;
		ldcb->DCB_bdd.DCB_apparent_head_cnt = 1;
		ldcb->DCB_bdd.DCB_apparent_blk_size = 512;
		ldcb->DCB_bdd.DCB_apparent_cyl_cnt = 1;
		ldcb->DCB_bdd.DCB_apparent_spt = ldcb->DCB_actual_sector_cnt[0];
	}

	ldcb->DCB_cmn.DCB_drive_lttr_equiv = 0;
	ldcb->DCB_cmn.DCB_user_drvlet = 0;
	ldcb->DCB_cmn.DCB_device_type = DEVICE_TYPE;

	if (prefdrive != -1)
		md = IspDriveLetterPickPref (ldcb, (UCHAR) ISP_PDL_FL_USE_RANGE, (UCHAR) prefdrive);
	else
		md = (unsigned char) 255;


	if (md == 255)
		md = IspDriveLetterPick (ldcb, 0);

	ldcb->DCB_cmn.DCB_unit_number = (UCHAR) md;
	ldcb->DCB_cmn.DCB_vrp_ptr = 0;	/* clear the copied VRP pointer...... */
	ldcb->DCB_cmn.DCB_device_flags |= DCB_DEV_WRITEABLE;

	if (!(flags & DCB_DEV_WRITEABLE))
		ldcb->DCB_cmn.DCB_device_flags &= ~DCB_DEV_WRITEABLE;

	ldcb->DCB_cmn.DCB_drive_lttr_equiv = md;
	ldcb->DCB_cmn.DCB_user_drvlet = (UCHAR) md;
	ldcb->DCB_cmn.DCB_unit_number = (UCHAR) md;	/* 0;  */

	cv->drive = (ULONG) md;
	ldcb->DCB_cmn.DCB_TSD_Flags = DCB_TSD_APPARENT_PRE_SET | DCB_TSD_MBPB_PBR;
	ldcb->DCB_cmn.DCB_partition_type = 0;
	ldcb->DCB_cmn.DCB_device_flags &= ~DCB_DEV_TSD_PROCESSED;
	ldcb->DCB_cmn.DCB_Partition_Start = 0;
	ldcb->DCB_cmn.DCB_device_flags |= DCB_DEV_LOGICAL | DCB_DEV_MEDIA_CHANGED | DCB_DEV_UNCERTAIN_MEDIA;

	ldcb->DCB_cmn.DCB_cAssoc = 1;

	ldcb->DCB_cmn.DCB_user_drvlet = 0xFF;

#if EXTRA_INFO
	_Debug_Printf_Service ("Add_Drive end\n");
#endif

	if ((md <= 26) && (md > 1))
	{
		IspAssociateDcb (ldcb, (char) md, ISP_D_A_FL_NOSHELLMSG);

		cv->notifytime = 2;	/* 2 second to notify arrival of disk */

		return 0;
	}

	return 1;
}

#define FIRST_READ_SIZE SECTOR_SIZE

int
trymountfile (PDCB dcb, cryptvol * cv, MOUNT_STRUCT * mf)
{
	USHORT offset;
	USHORT size;
	PIOP myiop;
	PIOR myior;
	int mounted = 0;
	char *readBuffer = NULL;

	if (dcb->DCB_cmn.DCB_device_type == DCB_type_disk)
	{
		int status;

		offset = (USHORT) (dcb->DCB_cmn.DCB_expansion_length + FIELDOFFSET (IOP, IOP_ior));
		size = offset + sizeof (IOR) + dcb->DCB_max_sg_elements * sizeof (SGD);
		myiop = IspCreateIop (size, offset, ISP_M_FL_MUST_SUCCEED | ISP_M_FL_SMART_ALLOC | ISP_M_FL_INTERRUPT_TIME | ISP_M_FL_PERSISTENT_IOP);
		myior = &myiop->IOP_ior;
		myior->IOR_private_client = offset;

		readBuffer = TCalloc (FIRST_READ_SIZE);
		if (readBuffer == NULL)
			goto error;

		dophysblock (myiop, cv->cryptsectorfirst, FIRST_READ_SIZE / 512, readBuffer, cv, IOR_READ);

		status = VolumeReadHeaderCache (mf->bCache, readBuffer, mf->szPassword,
					 mf->nPasswordLen, &cv->cryptoInfo);

		if (status != 0)
		{
			memset (cv, 0, sizeof (cryptvol));
			cv->cryptsectorfirst = 0x7fffffff;
			mounted = 0;
			goto error;
		}
		else
			cv->booted = 1;

		if (Add_Drive (dcb, cv, mf->nDosDriveNo) == 0)
		{
			mounted = 1;
		}
		else
		{
			/* No Drive letter available */
			memset (cv, 0, sizeof (cryptvol));
			cv->cryptsectorfirst = 0x7fffffff;
			mounted = -1;
		}

	      error:
		if (readBuffer != NULL)
			TCfree (readBuffer);

		IspDeallocMem ((PVOID) ((DWORD) myior - myior->IOR_private_client));
		return mounted;
	}

	return mounted;
}

void
readnullfilesize (int hand)
{
	int bytes;
	char buffer[512];
	R0_ReadFile (FALSE, hand, 0, 0, buffer, &bytes);
}

void
mountdiskfileR0 (MOUNT_STRUCT * mf)
{
	DWORD hfile;
	DWORD action;
	int tmf;
	int code;
	cryptvol *cv;
	int c;
	int writeable = 1;
	PDCB dcb;
	int flag = 0;
	unsigned char openflag = 0x81;

	char *fname = (char *) mf->wszVolume;


	installhook ();		/* only installs if not done already... */

	for (c = 0; c < NUMSLOTS; c++)
	{
		cv = cryptvols[c];
		if (strcmp (fname, (char *) &cv->mounted_file_name) == 0)
		{
			flag = 3 + 128;	/* already present */
			goto done;
		}
	}

	if (writeable)
	{
		code = R0_OpenCreateFile (FALSE, ACCESS_READWRITE | SHARE_DENYREADWRITE,
		      0, ACTION_OPENEXISTING, 0x81, fname, &hfile, &action);	/* R0_NO_CACHE(UBYTE)
										   ((R0_NO_CACHE)>>8) */

		if (code != 0)
		{
			writeable = 0;
			code = R0_OpenCreateFile (FALSE, ACCESS_READONLY | SHARE_DENYREAD,
						  0, ACTION_OPENEXISTING, 0x81, fname, &hfile, &action);	/* R0_NO_CACHE(UBYTE)
														   ((R0_NO_CACHE)>>8) */
		}

		if (code == 0)
			readnullfilesize (hfile);
	}
	else
	{
		code = R0_OpenCreateFile (FALSE, ACCESS_READONLY | SHARE_DENYREAD,
		      0, ACTION_OPENEXISTING, 0x81, fname, &hfile, &action);	/* R0_NO_CACHE(UBYTE)
										   ((R0_NO_CACHE)>>8) */

		if (code == 0)
			readnullfilesize (hfile);
	}

	if (code != 0)
	{
		flag = 1;
		goto done;
	}

	for (c = 0; c < NUMSLOTS; c++)
	{
		cv = cryptvols[c];

		if ((cv->booted == 0) && (cv->physdevDCB == 0))
		{
			cv->filehostdcb = 0;
			cv->mountfilehandle = hfile;
			cv->physdevDCB = &cv->logicaldcb;
			cv->cryptsectorfirst = 0x00000000;
			cv->cryptsectorlast = 0x7ffffff0;
			dcb = (PDCB) cv->physdevDCB;
			flag = 2;

			if (writeable != 0)
				dcb->DCB_cmn.DCB_device_flags = DCB_DEV_WRITEABLE;

			/* clears cv set above if failed.... */
			tmf = trymountfile (dcb, cv, mf);

			if (tmf)
			{
				_asm cli
				  flag = 3;

				mf->nReturnCode = flag;

				if (tmf > 0)	/* if tmg is -ve then no
						   drive letter (already had
						   blue screen..) */
				{
					mf->nReturnCode = flag;

					cv->booted = 2;
					strcpy ((char *) &cv->mounted_file_name, fname);

					goto done;
				}
			}	/* trymountfile */

		}		/* if cv->.... */

		if (flag)
			break;	/* out of for loop */
	}


	R0_CloseFile (hfile);

      done:

	switch (flag)
	{
	case 3 + 128:
		mf->nReturnCode = ERR_VOL_ALREADY_MOUNTED;
		break;
	case 1:
		mf->nReturnCode = ERR_FILE_OPEN_FAILED;
		break;
	case 2:
		mf->nReturnCode = ERR_VOL_MOUNT_FAILED;
		break;
	case 3:
		if (tmf > 0)
		{
			mf->nReturnCode = 0;
			mf->nDosDriveNo = cv->drive;
		}
		else
			mf->nReturnCode = ERR_NO_FREE_DRIVES;
		break;
	case 0:
		mf->nReturnCode = ERR_NO_FREE_SLOTS;
		break;
	}
}


void
outblock (PIOP iop, char *outbuffer, int sectorstart, int sectorcount, cryptvol * cv, char *workbuff)
{
	int logsec = sectorstart + 1;	/* get logical volume sector. */

	char *sendbuffer;

	if (!sectorcount)
		return;

	do
	{
		if (sectorcount <= MAXBLOCK)
		{
			sendbuffer = outbuffer;

			/* if copyflag 0, then buffer already set by caller. */
			ior.IOR_status = 0;
			if (workbuff)
			{
				sectorcopy (workbuff, outbuffer, sectorcount);
				sendbuffer = workbuff;
			}

			writelogical (iop, logsec, sectorcount, sendbuffer, cv);

			sectorcount = 0;
			return;
		}
		else
		{
			sendbuffer = outbuffer;
			if (workbuff)
			{
				sectorcopy (workbuff, outbuffer, MAXBLOCK);
				sendbuffer = workbuff;
			}

			writelogical (iop, logsec, MAXBLOCK, sendbuffer, cv);
			logsec += MAXBLOCK;
			sectorcount -= MAXBLOCK;
			outbuffer += (MAXBLOCK * 512);
		}
	}
	while ((sectorcount > 0) && (ior.IOR_status < 16));
}

void
inblock (PIOP iop, char *outbuffer, int sectorstart, int sectorcount, cryptvol * cv)
{
	int logsec = sectorstart + 1;	/* get logical volume sector. */

	do
	{
		ior.IOR_status = 0;
		if (sectorcount < MAXBLOCK)
		{
			readlogical (iop, logsec, sectorcount, (char *) transferbuffer, cv);
			memcpy (outbuffer, transferbuffer, sectorcount * 512);
			sectorcount = 0;
			return;
		}
		else
		{
			readlogical (iop, logsec, MAXBLOCK, (char *) transferbuffer, cv);
			memcpy (outbuffer, transferbuffer, MAXBLOCK * 512);
			logsec += MAXBLOCK;
			sectorcount -= MAXBLOCK;
			outbuffer += (MAXBLOCK * 512);
		}
	}
	while ((sectorcount > 0) && (ior.IOR_status < 16));
}

int
doR0fileio (int sector, int numsectors, char *buffer, cryptvol * cv, int iorop)
{
	CLIENT_STRUCT sregs;	/* static */
	PVRP v;

	int res;
	int bytes;		/* static */


	if (iorop == IOR_READ)
	{
		if (numsectors)
		{
			SaveClientState ((CLIENT_STRUCT *) & sregs);

			res = R0_ReadFile (FALSE, cv->mountfilehandle, numsectors << 9, sector << 9, buffer, &bytes);

			RestoreClientState ((CLIENT_STRUCT *) & sregs);
		}

		return res;
	}			/* IOR read */

	res = 0;
	if (iorop == IOR_WRITE)
	{
		if (numsectors)
		{
			SaveClientState ((CLIENT_STRUCT *) & sregs);

			res = R0_WriteFile (FALSE, cv->mountfilehandle, numsectors * 512, sector * 512, buffer, &bytes);

			RestoreClientState ((CLIENT_STRUCT *) & sregs);
		}

		if (res)
		{
			if (res == 5)
				res = 0x13;	/* WHY ARE WE GETTING ACCESS
						   DENIED 005 ON CD RATHER
						   THAN WP ? */

			if (res == 0x13)
			{
				if (cv->booted >= 2)
				{
					v = (PVRP) cv->ldcb->DCB_cmn.DCB_vrp_ptr;
					if (v)
					{
						if ((v->VRP_event_flags & VRP_ef_write_protected) == 0)
						{
							v->VRP_event_flags |= VRP_ef_write_protected | VRP_ef_media_uncertain;
						}
					}
				}	/* cv->booted */
			}	/* res=13 */
		}		/* res= something */

		return res;
	}			/* IOR write */

	return 0;
}

int
MapDosError (int error)
{
	int e;

	if (error == 0x13)
		return (IORS_WRITE_PROTECT);

	e = IORS_NOT_READY;	/* IORS_HW_FAILURE;      */
	return e;
}

char fileerrorstr[]=
{
	"TC has encountered an error reading a host file which\n"
	"it is using for a currently open scrambled disk volume.\n\n"
	"You should immediately dismount the file using the TC mount\n"
   "application, correct the error, and re mount the disk image file.\n\n\n"
      "The related disk will be unavailable, until you do, and you should\n"
	"save your work elsewhere."
};

int
dophysblock2 (PIOP iop, int sector, int numsectors, char *buffr, cryptvol * cv, USHORT iorop)
{
	int rstatus = 0;	/* status return value.... */
	PIOP myiop;
	PIOR myior;

	_BlockDev_Scatter_Gather *sgd;

	PDCB mydcb = cv->physdevDCB;	/* (PDCB) iop->IOP_physical_dcb; */
	USHORT offset;
	USHORT size;

	if (cv->mountfilehandle)
	{
		if (cv->booted <= 2)
			rstatus = doR0fileio (sector, numsectors, buffr, cv, iorop);
		else
			rstatus = 23;

		if ((rstatus) && (rstatus != 0x13))
		{
			iop->IOP_timer = iop->IOP_timer_orig = 32000;
			rstatus = MapDosError (rstatus);

			if (cv->booted <= 2 && (cv->booted))
			{
				Post_message (fileerrorstr, "TC: Mounted file error");
				cv->booted = 256;
			}
		}

		iop->IOP_ior.IOR_status = rstatus;
		return rstatus;
	}

	/* End up here, if we are handling a disk partition rather than
	   container file */
	offset = (USHORT) (mydcb->DCB_cmn.DCB_expansion_length + FIELDOFFSET (IOP, IOP_ior));
	size = offset + sizeof (IOR) + (8 * sizeof (SGD));
	iop->IOP_timer = iop->IOP_timer_orig = 160;

	myiop = IspCreateIop (size, offset, ISP_M_FL_SMART_ALLOC);

	if (myiop == NULL)
	{

		iop->IOP_ior.IOR_status = IORS_MEMORY_ERROR;
		return IORS_MEMORY_ERROR;
	}

	myior = &myiop->IOP_ior;

	/* Be aware that Criteria routine reads it's dmd bits from THIS dcb! */

	myiop->IOP_original_dcb = (ULONG) mydcb;	/* iop->IOP_original_dcb;
							   (ULONG) mydcb;        */
	myiop->IOP_physical_dcb = (ULONG) mydcb->DCB_cmn.DCB_physical_dcb;
	if (cv->booted == 1)
		cv->booted = 2;	/* Irrelevant here.....    */
	myior->IOR_next = 0;
	myior->IOR_start_addr[1] = 0;
	myior->IOR_flags = IORF_VERSION_002;
	myior->IOR_private_client = offset;
	myior->IOR_req_vol_handle = mydcb->DCB_cmn.DCB_vrp_ptr;
	myior->IOR_sgd_lin_phys = (ULONG) (myior + 1);
	myior->IOR_num_sgds = 0;
	myior->IOR_vol_designtr = mydcb->DCB_cmn.DCB_unit_number;
	myior->IOR_func = iorop;
	myior->IOR_flags |= IORF_BYPASS_VOLTRK | IORF_HIGH_PRIORITY | IORF_SCATTER_GATHER | IORF_SYNC_COMMAND | IORF_DONT_CACHE;
	if (iorop == IOR_READ)
		myior->IOR_flags |= IORF_DATA_IN;
	if (iorop == IOR_WRITE)
		myior->IOR_flags |= IORF_DATA_OUT;
	myior->IOR_start_addr[0] = sector;
	myior->IOR_xfer_count = numsectors;
	sgd = (_BlockDev_Scatter_Gather *) myior->IOR_sgd_lin_phys;	/* scatter gather
									   array... */
	sgd->BD_SG_Buffer_Ptr = (ULONG) buffr;	/* Buffer in LOCKED ram,
						   below 16mbyte, 4K
						   boundary.. */
	sgd->BD_SG_Count = numsectors;
	myior->IOR_buffer_ptr = (ULONG) sgd;	/* Implement as Scatter
						   gather, with One block */
	sgd++;
	sgd->BD_SG_Buffer_Ptr = 0;
	sgd->BD_SG_Count = 0;
	sgd++;
	myior->IOR_sgd_lin_phys = (ULONG) sgd;
	rstatus = myior->IOR_status;
	sgd->BD_SG_Buffer_Ptr = 0;
	sgd->BD_SG_Count = 0;
	sgd++;
	sgd->BD_SG_Buffer_Ptr = 0;
	sgd->BD_SG_Count = 0;
	sgd++;
	sgd->BD_SG_Buffer_Ptr = 0;
	sgd->BD_SG_Count = 0;
	myiop->IOP_timer = 40;
	myiop->IOP_timer_orig = 40;
	/* Call criteria, to set phys SGDs physical addresses if needed..... */
	if (IlbIntIoCriteria (myiop))
		myior->IOR_flags |= IORF_DOUBLE_BUFFER;	/* Double buffer, will
							   also make no
							   difference */
	IlbInternalRequest (myiop, mydcb, OnRequest);
	rstatus = myior->IOR_status;
	iop->IOP_ior.IOR_status = rstatus;	/* myior->IOR_status; */
	IspDeallocMem ((PVOID) ((DWORD) myior - myior->IOR_private_client));
	return rstatus;
}

int
dophysblock (PIOP iop, int sector, int numsectors, char *buffr, cryptvol * cv, USHORT iorop)
{
	int s, c;

	for (c = 0; c < 3; c++)
	{
		s = dophysblock2 (iop, sector, numsectors, buffr, cv, iorop);
		if (s == IORS_SUCCESS_WITH_RETRY)
			return 0;
		if (!s)
			return 0;
	}

	return s;
}

void
readlogical (PIOP iop, int temp_block, int num_sectors, char *buffer, cryptvol * cv)
{
	int secNum;

	secNum = temp_block;

#if EXTRA_INFO
	_Debug_Printf_Service ("secNum=%d,num_sectors=%d\n", secNum, num_sectors);
#endif

	dophysblock (iop, secNum + cv->cryptsectorfirst, num_sectors, buffer, cv, IOR_READ);

#if EXTRA_INFO
	_Debug_Printf_Service ("0x%08x\n", *((int *) buffer));
#endif

	cv->cryptoInfo->decrypt_sector ((unsigned long *) buffer,
					(unsigned __int64) secNum, num_sectors,
					&cv->cryptoInfo->ks[0],
					cv->cryptoInfo->iv,
					cv->cryptoInfo->cipher);

#if EXTRA_INFO
	_Debug_Printf_Service ("0x%08x\n", *((int *) buffer));
#endif

}

void
writelogical (PIOP iop, int temp_block, int num_sectors, char *buffer, cryptvol * cv)
{
	int secNum;
	
	secNum = temp_block;

#if EXTRA_INFO
	_Debug_Printf_Service ("0x%08x\n", *((int *) buffer));
#endif

	cv->cryptoInfo->encrypt_sector ((unsigned long *) buffer,
					(unsigned __int64) secNum, num_sectors,
					&cv->cryptoInfo->ks[0],
					cv->cryptoInfo->iv,
					cv->cryptoInfo->cipher);

#if EXTRA_INFO
	_Debug_Printf_Service ("0x%08x\n", *((int *) buffer));
#endif

	dophysblock (iop, secNum + cv->cryptsectorfirst, num_sectors, buffer, cv, IOR_WRITE);
}


BOOL
OnSystemExit (void)
{
	/* Called when Win32 is about to die. We must close down the files,
	   for any files mounted as encrypted disks. this call seems to be
	   the only chance we get. the system pukes amd hangsif we don't.
	   Corrupt screen etc. nd refuses to shut down..... */

	cryptvol *cv;
	int c;

	for (c = 0; c < NUMSLOTS; c++)
	{
		cv = cryptvols[c];
		unlockdrive (cv);
		if (cv->mountfilehandle)
			R0_CloseFile (cv->mountfilehandle);
	}

	killthread ();
	return AEP_SUCCESS;
}

void
Post_message (char *msg, char *header)
{
	MessageBox *m;
	int n;

	for (n = 0; n < MAX_MESSAGES - 1; n++)
	{
		m = &Msgs[n];
		if (m->PostPlease == 0)
			break;

	}

	m->PostPlease = 1;
	m->MessageHdr = header;
	m->MessageBody = msg;
}

void
ProcessWinMessagesBlueScreen (void)
{
	MessageBox *m;
	int n;

	for (n = 0; n < MAX_MESSAGES; n++)
	{
		m = &Msgs[n];
		if (m->PostPlease)
		{
			ShellMessageNCB (0, m->MessageBody, m->MessageHdr);
			m->PostPlease = 0;
		}
	}
}

/* The code below gets called by the IOS *every* 0.5 seconds... */
USHORT 
OnHalfSec (PAEP_boot_done aep) /* dummy param */
{
#if 0
	cryptvol *cv;
        int c;
	int notified = 0;
#endif

	halfseccount++;

	ProcessWinMessagesBlueScreen ();

#if 0
        for (c = 0; c < 8; c++)
	{
		cv = cryptvols[c];

		if (cv->notifytime)
		{
			cv->notifytime--;
			if (cv->notifytime == 0)
			{
				cv->notifytime = 0x8000ffff;
				if (!notified) /* prevent multiple notifications */
				{
					notified++;
					SHELL_CallAtAppyTime ((APPY_CALLBACK) & drivearrived, 0, 0);
				}
			}

		}
	}
#endif

	return AEP_SUCCESS;
}


/* ------------------------------------partition support
   ------------------------------------------- */

/* go round every drive reading all the partitions.... */
void
readallpartitions (MOUNT_STRUCT * mf, BOOL bVerifyOnly)
{
	int c = 0;
	PDCB dcb;
	USHORT offset;
	USHORT size;
	PIOP myiop;
	PIOR myior;
	int x, disks, z;
	char *vol = (char *) mf->wszVolume;

	mf->nReturnCode = ERR_INVALID_DEVICE;	/* Assume failure */

	if (strlen ((char *) mf->wszVolume) < 28)
		return;

	x = vol[16] - '0';	/* Disk number starting from 0 */
	z = vol[27] - '0';	/* Partition number start from 1 */
	disks = 0;		/* Count of disks */

	if (x < 0 || z < 1)
		return;

#if EXTRA_INFO
	_Debug_Printf_Service ("readallpartitions\n");
#endif

	while (dcb = dcblist[++c])
	{
		if ((dcb->DCB_cmn.DCB_device_type == 0) && (dcb->DCB_cmn.DCB_apparent_blk_shift == 9))
		{
			if (x != disks++)
				continue;

			offset = (USHORT) (dcb->DCB_cmn.DCB_expansion_length + FIELDOFFSET (IOP, IOP_ior));
			size = offset + sizeof (IOR) + dcb->DCB_max_sg_elements * sizeof (SGD);
			myiop = IspCreateIop (size, offset, ISP_M_FL_MUST_SUCCEED | ISP_M_FL_SMART_ALLOC | ISP_M_FL_INTERRUPT_TIME | ISP_M_FL_PERSISTENT_IOP);
			myior = &myiop->IOP_ior;
			myior->IOR_private_client = offset;

			DiskRead (dcb, myiop, 0, 1, partitiontestbuffer, IOR_READ);	/* ;single read in case
											   of media change... */
			memset (partitiontestbuffer, 0, 512);

			if (!DiskRead (dcb, myiop, 0, 1, partitiontestbuffer, IOR_READ))	/* +32768  */
			{
				UsePartitionInfo (dcb, myiop, partitiontestbuffer, 0, 0, &z, mf, bVerifyOnly);	/* +32768 */
			}

			IspDeallocMem ((PVOID) ((DWORD) myior - myior->IOR_private_client));

		}
	}

#if EXTRA_INFO
	_Debug_Printf_Service ("readallpartitions end\n");
#endif

}


int
DiskRead (PDCB mydcb, PIOP myiop, unsigned int sector, unsigned int numsectors, char *buffr, USHORT iorop)
{
	int rstatus = 0;	/* status return value....  */
	unsigned long *errnl = (unsigned long *) buffr;	/* no load test... */
	PIOR myior;
	_BlockDev_Scatter_Gather *sgd;

	myior = &myiop->IOP_ior;
	myiop->IOP_original_dcb = (ULONG) mydcb;
	myiop->IOP_physical_dcb = (ULONG) mydcb->DCB_cmn.DCB_physical_dcb;
	myior->IOR_next = 0;
	myior->IOR_start_addr[1] = 0;
	myior->IOR_flags = IORF_VERSION_002;
	myior->IOR_req_vol_handle = mydcb->DCB_cmn.DCB_vrp_ptr;
	myior->IOR_sgd_lin_phys = (ULONG) (myior + 1);
	myior->IOR_num_sgds = 0;
	myior->IOR_vol_designtr = mydcb->DCB_cmn.DCB_unit_number;
	myior->IOR_func = iorop;
	myior->IOR_flags |= IORF_BYPASS_VOLTRK | IORF_HIGH_PRIORITY | IORF_SCATTER_GATHER | IORF_SYNC_COMMAND;
	if (iorop == IOR_READ)
	{
		myior->IOR_flags |= IORF_DATA_IN;
		memset (buffr, 0, numsectors * 512);
		errnl[0] = 0xACE01DE4;
		errnl[1] = 0xEDB0CD01;
		errnl[2] = 0x4caf3321;
		errnl[3] = 0xa35a32c4;
	}

	if (iorop == IOR_WRITE)
		myior->IOR_flags |= IORF_DATA_OUT;
	myior->IOR_start_addr[0] = sector;
	myior->IOR_xfer_count = numsectors;
	myior->IOR_buffer_ptr = (ULONG) buffr;

	sgd = (_BlockDev_Scatter_Gather *) myior->IOR_sgd_lin_phys;	/* scatter gather
									   array... */
	sgd->BD_SG_Buffer_Ptr = (ULONG) buffr;	/* Buffer in LOCKED ram,
						   below 16mbyte, 4K
						   boundary.. */
	sgd->BD_SG_Count = numsectors;
	myior->IOR_buffer_ptr = (ULONG) sgd;	/* Implement as Scatter
						   gather, with One block */
	sgd++;
	sgd->BD_SG_Buffer_Ptr = 0;
	sgd->BD_SG_Count = 0;

	sgd++;
	myior->IOR_sgd_lin_phys = (ULONG) sgd;
	rstatus = myior->IOR_status;

	myiop->IOP_timer = 40;
	myiop->IOP_timer_orig = 40;

	if (mydcb->DCB_cmn.DCB_Sstor_Host == FALSE)
	{
		if (IlbIntIoCriteria (myiop))
			myior->IOR_flags |= IORF_DOUBLE_BUFFER;
		IlbInternalRequest (myiop, mydcb, 0);
		rstatus = myior->IOR_status;

		if (iorop == IOR_READ)
		{
			/* checks for partion reads of simulated drives that
			   dont return either data or error.... */
			if ((errnl[0] == 0xACE01DE4) &&
			    (errnl[1] == 0xEDB0CD01) &&
			    (errnl[2] == 0x4caf3321) &&
			    (errnl[3] == 0xa35a32c4))

				rstatus = 16;

		}

		return rstatus;
	}

	return 16;


}

/* This routine finds partitions */

void
UsePartitionInfo (PDCB dcb, PIOP myiop, char *diskbuffer, unsigned int relative, int recursed, int *partnum,
		  MOUNT_STRUCT * mf, BOOL bVerifyOnly)
{
	/* Note that this is recursive..... */
	partitionrec *pr;
	char *c;
	char *ndb;
	int flag = 0;
	cryptvol *cv = NULL;

	unsigned int ComputedStartSector;
	unsigned int ComputedEndSector;
	unsigned int cyl;
	unsigned int cylsize;
	unsigned int headsize;

#if EXTRA_INFO
	_Debug_Printf_Service ("UsePartitionInfo\n");
#endif

	c = diskbuffer;
	ndb = c + 512;		/* next disk buffer */
	c += 0x1be;

	headsize = dcb->DCB_bdd.DCB_apparent_spt;
	cylsize = dcb->DCB_bdd.DCB_apparent_head_cnt;
	cylsize = cylsize * headsize;

	c = diskbuffer;
	c += 0x1be;
	pr = (partitionrec *) c;


	cyl = (pr->ss) & (128 + 64);
	cyl = cyl << 2;
	cyl += pr->sc;
	cyl *= cylsize;		/* 16065; */

	ComputedStartSector = pr->sh * headsize;	/* 63; */
	ComputedStartSector += (((pr->ss) & 63) - 1);
	ComputedStartSector += cyl;


	cyl = (pr->es) & (128 + 64);
	cyl = cyl << 2;
	cyl += pr->ec;
	cyl *= cylsize;		/* 16065; */

	ComputedEndSector = pr->eh * headsize;	/* 63 */
	ComputedEndSector += (((pr->es) & 63) - 1);
	ComputedEndSector += cyl;
	ComputedEndSector = ComputedEndSector - ComputedStartSector;
	ComputedEndSector += 1;	/* allow for inclusive sectors... */


	pr = (partitionrec *) c;

	if (pr->boot == 0x80)
		dcb_boot = dcb;

	if ((pr->system == 5) || (pr->system == 0xF))
	{
		if (!recursed)
			relative = pr->StartSector;
		else
			pr->StartSector += relative;


		memset (ndb, 0, 512);
		DiskRead (dcb, myiop, pr->StartSector, 1, ndb, IOR_READ);
		UsePartitionInfo (dcb, myiop, ndb, relative, pr->StartSector, partnum, mf, bVerifyOnly);	/* recursed, and also
														   offset */
	}
	else
	{
		if (recursed)
			pr->StartSector += recursed;

		if (--(*partnum) == 0)
		{
			if (bVerifyOnly == TRUE)
				flag = 1;
			else
				flag = tryvol (dcb, myiop, pr, mf, &cv);	/* partition 1 */
			goto error;
		}
	}

	pr++;

	if (pr->boot == 0x80)
		dcb_boot = dcb;

	if ((pr->system == 5) || (pr->system == 0xF))
	{
		if (!recursed)
			relative = pr->StartSector;
		else
			pr->StartSector += relative;

		memset (ndb, 0, 512);
		DiskRead (dcb, myiop, pr->StartSector, 1, ndb, IOR_READ);
		UsePartitionInfo (dcb, myiop, ndb, relative, pr->StartSector, partnum, mf, bVerifyOnly);	/* recursed, and also
														   offset */
	}
	else if (!recursed)
	{
		if (--(*partnum) == 0)
		{
			if (bVerifyOnly == TRUE)
				flag = 1;
			else
				flag = tryvol (dcb, myiop, pr, mf, &cv);	/* partition 2 */
			goto error;
		}
	}

	if (recursed)
		goto error;

	pr++;

	if (pr->boot == 0x80)
		dcb_boot = dcb;

	if ((pr->system == 5) || (pr->system == 0xF))
	{
		if (!recursed)
			relative = pr->StartSector;
		else
			pr->StartSector += relative;

		memset (ndb, 0, 512);
		DiskRead (dcb, myiop, pr->StartSector, 1, ndb, IOR_READ);
		UsePartitionInfo (dcb, myiop, ndb, relative, pr->StartSector, partnum, mf, bVerifyOnly);	/* recursed, and also
														   offset */
	}
	else if (!recursed)
	{
		if (--(*partnum) == 0)
		{
			if (bVerifyOnly == TRUE)
				flag = 1;
			else
				flag = tryvol (dcb, myiop, pr, mf, &cv);	/* partition 3 */
			goto error;
		}
	}

	pr++;

	if (pr->boot == 0x80)
		dcb_boot = dcb;

	if ((pr->system == 5) || (pr->system == 0xF))
	{
		if (!recursed)
			relative = pr->StartSector;
		else
			pr->StartSector += relative;

		memset (ndb, 0, 512);
		DiskRead (dcb, myiop, pr->StartSector, 1, ndb, IOR_READ);
		UsePartitionInfo (dcb, myiop, ndb, relative, pr->StartSector, partnum, mf, bVerifyOnly);	/* recursed, and also
														   offset */
	}
	else if (!recursed)
	{
		if (--(*partnum) == 0)
		{
			if (bVerifyOnly == TRUE)
				flag = 1;
			else
				flag = tryvol (dcb, myiop, pr, mf, &cv);	/* partition 4 */
			goto error;
		}
	}

      error:

#if EXTRA_INFO
	_Debug_Printf_Service ("UsePartitionInfo end\n");
#endif

	if (bVerifyOnly == TRUE)
	{
		if (flag == 1)
		{
			/* Return partition info in the 'diskbuffer' buffer */

			char *peek = (char *) &pr->system;
			unsigned long *tmp = (void *) partitiontestbuffer;
			unsigned long secstart, seclast;

			mf->nReturnCode = 0;

			peek -= 4;
			peek += 8;	/* point at starting sector... */
			secstart = *(unsigned long *) peek;
			peek += 4;

			seclast = (secstart + *(unsigned long *) peek);

			if (pr->boot == 0x80)
			{
				/* For safety reasons we return 0 length for
				   the boot device */
				seclast = secstart;
			}

			tmp[0] = secstart;
			tmp[1] = seclast;
			tmp[2] = (unsigned long) dcb;	/* device */

		}
	}
	else if (cv != NULL)
	{
		/* cv is only set by tryvol, flag is set only when cv is set */
		switch (flag)
		{
		case 0:
			mf->nReturnCode = ERR_VOL_MOUNT_FAILED;
			break;
		case 1:
			mf->nReturnCode = 0;
			mf->nDosDriveNo = cv->drive;
			strcpy (cv->mounted_file_name, (char *) mf->wszVolume);
			break;
		case -1:
			mf->nReturnCode = ERR_NO_FREE_DRIVES;
			break;
		}
	}
}

int
tryvol (PDCB dcb, PIOP myiop, partitionrec * pr, MOUNT_STRUCT * mf, cryptvol ** pcv)
{
	cryptvol *cv;
	char *readBuffer;
	int mounted = 0;

	readBuffer = TCalloc (FIRST_READ_SIZE);
	if (readBuffer == NULL)
		goto error;

	if (cv = checkpartition (myiop, pr))
	{
		if (cv->booted == 0)
		{
			int status;

			dophysblock (myiop, cv->cryptsectorfirst, FIRST_READ_SIZE / 512, readBuffer, cv, IOR_READ);

			status = VolumeReadHeaderCache (mf->bCache, readBuffer, mf->szPassword,
					 mf->nPasswordLen, &cv->cryptoInfo);

			if (status != 0)
			{
				memset (cv, 0, sizeof (cryptvol));
				cv->cryptsectorfirst = 0x7fffffff;
				mounted = 0;
				goto error;
			}
			else
				cv->booted = 1;

			if (Add_Drive (dcb, cv, mf->nDosDriveNo) == 0)
			{
				cv->filehostdcb = dcb;
				lockdrive (cv->filehostdcb, myiop, 1);
				mounted = 1;
			}
			else
			{
				/* No Drive letter available */
				memset (cv, 0, sizeof (cryptvol));
				cv->cryptsectorfirst = 0x7fffffff;
				mounted = -1;
			}
		}
	}
	else
	{
		/* If the checkpartition fails it could be because the
		   partitions is already mounted or because there are no free
		   slots */
		mounted = 0;
	}

      error:
	if (readBuffer != NULL)
		TCfree (readBuffer);

	*pcv = cv;

	return mounted;

}

struct cryptvol *
checkpartition (PIOP iop, partitionrec * pr)
{

	cryptvol *flag = 0;
	cryptvol *cv;
	PDCB dcb = (PDCB) iop->IOP_physical_dcb;

	char *peek = (char *) &pr->system;

	pr->system = 0x74;

	if (pr->system == 0x74)
	{
		if (cv = addcryptedpartition (iop, peek))
		{
			flag = cv;
		}
	}

	return flag;

}

int
cmppart (PDCB dcb, unsigned int secstart, cryptvol * cv)
{
	if (cv->physdevDCB != dcb)
		return 0;
	if (cv->cryptsectorfirst != secstart)
		return 0;
	return 1;
}

struct cryptvol *
addcryptedpartition (PIOP iop, char *peek)
{

	unsigned int secstart;
	unsigned int seclast;
	PDCB device;
	int d;
	peek -= 4;
	peek += 8;		/* point at starting sector... */
	secstart = *(unsigned long *) peek;
	peek += 4;

	seclast = (secstart + *(unsigned long *) peek);
	device = (PDCB) iop->IOP_physical_dcb;

	/* have we got it already ? */
	if (cmppart (device, secstart, (cryptvol *) & cv1))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv2))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv3))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv4))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv5))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv6))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv7))
		return NULL;
	if (cmppart (device, secstart, (cryptvol *) & cv8))
		return NULL;

	d = tryaddpart ((cryptvol *) & cv1, secstart, seclast, device);
	if (d == 1)
		return &cv1;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv2, secstart, seclast, device);
	if (d == 1)
		return &cv2;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv3, secstart, seclast, device);
	if (d == 1)
		return &cv3;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv4, secstart, seclast, device);
	if (d == 1)
		return &cv4;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv5, secstart, seclast, device);
	if (d == 1)
		return &cv5;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv6, secstart, seclast, device);
	if (d == 1)
		return &cv6;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv7, secstart, seclast, device);
	if (d == 1)
		return &cv7;
	if (d == 2)
		return 0;

	d = tryaddpart ((cryptvol *) & cv8, secstart, seclast, device);
	if (d == 1)
		return &cv8;
	if (d == 2)
		return 0;

	return NULL;
}

int
tryaddpart (cryptvol * cv, unsigned int secstart, unsigned int seclast, PDCB device)
{
	/* THIS if CAN NEVER BE TRUE because cmppart does this job before
	   this func is called */
	if ((cv->physdevDCB == device) && (cv->cryptsectorfirst == secstart))
		return (2);

	if (cv->physdevDCB == 0)
	{
		cv->physdevDCB = device;
		cv->cryptsectorfirst = secstart;
		cv->cryptsectorlast = seclast;

		return (1);
	}

	return (0);
}

int
unlockdrive (cryptvol * cv)
{
	PDCB dcb = cv->filehostdcb;	/* physdevDCB; */
	PIOP myiop;
	PIOR myior;
	USHORT offset;
	USHORT size;

	if (!dcb)
		return -1;

	offset = (USHORT) (dcb->DCB_cmn.DCB_expansion_length + FIELDOFFSET (IOP, IOP_ior));
	size = offset + sizeof (IOR) + dcb->DCB_max_sg_elements * sizeof (SGD);
	myiop = IspCreateIop (size, offset, ISP_M_FL_MUST_SUCCEED | ISP_M_FL_SMART_ALLOC | ISP_M_FL_INTERRUPT_TIME | ISP_M_FL_PERSISTENT_IOP);
	myior = &myiop->IOP_ior;
	myior->IOR_private_client = offset;
	lockdrive (dcb, myiop, 0);	/* unlock it! */
	IspDeallocMem ((PVOID) ((DWORD) myior - myior->IOR_private_client));
	return 1;
}

int
lockdrive (PDCB mydcb, PIOP myiop, int lockmode)
{
	PIOR myior;
	int rstatus;
	int iorop;

	if (!mydcb)
		return -1;

	if (lockmode)
		iorop = IOR_LOCK_MEDIA;
	else
		iorop = IOR_UNLOCK_MEDIA;

	if ((mydcb->DCB_cmn.DCB_device_flags & DCB_DEV_REMOVABLE) == 0)
		return -1;

	myior = &myiop->IOP_ior;
	myiop->IOP_original_dcb = (ULONG) mydcb;
	myiop->IOP_physical_dcb = (ULONG) mydcb->DCB_cmn.DCB_physical_dcb;
	myior->IOR_next = 0;
	myior->IOR_start_addr[1] = 0;
	myior->IOR_flags = IORF_VERSION_002;
	myior->IOR_req_vol_handle = 0;
	myior->IOR_vol_designtr = 0xff;
	myior->IOR_func = iorop;
	myior->IOR_flags |= IORF_BYPASS_VOLTRK | IORF_HIGH_PRIORITY | IORF_SYNC_COMMAND;
	myior->IOR_start_addr[0] = 0;
	myior->IOR_xfer_count = 0;
	myior->IOR_buffer_ptr = 0;

	myiop->IOP_timer = 40;
	myiop->IOP_timer_orig = 40;

	IlbInternalRequest (myiop, mydcb, 0);
	rstatus = myior->IOR_status;
	return rstatus;
}


/* the ring 0 code to allow win32 gui to access disk sectors */

int
AppAccessBlockDevice (unsigned int devicenum, unsigned int sectorstart, unsigned int sectorlen, char *buffer, int mode)
{
	PDCB dcb;
	USHORT offset;
	USHORT size;
	PIOP myiop;
	PIOR myior;
	int status;
	USHORT diskop;

	if (mode == 0)
		diskop = IOR_READ;
	else
		diskop = IOR_WRITE;

	if (devicenum < 128)
		dcb = dcblist[devicenum + 1];
	else
		dcb = (PDCB) devicenum;

	if (diskop == IOR_WRITE && dcb == dcb_boot)
	{
		if (sectorstart == 0)
		{
			return ERR_ACCESS_DENIED;
		}
	}

	offset = (USHORT) (dcb->DCB_cmn.DCB_expansion_length + FIELDOFFSET (IOP, IOP_ior));
	size = offset + sizeof (IOR) + dcb->DCB_max_sg_elements * sizeof (SGD);
	myiop = IspCreateIop (size, offset, ISP_M_FL_MUST_SUCCEED | ISP_M_FL_SMART_ALLOC | ISP_M_FL_INTERRUPT_TIME | ISP_M_FL_PERSISTENT_IOP);
	myior = &myiop->IOP_ior;
	myior->IOR_private_client = offset;

	if (diskop == IOR_WRITE)
		memcpy (appaccessbuffer, buffer, sectorlen * 512);

	status = DiskRead (dcb, myiop, sectorstart, sectorlen, appaccessbuffer, diskop);	/* mode later...... */

	if (diskop == IOR_READ)
		memcpy (buffer, appaccessbuffer, sectorlen * 512);

	IspDeallocMem ((PVOID) ((DWORD) myior - myior->IOR_private_client));

	if (status != 0)
	{
		if (mode == 0)
			status = ERR_VOL_READING;
		else
			status = ERR_VOL_WRITING;
	}

	return status;
}

/* This code informs Windows of a drives arrival, this code
  crashes windows 95 for some cd's; so it's currently never called */
 
void 
drivearrived (void)
{
	cryptvol *cv;
	int c;

	for (c = 0; c < 8; c++)
	{
		cv = cryptvols[c];

		if (cv->notifytime & 0x80000000)
		{
			cv->notifytime = 0;
    
			IFSMgr_PNPEvent (DBT_DEVICEARRIVAL, cv->drive, PNPT_VOLUME | DBTF_MEDIA );
		}
	}
}


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.