reactos操作系统实现(132)
VfatReadFileData函数主要用来从磁盘上读取文件数据,具体实现代码如下: #001 static NTSTATUS #002 VfatReadFileData (PVFAT_IRP_CONTEXT IrpContext, #003 ULONG Length, #004 LARGE_INTEGER ReadOffset, #005 PULONG LengthRead) #006 /* #007 * FUNCTION: Reads data from a file #008 */ #009 { #010 ULONG CurrentCluster; #011 ULONG FirstCluster; #012 ULONG StartCluster; #013 ULONG ClusterCount; #014 LARGE_INTEGER StartOffset; #015 PDEVICE_EXTENSION DeviceExt; #016 BOOLEAN First = TRUE; #017 PVFATFCB Fcb; #018 PVFATCCB Ccb; #019 NTSTATUS Status; #020 ULONG BytesDone; #021 ULONG BytesPerSector; #022 ULONG BytesPerCluster; #023 ULONG LastCluster; #024 ULONG LastOffset; #025 #026 /* PRECONDITION */ #027 ASSERT(IrpContext);
获取扩展设备。 #028 DeviceExt = IrpContext->DeviceExt; #029 ASSERT(DeviceExt); #030 ASSERT(DeviceExt->FatInfo.BytesPerCluster); #031 ASSERT(IrpContext->FileObject); #032 ASSERT(IrpContext->FileObject->FsContext2 != NULL); #033 #034 DPRINT("VfatReadFileData(DeviceExt %p,FileObject %p," #035 "Length %d,ReadOffset 0x%I64x)/n",DeviceExt, #036 IrpContext->FileObject,Length,ReadOffset.QuadPart); #037 #038 *LengthRead = 0; #039
文件系统控制块。 #040 Ccb = (PVFATCCB)IrpContext->FileObject->FsContext2;
获取文件控制块。 #041 Fcb = IrpContext->FileObject->FsContext;
每个扇区有多少字节。 #042 BytesPerSector = DeviceExt->FatInfo.BytesPerSector;
每一簇有多少字节。 #043 BytesPerCluster = DeviceExt->FatInfo.BytesPerCluster; #044 #045 ASSERT(ReadOffset.QuadPart + Length <= ROUND_UP(Fcb->RFCB.FileSize.QuadPart,BytesPerSector)); #046 ASSERT(ReadOffset.u.LowPart % BytesPerSector == 0); #047 ASSERT(Length % BytesPerSector == 0); #048
是否读取FAT。 #049 /* Is this a read of the FAT? */ #050 if (Fcb->Flags & FCB_IS_FAT) #051 {
计算读取偏移位置,主要添加FAT的开始位置。。 #052 ReadOffset.QuadPart += DeviceExt->FatInfo.FATStart * BytesPerSector;
创建IRP去调用底层磁盘驱动程序。 #053 Status = VfatReadDiskPartial(IrpContext,&ReadOffset,TRUE); #054
如果读取成功,返回相应的长度数据。 #055 if (NT_SUCCESS(Status)) #056 { #057 *LengthRead = Length; #058 } #059 else #060 { #061 DPRINT1("FAT reading failed,Status %x/n",Status); #062 } #063 return Status; #064 }
是否读取卷数据,这样不需要添加FAT的偏移位置。 #065 /* Is this a read of the Volume ? */ #066 if (Fcb->Flags & FCB_IS_VOLUME) #067 { #068 Status = VfatReadDiskPartial(IrpContext,TRUE); #069 if (NT_SUCCESS(Status)) #070 { #071 *LengthRead = Length; #072 } #073 else #074 { #075 DPRINT1("Volume reading failed,Status); #076 } #077 return Status; #078 } #079
下面读取文件中数据。 #080 /* #081 * Find the first cluster #082 */
找到FAT的入口第一簇。 #083 FirstCluster = CurrentCluster = #084 vfatDirEntryGetFirstCluster (DeviceExt,&Fcb->entry); #085
如果是第一簇,在FAT12/FAT16需要做特别的处理。 #086 if (FirstCluster == 1) #087 { #088 // Directory of FAT12/16 needs a special handling #089 if (ReadOffset.u.LowPart + Length > DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector) #090 { #091 Length = DeviceExt->FatInfo.rootDirectorySectors * BytesPerSector - ReadOffset.u.LowPart; #092 } #093 ReadOffset.u.LowPart += DeviceExt->FatInfo.rootStart * BytesPerSector; #094 #095 // Fire up the read command #096 #097 Status = VfatReadDiskPartial (IrpContext,TRUE); #098 if (NT_SUCCESS(Status)) #099 { #100 *LengthRead = Length; #101 } #102 return Status; #103 } #104
从文件控制块里获取最后一次读取的簇数和最后偏移位置。 #105 ExAcquireFastMutex(&Fcb->LastMutex); #106 LastCluster = Fcb->LastCluster; #107 LastOffset = Fcb->LastOffset; #108 ExReleaseFastMutex(&Fcb->LastMutex); #109 #110 /* #111 * Find the cluster to start the read from #112 */
查找开始读取数据的簇开始位置。 #113 if (LastCluster > 0 && ReadOffset.u.LowPart >= LastOffset) #114 { #115 Status = OffsetToCluster(DeviceExt,LastCluster, #116 ROUND_DOWN(ReadOffset.u.LowPart,BytesPerCluster) - #117 LastOffset, #118 &CurrentCluster,FALSE); #119 #ifdef DEBUG_VERIFY_OFFSET_CACHING #120 /* DEBUG VERIFICATION */ #121 { #122 ULONG CorrectCluster; #123 OffsetToCluster(DeviceExt,FirstCluster, #124 ROUND_DOWN(ReadOffset.u.LowPart,BytesPerCluster), #125 &CorrectCluster,FALSE); #126 if (CorrectCluster != CurrentCluster) #127 KeBugCheck(FAT_FILE_SYSTEM); #128 } #129 #endif #130 } #131 else #132 { #133 Status = OffsetToCluster(DeviceExt, #134 ROUND_DOWN(ReadOffset.u.LowPart, #135 &CurrentCluster,FALSE); #136 } #137 if (!NT_SUCCESS(Status)) #138 { #139 return(Status); #140 } #141
更新最后一次读取的簇位置。 #142 ExAcquireFastMutex(&Fcb->LastMutex); #143 Fcb->LastCluster = CurrentCluster; #144 Fcb->LastOffset = ROUND_DOWN (ReadOffset.u.LowPart,BytesPerCluster); #145 ExReleaseFastMutex(&Fcb->LastMutex); #146
添加IRP的引用计数。 #147 KeInitializeEvent(&IrpContext->Event,NotificationEvent,FALSE); #148 IrpContext->RefCount = 1; #149
找到合适的开始簇位置。 #150 while (Length > 0 && CurrentCluster != 0xffffffff) #151 { #152 StartCluster = CurrentCluster; #153 StartOffset.QuadPart = ClusterToSector(DeviceExt,StartCluster) * BytesPerSector; #154 BytesDone = 0; #155 ClusterCount = 0; #156 #157 do #158 { #159 ClusterCount++; #160 if (First) #161 { #162 BytesDone = min (Length,BytesPerCluster - (ReadOffset.u.LowPart % BytesPerCluster)); #163 StartOffset.QuadPart += ReadOffset.u.LowPart % BytesPerCluster; #164 First = FALSE; #165 } #166 else #167 { #168 if (Length - BytesDone > BytesPerCluster) #169 { #170 BytesDone += BytesPerCluster; #171 } #172 else #173 { #174 BytesDone = Length; #175 } #176 } #177 Status = NextCluster(DeviceExt,&CurrentCluster,FALSE); #178 } #179 while (StartCluster + ClusterCount == CurrentCluster && NT_SUCCESS(Status) && Length > BytesDone); #180 DPRINT("start %08x,next %08x,count %d/n", #181 StartCluster,CurrentCluster,ClusterCount); #182 #183 ExAcquireFastMutex(&Fcb->LastMutex); #184 Fcb->LastCluster = StartCluster + (ClusterCount - 1); #185 Fcb->LastOffset = ROUND_DOWN(ReadOffset.u.LowPart,BytesPerCluster) + (ClusterCount - 1) * BytesPerCluster; #186 ExReleaseFastMutex(&Fcb->LastMutex); #187 #188 // Fire up the read command #189 Status = VfatReadDiskPartial (IrpContext,&StartOffset,BytesDone,*LengthRead,FALSE); #190 if (!NT_SUCCESS(Status) && Status != STATUS_PENDING) #191 { #192 break; #193 } #194 *LengthRead += BytesDone; #195 Length -= BytesDone; #196 ReadOffset.u.LowPart += BytesDone; #197 }
如果这个IRP还有在其它地方有引用,说明读取还在阻塞状态。 #198 if (0 != InterlockedDecrement((PLONG)&IrpContext->RefCount)) #199 { #200 KeWaitForSingleObject(&IrpContext->Event,Executive,KernelMode,FALSE,NULL); #201 } #202 if (NT_SUCCESS(Status) || Status == STATUS_PENDING) #203 { #204 if (Length > 0) #205 { #206 Status = STATUS_UNSUCCESSFUL; #207 } #208 else #209 { #210 Status = IrpContext->Irp->IoStatus.Status; #211 } #212 } #213 return Status; #214} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- ruby-on-rails – 数据未进入sqlite数据库 – Ruby on Rail
- MSSQL XML使用(一):由简单的select语句Auto 生产XML
- jsonp实现跨域调用百度地图接口
- c# – 正在使用aync / await一个好主意的Web服务?
- c# – Entity Framework如何为主键值生成GUID?
- ruby-on-rails – Rails:当使用带有给href的model属性的li
- PostgreSQL:全文搜索 – 如何搜索部分单词?
- 为什么这个代码不适用于ruby 1.9但适用于ruby 1.8?
- c# – 什么是托管代码和非托管代码?
- c# – 没有字符串拆分的解析