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, Length, 0, 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, &ReadOffset, Length, 0, TRUE);

#069      if (NT_SUCCESS(Status))

#070      {

#071        *LengthRead = Length;

#072      }

#073      else

#074      {

#075        DPRINT1("Volume reading failed, Status %x/n", 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, &ReadOffset, Length, 0, 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, FirstCluster,

#134                               ROUND_DOWN(ReadOffset.u.LowPart, BytesPerCluster),

#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, FirstCluster, &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  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了小程序应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

caimouse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值