您的位置:首页 > Web前端 > React

reactos操作系统实现(122)

2009-11-01 10:50 381 查看
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,
#004 IN
ULONG SectorSize,
#005 IN
BOOLEAN ReturnRecognizedPartitions,
#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 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: