应用程序对设备I/O进行Win32调用,这个调用由I/O系统服务接收,然后I/O管理器从这个请求构造一个合适的I/O请求包(IRP)。那么I/O管理器是怎么样创建这个I/O请求包(IRP)的呢?又是怎么样传送给驱动程序的呢?我们带着这两个问题来分析下面实现文件读取的代码,如下:
#001 NTSTATUS
#002 NTAPI
#003 NtReadFile(IN HANDLE FileHandle,
#004 IN HANDLE Event OPTIONAL,
#005 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
#006 IN PVOID ApcContext OPTIONAL,
#007 OUT PIO_STATUS_BLOCK IoStatusBlock,
#008 OUT PVOID Buffer,
#009 IN ULONG Length,
#010 IN PLARGE_INTEGER ByteOffset OPTIONAL,
#011 IN PULONG Key OPTIONAL)
#012 {
#013 NTSTATUS Status = STATUS_SUCCESS;
#014 PFILE_OBJECT FileObject;
#015 PIRP Irp;
#016 PDEVICE_OBJECT DeviceObject;
#017 PIO_STACK_LOCATION StackPtr;
#018 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
#019 PKEVENT EventObject = NULL;
#020 LARGE_INTEGER CapturedByteOffset;
#021 ULONG CapturedKey = 0;
#022 BOOLEAN Synchronous = FALSE;
#023 PMDL Mdl;
#024 PAGED_CODE();
#025 CapturedByteOffset.QuadPart = 0;
#026 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
#027检查是否在用户模式调用。
#028 /* Validate User-Mode Buffers */
#029 if(PreviousMode != KernelMode)
#030 {使用SEH机制,以便截取异常。
#031 _SEH2_TRY
#032 {检测状态块。
#033 /* Probe the status block */ #034 ProbeForWriteIoStatusBlock(IoStatusBlock); #035
检查读取缓冲区。
#036 /* Probe the read buffer */
#037 ProbeForWrite(Buffer, Length, 1);
#038
#039 /* Check if we got a byte offset */
#040 if (ByteOffset)
#041 {
#042 /* Capture and probe it */
#043 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);
#044 }
#045
#046 /* Capture and probe the key */
#047 if (Key) CapturedKey = ProbeForReadUlong(Key);
#048 }
#049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
#050 {
#051 /* Get the exception code */
#052 Status = _SEH2_GetExceptionCode();
#053 }
#054 _SEH2_END;
#055
#056 /* Check for probe failure */
#057 if (!NT_SUCCESS(Status)) return Status;
#058 }
#059 else
#060 {
#061 /* Kernel mode: capture directly */
#062 if (ByteOffset) CapturedByteOffset = *ByteOffset;
#063 if (Key) CapturedKey = *Key;
#064 }
#065 获取文件对象。
#066 /* Get File Object */ #067 Status = ObReferenceObjectByHandle(FileHandle, #068 FILE_READ_DATA, #069 IoFileObjectType, #070 PreviousMode, #071 (PVOID*)&FileObject, #072 NULL); #073 if (!NT_SUCCESS(Status)) return Status; #074