www.pudn.com > truecrypt.zip > NTDRIVER.C


/* Copyright (C) 2004 TrueCrypt Team, truecrypt.org 
   This product uses components written by Paul Le Roux  */ 
 
#include "TCdefs.h" 
#include "crypto.h" 
#include "fat.h" 
 
#include "apidrvr.h" 
#include "ntdriver.h" 
#include "ntvol.h" 
#include "ntrawdv.h" 
#include "ntfiledv.h" 
#include "cache.h" 
 
#include  
#include  
#include  
#include  
#include  
 
/* Init section, which is thrown away as soon as DriverEntry returns */ 
#pragma alloc_text(INIT,DriverEntry) 
#pragma alloc_text(INIT,TCCreateRootDeviceObject) 
 
/* Sync. mutex for above password data */ 
KMUTEX driverMutex; 
 
/* DriverEntry initialize's the dispatch addresses to be passed back to NT. 
   RUNS AT IRQL = PASSIVE_LEVEL(0) */ 
NTSTATUS 
DriverEntry (PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 
{ 
	if (RegistryPath);	/* Remove warning */ 
 
	DriverObject->MajorFunction[IRP_MJ_CREATE] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_CLOSE] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_READ] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_WRITE] = TCDispatchQueueIRP; 
	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TCDispatchQueueIRP; 
 
	DriverObject->DriverUnload = TCUnloadDriver; 
 
	KeInitializeMutex (&driverMutex, 1); 
 
	return TCCreateRootDeviceObject (DriverObject); 
} 
 
#ifdef _DEBUG 
// Dumps a memory region to debug output 
void DumpMem(unsigned char *mem, int len) 
{ 
	unsigned char str[20]; 
	unsigned char *m = mem; 
	int i,j; 
 
	for (j=0;j ' ' && m[i] < '~') 
				str[i]=m[i]; 
			else 
				str[i]='.'; 
		} 
 
		Dump ("0x%08x  %02x %02x %02x %02x %02x %02x %02x %02x  %s", 
			m, m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], str); 
 
		m+=8; 
	} 
} 
#endif 
 
/* TCDispatchQueueIRP queues any IRP's so that they can be processed later 
   by the thread -- or in some cases handles them immediately! */ 
NTSTATUS 
TCDispatchQueueIRP (PDEVICE_OBJECT DeviceObject, PIRP Irp) 
{ 
	PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; 
	PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); 
	NTSTATUS ntStatus; 
 
#ifdef USE_KERNEL_MUTEX 
	if (Extension->bRootDevice == FALSE) 
		KeWaitForMutexObject (&Extension->KernelMutex, Executive, KernelMode, 
				      FALSE, NULL); 
#endif 
 
#ifdef _DEBUG 
	if (irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) 
		Dump ("TCDispatchQueueIRP BEGIN MajorFunction = %ls 0x%08x IoControlCode = %ls 0x%08x\n", 
		      TCTranslateCode (irpSp->MajorFunction), (int) irpSp->MajorFunction, 
		      TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode), 
		      (int) irpSp->Parameters.DeviceIoControl.IoControlCode); 
	//else 
	//	Dump ("TCDispatchQueueIRP BEGIN MajorFunction = %ls 0x%08x\n", 
	//	      TCTranslateCode (irpSp->MajorFunction), (int) irpSp->MajorFunction); 
#endif 
 
	if (Extension->bRootDevice == FALSE) 
	{ 
		if (irpSp->MajorFunction == IRP_MJ_READ || irpSp->MajorFunction == IRP_MJ_WRITE || 
		    irpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL) 
		{ 
			if ((DeviceObject->Flags & DO_VERIFY_VOLUME)) 
			{ 
				if (!(irpSp->Flags & SL_OVERRIDE_VERIFY_VOLUME)) 
				{ 
					Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 
					Irp->IoStatus.Information = 0; 
					if (!NT_SUCCESS (Irp->IoStatus.Status) && 
					    IoIsErrorUserInduced (Irp->IoStatus.Status)) 
					{ 
						IoSetHardErrorOrVerifyDevice (Irp, DeviceObject); 
					} 
					ntStatus = Irp->IoStatus.Status; 
					IoCompleteRequest (Irp, IO_NO_INCREMENT); 
					//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
					if (Extension->bRootDevice == FALSE) 
						KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
					return ntStatus; 
				} 
				else if (Extension->bShuttingDown == TRUE) 
				{ 
					Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 
					Irp->IoStatus.Information = 0; 
					if (!NT_SUCCESS (Irp->IoStatus.Status) && 
					    IoIsErrorUserInduced (Irp->IoStatus.Status)) 
					{ 
						IoSetHardErrorOrVerifyDevice (Irp, DeviceObject); 
					} 
					ntStatus = Irp->IoStatus.Status; 
					IoCompleteRequest (Irp, IO_NO_INCREMENT); 
					//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
					if (Extension->bRootDevice == FALSE) 
						KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
					return ntStatus; 
				} 
			} 
			else if (Extension->bShuttingDown == TRUE) 
			{ 
				if (DeviceObject->Vpb && DeviceObject->Vpb->Flags & VPB_MOUNTED) 
				{ 
					Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE; 
					Irp->IoStatus.Information = 0; 
					if (!NT_SUCCESS (Irp->IoStatus.Status) && 
					    IoIsErrorUserInduced (Irp->IoStatus.Status)) 
					{ 
						IoSetHardErrorOrVerifyDevice (Irp, DeviceObject); 
					} 
					DeviceObject->Flags |= DO_VERIFY_VOLUME; 
				} 
				else 
				{ 
					Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 
					Irp->IoStatus.Information = 0; 
				} 
 
				ntStatus = Irp->IoStatus.Status; 
				IoCompleteRequest (Irp, IO_NO_INCREMENT); 
				//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
				if (Extension->bRootDevice == FALSE) 
					KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
				return ntStatus; 
			} 
		} 
		else if ((DeviceObject->Flags & DO_VERIFY_VOLUME)) 
		{		/* If shutting down or media removed */ 
			if (Extension->bShuttingDown == TRUE) 
			{ 
				Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 
				Irp->IoStatus.Information = 0; 
				if (!NT_SUCCESS (Irp->IoStatus.Status) && 
				IoIsErrorUserInduced (Irp->IoStatus.Status)) 
				{ 
					IoSetHardErrorOrVerifyDevice (Irp, DeviceObject); 
				} 
				ntStatus = Irp->IoStatus.Status; 
				IoCompleteRequest (Irp, IO_NO_INCREMENT); 
				//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
				if (Extension->bRootDevice == FALSE) 
					KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
				return ntStatus; 
			} 
			else 
			{ 
				Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 
				Irp->IoStatus.Information = 0; 
				ntStatus = Irp->IoStatus.Status; 
				IoCompleteRequest (Irp, IO_NO_INCREMENT); 
				//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
				if (Extension->bRootDevice == FALSE) 
					KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
				return ntStatus; 
			} 
		} 
	} 
 
	switch (irpSp->MajorFunction) 
	{ 
	case IRP_MJ_CLOSE: 
	case IRP_MJ_CREATE: 
	case IRP_MJ_CLEANUP: 
#ifdef USE_KERNEL_MUTEX 
		if (Extension->bRootDevice == FALSE) 
			KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
		return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); 
 
	case IRP_MJ_SHUTDOWN: 
	case IRP_MJ_FLUSH_BUFFERS: 
	case IRP_MJ_READ: 
	case IRP_MJ_WRITE: 
	case IRP_MJ_DEVICE_CONTROL: 
		if (Extension->bRootDevice == FALSE) 
		{ 
			ASSERT (Extension->bShuttingDown == FALSE); 
 
			IoMarkIrpPending (Irp); 
 
			ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL || 
				KeGetCurrentIrql ()== APC_LEVEL); 
 
			ExInterlockedInsertTailList ( 
						      &Extension->ListEntry, 
					       &Irp->Tail.Overlay.ListEntry, 
						  &Extension->ListSpinLock); 
 
			ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL || 
				KeGetCurrentIrql ()== APC_LEVEL); 
 
			KeReleaseSemaphore ( 
					       &Extension->RequestSemaphore, 
						   (KPRIORITY) 0, 
						   1, 
						   FALSE); 
 
			//Dump ("TCDispatchQueueIRP STATUS_PENDING END\n"); 
#ifdef USE_KERNEL_MUTEX 
			if (Extension->bRootDevice == FALSE) 
				KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
			return STATUS_PENDING; 
		} 
		else 
		{ 
			if (irpSp->Parameters.DeviceIoControl.IoControlCode >= TC_FIRST_PRIVATE && 
			    irpSp->Parameters.DeviceIoControl.IoControlCode <= TC_LAST_PRIVATE) 
			{ 
				ntStatus = TCDeviceControl (DeviceObject, Extension, Irp); 
				//Dump ("TCDispatchQueueIRP NTSTATUS = 0x%08x END\n", ntStatus); 
#ifdef USE_KERNEL_MUTEX 
				if (Extension->bRootDevice == FALSE) 
					KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
				return ntStatus; 
			} 
 
			if (irpSp->MajorFunction == IRP_MJ_FLUSH_BUFFERS || irpSp->MajorFunction == IRP_MJ_SHUTDOWN) 
			{ 
#ifdef USE_KERNEL_MUTEX 
				if (Extension->bRootDevice == FALSE) 
					KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
				return COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); 
			} 
		} 
 
#ifdef USE_KERNEL_MUTEX 
		if (Extension->bRootDevice == FALSE) 
			KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
 
		return COMPLETE_IRP (DeviceObject, Irp, STATUS_DRIVER_INTERNAL_ERROR, 0); 
	} 
 
#ifdef _DEBUG 
	Dump ("ERROR: Unknown irpSp->MajorFunction in TCDispatchQueueIRP %ls 0x%08x END\n", 
	TCTranslateCode (irpSp->MajorFunction), (int) irpSp->MajorFunction); 
#endif 
 
#ifdef USE_KERNEL_MUTEX 
	if (Extension->bRootDevice == FALSE) 
		KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
	return COMPLETE_IRP (DeviceObject, Irp, STATUS_DRIVER_INTERNAL_ERROR, 0); 
} 
 
NTSTATUS 
TCCreateRootDeviceObject (PDRIVER_OBJECT DriverObject) 
{ 
	UNICODE_STRING Win32NameString, ntUnicodeString; 
	WCHAR dosname[32], ntname[32]; 
	PDEVICE_OBJECT DeviceObject; 
	NTSTATUS ntStatus; 
	BOOL *bRootExtension; 
 
	Dump ("TCCreateRootDeviceObject BEGIN\n"); 
 
	wcscpy (dosname, (LPWSTR) DOS_ROOT_PREFIX); 
	wcscpy (ntname, (LPWSTR) NT_ROOT_PREFIX); 
	RtlInitUnicodeString (&ntUnicodeString, ntname); 
	RtlInitUnicodeString (&Win32NameString, dosname); 
 
	Dump ("Creating root device nt=%ls dos=%ls\n", ntname, dosname); 
 
	ntStatus = IoCreateDevice ( 
					  DriverObject,		/* Our Driver Object */ 
					  sizeof (BOOL),	/* Size of state information */ 
					  &ntUnicodeString,	/* Device name "\Device\Name" */ 
					  FILE_DEVICE_DISK,	/* Device type */ 
					  0,				/* Device characteristics */ 
					  FALSE,			/* Exclusive device */ 
					  &DeviceObject);	/* Returned ptr to Device Object */ 
 
	if (!NT_SUCCESS (ntStatus)) 
	{ 
		Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); 
		return ntStatus;/* Failed to create DeviceObject */ 
	} 
 
	DeviceObject->Flags |= DO_DIRECT_IO; 
	DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT; 
 
	/* Setup the device extension */ 
	bRootExtension = (BOOL *) DeviceObject->DeviceExtension; 
	*bRootExtension = TRUE; 
 
	/* The symlinks for mount devices are created from user-mode */ 
	ntStatus = IoCreateSymbolicLink (&Win32NameString, &ntUnicodeString); 
	if (!NT_SUCCESS (ntStatus)) 
	{ 
		Dump ("TCCreateRootDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); 
		IoDeleteDevice (DeviceObject); 
		return ntStatus; 
	} 
 
	ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL); 
	Dump ("TCCreateRootDeviceObject STATUS_SUCCESS END\n"); 
	return STATUS_SUCCESS; 
} 
 
NTSTATUS 
TCCreateDeviceObject (PDRIVER_OBJECT DriverObject, 
		       PDEVICE_OBJECT * ppDeviceObject, 
		       int nDosDriveNo) 
{ 
	UNICODE_STRING Win32NameString, ntUnicodeString; 
	WCHAR dosname[32], ntname[32]; 
	PEXTENSION Extension; 
	NTSTATUS ntStatus; 
 
	Dump ("TCCreateDeviceObject BEGIN\n"); 
 
	TCGetDosNameFromNumber (dosname, nDosDriveNo); 
	TCGetNTNameFromNumber (ntname, nDosDriveNo); 
	RtlInitUnicodeString (&ntUnicodeString, ntname); 
	RtlInitUnicodeString (&Win32NameString, dosname); 
 
	Dump ("Creating device nt=%ls dos=%ls\n", ntname, dosname); 
 
	ntStatus = IoCreateDevice ( 
					  DriverObject,			/* Our Driver Object */ 
					  sizeof (EXTENSION),	/* Size of state information */ 
					  &ntUnicodeString,		/* Device name "\Device\Name" */ 
					  FILE_DEVICE_DISK,		/* Device type */ 
					  0,					/* Device characteristics */ 
					  FALSE,				/* Exclusive device */ 
					  ppDeviceObject);		/* Returned ptr to Device Object */ 
 
	if (!NT_SUCCESS (ntStatus)) 
	{ 
		Dump ("TCCreateDeviceObject NTSTATUS = 0x%08x END\n", ntStatus); 
		return ntStatus;/* Failed to create DeviceObject */ 
	} 
	/* Initialize device object and extension. */ 
 
	(*ppDeviceObject)->Flags |= DO_DIRECT_IO; 
	(*ppDeviceObject)->AlignmentRequirement = FILE_WORD_ALIGNMENT; 
 
	/* Setup the device extension */ 
	Extension = (PEXTENSION) (*ppDeviceObject)->DeviceExtension; 
	memset (Extension, 0, sizeof (EXTENSION)); 
 
	Extension->lMagicNumber = 0xabfeacde; 
	Extension->nDosDriveNo = nDosDriveNo; 
 
	KeInitializeEvent (&Extension->keCreateEvent, SynchronizationEvent, FALSE); 
	KeInitializeSemaphore (&Extension->RequestSemaphore, 0L, MAXLONG); 
#ifdef USE_KERNEL_MUTEX 
	KeInitializeMutex (&Extension->KernelMutex, 1); 
#endif 
	KeInitializeSpinLock (&Extension->ListSpinLock); 
	InitializeListHead (&Extension->ListEntry); 
 
	ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL); 
	Dump ("TCCreateDeviceObject STATUS_SUCCESS END\n"); 
 
	return STATUS_SUCCESS; 
} 
 
/* TCDeviceControl handles certain requests from NT, these are needed for NT 
   to recognize the drive, also this function handles  our device specific 
   function codes, such as mount/unmount */ 
NTSTATUS 
TCDeviceControl (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, PIRP Irp) 
{ 
	PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation (Irp); 
	NTSTATUS ntStatus; 
 
#ifdef _DEBUG 
	 Dump ("TCDeviceControl BEGIN IoControlCode = %ls 0x%08x\n", 
	 TCTranslateCode (irpSp->Parameters.DeviceIoControl.IoControlCode), 
	      irpSp->Parameters.DeviceIoControl.IoControlCode); 
#endif 
 
	Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;	/* Assume failure. */ 
 
	/* Determine which I/O control code was specified.  */ 
	switch (irpSp->Parameters.DeviceIoControl.IoControlCode) 
	{ 
 
	case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: 
		if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (MOUNTDEV_NAME)) 
		{ 
			Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); 
			Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
		} 
		else 
		{ 
			ULONG outLength; 
			UNICODE_STRING ntUnicodeString; 
			WCHAR ntName[64]; 
			PMOUNTDEV_NAME outputBuffer = (PMOUNTDEV_NAME) Irp->AssociatedIrp.SystemBuffer; 
 
			Dump("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME:"); 
 
			TCGetNTNameFromNumber (ntName, Extension->nDosDriveNo); 
			RtlInitUnicodeString (&ntUnicodeString, ntName); 
 
			outputBuffer->NameLength = ntUnicodeString.Length; 
			outLength = ntUnicodeString.Length + sizeof(USHORT); 
 
			if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) 
			{ 
				Irp->IoStatus.Information = sizeof (MOUNTDEV_NAME); 
				Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
 
				break; 
			} 
 
			RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); 
 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = outLength; 
 
			Dump ("name = %ls\n",ntName); 
		} 
		break; 
 
	case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: 
		if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (MOUNTDEV_UNIQUE_ID)) 
		{ 
			Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); 
			Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
		} 
		else 
		{ 
			ULONG outLength; 
			UCHAR volId[128], tmp[] = { 0,0 }; 
			PMOUNTDEV_UNIQUE_ID outputBuffer = (PMOUNTDEV_UNIQUE_ID) Irp->AssociatedIrp.SystemBuffer; 
 
			Dump("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID:"); 
 
			strcpy (volId, TC_UNIQUE_ID_PREFIX);  
			tmp[0] = 'A' + Extension->nDosDriveNo; 
			strcat (volId, tmp); 
			 
			outputBuffer->UniqueIdLength = (USHORT) strlen(volId); 
			outLength = strlen(volId) + sizeof(USHORT); 
 
			if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) 
			{ 
				Irp->IoStatus.Information = sizeof (MOUNTDEV_UNIQUE_ID); 
				Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
				break; 
			} 
 
			RtlCopyMemory ((PCHAR)outputBuffer->UniqueId, volId, strlen(volId)); 
 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = outLength; 
 
			Dump ("id = %s\n",volId); 
		} 
		break; 
 
		case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: 
		{ 
			ULONG outLength; 
			UNICODE_STRING ntUnicodeString; 
			WCHAR ntName[64]; 
			PMOUNTDEV_SUGGESTED_LINK_NAME outputBuffer = (PMOUNTDEV_SUGGESTED_LINK_NAME) Irp->AssociatedIrp.SystemBuffer; 
			 
			Dump("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME:"); 
 
			TCGetDosNameFromNumber (ntName, Extension->nDosDriveNo); 
			RtlInitUnicodeString (&ntUnicodeString, ntName); 
 
			outLength = FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME,Name) + ntUnicodeString.Length; 
 
			outputBuffer->UseOnlyIfThereAreNoOtherLinks = FALSE; 
			outputBuffer->NameLength = ntUnicodeString.Length; 
 
			if(irpSp->Parameters.DeviceIoControl.OutputBufferLength < outLength) 
			{ 
				Irp->IoStatus.Information = sizeof (MOUNTDEV_SUGGESTED_LINK_NAME); 
				Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
				break; 
			} 
 
			RtlCopyMemory ((PCHAR)outputBuffer->Name,ntUnicodeString.Buffer, ntUnicodeString.Length); 
		 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = outLength; 
 
			Dump ("link = %ls\n",ntName); 
		} 
		break; 
 
	case IOCTL_DISK_GET_MEDIA_TYPES: 
	case IOCTL_DISK_GET_DRIVE_GEOMETRY: 
		/* Return the drive geometry for the disk.  Note that we 
		   return values which were made up to suit the disk size.  */ 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < 
		    sizeof (DISK_GEOMETRY)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			PDISK_GEOMETRY outputBuffer = (PDISK_GEOMETRY) 
			Irp->AssociatedIrp.SystemBuffer; 
 
			outputBuffer->MediaType = FixedMedia; 
			outputBuffer->Cylinders.QuadPart = Extension->NumberOfCylinders; 
			outputBuffer->TracksPerCylinder = Extension->TracksPerCylinder; 
			outputBuffer->SectorsPerTrack = Extension->SectorsPerTrack; 
			outputBuffer->BytesPerSector = Extension->BytesPerSector; 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = sizeof (DISK_GEOMETRY); 
		} 
		break; 
 
	case IOCTL_DISK_GET_PARTITION_INFO: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < 
		    sizeof (PARTITION_INFORMATION)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			PPARTITION_INFORMATION outputBuffer = (PPARTITION_INFORMATION) 
			Irp->AssociatedIrp.SystemBuffer; 
 
			outputBuffer->PartitionType = Extension->PartitionType; 
			outputBuffer->BootIndicator = FALSE; 
			outputBuffer->RecognizedPartition = TRUE; 
			outputBuffer->RewritePartition = FALSE; 
			outputBuffer->StartingOffset = RtlConvertUlongToLargeInteger (0); 
			outputBuffer->PartitionLength.QuadPart= Extension->DiskLength; 
			outputBuffer->HiddenSectors = 1L; 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = sizeof (PARTITION_INFORMATION); 
		} 
		break; 
	 
	case IOCTL_DISK_GET_LENGTH_INFO: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (GET_LENGTH_INFORMATION)) 
		{ 
			Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW; 
			Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); 
		} 
		else 
		{ 
			PGET_LENGTH_INFORMATION outputBuffer = (PGET_LENGTH_INFORMATION) Irp->AssociatedIrp.SystemBuffer; 
 
			outputBuffer->Length.QuadPart = Extension->DiskLength; 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = sizeof (GET_LENGTH_INFORMATION); 
		} 
		break; 
 
	case IOCTL_DISK_VERIFY: 
		{ 
			PVERIFY_INFORMATION pVerifyInformation; 
			pVerifyInformation = (PVERIFY_INFORMATION) Irp->AssociatedIrp.SystemBuffer; 
			irpSp->Parameters.Read.ByteOffset.LowPart = 
				pVerifyInformation->StartingOffset.LowPart; 
			irpSp->Parameters.Read.ByteOffset.HighPart = 
				pVerifyInformation->StartingOffset.HighPart; 
			irpSp->Parameters.Read.Length = pVerifyInformation->Length; 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = pVerifyInformation->Length; 
		} 
		break; 
 
	case IOCTL_DISK_CHECK_VERIFY: 
		{ 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = 0; 
		} 
		break; 
 
	case IOCTL_DISK_IS_WRITABLE: 
		{ 
			if (Extension->bReadOnly == TRUE) 
				Irp->IoStatus.Status = STATUS_MEDIA_WRITE_PROTECTED; 
			else 
				Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = 0; 
 
		} 
		break; 
 
	case DRIVER_VERSION: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < 4) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			LONG tmp = VERSION_NUM; 
			memcpy (Irp->AssociatedIrp.SystemBuffer, &tmp, 4); 
			Irp->IoStatus.Information = 4; 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
		} 
		break; 
 
	case OPEN_TEST: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (OPEN_TEST_STRUCT)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			OPEN_TEST_STRUCT *opentest = (OPEN_TEST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; 
			OBJECT_ATTRIBUTES ObjectAttributes; 
			HANDLE NtFileHandle; 
			UNICODE_STRING FullFileName; 
			IO_STATUS_BLOCK IoStatus; 
 
			RtlInitUnicodeString (&FullFileName, opentest->wszFileName); 
 
			InitializeObjectAttributes (&ObjectAttributes, &FullFileName, OBJ_CASE_INSENSITIVE, 
						    NULL, NULL); 
 
			ntStatus = ZwCreateFile (&NtFileHandle, 
						 SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatus, NULL /* alloc size = none  */ , 
						 FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | 
			FILE_NO_INTERMEDIATE_BUFFERING | FILE_RANDOM_ACCESS, 
				  NULL /* eabuffer  */ , 0 /* ealength */ ); 
 
			if (NT_SUCCESS (ntStatus)) 
			{ 
				ZwClose (NtFileHandle); 
				Dump ("Open test on file %ls success.\n", opentest->wszFileName); 
			} 
			else 
			{ 
				Dump ("Open test on file %ls failed NTSTATUS 0x%08x\n", opentest->wszFileName, ntStatus); 
			} 
 
			Irp->IoStatus.Information = 0; 
			Irp->IoStatus.Status = ntStatus; 
		} 
		break; 
 
	case WIPE_CACHE: 
		KeWaitForMutexObject (&driverMutex, Executive, KernelMode, 
				      FALSE, NULL); 
 
		WipeCache (); 
 
		KeReleaseMutex (&driverMutex, FALSE); 
 
		Irp->IoStatus.Status = STATUS_SUCCESS; 
		Irp->IoStatus.Information = 0; 
		break; 
 
	case CACHE_STATUS: 
		Irp->IoStatus.Status = cacheEmpty ? STATUS_PIPE_EMPTY : STATUS_SUCCESS; 
		Irp->IoStatus.Information = 0; 
		break; 
 
#ifdef DEBUG 
	case HALT_SYSTEM: 
		KeBugCheck ((ULONG) 0x5050); 
		break; 
#endif 
 
	case MOUNT_LIST: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (MOUNT_LIST_STRUCT)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			MOUNT_LIST_STRUCT *list = (MOUNT_LIST_STRUCT *) Irp->AssociatedIrp.SystemBuffer; 
			PDEVICE_OBJECT ListDevice; 
 
			list->ulMountedDrives = 0; 
			for (ListDevice = DeviceObject->DriverObject->DeviceObject; 
			     ListDevice != (PDEVICE_OBJECT) NULL; ListDevice = ListDevice->NextDevice) 
			{ 
 
				PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; 
				if (ListExtension->bRootDevice == FALSE) 
				{ 
					list->ulMountedDrives |= (1 << ListExtension->nDosDriveNo); 
					wcscpy (list->wszVolume[ListExtension->nDosDriveNo], ListExtension->wszVolume); 
					list->diskLength[ListExtension->nDosDriveNo] = ListExtension->DiskLength; 
					list->cipher[ListExtension->nDosDriveNo] = ListExtension->cryptoInfo->cipher; 
				} 
			} 
 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
			Irp->IoStatus.Information = sizeof (MOUNT_LIST_STRUCT); 
		} 
		break; 
 
	case VOLUME_PROPERTIES: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (VOLUME_PROPERTIES_STRUCT)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			VOLUME_PROPERTIES_STRUCT *prop = (VOLUME_PROPERTIES_STRUCT *) Irp->AssociatedIrp.SystemBuffer; 
			PDEVICE_OBJECT ListDevice; 
 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
 
			for (ListDevice = DeviceObject->DriverObject->DeviceObject; 
			     ListDevice != (PDEVICE_OBJECT) NULL; ListDevice = ListDevice->NextDevice) 
			{ 
 
				PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; 
				if (ListExtension->bRootDevice == FALSE && ListExtension->nDosDriveNo == prop->driveNo) 
				{ 
					wcscpy (prop->wszVolume, ListExtension->wszVolume); 
					prop->diskLength = ListExtension->DiskLength; 
					prop->cipher = ListExtension->cryptoInfo->cipher; 
					prop->pkcs5 = ListExtension->cryptoInfo->pkcs5; 
					prop->pkcs5Iterations = ListExtension->cryptoInfo->noIterations; 
					prop->volumeCreationTime = ListExtension->cryptoInfo->volume_creation_time; 
					prop->headerCreationTime = ListExtension->cryptoInfo->header_creation_time; 
 
					Irp->IoStatus.Status = STATUS_SUCCESS; 
					Irp->IoStatus.Information = sizeof (VOLUME_PROPERTIES_STRUCT); 
					break; 
				} 
			} 
		} 
		break; 
 
	case UNMOUNT_PENDING: 
		Extension->bShuttingDown = TRUE; 
		Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE; 
		Irp->IoStatus.Information = 0; 
		if (DeviceObject->Vpb && DeviceObject->Vpb->Flags & VPB_MOUNTED) 
		{ 
			IoSetHardErrorOrVerifyDevice (Irp, DeviceObject); 
			DeviceObject->Flags |= DO_VERIFY_VOLUME; 
		} 
		break; 
 
	case UNMOUNT: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (UNMOUNT_STRUCT)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			UNMOUNT_STRUCT *unmount = (UNMOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; 
			PDEVICE_OBJECT ListDevice; 
 
			unmount->nReturnCode = ERR_DRIVE_NOT_FOUND; 
 
			for (ListDevice = DeviceObject->DriverObject->DeviceObject; 
			     ListDevice != (PDEVICE_OBJECT) NULL; 
			     ListDevice = ListDevice->NextDevice) 
			{ 
 
				PEXTENSION ListExtension = (PEXTENSION) ListDevice->DeviceExtension; 
 
				if (ListExtension->bRootDevice == FALSE) 
				{ 
					if (unmount->nDosDriveNo == ListExtension->nDosDriveNo) 
					{ 
						if (ListDevice->Vpb && ListDevice->Vpb->ReferenceCount == 0 && (ListDevice->Vpb->Flags & VPB_MOUNTED) == 0) 
						{ 
							Dump ("Deleting DeviceObject with ref count %ld\n", ListDevice->ReferenceCount); 
							ListDevice->ReferenceCount = 0; 
							TCDeleteDeviceObject (ListDevice, (PEXTENSION) ListDevice->DeviceExtension); 
							unmount->nReturnCode = 0; 
							break; 
						} 
						else 
						{ 
							unmount->nReturnCode = ERR_FILES_OPEN; 
							break; 
						} 
					}	/* if the drive numbers are 
						   equal */ 
				}	/* if it's not the root device */ 
			}	/* for all the device objects the driver 
				   knows about */ 
 
			Irp->IoStatus.Information = sizeof (unmount->nReturnCode); 
			Irp->IoStatus.Status = STATUS_SUCCESS; 
		} 
		break; 
 
 
	case MOUNT: 
		if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (MOUNT_STRUCT)) 
		{ 
			Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 
			Irp->IoStatus.Information = 0; 
		} 
		else 
		{ 
			MOUNT_STRUCT *mount = (MOUNT_STRUCT *) Irp->AssociatedIrp.SystemBuffer; 
			ULONG *outputBuffer = (ULONG *) Irp->AssociatedIrp.SystemBuffer; 
			PDEVICE_OBJECT NewDeviceObject; 
 
			/* Make sure the user is asking for a resonable 
			   nDosDriveNo */ 
			if (mount->nDosDriveNo >= 0 && mount->nDosDriveNo <= 25) 
			{ 
				Dump ("Mount request looks valid\n"); 
			} 
			else 
			{ 
				Dump ("WARNING: MOUNT DRIVE LETTER INVALID\n"); 
				Irp->IoStatus.Information = sizeof (mount->nReturnCode); 
				Irp->IoStatus.Status = STATUS_SUCCESS; 
				mount->nReturnCode = ERR_BAD_DRIVE_LETTER; 
				break; 
			} 
 
			ntStatus = TCCreateDeviceObject (DeviceObject->DriverObject, &NewDeviceObject, 
							mount->nDosDriveNo); 
			if (!NT_SUCCESS (ntStatus)) 
			{ 
				Dump ("Mount CREATE DEVICE ERROR, ntStatus = 0x%08x\n", ntStatus); 
				Irp->IoStatus.Information = 0; 
				Irp->IoStatus.Status = ntStatus; 
				break; 
			} 
			else 
			{ 
				PEXTENSION NewExtension = (PEXTENSION) NewDeviceObject->DeviceExtension; 
				ntStatus = TCStartThread (NewDeviceObject, NewExtension, mount); 
				if (!NT_SUCCESS (ntStatus)) 
				{ 
					Dump ("Mount FAILURE NT ERROR, ntStatus = 0x%08x\n", ntStatus); 
					Irp->IoStatus.Information = 0; 
					Irp->IoStatus.Status = ntStatus; 
					TCDeleteDeviceObject (NewDeviceObject, NewExtension); 
					break; 
				} 
				else 
				{ 
					if (mount->nReturnCode == 0) 
					{ 
						Dump ("Mount SUCCESS TC code = 0x%08x READ-ONLY = %d\n", mount->nReturnCode, 
						   NewExtension->bReadOnly); 
						if (NewExtension->bReadOnly == TRUE) 
							NewDeviceObject->Characteristics |= FILE_READ_ONLY_DEVICE; 
						NewDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 
					} 
					else 
					{ 
						Dump ("Mount FAILURE TC code = 0x%08x\n", mount->nReturnCode); 
						TCDeleteDeviceObject (NewDeviceObject, NewExtension); 
					} 
					Irp->IoStatus.Information = sizeof (mount->nReturnCode); 
					Irp->IoStatus.Status = STATUS_SUCCESS; 
					break; 
				} 
			} 
		} 
		break; 
	} 
 
	/* Finish the I/O operation by simply completing the packet and 
	   returning the same NTSTATUS as in the packet itself.  */ 
	ntStatus = COMPLETE_IRP (DeviceObject, Irp, Irp->IoStatus.Status, Irp->IoStatus.Information); 
	Dump ("TCDeviceControl NTSTATUS = 0x%08x END\n", ntStatus); 
	return ntStatus; 
} 
 
NTSTATUS 
TCStartThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension, MOUNT_STRUCT * mount) 
{ 
	PTHREAD_BLOCK pThreadBlock = TCalloc (sizeof (THREAD_BLOCK)); 
	HANDLE hThread; 
	NTSTATUS ntStatus; 
 
	Dump ("Starting thread...\n"); 
 
	if (pThreadBlock == NULL) 
	{ 
		return STATUS_INSUFFICIENT_RESOURCES; 
	} 
	else 
	{ 
		pThreadBlock->DeviceObject = DeviceObject; 
		pThreadBlock->mount = mount; 
	} 
 
	Extension->bThreadShouldQuit = FALSE; 
 
	ntStatus = PsCreateSystemThread (&hThread, 
					 THREAD_ALL_ACCESS, 
					 NULL, 
					 NULL, 
					 NULL, 
					 TCThreadIRP, 
					 pThreadBlock); 
 
	if (!NT_SUCCESS (ntStatus)) 
	{ 
		Dump ("PsCreateSystemThread Failed END\n"); 
		TCfree (pThreadBlock); 
		return ntStatus; 
	} 
 
	ObReferenceObjectByHandle (hThread, 
				   THREAD_ALL_ACCESS, 
				   NULL, 
				   KernelMode, 
				   &Extension->peThread, 
				   NULL); 
	ZwClose (hThread); 
 
	Dump ("Waiting for thread to initialize...\n"); 
 
	KeWaitForSingleObject (&Extension->keCreateEvent, 
			       UserRequest, 
			       UserMode, 
			       FALSE, 
			       NULL); 
 
	Dump ("Waiting completed! Thread returns 0x%08x\n", pThreadBlock->ntCreateStatus); 
	ntStatus = pThreadBlock->ntCreateStatus; 
	TCfree (pThreadBlock); 
	return ntStatus; 
} 
 
void 
TCStopThread (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) 
{ 
	NTSTATUS ntStatus; 
 
	if (DeviceObject);	/* Remove compiler warning */ 
 
	Dump ("Signalling thread to quit...\n"); 
 
	Extension->bThreadShouldQuit = TRUE; 
 
	KeReleaseSemaphore (&Extension->RequestSemaphore, 
			    0, 
			    1, 
			    TRUE); 
 
	ntStatus = KeWaitForSingleObject (&Extension->peThread, 
					  UserRequest, 
					  UserMode, 
					  FALSE, 
					  NULL); 
	if (ntStatus != STATUS_SUCCESS) 
		Dump ("Failed waiting for crypto thread to quit: 0x%08x...\n", 
		      ntStatus); 
 
	ObDereferenceObject (&Extension->peThread); 
	Extension->peThread = NULL; 
 
	Dump ("Thread exited!\n"); 
} 
 
/* TCThreadIRP does all the work of processing IRP's, and dispatching them 
   to either the ReadWrite function or the DeviceControl function */ 
VOID 
TCThreadIRP (PVOID Context) 
{ 
	PTHREAD_BLOCK pThreadBlock = (PTHREAD_BLOCK) Context; 
	PDEVICE_OBJECT DeviceObject = pThreadBlock->DeviceObject; 
	PDRIVER_OBJECT DriverObject = DeviceObject->DriverObject; 
	PEXTENSION Extension = (PEXTENSION) DeviceObject->DeviceExtension; 
	LARGE_INTEGER queueWait; 
	BOOL bDevice; 
 
	/* Set thread priority to lowest realtime level. */ 
 
	KeSetPriorityThread (KeGetCurrentThread (), LOW_REALTIME_PRIORITY); 
 
	queueWait.QuadPart = -WAIT_SECONDS (1); 
 
	Dump ("Mount THREAD OPENING VOLUME BEGIN\n"); 
 
#ifdef USE_KERNEL_MUTEX 
	KeWaitForMutexObject (&Extension->KernelMutex, Executive, KernelMode, 
			      FALSE, NULL); 
#endif 
 
	if (memcmp (pThreadBlock->mount->wszVolume, WIDE ("\\Device"), 14) != 0) 
	{ 
		wcscpy (pThreadBlock->wszMountVolume, WIDE ("\\??\\")); 
		wcscat (pThreadBlock->wszMountVolume, pThreadBlock->mount->wszVolume); 
		bDevice = FALSE; 
	} 
	else 
	{ 
		wcscpy (pThreadBlock->wszMountVolume, pThreadBlock->mount->wszVolume); 
		bDevice = TRUE; 
	} 
 
	Dump ("Mount THREAD request for File %ls DriveNumber %d Device = %d\n", 
	      pThreadBlock->wszMountVolume, pThreadBlock->mount->nDosDriveNo, bDevice); 
 
	pThreadBlock->ntCreateStatus = TCOpenVolume (DeviceObject, 
						      Extension, 
						      pThreadBlock->mount, 
					       pThreadBlock->wszMountVolume, 
						      bDevice); 
 
#ifdef USE_KERNEL_MUTEX 
	KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
 
	if (!NT_SUCCESS (pThreadBlock->ntCreateStatus) || pThreadBlock->mount->nReturnCode != 0) 
	{ 
		KeSetEvent (&Extension->keCreateEvent, 0, FALSE); 
		PsTerminateSystemThread (STATUS_SUCCESS); 
	} 
	else 
	{ 
		KeSetEvent (&Extension->keCreateEvent, 0, FALSE); 
		/* From this point on pThreadBlock cannot be used as it will 
		   have been released! */ 
		pThreadBlock = NULL; 
	} 
 
 
	for (;;) 
	{ 
		NTSTATUS ntStatus; 
 
		ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL); 
 
		/* Wait for a request from the dispatch routines. */ 
		ntStatus = KeWaitForSingleObject ((PVOID) & Extension->RequestSemaphore, 
				  Executive, KernelMode, FALSE, &queueWait); 
 
		if (ntStatus != STATUS_TIMEOUT) 
		{ 
 
#ifdef USE_KERNEL_MUTEX 
			KeWaitForMutexObject (&Extension->KernelMutex, Executive, KernelMode, 
					      FALSE, NULL); 
#endif 
 
		//	Dump ("DRIVER THREAD PROCESSING DEVICEOBJECT 0x%08x \n", DeviceObject); 
 
			for (;;) 
			{ 
				PIO_STACK_LOCATION irpSp; 
				PLIST_ENTRY request; 
				PIRP Irp; 
 
				request = ExInterlockedRemoveHeadList (&Extension->ListEntry, 
						  &Extension->ListSpinLock); 
				if (request == NULL) 
					break; 
 
				ASSERT (KeGetCurrentIrql ()== PASSIVE_LEVEL); 
 
				Irp = CONTAINING_RECORD (request, IRP, Tail.Overlay.ListEntry); 
				irpSp = IoGetCurrentIrpStackLocation (Irp); 
 
				switch (irpSp->MajorFunction) 
				{ 
				case IRP_MJ_READ: 
				case IRP_MJ_WRITE: 
					TCReadWrite (DeviceObject, Extension, Irp); 
					break; 
 
				case IRP_MJ_FLUSH_BUFFERS: 
					if (Extension->bRawDevice == FALSE) 
						TCSendIRP_FileDevice (DeviceObject, Extension, NULL, Irp->Flags, IRP_MJ_FLUSH_BUFFERS, Irp); 
					else 
					{ 
						COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); 
					} 
					break; 
 
				case IRP_MJ_SHUTDOWN: 
					COMPLETE_IRP (DeviceObject, Irp, STATUS_SUCCESS, 0); 
					break; 
 
				case IRP_MJ_DEVICE_CONTROL: 
					if (irpSp->Parameters.DeviceIoControl.IoControlCode != IOCTL_DISK_CHECK_VERIFY) 
						TCDeviceControl (DeviceObject, Extension, Irp); 
					else 
					{ 
						if (Extension->bRawDevice == TRUE) 
							TCSendIRP_RawDevice (DeviceObject, Extension, NULL, 0, IRP_MJ_DEVICE_CONTROL, Irp); 
						else 
							TCDeviceControl (DeviceObject, Extension, Irp); 
					} 
					break; 
				}	/* end of switch on 
					   irpSp->MajorFunction */ 
			}	/* for any remaining IRP's for this device */ 
 
#ifdef USE_KERNEL_MUTEX 
			KeReleaseMutex (&Extension->KernelMutex, FALSE); 
#endif 
 
			if (Extension->bThreadShouldQuit) 
			{ 
			//	Dump ("END PROCESSING DEVICEOBJECT THREAD ENDING 0x%08x Number = %d\n", 
			//	      DeviceObject, Extension->nDosDriveNo); 
				Dump ("Closing volume along with Thread!\n"); 
				TCCloseVolume (DeviceObject, Extension); 
				PsTerminateSystemThread (STATUS_SUCCESS); 
			} 
			//else 
			//{ 
			//	Dump ("END PROCESSING DEVICEOBJECT 0x%08x Number = %d\n", 
			//	      DeviceObject, Extension->nDosDriveNo); 
			//} 
		} 
 
	}			/* outermost for */ 
} 
 
void 
TCGetNTNameFromNumber (LPWSTR ntname, int nDriveNo) 
{ 
	WCHAR tmp[3] = 
	{0, ':', 0}; 
	int j = nDriveNo + (WCHAR) 'A'; 
 
	tmp[0] = (short) j; 
	wcscpy (ntname, (LPWSTR) NT_MOUNT_PREFIX); 
	wcsncat (ntname, tmp, 1); 
} 
 
void 
TCGetDosNameFromNumber (LPWSTR dosname, int nDriveNo) 
{ 
	WCHAR tmp[3] = 
	{0, ':', 0}; 
	int j = nDriveNo + (WCHAR) 'A'; 
 
	tmp[0] = (short) j; 
	wcscpy (dosname, (LPWSTR) DOS_MOUNT_PREFIX); 
	wcscat (dosname, tmp); 
} 
 
#ifdef _DEBUG 
LPWSTR 
TCTranslateCode (ULONG ulCode) 
{ 
	if (ulCode ==			 IOCTL_DISK_GET_DRIVE_GEOMETRY) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY"); 
	else if (ulCode ==		 IOCTL_DISK_GET_DRIVE_GEOMETRY_EX) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_QUERY_DEVICE_NAME) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_QUERY_UNIQUE_ID) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_QUERY_UNIQUE_ID"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_UNIQUE_ID_CHANGE_NOTIFY"); 
	else if (ulCode ==		 IOCTL_VOLUME_ONLINE) 
		return (LPWSTR) _T ("IOCTL_VOLUME_ONLINE"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_LINK_CREATED) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_CREATED"); 
	else if (ulCode ==		 IOCTL_MOUNTDEV_LINK_DELETED) 
		return (LPWSTR) _T ("IOCTL_MOUNTDEV_LINK_DELETED"); 
	else if (ulCode ==		 IOCTL_MOUNTMGR_QUERY_POINTS) 
		return (LPWSTR) _T ("IOCTL_MOUNTMGR_QUERY_POINTS"); 
	else if (ulCode ==		 IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED) 
		return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_CREATED"); 
	else if (ulCode ==		 IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED) 
		return (LPWSTR) _T ("IOCTL_MOUNTMGR_VOLUME_MOUNT_POINT_DELETED"); 
	else if (ulCode ==		 IOCTL_DISK_GET_LENGTH_INFO) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_LENGTH_INFO"); 
	else if (ulCode ==		 IOCTL_STORAGE_GET_DEVICE_NUMBER) 
		return (LPWSTR) _T ("IOCTL_STORAGE_GET_DEVICE_NUMBER"); 
	else if (ulCode ==		 IOCTL_DISK_GET_PARTITION_INFO) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO"); 
	else if (ulCode ==		 IOCTL_DISK_GET_PARTITION_INFO_EX) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_PARTITION_INFO_EX"); 
	else if (ulCode ==		 IOCTL_DISK_SET_PARTITION_INFO) 
		return (LPWSTR) _T ("IOCTL_DISK_SET_PARTITION_INFO"); 
	else if (ulCode ==		 IOCTL_DISK_GET_DRIVE_LAYOUT) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_DRIVE_LAYOUT"); 
	else if (ulCode ==		 IOCTL_DISK_SET_DRIVE_LAYOUT_EX) 
		return (LPWSTR) _T ("IOCTL_DISK_SET_DRIVE_LAYOUT_EX"); 
	else if (ulCode ==		 IOCTL_DISK_VERIFY) 
		return (LPWSTR) _T ("IOCTL_DISK_VERIFY"); 
	else if (ulCode == IOCTL_DISK_FORMAT_TRACKS) 
		return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS"); 
	else if (ulCode == IOCTL_DISK_REASSIGN_BLOCKS) 
		return (LPWSTR) _T ("IOCTL_DISK_REASSIGN_BLOCKS"); 
	else if (ulCode == IOCTL_DISK_PERFORMANCE) 
		return (LPWSTR) _T ("IOCTL_DISK_PERFORMANCE"); 
	else if (ulCode == IOCTL_DISK_IS_WRITABLE) 
		return (LPWSTR) _T ("IOCTL_DISK_IS_WRITABLE"); 
	else if (ulCode == IOCTL_DISK_LOGGING) 
		return (LPWSTR) _T ("IOCTL_DISK_LOGGING"); 
	else if (ulCode == IOCTL_DISK_FORMAT_TRACKS_EX) 
		return (LPWSTR) _T ("IOCTL_DISK_FORMAT_TRACKS_EX"); 
	else if (ulCode == IOCTL_DISK_HISTOGRAM_STRUCTURE) 
		return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_STRUCTURE"); 
	else if (ulCode == IOCTL_DISK_HISTOGRAM_DATA) 
		return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_DATA"); 
	else if (ulCode == IOCTL_DISK_HISTOGRAM_RESET) 
		return (LPWSTR) _T ("IOCTL_DISK_HISTOGRAM_RESET"); 
	else if (ulCode == IOCTL_DISK_REQUEST_STRUCTURE) 
		return (LPWSTR) _T ("IOCTL_DISK_REQUEST_STRUCTURE"); 
	else if (ulCode == IOCTL_DISK_REQUEST_DATA) 
		return (LPWSTR) _T ("IOCTL_DISK_REQUEST_DATA"); 
	else if (ulCode == IOCTL_DISK_CONTROLLER_NUMBER) 
		return (LPWSTR) _T ("IOCTL_DISK_CONTROLLER_NUMBER"); 
	else if (ulCode == SMART_GET_VERSION) 
		return (LPWSTR) _T ("SMART_GET_VERSION"); 
	else if (ulCode == SMART_SEND_DRIVE_COMMAND) 
		return (LPWSTR) _T ("SMART_SEND_DRIVE_COMMAND"); 
	else if (ulCode == SMART_RCV_DRIVE_DATA) 
		return (LPWSTR) _T ("SMART_RCV_DRIVE_DATA"); 
	else if (ulCode == IOCTL_DISK_INTERNAL_SET_VERIFY) 
		return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_SET_VERIFY"); 
	else if (ulCode == IOCTL_DISK_INTERNAL_CLEAR_VERIFY) 
		return (LPWSTR) _T ("IOCTL_DISK_INTERNAL_CLEAR_VERIFY"); 
	else if (ulCode == IOCTL_DISK_CHECK_VERIFY) 
		return (LPWSTR) _T ("IOCTL_DISK_CHECK_VERIFY"); 
	else if (ulCode == IOCTL_DISK_MEDIA_REMOVAL) 
		return (LPWSTR) _T ("IOCTL_DISK_MEDIA_REMOVAL"); 
	else if (ulCode == IOCTL_DISK_EJECT_MEDIA) 
		return (LPWSTR) _T ("IOCTL_DISK_EJECT_MEDIA"); 
	else if (ulCode == IOCTL_DISK_LOAD_MEDIA) 
		return (LPWSTR) _T ("IOCTL_DISK_LOAD_MEDIA"); 
	else if (ulCode == IOCTL_DISK_RESERVE) 
		return (LPWSTR) _T ("IOCTL_DISK_RESERVE"); 
	else if (ulCode == IOCTL_DISK_RELEASE) 
		return (LPWSTR) _T ("IOCTL_DISK_RELEASE"); 
	else if (ulCode == IOCTL_DISK_FIND_NEW_DEVICES) 
		return (LPWSTR) _T ("IOCTL_DISK_FIND_NEW_DEVICES"); 
	else if (ulCode == IOCTL_DISK_GET_MEDIA_TYPES) 
		return (LPWSTR) _T ("IOCTL_DISK_GET_MEDIA_TYPES"); 
	else if (ulCode == IOCTL_STORAGE_SET_HOTPLUG_INFO) 
		return (LPWSTR) _T ("IOCTL_STORAGE_SET_HOTPLUG_INFO"); 
	else if (ulCode == IRP_MJ_READ) 
		return (LPWSTR) _T ("IRP_MJ_READ"); 
	else if (ulCode == IRP_MJ_WRITE) 
		return (LPWSTR) _T ("IRP_MJ_WRITE"); 
	else if (ulCode == IRP_MJ_CREATE) 
		return (LPWSTR) _T ("IRP_MJ_CREATE"); 
	else if (ulCode == IRP_MJ_CLOSE) 
		return (LPWSTR) _T ("IRP_MJ_CLOSE"); 
	else if (ulCode == IRP_MJ_CLEANUP) 
		return (LPWSTR) _T ("IRP_MJ_CLEANUP"); 
	else if (ulCode == IRP_MJ_FLUSH_BUFFERS) 
		return (LPWSTR) _T ("IRP_MJ_FLUSH_BUFFERS"); 
	else if (ulCode == IRP_MJ_SHUTDOWN) 
		return (LPWSTR) _T ("IRP_MJ_SHUTDOWN"); 
	else if (ulCode == IRP_MJ_DEVICE_CONTROL) 
		return (LPWSTR) _T ("IRP_MJ_DEVICE_CONTROL"); 
	else if (ulCode == MOUNT) 
		return (LPWSTR) _T ("MOUNT"); 
	else if (ulCode == UNMOUNT) 
		return (LPWSTR) _T ("UNMOUNT"); 
	else if (ulCode == MOUNT_LIST) 
		return (LPWSTR) _T ("MOUNT_LIST"); 
	else if (ulCode == OPEN_TEST) 
		return (LPWSTR) _T ("OPEN_TEST"); 
	else if (ulCode == UNMOUNT_PENDING) 
		return (LPWSTR) _T ("UNMOUNT_PENDING"); 
	else 
	{ 
		Dump("Unknown IOCTL recieved: DeviceType = 0x%x Function = 0x%x", (int)(ulCode>>16), (int)((ulCode&0x1FFF)>>2)); 
		return (LPWSTR) _T ("UNKNOWN"); 
	} 
} 
 
#endif 
 
PDEVICE_OBJECT 
TCDeleteDeviceObject (PDEVICE_OBJECT DeviceObject, PEXTENSION Extension) 
{ 
	PDEVICE_OBJECT OldDeviceObject = DeviceObject; 
	UNICODE_STRING Win32NameString; 
	WCHAR dosname[32]; 
	NTSTATUS ntStatus; 
 
	Dump ("TCDeleteDeviceObject BEGIN\n"); 
 
	if (Extension->bRootDevice == TRUE) 
	{ 
		RtlInitUnicodeString (&Win32NameString, (LPWSTR) DOS_ROOT_PREFIX); 
	} 
	else 
	{ 
		if (Extension->peThread != NULL) 
			TCStopThread (DeviceObject, Extension); 
		TCGetDosNameFromNumber (dosname, Extension->nDosDriveNo); 
		RtlInitUnicodeString (&Win32NameString, dosname); 
	} 
 
	ntStatus = IoDeleteSymbolicLink (&Win32NameString); 
	if (!NT_SUCCESS (ntStatus)) 
	{ 
		Dump ("IoDeleteSymbolicLink failed ntStatus = 0x%08x\n", ntStatus); 
	} 
 
	DeviceObject = DeviceObject->NextDevice; 
	IoDeleteDevice (OldDeviceObject); 
 
	Dump ("TCDeleteDeviceObject END\n"); 
	return DeviceObject; 
} 
 
VOID 
TCUnloadDriver (PDRIVER_OBJECT DriverObject) 
{ 
	PDEVICE_OBJECT DeviceObject = DriverObject->DeviceObject; 
 
	Dump ("TCUnloadDriver BEGIN\n"); 
 
	/* Now walk the list of driver objects and get rid of them */ 
	while (DeviceObject != (PDEVICE_OBJECT) NULL) 
	{ 
		DeviceObject = TCDeleteDeviceObject (DeviceObject, 
				(PEXTENSION) DeviceObject->DeviceExtension); 
	} 
 
	Dump ("TCUnloadDriver END\n"); 
}