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
清空缓冲区,然后创建一个读取MBR的IRP包。 #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} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |