#include <ntddk.h>
#define MAX_FILE_LEN 4096
typedef struct _FileExtend
{
	PCHAR Buffer;
	ULONG Length;
} FileExtend, *PFileExtend;
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS DispatchGeneric(IN PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS DispatchRead(IN PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS DispatchWrite(IN PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS DispatchQueryInfo(IN PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS status = STATUS_SUCCESS;
	UNICODE_STRING deviceName = RTL_CONSTANT_STRING(L"\\Device\\FileOperation");
	UNICODE_STRING deviceSymbolicLinkName = RTL_CONSTANT_STRING(L"\\??\\FileOperation");
	PDEVICE_OBJECT DeviceObject = NULL;
	ULONG sub = 0;
	PFileExtend FileExtend = NULL;
	UNREFERENCED_PARAMETER(RegistryPath);
	KdPrint(("驱动加载\n"));
	
	for (sub = 0; sub <= IRP_MJ_MAXIMUM_FUNCTION; sub++)
	{
		DriverObject->MajorFunction[sub] = DispatchGeneric;
	}
	
	DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead;
	
	DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite;
	
	DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = DispatchQueryInfo;
	
	status = IoCreateDevice(DriverObject, sizeof(FileExtend), &deviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DeviceObject);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("创建设备失败:%x\n", status));
		return status;
	}
	
	FileExtend = (PFileExtend)(DeviceObject->DeviceExtension);
	FileExtend->Buffer = ExAllocatePool(PagedPool, MAX_FILE_LEN);
	if (FileExtend->Buffer == NULL)
	{
		KdPrint(("分配内存失败\n"));
		IoDeleteDevice(DeviceObject);
		DriverObject->DeviceObject = NULL;
		status = STATUS_INSUFFICIENT_RESOURCES;
		return status;
	}
	FileExtend->Length = 0;
	
	status = IoCreateSymbolicLink(&deviceSymbolicLinkName, &deviceName);
	if (!NT_SUCCESS(status))
	{
		KdPrint(("创建符号链接失败:%x\n", status));
		IoDeleteDevice(DeviceObject);
		return status;
	}
	DeviceObject->Flags |= DO_BUFFERED_IO;
	DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
	DriverObject->DriverUnload = DriverUnload;
	return status;
}
VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNICODE_STRING deviceSymbolicLinkName = RTL_CONSTANT_STRING(L"\\??\\FileOperation");
	PFileExtend FileExtend = NULL;
	UNREFERENCED_PARAMETER(DriverObject);
	KdPrint(("驱动卸载\n"));
	if (DriverObject->DeviceObject != NULL)
	{
		FileExtend = (PFileExtend)(DriverObject->DeviceObject->DeviceExtension);
		if (FileExtend != NULL && FileExtend->Buffer != NULL)
		{
			ExFreePool(FileExtend->Buffer);
			FileExtend->Buffer = NULL;
		}
		IoDeleteSymbolicLink(&deviceSymbolicLinkName);
		IoDeleteDevice(DriverObject->DeviceObject);
	}
}
NTSTATUS DispatchGeneric(IN PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	Irp->IoStatus.Status = status;
	Irp->IoStatus.Information = 0;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	UNREFERENCED_PARAMETER(DeviceObject);
	return status;
}
NTSTATUS DispatchRead(IN PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG Length = 0;
	ULONG Offset = 0;
	ULONG ReadLength = 0;
	PFileExtend FileExtend = NULL;
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	KdPrint(("读操作\n"));
	FileExtend = (PFileExtend)DeviceObject->DeviceExtension;
	__try
	{
		Length = stack->Parameters.Read.Length;
		Offset = stack->Parameters.Read.ByteOffset.LowPart;
		if (Length + Offset < MAX_FILE_LEN)
		{
			if (Length + Offset > FileExtend->Length)
			{
				ReadLength = FileExtend->Length - Offset;
			}
			else
			{
				ReadLength = Length;
			}
			RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, FileExtend->Buffer + Offset, ReadLength);
		}
		else
		{
			status = STATUS_BUFFER_TOO_SMALL;
			ReadLength = 0;
		}
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		status = GetExceptionCode();
		ReadLength = 0;
	}
	Irp->IoStatus.Status = status;
	Irp->IoStatus.Information = ReadLength;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return status;
}
NTSTATUS DispatchWrite(IN PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG Length = 0;
	ULONG Offset = 0;
	ULONG WriteLength = 0;
	PFileExtend FileExtend = (PFileExtend)(DeviceObject->DeviceExtension);
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	KdPrint(("写操作\n"));
	__try
	{
		Length = stack->Parameters.Write.Length;
		Offset = stack->Parameters.Write.ByteOffset.LowPart;
		if (Length + Offset <= MAX_FILE_LEN)
		{
			if (Length + Offset > FileExtend->Length)
			{
				FileExtend->Length = Length + Offset;
			}
			RtlCopyMemory(FileExtend->Buffer + Offset, Irp->AssociatedIrp.SystemBuffer, Length);
			WriteLength = Length;
		}
		else
		{
			status = STATUS_BUFFER_TOO_SMALL;
			WriteLength = 0;
		}
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		status = GetExceptionCode();
		WriteLength = 0;
	}
	Irp->IoStatus.Status = status;
	Irp->IoStatus.Information = WriteLength;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return status;
}
NTSTATUS DispatchQueryInfo(IN PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
	NTSTATUS status = STATUS_SUCCESS;
	ULONG Length = 0;
	PFileExtend FileExtend = (PFileExtend)(DeviceObject->DeviceExtension);
	PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
	__try
	{
		Length = stack->Parameters.QueryFile.Length;
		if (stack->Parameters.QueryFile.FileInformationClass == FileStandardInformation && Length >= sizeof(FILE_STANDARD_INFORMATION))
		{
			PFILE_STANDARD_INFORMATION pfsi = (PFILE_STANDARD_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
			pfsi->EndOfFile.LowPart = FileExtend->Length;
			Length = sizeof(FILE_STANDARD_INFORMATION);
		}
		else
		{
			status = STATUS_BUFFER_TOO_SMALL;
			Length = 0;
		}
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		status = GetExceptionCode();
		Length = 0;
	}
	Irp->IoStatus.Information = Length;
	Irp->IoStatus.Status = status;
	IoCompleteRequest(Irp, IO_NO_INCREMENT);
	return status;
}
#include <Windows.h>
#include <stdio.h>
#include <winioctl.h>
#define IOTEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, GENERIC_ALL)
int main()
{
  HANDLE hDevice = CreateFile(L"\\\\.\\FileOperation",
    GENERIC_ALL,
    FILE_SHARE_READ | FILE_SHARE_WRITE,
    NULL,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    NULL);
  if (hDevice == INVALID_HANDLE_VALUE)
  {
    printf("设备打开失败%d\n", GetLastError());
    getchar();
    return -1;
  }
  printf("设备打开成功\n");
  DWORD dwRet = 0;
  WriteFile(hDevice, "这是一段来自用户层数据", strlen("这是一段来自用户层数据"), &dwRet, NULL);
  CHAR Buffer[1024] = { 0 };
  ReadFile(hDevice, Buffer, 1024, &dwRet, NULL);
  printf("读到的数据:%s\n", Buffer);
  DWORD dwSize = GetFileSize(hDevice, NULL);
  printf("文件长度%d\n", dwSize);
  
  CloseHandle(hDevice);
  getchar();
  return 0;
}