reactos操作系统实现(87)

应用程序对设备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

检查事件是否响应。

#075 /* Check for event */

#076 if (Event)

#077 {

#078 /* Reference it */

#079 Status = ObReferenceObjectByHandle(Event,

#080 EVENT_MODIFY_STATE,

#081 ExEventObjectType,

#082 PreviousMode,

#083 (PVOID*)&EventObject,

#084 NULL);

#085 if (!NT_SUCCESS(Status))

#086 {

#087 /* Fail */

#088 ObDereferenceObject(FileObject);

#089 return Status;

#090 }

#091

#092 /* Otherwise reset the event */

#093 KeClearEvent(EventObject);

#094 }

#095

检查是否使用同步I/O的方式。

#096 /* Check if we should use Sync IO or not */

#097 if (FileObject->Flags & FO_SYNCHRONOUS_IO)

#098 {

这里是使用同步模式。

#099 /* Lock the file object */

#100 IopLockFileObject(FileObject);

#101

#102 /* Check if we don't have a byte offset avilable */

#103 if (!(ByteOffset) ||

#104 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&

#105 (CapturedByteOffset.u.HighPart == -1)))

#106 {

#107 /* Use the Current Byte Offset instead */

#108 CapturedByteOffset = FileObject->CurrentByteOffset;

#109 }

#110

#111 /* Remember we are sync */

#112 Synchronous = TRUE;

#113 }

#114 else if (!(ByteOffset) &&

#115 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))

#116 {

非法文件对象。

#117 /* Otherwise, this was async I/O without a byte offset, so fail */

#118 if (EventObject) ObDereferenceObject(EventObject);

#119 ObDereferenceObject(FileObject);

#120 return STATUS_INVALID_PARAMETER;

#121 }

#122

从文件里获取设备对象。

#123 /* Get the device object */

#124 DeviceObject = IoGetRelatedDeviceObject(FileObject);

#125

#126 /* Clear the File Object's event */

#127 KeClearEvent(&FileObject->Event);

#128

分配一个读取文件的请求包(IRP)。

#129 /* Allocate the IRP */

#130 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

#131 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);

#132

设置IRP的属性。

#133 /* Set the IRP */

#134 Irp->Tail.Overlay.OriginalFileObject = FileObject;

#135 Irp->Tail.Overlay.Thread = PsGetCurrentThread();

#136 Irp->RequestorMode = PreviousMode;

#137 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;

#138 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;

#139 Irp->UserIosb = IoStatusBlock;

#140 Irp->UserEvent = EventObject;

#141 Irp->PendingReturned = FALSE;

#142 Irp->Cancel = FALSE;

#143 Irp->CancelRoutine = NULL;

#144 Irp->AssociatedIrp.SystemBuffer = NULL;

#145 Irp->MdlAddress = NULL;

#146

设置IRP的调用栈。

#147 /* Set the Stack Data */

#148 StackPtr = IoGetNextIrpStackLocation(Irp);

#149 StackPtr->MajorFunction = IRP_MJ_READ;

#150 StackPtr->FileObject = FileObject;

#151 StackPtr->Parameters.Read.Key = CapturedKey;

#152 StackPtr->Parameters.Read.Length = Length;

#153 StackPtr->Parameters.Read.ByteOffset = CapturedByteOffset;

#154

检查设备对象是否使用缓冲I/O的方式,还是使用直接I/O的方式。

#155 /* Check if this is buffered I/O */

#156 if (DeviceObject->Flags & DO_BUFFERED_IO)

#157 {

使用缓冲I/O的方式,就分配非分页内存。

#158 /* Check if we have a buffer length */

#159 if (Length)

#160 {

#161 /* Enter SEH */

#162 _SEH2_TRY

#163 {

#164 /* Allocate a buffer */

#165 Irp->AssociatedIrp.SystemBuffer =

#166 ExAllocatePoolWithTag(NonPagedPool,

#167 Length,

#168 TAG_SYSB);

#169 }

#170 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#171 {

#172 /* Allocating failed, clean up */

#173 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);

#174 Status = _SEH2_GetExceptionCode();

#175 }

#176 _SEH2_END;

#177 if (!NT_SUCCESS(Status)) return Status;

#178

#179 /* Set the buffer and flags */

#180 Irp->UserBuffer = Buffer;

#181 Irp->Flags = (IRP_BUFFERED_IO |

#182 IRP_DEALLOCATE_BUFFER |

#183 IRP_INPUT_OPERATION);

#184 }

#185 else

#186 {

#187 /* Not reading anything */

#188 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;

#189 }

#190 }

#191 else if (DeviceObject->Flags & DO_DIRECT_IO)

#192 {

使用直接I/O的方式,就创建内存描述符列表。

#193 /* Check if we have a buffer length */

#194 if (Length)

#195 {

#196 _SEH2_TRY

#197 {

#198 /* Allocate an MDL */

#199 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);

#200 MmProbeAndLockPages(Mdl, PreviousMode, IoWriteAccess);

#201 }

#202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#203 {

#204 /* Allocating failed, clean up */

#205 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);

#206 Status = _SEH2_GetExceptionCode();

#207 _SEH2_YIELD(return Status);

#208 }

#209 _SEH2_END;

#210

#211 }

#212

#213 /* No allocation flags */

#214 Irp->Flags = 0;

#215 }

#216 else

#217 {

#218 /* No allocation flags, and use the buffer directly */

#219 Irp->Flags = 0;

#220 Irp->UserBuffer = Buffer;

#221 }

#222

设置读取的标志。

#223 /* Now set the deferred read flags */

#224 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION);

#225 #if 0

#226 /* FIXME: VFAT SUCKS */

#227 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;

#228 #endif

#229

调用函数IopPerformSynchronousRequestIRP发送给过滤驱动程序,或者目标驱动程序。

#230 /* Perform the call */

#231 return IopPerformSynchronousRequest(DeviceObject,

#232 Irp,

#233 FileObject,

#234 TRUE,

#235 PreviousMode,

#236 Synchronous,

#237 IopReadTransfer);

#238 }

#239

下面继续分析写文件的操作函数,就可以知道写文件时怎么样发送I/O请求包,实现代码如下:

#001 NTSTATUS

#002 NTAPI

#003 NtWriteFile(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 IN 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 OBJECT_HANDLE_INFORMATION ObjectHandleInfo;

#025 PAGED_CODE();

#026 CapturedByteOffset.QuadPart = 0;

#027 IOTRACE(IO_API_DEBUG, "FileHandle: %p/n", FileHandle);

#028

获取文件对象。

#029 /* Get File Object */

#030 Status = ObReferenceObjectByHandle(FileHandle,

#031 0,

#032 IoFileObjectType,

#033 PreviousMode,

#034 (PVOID*)&FileObject,

#035 &ObjectHandleInfo);

#036 if (!NT_SUCCESS(Status)) return Status;

#037

检查是否用户模式调用,如果是就需要使用SEH机制。

#038 /* Validate User-Mode Buffers */

#039 if(PreviousMode != KernelMode)

#040 {

#041 _SEH2_TRY

#042 {

检查是否有写文件的权限。

#043 /*

#044 * Check if the handle has either FILE_WRITE_DATA or

#045 * FILE_APPEND_DATA granted. However, if this is a named pipe,

#046 * make sure we don't ask for FILE_APPEND_DATA as it interferes

#047 * with the FILE_CREATE_PIPE_INSTANCE access right!

#048 */

#049 if (!(ObjectHandleInfo.GrantedAccess &

#050 ((!(FileObject->Flags & FO_NAMED_PIPE) ?

#051 FILE_APPEND_DATA : 0) | FILE_WRITE_DATA)))

#052 {

#053 /* We failed */

#054 ObDereferenceObject(FileObject);

#055 _SEH2_YIELD(return STATUS_ACCESS_DENIED);

#056 }

#057

获取状态代码块。

#058 /* Probe the status block */

#059 ProbeForWriteIoStatusBlock(IoStatusBlock);

#060

#061 /* Probe the read buffer */

#062 ProbeForRead(Buffer, Length, 1);

#063

#064 /* Check if we got a byte offset */

#065 if (ByteOffset)

#066 {

#067 /* Capture and probe it */

#068 CapturedByteOffset = ProbeForReadLargeInteger(ByteOffset);

#069 }

#070

#071 /* Capture and probe the key */

#072 if (Key) CapturedKey = ProbeForReadUlong(Key);

#073 }

#074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#075 {

#076 /* Get the exception code */

#077 Status = _SEH2_GetExceptionCode();

#078 }

#079 _SEH2_END;

#080

#081 /* Check for probe failure */

#082 if (!NT_SUCCESS(Status)) return Status;

#083 }

#084 else

#085 {

#086 /* Kernel mode: capture directly */

#087 if (ByteOffset) CapturedByteOffset = *ByteOffset;

#088 if (Key) CapturedKey = *Key;

#089 }

#090

检查是否为追加的模式。

#091 /* Check if this is an append operation */

#092 if ((ObjectHandleInfo.GrantedAccess &

#093 (FILE_APPEND_DATA | FILE_WRITE_DATA)) == FILE_APPEND_DATA)

#094 {

#095 /* Give the drivers something to understand */

#096 CapturedByteOffset.u.LowPart = FILE_WRITE_TO_END_OF_FILE;

#097 CapturedByteOffset.u.HighPart = -1;

#098 }

#099

检查是否使用事件。

#100 /* Check for event */

#101 if (Event)

#102 {

#103 /* Reference it */

#104 Status = ObReferenceObjectByHandle(Event,

#105 EVENT_MODIFY_STATE,

#106 ExEventObjectType,

#107 PreviousMode,

#108 (PVOID*)&EventObject,

#109 NULL);

#110 if (!NT_SUCCESS(Status))

#111 {

#112 /* Fail */

#113 ObDereferenceObject(FileObject);

#114 return Status;

#115 }

#116

清空事件。

#117 /* Otherwise reset the event */

#118 KeClearEvent(EventObject);

#119 }

#120

检查是否使用同步I/O的方式。

#121 /* Check if we should use Sync IO or not */

#122 if (FileObject->Flags & FO_SYNCHRONOUS_IO)

#123 {

#124 /* Lock the file object */

#125 IopLockFileObject(FileObject);

#126

#127 /* Check if we don't have a byte offset avilable */

#128 if (!(ByteOffset) ||

#129 ((CapturedByteOffset.u.LowPart == FILE_USE_FILE_POINTER_POSITION) &&

#130 (CapturedByteOffset.u.HighPart == -1)))

#131 {

#132 /* Use the Current Byte Offset instead */

#133 CapturedByteOffset = FileObject->CurrentByteOffset;

#134 }

#135

#136 /* Remember we are sync */

#137 Synchronous = TRUE;

#138 }

#139 else if (!(ByteOffset) &&

#140 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT)))

#141 {

#142 /* Otherwise, this was async I/O without a byte offset, so fail */

#143 if (EventObject) ObDereferenceObject(EventObject);

#144 ObDereferenceObject(FileObject);

#145 return STATUS_INVALID_PARAMETER;

#146 }

#147

获取文件对应的设备对象。

#148 /* Get the device object */

#149 DeviceObject = IoGetRelatedDeviceObject(FileObject);

#150

#151 /* Clear the File Object's event */

#152 KeClearEvent(&FileObject->Event);

#153

分配一个请求包(IRP)。

#154 /* Allocate the IRP */

#155 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);

#156 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);

#157

设置IRP的属性。

#158 /* Set the IRP */

#159 Irp->Tail.Overlay.OriginalFileObject = FileObject;

#160 Irp->Tail.Overlay.Thread = PsGetCurrentThread();

#161 Irp->RequestorMode = PreviousMode;

#162 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;

#163 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;

#164 Irp->UserIosb = IoStatusBlock;

#165 Irp->UserEvent = EventObject;

#166 Irp->PendingReturned = FALSE;

#167 Irp->Cancel = FALSE;

#168 Irp->CancelRoutine = NULL;

#169 Irp->AssociatedIrp.SystemBuffer = NULL;

#170 Irp->MdlAddress = NULL;

#171

设置与IRP一致的栈空间。

#172 /* Set the Stack Data */

#173 StackPtr = IoGetNextIrpStackLocation(Irp);

#174 StackPtr->MajorFunction = IRP_MJ_WRITE;

#175 StackPtr->FileObject = FileObject;

#176 StackPtr->Flags = FileObject->Flags & FO_WRITE_THROUGH ?

#177 SL_WRITE_THROUGH : 0;

#178 StackPtr->Parameters.Write.Key = CapturedKey;

#179 StackPtr->Parameters.Write.Length = Length;

#180 StackPtr->Parameters.Write.ByteOffset = CapturedByteOffset;

#181

检查是否使用缓冲I/O的方式。

#182 /* Check if this is buffered I/O */

#183 if (DeviceObject->Flags & DO_BUFFERED_IO)

#184 {

#185 /* Check if we have a buffer length */

#186 if (Length)

#187 {

#188 /* Enter SEH */

#189 _SEH2_TRY

#190 {

#191 /* Allocate a buffer */

#192 Irp->AssociatedIrp.SystemBuffer =

#193 ExAllocatePoolWithTag(NonPagedPool,

#194 Length,

#195 TAG_SYSB);

#196

#197 /* Copy the data into it */

#198 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Buffer, Length);

#199 }

#200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#201 {

#202 /* Allocating failed, clean up */

#203 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);

#204 Status = _SEH2_GetExceptionCode();

#205 _SEH2_YIELD(return Status);

#206 }

#207 _SEH2_END;

#208

#209 /* Set the flags */

#210 Irp->Flags = (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);

#211 }

#212 else

#213 {

#214 /* Not writing anything */

#215 Irp->Flags = IRP_BUFFERED_IO;

#216 }

#217 }

#218 else if (DeviceObject->Flags & DO_DIRECT_IO)

#219 {

这里使用直接I/O的模式,因此调用IoAllocateMdl来创建内存描述符表。

#220 /* Check if we have a buffer length */

#221 if (Length)

#222 {

#223 _SEH2_TRY

#224 {

#225 /* Allocate an MDL */

#226 Mdl = IoAllocateMdl(Buffer, Length, FALSE, TRUE, Irp);

#227 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);

#228 }

#229 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

#230 {

#231 /* Allocating failed, clean up */

#232 IopCleanupAfterException(FileObject, Irp, EventObject, NULL);

#233 Status = _SEH2_GetExceptionCode();

#234 _SEH2_YIELD(return Status);

#235 }

#236 _SEH2_END;

#237 }

#238

#239 /* No allocation flags */

#240 Irp->Flags = 0;

#241 }

#242 else

#243 {

#244 /* No allocation flags, and use the buffer directly */

#245 Irp->Flags = 0;

#246 Irp->UserBuffer = Buffer;

#247 }

#248

#249 /* Now set the deferred read flags */

#250 Irp->Flags |= (IRP_WRITE_OPERATION | IRP_DEFER_IO_COMPLETION);

#251 #if 0

#252 /* FIXME: VFAT SUCKS */

#253 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;

#254 #endif

#255

调用函数IopPerformSynchronousRequest来分IRP请求包给相应的驱动程序。

#256 /* Perform the call */

#257 return IopPerformSynchronousRequest(DeviceObject,

#258 Irp,

#259 FileObject,

#260 TRUE,

#261 PreviousMode,

#262 Synchronous,

#263 IopWriteTransfer);

#264 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值