reactos操作系统实现(122)

IoReadPartitionTable函数是读取磁盘分区表数据。它的实现代码如下:

#001 NTSTATUS

#002 FASTCALL

#003 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,

#004 IN ULONG SectorSize,

#005 IN BOOLEAN ReturnRecognizedPartitions,

#006 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)

#007 {

在这里调用硬件抽象层的函数,其实它是调用reactos/ntoskrnl/fstub/disksup.c里的函数。

#008 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,

#009 SectorSize,

#010 ReturnRecognizedPartitions,

#011 PartitionBuffer);

#012 }

下面来分析函数HalIoReadPartitionTable,它就是函数xHalIoReadPartitionTable的调用,上面使用调用表的原因,就是方便兼容不同的系统调用。具体实现代码如下:

#001 NTSTATUS

#002 FASTCALL

#003 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,

#006 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)

#007 {

#008 KEVENT Event;

#009 IO_STATUS_BLOCK IoStatusBlock;

#010 PIRP Irp;

#011 PPARTITION_DESCRIPTOR PartitionDescriptor;

#012 CCHAR Entry;

#013 NTSTATUS Status;

#014 PPARTITION_INFORMATION PartitionInfo;

#015 PUCHAR Buffer = NULL;

#016 ULONG BufferSize = 2048,InputSize;

#017 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;

#018 LONG j = -1,i = -1,k;

#019 DISK_GEOMETRY DiskGeometry;

#020 LONGLONG EndSector,MaxSector,StartOffset;

#021 ULONGLONG MaxOffset;

#022 LARGE_INTEGER Offset,VolumeOffset;

#023 BOOLEAN IsPrimary = TRUE,IsEzDrive = FALSE,MbrFound = FALSE;

#024 BOOLEAN IsValid,IsEmpty = TRUE;

#025 PVOID MbrBuffer;

#026 PIO_STACK_LOCATION IoStackLocation;

#027 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;

#028 UCHAR PartitionType;

#029 LARGE_INTEGER HiddenSectors64;

#030 VolumeOffset.QuadPart = Offset.QuadPart = 0;

#031 PAGED_CODE();

#032

分配保存分区的内存区。

#033 /* Allocate the buffer */

#034 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,

#035 BufferSize,

#036 TAG_FILE_SYSTEM);

#037 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;

#038

输入的大小。

#039 /* Normalize the buffer size */

#040 InputSize = max(512,SectorSize);

#041

检查是否EZ的驱动设备。

#042 /* Check for EZ Drive */

#043 HalExamineMBR(DeviceObject,InputSize,0x55,&MbrBuffer);

#044 if (MbrBuffer)

#045 {

#046 /* EZ Drive found,bias the offset */

#047 IsEzDrive = TRUE;

#048 ExFreePool(MbrBuffer);

#049 Offset.QuadPart = 512;

#050 }

#051

获取驱动器的属性,比如磁头数等等。

#052 /* Get drive geometry */

#053 Status = HalpGetFullGeometry(DeviceObject,&DiskGeometry,&MaxOffset);

#054 if (!NT_SUCCESS(Status))

#055 {

#056 ExFreePoolWithTag(*PartitionBuffer,TAG_FILE_SYSTEM);

#057 *PartitionBuffer = NULL;

#058 return Status;

#059 }

#060

设置最大扇区数。

#061 /* Get the end and maximum sector */

#062 EndSector = MaxOffset;

#063 MaxSector = MaxOffset << 1;

#064 DPRINT("FSTUB: MaxOffset = %#I64x,MaxSector = %#I64x/n",

#065 MaxOffset,MaxSector);

#066

分配一页大小的缓冲区。

#067 /* Allocate our buffer */

#068 Buffer = ExAllocatePoolWithTag(NonPagedPool,PAGE_SIZE,TAG_FILE_SYSTEM);

#069 if (!Buffer)

#070 {

#071 /* Fail,free the input buffer */

#072 ExFreePoolWithTag(*PartitionBuffer,TAG_FILE_SYSTEM);

#073 *PartitionBuffer = NULL;

#074 return STATUS_INSUFFICIENT_RESOURCES;

#075 }

#076

开始分区循环处理。

#077 /* Start partition loop */

#078 do

#079 {

假定分区是无效的。

#080 /* Assume the partition is valid */

#081 IsValid = TRUE;

#082

初始化通知事件。

#083 /* Initialize the event */

#084 KeInitializeEvent(&Event,NotificationEvent,FALSE);

#085

清空缓冲区,然后创建一个读取MBRIRP包。

#086 /* Clear the buffer and build the IRP */

#087 RtlZeroMemory(Buffer,InputSize);

#088 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,

#089 DeviceObject,

#090 Buffer,

#091 InputSize,

#092 &Offset,

#093 &Event,

#094 &IoStatusBlock);

#095 if (!Irp)

#096 {

#097 /* Failed */

#098 Status = STATUS_INSUFFICIENT_RESOURCES;

#099 break;

#100 }

#101

获取IO的栈位置和设置不进行卷检验。

#102 /* Make sure to disable volume verification */

#103 IoStackLocation = IoGetNextIrpStackLocation(Irp);

#104 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;

#105

把这个IRP发送给低层的驱动程序进行处理。

#106 /* Call the driver */

#107 Status = IoCallDriver(DeviceObject,Irp);

#108 if (Status == STATUS_PENDING)

#109 {

如果这个IRP状态在阻塞中,说明这个IRP需要进入等待状态。

#110 /* Wait for completion */

#111 KeWaitForSingleObject(&Event,Executive,KernelMode,FALSE,NULL);

#112 Status = IoStatusBlock.Status;

#113 }

#114

#115 /* Normalize status code and check for failure */

#116 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;

如果状态不成功就终止分区查找。

#117 if (!NT_SUCCESS(Status)) break;

#118

如果是EZ的驱动设备,就设置为0开始。

#119 /* If we biased for EZ-Drive,unbias now */

#120 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;

#121

检查这个扇区标志是否为MBR的标志。

#122 /* Make sure this is a valid MBR */

#123 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)

#124 {

#125 /* It's not,fail */

#126 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "

#127 "partition table %d/n",j + 1);

#128 break;

#129 }

#130

这里确认这个是MBR扇区了。

#131 /* At this point we have a valid MBR */

#132 MbrFound = TRUE;

#133

#134 /* Check if we weren't given an offset */

#135 if (!Offset.QuadPart)

#136 {

获取分区的标志。

#137 /* Then read the signature off the disk */

#138 (*PartitionBuffer)->Signature = ((PULONG)Buffer)

#139 [PARTITION_TABLE_OFFSET / 2 - 1];

#140 }

#141

获取磁盘分区描述列表。

#142 /* Get the partition descriptor array */

#143 PartitionDescriptor = (PPARTITION_DESCRIPTOR)

#144 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);

#145

获取这个分区的类型。

#146 /* Get the partition type */

#147 PartitionType = PartitionDescriptor->PartitionType;

#148

下一个分区计数。

#149 /* Start looping partitions */

#150 j++;

#151 DPRINT("FSTUB: Partition Table %d:/n",j);

遍历四个分区表。

#152 for (Entry = 1,k = 0; Entry <= 4; Entry++,PartitionDescriptor++)

#153 {

获取分区类型。

#154 /* Get the partition type */

#155 PartitionType = PartitionDescriptor->PartitionType;

#156

#157 /* Print debug messages */

#158 DPRINT("Partition Entry %d,%d: type %#x %s/n",

#159 j,

#160 Entry,

#161 PartitionType,

#162 (PartitionDescriptor->ActiveFlag) ? "Active" : "");

#163 DPRINT("/tOffset %#08lx for %#08lx Sectors/n",

#164 GET_STARTING_SECTOR(PartitionDescriptor),

#165 GET_PARTITION_LENGTH(PartitionDescriptor));

#166

检查分区表是否有效。

#167 /* Make sure that the partition is valid,unless it's the first */

#168 if (!(HalpIsValidPartitionEntry(PartitionDescriptor,

#169 MaxOffset,

#170 MaxSector)) && !(j))

#171 {

#172 /* It's invalid,so fail */

#173 IsValid = FALSE;

#174 break;

#175 }

#176

检查否包括的分区类型。

#177 /* Check if it's a container */

#178 if (IsContainerPartition(PartitionType))

#179 {

#180 /* Increase the count of containers */

#181 if (++k != 1)

#182 {

#183 /* More then one table is invalid */

#184 DPRINT1("FSTUB: Multiple container partitions found in "

#185 "partition table %d/n - table is invalid/n",

#186 j);

#187 IsValid = FALSE;

#188 break;

#189 }

#190 }

#191

检查这个分区表是否为空。

#192 /* Check if the partition is supposedly empty */

#193 if (IsEmpty)

#194 {

#195 /* But check if it actually has a start and/or length */

#196 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||

#197 (GET_PARTITION_LENGTH(PartitionDescriptor)))

#198 {

#199 /* So then it's not really empty */

#200 IsEmpty = FALSE;

#201 }

#202 }

#203

如果调用这个函数只想读取已经声明类型的扇区,但有不认识的就直接返回。

#204 /* Check if the caller wanted only recognized partitions */

#205 if (ReturnRecognizedPartitions)

#206 {

#207 /* Then check if this one is unused,or a container */

#208 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||

#209 IsContainerPartition(PartitionType))

#210 {

#211 /* Skip it,since the caller doesn't want it */

#212 continue;

#213 }

#214 }

#215

#216 /* Increase the structure count and check if they can fit */

检查内存里是否有下一个分区存在。

#217 if ((sizeof(DRIVE_LAYOUT_INFORMATION) +

#218 (++i * sizeof(PARTITION_INFORMATION))) >

#219 BufferSize)

#220 {

#221 /* Allocate a new buffer that's twice as big */

#222 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,

#223 BufferSize << 1,

#224 TAG_FILE_SYSTEM);

#225 if (!DriveLayoutInfo)

#226 {

#227 /* Out of memory,unto this extra structure */

#228 --i;

#229 Status = STATUS_INSUFFICIENT_RESOURCES;

#230 break;

#231 }

#232

把旧缓冲区的内容移到设备信息里。

#233 /* Copy the contents of the old buffer */

#234 RtlMoveMemory(DriveLayoutInfo,

#235 *PartitionBuffer,

#236 BufferSize);

#237

#238 /* Free the old buffer and set this one as the new one */

#239 ExFreePoolWithTag(*PartitionBuffer,TAG_FILE_SYSTEM);

#240 *PartitionBuffer = DriveLayoutInfo;

#241

#242 /* Double the size */

#243 BufferSize <<= 1;

#244 }

#245

#246 /* Now get the current structure being filled and initialize it */

初始化当前分区属性。

#247 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];

#248 PartitionInfo->PartitionType = PartitionType;

#249 PartitionInfo->RewritePartition = FALSE;

#250

#251 /* Check if we're dealing with a partition that's in use */

判断分区是否已经使用。

#252 if (PartitionType != PARTITION_ENTRY_UNUSED)

#253 {

#254 /* Check if it's bootable */

#255 PartitionInfo->BootIndicator = PartitionDescriptor->

#256 ActiveFlag & 0x80 ?

#257 TRUE : FALSE;

#258

#259 /* Check if its' a container */

#260 if (IsContainerPartition(PartitionType))

#261 {

#262 /* Then don't recognize it and use the volume offset */

#263 PartitionInfo->RecognizedPartition = FALSE;

#264 StartOffset = VolumeOffset.QuadPart;

#265 }

#266 else

#267 {

#268 /* Then recognize it and use the partition offset */

#269 PartitionInfo->RecognizedPartition = TRUE;

#270 StartOffset = Offset.QuadPart;

#271 }

#272

#273 /* Get the starting offset */

#274 PartitionInfo->StartingOffset.QuadPart =

#275 StartOffset +

#276 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),

#277 SectorSize);

#278

#279 /* Calculate the number of hidden sectors */

#280 HiddenSectors64.QuadPart = (PartitionInfo->

#281 StartingOffset.QuadPart -

#282 StartOffset) /

#283 SectorSize;

#284 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;

#285

#286 /* Get the partition length */

#287 PartitionInfo->PartitionLength.QuadPart =

#288 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),

#289 SectorSize);

#290

#291 /* FIXME: REACTOS HACK */

#292 PartitionInfo->PartitionNumber = i + 1;

#293 }

#294 else

#295 {

#296 /* Otherwise,clear all the relevant fields */

#297 PartitionInfo->BootIndicator = FALSE;

#298 PartitionInfo->RecognizedPartition = FALSE;

#299 PartitionInfo->StartingOffset.QuadPart = 0;

#300 PartitionInfo->PartitionLength.QuadPart = 0;

#301 PartitionInfo->HiddenSectors = 0;

#302

#303 /* FIXME: REACTOS HACK */

#304 PartitionInfo->PartitionNumber = 0;

#305 }

#306 }

#307

如果返回状态是错误的,就返回出错。

#308 /* Finish debug log,and check for failure */

#309 DPRINT("/n");

#310 if (!NT_SUCCESS(Status)) break;

#311

#312 /* Also check if we hit an invalid entry here */

#313 if (!IsValid)

#314 {

#315 /* We did,so break out of the loop minus one entry */

#316 j--;

#317 break;

#318 }

#319

#320 /* Reset the offset */

#321 Offset.QuadPart = 0;

#322

#323 /* Go back to the descriptor array and loop it */

#324 PartitionDescriptor = (PPARTITION_DESCRIPTOR)

#325 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);

#326 for (Entry = 1; Entry <= 4; Entry++,PartitionDescriptor++)

#327 {

#328 /* Check if this is a container partition,since we skipped them */

#329 if (IsContainerPartition(PartitionType))

#330 {

#331 /* Get its offset */

#332 Offset.QuadPart = VolumeOffset.QuadPart +

#333 UInt32x32To64(

#334 GET_STARTING_SECTOR(PartitionDescriptor),

#335 SectorSize);

#336

#337 /* If this is a primary partition,this is the volume offset */

#338 if (IsPrimary) VolumeOffset = Offset;

#339

#340 /* Also update the maximum sector */

#341 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);

#342 DPRINT1("FSTUB: MaxSector now = %#08lx/n",MaxSector);

#343 break;

#344 }

#345 }

#346

#347 /* Loop the next partitions,which are not primary anymore */

#348 IsPrimary = FALSE;

#349 } while (Offset.HighPart | Offset.LowPart);

#350

#351 /* Check if this is a removable device that's probably a super-floppy */

检查是否可移动的设备。

#352 if ((DiskGeometry.MediaType == RemovableMedia) &&

#353 !(j) &&

#354 (MbrFound) &&

#355 (IsEmpty))

#356 {

#357 /* Read the jump bytes to detect super-floppy */

#358 if ((BootSectorInfo->JumpByte[0] == 0xeb) ||

#359 (BootSectorInfo->JumpByte[0] == 0xe9))

#360 {

#361 /* Super floppes don't have typical MBRs,so skip them */

#362 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "

#363 "table - disk is a super floppy and has no valid MBR/n",

#364 BootSectorInfo->JumpByte);

#365 j = -1;

#366 }

#367 }

#368

检查是否没有找到磁盘分区。

#369 /* Check if we're still at partition -1 */

#370 if (j == -1)

#371 {

#372 /* The likely cause is the super floppy detection above */

#373 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))

#374 {

#375 /* Print out debugging information */

#376 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "

#377 "super-floppy/n",

#378 DeviceObject);

#379 DPRINT1("FSTUB: Drive has %#08lx sectors and is %#016I64x "

#380 "bytes large/n",

#381 EndSector,EndSector * DiskGeometry.BytesPerSector);

#382

#383 /* We should at least have some sectors */

#384 if (EndSector > 0)

#385 {

#386 /* Get the entry we'll use */

#387 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];

#388

#389 /* Fill it out with data for a super-floppy */

#390 PartitionInfo->RewritePartition = FALSE;

#391 PartitionInfo->RecognizedPartition = TRUE;

#392 PartitionInfo->PartitionType = PARTITION_FAT_16;

#393 PartitionInfo->BootIndicator = FALSE;

#394 PartitionInfo->HiddenSectors = 0;

#395 PartitionInfo->StartingOffset.QuadPart = 0;

#396 PartitionInfo->PartitionLength.QuadPart = (EndSector *

#397 DiskGeometry.

#398 BytesPerSector);

#399

#400 /* FIXME: REACTOS HACK */

#401 PartitionInfo->PartitionNumber = 0;

#402

#403 /* Set the signature and set the count back to 0 */

#404 (*PartitionBuffer)->Signature = 1;

#405 i = 0;

#406 }

#407 }

#408 else

#409 {

#410 /* Otherwise,this isn't a super floppy,so set an invalid count */

#411 i = -1;

#412 }

#413 }

#414

设置当前找到的分区数。

#415 /* Set the partition count */

#416 (*PartitionBuffer)->PartitionCount = ++i;

#417

#418 /* If we have no count,delete the signature */

#419 if (!i) (*PartitionBuffer)->Signature = 0;

#420

释放前面分配的内存。

#421 /* Free the buffer and check for success */

#422 if (Buffer) ExFreePoolWithTag(Buffer,TAG_FILE_SYSTEM);

#423 if (!NT_SUCCESS(Status)) ExFreePoolWithTag(*PartitionBuffer,TAG_FILE_SYSTEM);

#424

#425 /* Return status */

#426 return Status;

#427}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom