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}