首页 »编程综合 » reactos:reactos操作系统实现(87) »正文
reactos:reactos操作系统实现(87)
来源: 发布时间:星期一, 2009年9月28日 浏览:0次 评论:0
应用 对设备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 ByteOff 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 CapturedByteOff; #021 ULONG CapturedKey = 0; #022 BOOLEAN Synchronous = FALSE; #023 PMDL Mdl; #024 PAGED_CODE; #025 CapturedByteOff.QuadPart = 0; #026 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle); #027
检查是否在用户模式 #028 /* Validate User-Mode Buffers */ #029 (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 we got a off */ #040 (ByteOff) #041 { #042 /* Capture and probe it */ #043 CapturedByteOff = ProbeForReadLargeInteger(ByteOff); #044 } #045 #046 /* Capture and probe the key */ #047 (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 (!NT_SUCCESS(Status)) Status; #058 } #059 #060 { #061 /* Kernel mode: capture directly */ #062 (ByteOff) CapturedByteOff = *ByteOff; #063 (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 (!NT_SUCCESS(Status)) Status; #074 检查事件是否响应 #075 /* Check for event */ #076 (Event) #077 { #078 /* Reference it */ #079 Status = ObReferenceObjectByHandle(Event, #080 EVENT_MODIFY_STATE, #081 ExEventObjectType, #082 PreviousMode, #083 (PVOID*)&EventObject, #084 NULL); #085 (!NT_SUCCESS(Status)) #086 { #087 /* Fail */ #088 ObDereferenceObject(FileObject); #089 Status; #090 } #091 #092 /* Otherwise re the event */ #093 KeClearEvent(EventObject); #094 } #095
检查是否使用同步I/O 方式 #096 /* Check we should use Sync IO or not */ #097 (FileObject->Flags & FO_SYNCHRONOUS_IO) #098 { 这里是使用同步模式 #099 /* Lock the file object */ #100 IopLockFileObject(FileObject); #101 #102 /* Check we don't have a off avilable */ #103 (!(ByteOff) || #104 ((CapturedByteOff.u.LowPart FILE_USE_FILE_POINTER_POSITION) && #105 (CapturedByteOff.u.HighPart -1))) #106 { #107 /* Use the Current Byte Off instead */ #108 CapturedByteOff = FileObject->CurrentByteOff; #109 } #110 #111 /* Remember we are sync */ #112 Synchronous = TRUE; #113 } #114 (!(ByteOff) && #115 !(FileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) #116 { 非法文件对象 #117 /* Otherwise, this was async I/O without a off, so fail */ #118 (EventObject) ObDereferenceObject(EventObject); #119 ObDereferenceObject(FileObject); #120 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 (!Irp) 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.Buffer = 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.ByteOff = CapturedByteOff; #154 检查设备对象是否使用缓冲I/O 方式 还是使用直接I/O 方式 #155 /* Check this is buffered I/O */ #156 (DeviceObject->Flags & DO_BUFFERED_IO) #157 { 使用缓冲I/O 方式 就分配非分页内存 #158 /* Check we have a buffer length */ #159 (Length) #160 { #161 /* Enter SEH */ #162 _SEH2_TRY #163 { #164 /* Allocate a buffer */ #165 Irp->AssociatedIrp.Buffer = #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 (!NT_SUCCESS(Status)) 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 #186 { #187 /* Not reading anything */ #188 Irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; #189 } #190 } #191 (DeviceObject->Flags & DO_DIRECT_IO) #192 {
使用直接I/O 方式 就创建内存描述符列表 #193 /* Check we have a buffer length */ #194 (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( Status); #208 } #209 _SEH2_END; #210 #211 } #212 #213 /* No allocation flags */ #214 Irp->Flags = 0; #215 } #216 #217 { #218 /* No allocation flags, and use the buffer directly */ #219 Irp->Flags = 0; #220 Irp->UserBuffer = Buffer; #221 } #222
设置读取 标志 #223 /* Now the deferred read flags */ #224 Irp->Flags |= (IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION); #225 # 0 #226 /* FIXME: VFAT SUCKS */ #227 (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE; #228 #end #229 IopPerformSynchronousRequest把IRP发送给过滤驱动 或者目标驱动 #230 /* Perform the call */ #231 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 ByteOff 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 CapturedByteOff; #021 ULONG CapturedKey = 0; #022 BOOLEAN Synchronous = FALSE; #023 PMDL Mdl; #024 OBJECT_HANDLE_INFORMATION ObjectHandleInfo; #025 PAGED_CODE; #026 CapturedByteOff.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 (!NT_SUCCESS(Status)) Status; #037 检查是否用户模式 如果是就需要使用SEH机制
#038 /* Validate User-Mode Buffers */ #039 (PreviousMode != KernelMode) #040 { #041 _SEH2_TRY #042 { 检查是否有写文件 权限 #043 /* #044 * Check the handle has either FILE_WRITE_DATA or #045 * FILE_APPEND_DATA granted. However, this is a named pipe, #046 * make sure we don't ask for FILE_APPEND_DATA as it erferes #047 * with the FILE_CREATE_PIPE_INSTANCE access right! #048 */ #049 (!(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( 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 we got a off */ #065 (ByteOff) #066 { #067 /* Capture and probe it */ #068 CapturedByteOff = ProbeForReadLargeInteger(ByteOff); #069 } #070 #071 /* Capture and probe the key */ #072 (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 (!NT_SUCCESS(Status)) Status; #083 } #084 #085 { #086 /* Kernel mode: capture directly */ #087 (ByteOff) CapturedByteOff = *ByteOff; #088 (Key) CapturedKey = *Key; #089 } #090
相关文章
读者评论
发表评论
|
|