VfatReadDiskPartial函数主要用来构造一个IRP给底层驱动程序去读取数据返回。具体实现代码如下:
#001 NTSTATUS
#002 VfatReadDiskPartial (IN PVFAT_IRP_CONTEXT IrpContext,
#003 IN PLARGE_INTEGER ReadOffset,
#004 IN ULONG ReadLength,
#005 ULONG BufferOffset,
#006 IN BOOLEAN Wait)
#007 {
#008 PIRP Irp;
#009 PIO_STACK_LOCATION StackPtr;
#010 NTSTATUS Status;
#011 PVOID Buffer;
#012
#013 DPRINT ("VfatReadDiskPartial(IrpContext %p, ReadOffset %I64x, ReadLength %d, BufferOffset %x, Wait %d)/n",
#014 IrpContext, ReadOffset->QuadPart, ReadLength, BufferOffset, Wait);
#015
#016 DPRINT ("Building asynchronous FSD Request.../n");
#017
从IRP的MDL地址获取内存缓冲区。
#018 Buffer = (PCHAR)MmGetMdlVirtualAddress(IrpContext->Irp->MdlAddress) + BufferOffset;
#019
创建一个新的IRP。
#020 Irp = IoAllocateIrp(IrpContext->DeviceExt->StorageDevice->StackSize, TRUE);
#021 if (Irp == NULL)
#022 {
#023 DPRINT("IoAllocateIrp failed/n");
#024 return(STATUS_UNSUCCESSFUL);
#025 }
#026
设置IRP属性。
#027 Irp->UserIosb = NULL;
#028 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
#029
#030 StackPtr = IoGetNextIrpStackLocation(Irp);
#031 StackPtr->MajorFunction = IRP_MJ_READ;
#032 StackPtr->MinorFunction = 0;
#033 StackPtr->Flags = 0;
#034 StackPtr->Control = 0;
设置访问设备对象。
#035 StackPtr->DeviceObject = IrpContext->DeviceExt->StorageDevice;
#036 StackPtr->FileObject = NULL;
#037 StackPtr->CompletionRoutine = NULL;
#038 StackPtr->Parameters.Read.Length = ReadLength;
#039 StackPtr->Parameters.Read.ByteOffset = *ReadOffset;
#040
创建一个直接内存访问MDL。
#041 if (!IoAllocateMdl(Buffer, ReadLength, FALSE, FALSE, Irp))
#042 {
#043 DPRINT("IoAllocateMdl failed/n");
#044 IoFreeIrp(Irp);
#045 return STATUS_UNSUCCESSFUL;
#046 }
#047
#048 IoBuildPartialMdl(IrpContext->Irp->MdlAddress, Irp->MdlAddress, Buffer, ReadLength);
#049
设置I/O完成端口函数。
#050 IoSetCompletionRoutine(Irp,
#051 VfatReadWritePartialCompletion,
#052 IrpContext,
#053 TRUE,
#054 TRUE,
#055 TRUE);
#056
#057 if (Wait)
#058 {
#059 KeInitializeEvent(&IrpContext->Event, NotificationEvent, FALSE);
#060 IrpContext->RefCount = 1;
#061 }
#062 else
#063 {
#064 InterlockedIncrement((PLONG)&IrpContext->RefCount);
#065 }
#066
调储存驱动程序来读取文件数据。
#067 DPRINT ("Calling IO Driver... with irp %p/n", Irp);
#068 Status = IoCallDriver (IrpContext->DeviceExt->StorageDevice, Irp);
#069
如果读取数据在阻塞状态,就等底层驱动程序完成。
#070 if (Wait && Status == STATUS_PENDING)
#071 {
#072 KeWaitForSingleObject(&IrpContext->Event, Executive, KernelMode, FALSE, NULL);
#073 Status = IrpContext->Irp->IoStatus.Status;
#074 }
#075
#076 DPRINT("%x/n", Status);
#077 return Status;
#078 }