//
//  Macro to test if this is my device object
//

#define IS_MY_DEVICE_OBJECT(_devObj) \
    (((_devObj) != NULL) && \
     ((_devObj)->DriverObject == gIntcDriverObject) && \
      ((_devObj)->DeviceExtension != NULL))

//
//  Macro to test if this is my control device object
//
#define IS_INTC_DEVICE_OBJECT(_devObj)			\
	( ( (_devObj) == gIntcControlDeviceObject &&		\
	    ((PINTERCEPTER_DEVICE_EXTENSION)(_devObj)->DeviceExtension)->Type == INTC_DEVICE	\
	  ) ? TRUE : FALSE									\
	)	

//
//  Macro to test if this is hooked fs control device object
//
#define IS_HOOKED_FS_DEVICE_OBJECT(_devObj)			\
	( ( (_devObj) == gIntcControlDeviceObject &&		\
	    ((PINTERCEPTER_DEVICE_EXTENSION)(_devObj)->DeviceExtension)->Type == HOOKED_FS_DEVICE	\
	  ) ? TRUE : FALSE									\
	)	

//
//  Macro to test if FAST_IO_DISPATCH handling routine is valid
//

#define VALID_FAST_IO_DISPATCH_HANDLER(_FastIoDispatchPtr, _FieldName) \
    (((_FastIoDispatchPtr) != NULL) && \
     (((_FastIoDispatchPtr)->SizeOfFastIoDispatch) >= \
            (FIELD_OFFSET(FAST_IO_DISPATCH, _FieldName) + sizeof(void *))) && \
     ((_FastIoDispatchPtr)->_FieldName != NULL))


// device type
#define INTC_DEVICE		1
#define HOOKED_FS_DEVICE	2 

static const ULONG MAX_TARGET_FILES	 = 20; // later will be dynamicly resizeble buffer
static const ULONG NOT_TARGET_FILE	 = -1; 

typedef struct _INTC_CRYPT_EXTENSION
{
	PVOID TargetFileID;
	PVOID RealUserBuffer;
	PVOID AllocUserBuffer;
	// some other data and counters (later)
	
} INTC_CRYPT_EXTENSION, *PINTC_CRYPT_EXTENSION;

typedef struct _INTERCEPTER_DEVICE_EXTENSION
{
	unsigned	Type;				// 1 - CONTROL DEVICE; 2 - HOOKED_FS

	PDEVICE_OBJECT	pAttachedToDeviceObject;	// target dev object (we filtering his IRP's)
	PDEVICE_OBJECT	pNextDeviceObject;		// next device for sending IRP's down
	unsigned	DriveLetter;				

	UNICODE_STRING	TargetFile;

	INTC_CRYPT_EXTENSION CryptExt[/*MAX_TARGET_FILES*/20];

	//IO_REMOVE_LOCK RemoveLock;
} INTERCEPTER_DEVICE_EXTENSION, *PINTERCEPTER_DEVICE_EXTENSION;


//
// GLOBALS
//
PDEVICE_OBJECT gIntcControlDeviceObject;		// intercepter control device object
PDRIVER_OBJECT gIntcDriverObject;			// This is our Driver Object




VOID
	IntcLockUserBuffer (
//    IN PIRP_CONTEXT IrpContext,
		IN OUT PIRP Irp,
		IN LOCK_OPERATION Operation,
		IN ULONG BufferLength )

/*++
Routine Description:

    This routine locks the specified buffer for the specified type of
    access. The file system requires this routine because it does not
    ask the I/O system to lock its buffers for direct I/O. This routine
    can only be called from the file system driver (FSD) while still in the user context.

    Note that this is the *input/output* buffer.

Arguments:
    Irp - Pointer to the Irp for which the buffer will be locked.
    Operation - IoWriteAccess for read operations, or IoReadAccess for
                write operations.
    BufferLength - Length of user buffer.

Return Value:
    None
--*/

{
	NTSTATUS Status;
    PMDL Mdl = NULL;

	if (Irp->MdlAddress == NULL) {
        //
        // Allocate the Mdl and Raise if the allocation fails.
		//
		// When the IRP is completed, the system unlocks and frees all the MDLs 
		// that are associated with the IRP. The system unlocks the MDLs before 
		// it queues the I/O completion routine and frees them after the I/O completion routine executes
        //

		////KdPrint(("User->Buffer %s", (char*)Irp->UserBuffer));
        Mdl = IoAllocateMdl( Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp );
        if (Mdl == NULL) {
            ////FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES );
			ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
        }
////KdPrint(("IoAllocateMdl [ok]"));
        //
        // now probe the buffer described by the Irp. If there is an exception,
        // deallocate the Mdl and return the appropriate "expected" status.
        //
        try {
            MmProbeAndLockPages( Mdl,
                                 Irp->RequestorMode,
                                 Operation );
        } except(EXCEPTION_EXECUTE_HANDLER) {
            
            Status = GetExceptionCode();
            IoFreeMdl( Mdl );
            Irp->MdlAddress = NULL;
            ////FatRaiseStatus( IrpContext,
			//ExRaiseStatus( FsRtlIsNtstatusExpected(Status) ? Status : STATUS_INVALID_USER_BUFFER );
			ExRaiseStatus( Status );
        }
    }

    //UNREFERENCED_PARAMETER( IrpContext );
}


PVOID
	IntcMapUserBuffer (
		//IN PIRP_CONTEXT IrpContext,
		IN OUT PIRP Irp
		)
/*++
Routine Description:
    This routine conditionally maps the user buffer for the current I/O
    request in the specified mode. If the buffer is already mapped, it
    just returns its address.
   
    Note that this is the *input/output* buffer.

Arguments:
    Irp - Pointer to the Irp for the request.

Return Value:
    Mapped address
--*/
{
    //UNREFERENCED_PARAMETER( IrpContext );
	PVOID Address;
    //
    // If there is no Mdl, then we must be in the FSD, and can simply
    // return the UserBuffer field from the Irp.
    //
    if (Irp->MdlAddress == NULL) {
        return Irp->UserBuffer;
    } else {
        Address = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority );
        if (Address == NULL) {
            ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
        }
        return Address;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////


NTSTATUS 
	IntcCloseRoutine(
		IN PDEVICE_OBJECT pDevice,
		IN PIRP pIrp
		)
{
	PINTERCEPTER_DEVICE_EXTENSION pde;
	PIO_STACK_LOCATION  currentIrpStack;

	if (IS_INTC_DEVICE_OBJECT(pDevice)) { 
		// our IRP
		return IntcDeviceRoutine(pDevice, pIrp);
	}

	pde = pDevice->DeviceExtension;
	currentIrpStack = IoGetCurrentIrpStackLocation( pIrp );
	
	// a bug... but i will not dalete my markers, do not whant to loose FILE_OBJECT's
	//	DelTargetFile (pde, GetTargetFile(pde, currentIrpStack->FileObject->FsContext));

	//
	// don't care about complection of this request
	//
	IoSkipCurrentIrpStackLocation( pIrp );
	return IoCallDriver ( pde->pNextDeviceObject, pIrp );
}



NTSTATUS 
	IntcReadRoutine(
		IN PDEVICE_OBJECT pDevice,
		IN PIRP pIrp
		)
{
	PINTERCEPTER_DEVICE_EXTENSION pde;
	PIO_STACK_LOCATION  currentIrpStack;

	if (IS_INTC_DEVICE_OBJECT(pDevice)) { 
		// our IRP
		return IntcDeviceRoutine(pDevice, pIrp);
	}

	pde = pDevice->DeviceExtension;
	currentIrpStack = IoGetCurrentIrpStackLocation( pIrp );

	if (GetTargetFile (pde, currentIrpStack->FileObject->FsContext) == NOT_TARGET_FILE )
	{
		//
		// this file do not need to be crypted (scip complection)
		//
		IoSkipCurrentIrpStackLocation( pIrp );
	} else {
		//
		// set up complection routine to decrypt data 
		// that OLREDY in users buffer (after reeding)
		//
		IoCopyCurrentIrpStackLocationToNext( pIrp ); 

		IoSetCompletionRoutine(	
			pIrp,			// Irp
			IntcRdWrCompletion,	// CompletionRoutine
			pde,			// Context
			TRUE,			// InvokeOnSuccess
			TRUE,			// InvokeOnError
			TRUE);			// InvokeOnCancel
	}

	return IoCallDriver ( pde->pNextDeviceObject, pIrp );
}

NTSTATUS 
	IntcWriteRoutine(
		IN PDEVICE_OBJECT pDevice,
		IN PIRP pIrp
		)
{	
	PINTERCEPTER_DEVICE_EXTENSION pde;
	PIO_STACK_LOCATION  currentIrpStack;

	NTSTATUS status;

	PVOID UserBuffer;
	ULONG UserBufferLength;
	PVOID UserBufferCryptCopy; 
	LARGE_INTEGER UserBufferOffset;

	PVOID AllocBuffer;
	PVOID MdlAddress;

	ULONG ZeroBits;
	SIZE_T RegionSize;
	ULONG FileID;

	if (IS_INTC_DEVICE_OBJECT(pDevice)) { 
		//KdPrint((" My DEVICE" ));
		return IntcDeviceRoutine(pDevice, pIrp);
	}

	pde = pDevice->DeviceExtension;
	currentIrpStack = IoGetCurrentIrpStackLocation( pIrp );

	FileID = GetTargetFile (pde, currentIrpStack->FileObject->FsContext);
	if (FileID == NOT_TARGET_FILE)
	{
		//
		// this file do not need to be crypted (scip complection)
		//
		IoSkipCurrentIrpStackLocation( pIrp );
		return IoCallDriver ( pde->pNextDeviceObject, pIrp );
	}

//	KdPrint(("IRP_MJ_WRITE:"));

	if (pIrp->Flags & DO_BUFFERED_IO) {
		//KdPrint((" Buffered IO")); // pIrp->AssociatedIrp.SystemBuffer

		IoSkipCurrentIrpStackLocation( pIrp );
		return IoCallDriver ( pde->pNextDeviceObject, pIrp );
	}
								
	if (pIrp->Flags & DO_DIRECT_IO) {
		//KdPrint((" Direct IO"));	// MmGetMdlVirtualAddress(pIrp->MdlAddress);

		IoSkipCurrentIrpStackLocation( pIrp );
		return IoCallDriver ( pde->pNextDeviceObject, pIrp );
	}

	// METHOD_NEITHER:
	
	//KdPrint((" METHOD_NEITHER"));		
	try {	

		switch (pIrp->RequestorMode) 
		{
		case UserMode:
//			KdPrint(("user_mode"));
			// do not care about user buffer 
			// i whant CASH!!!
			IoSkipCurrentIrpStackLocation( pIrp );
			return IoCallDriver ( pde->pNextDeviceObject, pIrp );

			//
			// REMARK: Buffer valid only for reading!!!
			//
			ProbeForRead (pIrp->UserBuffer, UserBufferLength, 1);
 			// some text 
						
			break; // UserMode

		case KernelMode:
//			KdPrint (("KernelMode"));

			if (pIrp->MdlAddress != 0 && pIrp->RequestorMode == KernelMode) {
				
				// this is cash manager writes some data 
				// so CRYPT IT before store on disk

				UserBufferLength = MmGetMdlByteCount (pIrp->MdlAddress);
				UserBufferOffset = currentIrpStack->Parameters.Write.ByteOffset;
				
				IntcLockUserBuffer (
					pIrp,
					IoModifyAccess,
					UserBufferLength );

				MdlAddress = IntcMapUserBuffer ( pIrp );

				if (MdlAddress == NULL) {
					KdPrint((" ERROR MmGetSystemAddressForMdlSafe !"));
				} else {

					//ShowFileBuff(" MDL_BUFF", MdlAddress, UserBufferLength);
//					KdPrint((" get_mdel_buff ok"));

					
					IntercepterCryptData (
						MdlAddress,
						0, // dest_buff = src_buff
						UserBufferLength,
						UserBufferOffset );
					
				}
			}

			break; // KernelMode
		} //switch (pIrp->ReguestorMode) 
	} except (EXCEPTION_EXECUTE_HANDLER) {

#if DBG
		KdPrint(("IRP_MJ_WRITE(crypr): "));
		PRINT_EXEPTION
#endif  // DBG

		return CompleteRequest( pIrp, GetExceptionCode(), 0);
	}

	//KdPrint((" [CRYPTED]"));

	//
	// set up complection routine to restore (DECRYTP) crypted data thet now stored in system buff
	//
	IoCopyCurrentIrpStackLocationToNext( pIrp ); 

	IoSetCompletionRoutine(	
		pIrp,			// Irp
		IntcRdWrCompletion,	// CompletionRoutine
		pde,			// Context
		TRUE,			// InvokeOnSuccess
		TRUE,			// InvokeOnError
		TRUE);			// InvokeOnCancel

	return IoCallDriver ( pde->pNextDeviceObject, pIrp );
}


NTSTATUS 
	IntcRdWrCompletion (
		IN PDEVICE_OBJECT DeviceObject, 
		IN PIRP pIrp,
		IN PINTERCEPTER_DEVICE_EXTENSION pde
		)
{
	PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	
	PVOID AllocBuff;
	SIZE_T RegionSize;
	PVOID UserBuffer;
	ULONG		  UserBufferLength;
	LARGE_INTEGER UserBufferOffset;
	NTSTATUS status;
	ULONG FileID;
	PVOID MdlAddress;
	//UNREFERENCED_PARAMETER( pde );
	UNREFERENCED_PARAMETER( DeviceObject );

	
	switch (currentIrpStack->MajorFunction) {

	case IRP_MJ_WRITE:
//		KdPrint(("IRP_MJ_WRITE(complection)"));

		UserBufferOffset = currentIrpStack->Parameters.Write.ByteOffset;

		if (pIrp->RequestorMode == KernelMode) { 
//			KdPrint((" KernelMode"));
					
			UserBufferLength = MmGetMdlByteCount (pIrp->MdlAddress);
			
			goto crypt;
		} else {
//			KdPrint((" UserMode, end"));
			UserBufferLength = currentIrpStack->Parameters.Read.Length;
			// do not care about user space
			// it resives data from cash

			goto end;
		}

		break;

	case IRP_MJ_READ:
//		KdPrint(("IRP_MJ_READ(complection)"));

		UserBufferOffset = currentIrpStack->Parameters.Read.ByteOffset;		
		if (pIrp->RequestorMode == KernelMode) { 
//			KdPrint((" KernelMode"));
			UserBufferLength = MmGetMdlByteCount (pIrp->MdlAddress);

		} else {
			//KdPrint((" UserMode"));
			// do not care about user space
			// it resives data from cash
			goto end;
			UserBufferLength = currentIrpStack->Parameters.Read.Length;
		}

crypt:
		try {

			if (pIrp->MdlAddress != 0 && pIrp->RequestorMode == KernelMode) {

				UserBufferLength = MmGetMdlByteCount (pIrp->MdlAddress);

				IntcLockUserBuffer (
					pIrp,
					IoModifyAccess,
					UserBufferLength );

				MdlAddress = IntcMapUserBuffer ( pIrp );

				if (MdlAddress == NULL) {
					KdPrint((" ERROR MmGetSystemAddressForMdlSafe !"));
				} else {
					//ShowFileBuff(" MDL_BUFF", MdlAddress, UserBufferLength);
//					KdPrint((" get MDL_BUFF ok"));
// read data in-to system kesh!

					IntercepterCryptData (
						MdlAddress,
						0, // dest_buff = src_buff
						UserBufferLength,
						UserBufferOffset );
					
//					KdPrint((" Mdl decrypt OK"));
					
					goto end;
				}
			}

		} except (EXCEPTION_EXECUTE_HANDLER) {

#if DBG
			switch (currentIrpStack->MajorFunction) {
			case IRP_MJ_WRITE:
				KdPrint(("IRP_MJ_WRITE(complection)"));
				break;
			case IRP_MJ_READ:
				KdPrint(("IRP_MJ_READ(complection)"));
				break;
			}

			PRINT_EXEPTION
#endif  // DBG

			//return CompleteRequest( pIrp, GetExceptionCode(), 0);
			// CAN I COMPLEATE REQUEST WITH FAIL ON COMPLECTION ROUTINE?????
		}		

		//KdPrint((" crypt is [OK]"));
		break;
	}

end:
	// IoReleaseRemoveLock(&pde->RemoveLock, pIrp); // not need (we will not remove our filter (indeet for our will))
	if( pIrp->PendingReturned ) {
        IoMarkIrpPending( pIrp );
    }

	return pIrp->IoStatus.Status;
}


NTSTATUS
	IntcCreateRoutine(
		IN PDEVICE_OBJECT pDevice,
		IN PIRP pIrp
		)
{
	PINTERCEPTER_DEVICE_EXTENSION pde;
	PIO_STACK_LOCATION  currentIrpStack;

#if DBG
	char name[32]="";
	GetProcess(name);
#endif	

	if (IS_INTC_DEVICE_OBJECT(pDevice)) { 
		return IntcDeviceRoutine(pDevice, pIrp);
	}

	pde = (PINTERCEPTER_DEVICE_EXTENSION)(pDevice->DeviceExtension);
	currentIrpStack = IoGetCurrentIrpStackLocation( pIrp );

	if ( RtlEqualUnicodeString (&pde->TargetFile, &currentIrpStack->FileObject->FileName, TRUE) 
		// ||( currentIrpStack->FileObject->RelatedFileObject != 0 &&
		//      RtlEqualUnicodeString (&pde->TargetFile, &currentIrpStack->FileObject->RelatedFileObject->FileName, TRUE)     
		//   ) 
	   )
	{ 

#if DBG
//		GetProcess(name);
		////KdPrint(("IRP_MJ_CREATE:\n %s created TARGET file '%ws' %x\n '%ws'", name, currentIrpStack->FileObject->FileName.Buffer, currentIrpStack->FileObject->RelatedFileObject, pde->TargetFile.Buffer)); 
//		KdPrint(("IRP_MJ_CREATE:\n %s created TARGET file", name)); 
		if (currentIrpStack->FileObject->RelatedFileObject != 0) {
			////KdPrint((" RELATED FILE_OBJECT: '%ws'", currentIrpStack->FileObject->RelatedFileObject->FileName.Buffer)); 
			//KdPrint((" RELATED FILE_OBJECT")); 
		}

#endif
		
		//
		// force NO cashing option for target files
		//
		// SetFlag(currentIrpStack->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING); 
		// !! we can't do that :)
		
		//
		// set complection routine for IRP_MJ_CREATE
		// to see if file is CASHED and strore it in need cryption buffer
		//
		IoCopyCurrentIrpStackLocationToNext( pIrp );

		IoSetCompletionRoutine(	
			pIrp,					// Irp
			IntcCreateCompletion,	// CompletionRoutine
			pde,					// Context
			TRUE,					// InvokeOnSuccess
			TRUE,					// InvokeOnError
			TRUE);					// InvokeOnCancel
	} else {
	
		//
		// Get this driver out of the driver stack and get to the next driver as
		// quickly as possible.
		//
		IoSkipCurrentIrpStackLocation( pIrp );
	}

	return IoCallDriver ( pde->pNextDeviceObject, pIrp );
}


NTSTATUS 
	IntcCreateCompletion (
		IN PDEVICE_OBJECT DeviceObject, 
		IN PIRP pIrp,
		IN PINTERCEPTER_DEVICE_EXTENSION pde
		)
{
	PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(pIrp);
	UNREFERENCED_PARAMETER( DeviceObject );

	////KdPrint(("IRP_MJ_CREATE(complection):"));

	if (currentIrpStack->FileObject->SectionObjectPointer->DataSectionObject != 0) {
//		KdPrint((" Data olready in memmory"));
	}

	AddTargetFile (pde, currentIrpStack->FileObject->FsContext);

	if( pIrp->PendingReturned ) {
        	IoMarkIrpPending( pIrp );
	}

	//KdPrint((" [OK]"));
	return pIrp->IoStatus.Status;
}


NTSTATUS
	IntcDispatchAny(
		IN PDEVICE_OBJECT pDevice,
		IN PIRP pIrp
		)
{	
	PINTERCEPTER_DEVICE_EXTENSION pde;
	PIO_STACK_LOCATION  currentIrpStack;


	if (IS_INTC_DEVICE_OBJECT(pDevice)) { 
		return IntcDeviceRoutine(pDevice, pIrp);
	}

	pde = pDevice->DeviceExtension;
	currentIrpStack = IoGetCurrentIrpStackLocation( pIrp );


	//
	//  Get this driver out of the driver stack and get to the next driver as
	//  quickly as possible.
	//		
	IoSkipCurrentIrpStackLocation( pIrp );

	//
	//  Call the appropriate file system driver with the request.
	//
	return IoCallDriver ( pde->pNextDeviceObject, pIrp );
}


///////////////////////////////////////////////////////////////////////////////


NTSTATUS HookDrive( IN ULONG			Drive,			// driver latter to attach to
					IN PDRIVER_OBJECT	pDriverObject ) // pointer to the driver object
{
	PDEVICE_OBJECT					pTargetDeviceObject;				// file sys device
	PDEVICE_OBJECT				    pIntercepterDeviceObject;
	PINTERCEPTER_DEVICE_EXTENSION	pde; 
	
	UNICODE_STRING      fileNameUnicodeString;
	PFILE_OBJECT        fileObject;
	OBJECT_ATTRIBUTES   objectAttributes;
	HANDLE              ntFileHandle;   
	IO_STATUS_BLOCK     ioStatus;
    
    NTSTATUS            ntStatus;
    ULONG               i;
	
	
    //
    // We have to figure out what device to hook - first open the volume's  root directory
    //
		
    RtlInitUnicodeString( &fileNameUnicodeString, L"\\DosDevices\\C:\\" ); // HOOK C ONLY! by hands)))
		
    InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString, 
                                OBJ_CASE_INSENSITIVE, NULL, NULL );
    ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE|FILE_ANY_ACCESS, 
                                 &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, 
                                 FILE_OPEN, 
                                 FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, 
                                 NULL, 0 );
    if( !NT_SUCCESS( ntStatus ) ) {
		////KdPrint(("Intercepter: Could not open drive "));
        return ntStatus;
	}

    //////KdPrint(("Intercepter:  opened the root directory!!! handle " ));   
		
		
    //
    // Got the file handle, so now look-up the file-object it refers to
    //
    ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA, 
                                              NULL, KernelMode, &fileObject, NULL );
    if( !NT_SUCCESS( ntStatus )) {
		////KdPrint(("Intercepter: Could not get fileobject from handle" ));
		ZwClose( ntFileHandle );
		return ntStatus;
    }

    //  
    // Next, find out what device is associated with the file object by getting its related device object
    //
    pTargetDeviceObject = IoGetRelatedDeviceObject( fileObject );

    if( ! pTargetDeviceObject ) {
	    ////KdPrint(("Intercepter: Could not get related device object"));
		ObDereferenceObject( fileObject );
		ZwClose( ntFileHandle );
		return 0xC0000001;
	}

	//
	// we successfully get filesystem dev objec pointer - close fandles
	//
    ObDereferenceObject( fileObject );
    ZwClose( ntFileHandle );

	//
	// Creating the Filter Device Object
	//
	ntStatus = IoCreateDevice(
		pDriverObject,							//DriverObject
		sizeof(INTERCEPTER_DEVICE_EXTENSION),	//DeviceExtensionSize
		NULL,									//DeviceName
		pTargetDeviceObject->DeviceType,		//DeviceType
		0,										//DeviceCharacteristics // pTargetDeviceObject->Characteristics, 
		FALSE,									//Exclusive
		&pIntercepterDeviceObject);				//new filter DeviceObject

	if( !NT_SUCCESS(ntStatus) ) {
	    ////KdPrint(("Intercepter: failed to create associated device" ));   
        return ntStatus;
    }

    //
    //  Propagate flags from Device Object we are trying to attach to.
    //  Note that we do this before the actual attachment to make sure
    //  the flags are properly set once we are attached (since an IRP
    //  can come in immediately after attachment but before the flags would
    //  be set).
    //

	SetFlag( pIntercepterDeviceObject->Flags,
		FlagOn( pTargetDeviceObject->Flags,
			(DO_BUFFERED_IO |
			 DO_DIRECT_IO |
			 DO_SUPPORTS_TRANSACTIONS) ));

	//
	// Propagating the FILE_DEVICE_SECURE_OPEN Flag
	// NOT needet when volume connecting
	// but SFilter do, so do we
	//
	
    SetFlag( pIntercepterDeviceObject->Characteristics,
             FlagOn( pTargetDeviceObject->Characteristics,
                     (FILE_DEVICE_SECURE_OPEN) ));
	
	// pIntercepterDeviceObject->Characteristics |= pTargetDeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN; 


	pde = pIntercepterDeviceObject->DeviceExtension;
	pde->pNextDeviceObject = NULL; 
	pde->pAttachedToDeviceObject = pTargetDeviceObject; 
	pde->Type = HOOKED_FS_DEVICE;

	RtlInitUnicodeString( &pde->TargetFile, L"\\test_crypt\\file.bmp");  // target file
	KdPrint (("Target Target filename  %ws", pde->TargetFile.Buffer));

	// null target file id's
	for (i = 0; i < MAX_TARGET_FILES; ++i) {
		*( &(pde->CryptExt->TargetFileID ) + i) = 0;
	}

    //hookExtension->LogicalDrive = 'A'+Drive;

//	IoInitializeRemoveLock (&pde->RemoveLock, 0, 0, 0);
		
	//
    // Finally, attach to the device. The second we're successfully attached, we may 
    // start receiving IRPs targetted at the device we've hooked.
    //

	ntStatus = IoAttachDeviceToDeviceStackSafe (
		pIntercepterDeviceObject, 
		pTargetDeviceObject,		// file sys object (owr target) 
		&pde->pNextDeviceObject);

	if (!NT_SUCCESS(ntStatus)) {
		if (ntStatus == STATUS_NO_SUCH_DEVICE) {
			////KdPrint(("Error on attach to device stack  - STATUS_NO_SUCH_DEVICE"));
		} 
		IoDeleteDevice(pIntercepterDeviceObject);
	
        ////KdPrint(("Intercepter: Connect with Filesystem failed" ));

        return ntStatus;
	}

	//
    //  Finished all initialization of the new device object,  so clear
    //  the initializing flag now.  This allows other filters to now
    //  attach to our device object.
    //

	ClearFlag( pIntercepterDeviceObject->Flags, DO_DEVICE_INITIALIZING );

	KdPrint(("HOOK DRIVE  - OK"));


    return STATUS_SUCCESS;
}

NTSTATUS IntercepterCryptData (IN PVOID  src_buff, 
						  	   IN PVOID dest_buff, // = 0 if  src_buff == dest_buff
							   IN ULONG buff_size, 
							   IN LARGE_INTEGER buff_offset)
{
	char  *src_buff_cur = (char*)src_buff;
	char *dest_buff_cur = dest_buff != 0 ? (char*)dest_buff : (char*)src_buff;
	char tmp;
	UNREFERENCED_PARAMETER( buff_offset );
	
	if (src_buff == 0) {
		return STATUS_SUCCESS;
	}
	for (; src_buff_cur < (char*)src_buff + buff_size; ++src_buff_cur, ++dest_buff_cur)	{
		*dest_buff_cur = *src_buff_cur ^ 'A';
	}

	return STATUS_SUCCESS;
}


void 
	AddTargetFile (
		IN PINTERCEPTER_DEVICE_EXTENSION pde,
		IN PVOID FileID)
{
	ULONG i;

	if (FileID == 0 || pde == 0) {
		return;
	}
	
	if (GetTargetFile (pde, FileID) != NOT_TARGET_FILE) {
		////KdPrint((" file olready marked"));
		return;
	}

	for (i = 0; i < MAX_TARGET_FILES; ++i) {
		if (*( &(pde->CryptExt->TargetFileID) + i) == 0) {
			*( &(pde->CryptExt->TargetFileID) + i) = FileID;
			////KdPrint((" marjed for crypt %x[%i]", FileID, i));
			return;
		}
	}
	////KdPrint(("INTC: WARNING, maximum (%i) files reached.\nFile can't be marked as NEEDCRYPTION", MAX_TARGET_FILES));
	return;
}

void 
	DelTargetFile (
		IN PINTERCEPTER_DEVICE_EXTENSION pde,
		IN ULONG FileID)
{
	if (pde == 0 || FileID > MAX_TARGET_FILES || FileID == NOT_TARGET_FILE) {
		return;
	}
	
#if DBG
	if (*( &(pde->CryptExt->AllocUserBuffer) + FileID) != 0) {
		//KdPrint((" Posible memmory leek. Alloc buffer not freed!"));
	}
#endif
	*( &(pde->CryptExt->TargetFileID   ) + FileID) = 0;
	*( &(pde->CryptExt->RealUserBuffer ) + FileID) = 0;
	*( &(pde->CryptExt->AllocUserBuffer) + FileID) = 0;
	//KdPrint((" TargetFile DELETED"));
	return;
}

ULONG 
	GetTargetFile (
		IN PINTERCEPTER_DEVICE_EXTENSION pde,
		IN PVOID FileID)
{
	ULONG i;
	
	if (FileID == 0 || pde == 0) {
		return NOT_TARGET_FILE;
	}
		
	for (i = 0; i < MAX_TARGET_FILES; ++i) {
		if ( *(&(pde->CryptExt->TargetFileID) + i) == FileID) {
			//////KdPrint((" IS TargetFile %x[%i]", FileID, i));
			return i;
		}
	}

	return NOT_TARGET_FILE;
}

/////////////////////////////////////////////////////////////////////////////
//
//                      FastIO Handling routines
// from SFilter
/////////////////////////////////////////////////////////////////////////////

BOOLEAN
IntcFastIoRead (
    __in PFILE_OBJECT FileObject,
    __in PLARGE_INTEGER FileOffset,
    __in ULONG Length,
    __in BOOLEAN Wait,
    __in ULONG LockKey,
    __out_bcount(Length) PVOID Buffer,
    __inout PIO_STATUS_BLOCK IoStatus,
    __in PDEVICE_OBJECT DeviceObject
    )

/*++

Routine Description:

    This routine is the fast I/O "pass through" routine for reading from a
    file.

    This function simply invokes the file system's corresponding routine, or
    returns FALSE if the file system does not implement the function.

Arguments:

    FileObject - Pointer to the file object to be read.

    FileOffset - Byte offset in the file of the read.

    Length - Length of the read operation to be performed.

    Wait - Indicates whether or not the caller is willing to wait if the
        appropriate locks, etc. cannot be acquired

    LockKey - Provides the caller's key for file locks.

    Buffer - Pointer to the caller's buffer to receive the data read.

    IoStatus - Pointer to a variable to receive the I/O status of the
        operation.

    DeviceObject - Pointer to this driver's device object, the device on
        which the operation is to occur.

Return Value:

    The function value is TRUE or FALSE based on whether or not fast I/O
    is possible for this file.

--*/

{
    PDEVICE_OBJECT nextDeviceObject;
    PFAST_IO_DISPATCH fastIoDispatch;
	BOOLEAN retval;
	PINTERCEPTER_DEVICE_EXTENSION pde = DeviceObject->DeviceExtension;

#if DBG
	char name[32]="";
#endif
    PAGED_CODE();

#if DBG
	/*
	if (FileObject != 0 && GetTargetFile (pde, FileObject->FsContext)!= NOT_TARGET_FILE) {
		GetProcess(name);
		KdPrint(("IntcFastIoRead '%s'", name));
	}
	*/
#endif


	if (IS_INTC_DEVICE_OBJECT (DeviceObject)) {
		return FALSE;
	}

	if (IS_MY_DEVICE_OBJECT (DeviceObject)) {

        ASSERT(IS_MY_DEVICE_OBJECT( DeviceObject ));

        //
        //  Pass through logic for this type of Fast I/O
        //
		pde = DeviceObject->DeviceExtension;
        nextDeviceObject = pde->pAttachedToDeviceObject;
        ASSERT(nextDeviceObject);

        fastIoDispatch = nextDeviceObject->DriverObject->FastIoDispatch;

        if (VALID_FAST_IO_DISPATCH_HANDLER( fastIoDispatch, FastIoRead )) {

            retval = (fastIoDispatch->FastIoRead)(
                        FileObject,
                        FileOffset,
                        Length,
                        Wait,
                        LockKey,
                        Buffer,
                        IoStatus,
                        nextDeviceObject );
// do not care about FASTIO crypt buffers
// hope cash manager do not use them for reading data from files
return retval;

// IF need, we can DeCrypt data in user buffer

			if (FileObject == 0 || GetTargetFile (pde, FileObject->FsContext) == NOT_TARGET_FILE) {
				return retval;
			}

			try{
 				ProbeForWrite(Buffer, Length, 1);
				
				IntercepterCryptData (
					Buffer,
		 			0,					// dest_buff = src_buff
					Length,
					*FileOffset);
#if DBG
				////KdPrint((" DECRYPTED fastIo read"));// [%s]", (char*)Buffer));
#endif
				return retval;
			}
			except (EXCEPTION_EXECUTE_HANDLER) {
				PRINT_EXEPTION
				return FALSE;
			}
		}
    }
    return FALSE;
}
