01748 :
01749
01750 This routine walks
the disk reading
the partition tables and creates
01751 an entry in
the partition list buffer
for each partition.
01752
01753 The algorithm used by
this routine
is two-fold:
01754
01755 1) Read each partition table and
for each valid, recognized
01756 partition found, to build a descriptor in a partition list.
01757 Extended partitions are located in order to find other
01758 partition tables, but no descriptors are built
for these.
01759 The partition list
is built in nonpaged
pool that
is allocated
01760 by
this routine. It
is the caller's responsibility to free
01761
this pool after
it has gathered
the appropriate information
01762 from
the list.
01763
01764 2) Read each partition table and
for each and every entry, build
01765 a descriptor in
the partition list. Extended partitions are
01766 located to find each partition table on
the disk, and entries
01767 are built
for these as well. The partition list
is build in
01768 nonpaged
pool that
is allocated by
this routine. It
is the
01769 caller's responsibility to free
this pool after
it has copied
01770
the information back to its caller.
01771
01772 The first algorithm
is used when
the ReturnRecognizedPartitions flag
01773
is set. This
is used to determine how many partition device objects
01774
the device driver
is to create, and where each lives on
the drive.
01775
01776 The second algorithm
is used when
the ReturnRecognizedPartitions flag
01777
is clear. This
is used to find all of
the partition tables and their
01778 entries
for a utility such as fdisk, that would like to revamp where
01779
the partitions live.
01780
01781 Arguments:
01782
01783 DeviceObject - Pointer to device object
for this disk.
01784
01785
SectorSize - Sector size on
the device.
01786
01787 ReturnRecognizedPartitions -
A flag indicated whether
only recognized
01788 partition descriptors are to be returned, or whether all partition
01789 entries are to be returned.
01790
01791 PartitionBuffer - Pointer to
the pointer of
the buffer in which
the list
01792 of partition will be stored.
01793
01794 Return Value:
01795
01796 The functional value
is STATUS_SUCCESS
if at least one sector table was
01797 read.
01798
01799 Notes:
01800
01801 It
is the responsibility of
the caller to deallocate
the partition list
01802 buffer allocated by
this routine.
01803
01804 --*/
01805
01806 {
01807 ULONG partitionBufferSize =
PARTITION_BUFFER_SIZE;
01808 PDRIVE_LAYOUT_INFORMATION newPartitionBuffer =
NULL;
01809
01810 LONG partitionTableCounter = -1;
01811
01812 DISK_GEOMETRY diskGeometry;
01813 ULONGLONG endSector;
01814 ULONGLONG maxSector;
01815 ULONGLONG maxOffset;
01816
01817 LARGE_INTEGER partitionTableOffset;
01818 LARGE_INTEGER volumeStartOffset;
01819 LARGE_INTEGER tempInt;
01820 BOOLEAN primaryPartitionTable;
01821 LONG partitionNumber;
01822 PUCHAR readBuffer = (PUCHAR)
NULL;
01823
KEVENT event;
01824
01825 IO_STATUS_BLOCK ioStatus;
01826
PIRP irp;
01827
PPARTITION_DESCRIPTOR partitionTableEntry;
01828 CCHAR partitionEntry;
01829
NTSTATUS status = STATUS_SUCCESS;
01830 ULONG readSize;
01831 PPARTITION_INFORMATION partitionInfo;
01832 BOOLEAN foundEZHooker =
FALSE;
01833
01834 BOOLEAN mbrSignatureFound =
FALSE;
01835 BOOLEAN emptyPartitionTable =
TRUE;
01836
01837
PAGED_CODE();
01838
01839
01840
01841
01842
01843
01844 *PartitionBuffer =
ExAllocatePoolWithTag( NonPagedPool,
01845 partitionBufferSize,
01846 'btsF' );
01847
01848
if (*PartitionBuffer ==
NULL) {
01849
return STATUS_INSUFFICIENT_RESOURCES;
01850 }
01851
01852
01853
01854
01855
01856
01857
01858
01859
01860
if (
SectorSize >= 512) {
01861 readSize =
SectorSize;
01862 }
else {
01863 readSize = 512;
01864 }
01865
01866
01867
01868
01869
01870
01871 {
01872
01873 PVOID buff;
01874
01875
HalExamineMBR(
01876 DeviceObject,
01877 readSize,
01878 (ULONG)0x55,
01879 &buff
01880 );
01881
01882
if (buff) {
01883
01884 foundEZHooker =
TRUE;
01885
ExFreePool(buff);
01886 partitionTableOffset.QuadPart = 512;
01887
01888 }
else {
01889
01890 partitionTableOffset.QuadPart = 0;
01891
01892 }
01893
01894 }
01895
01896
01897
01898
01899
01900
01901 status =
HalpGetFullGeometry(DeviceObject,
01902 &diskGeometry,
01903 &maxOffset);
01904
01905
if(!
NT_SUCCESS(status)) {
01906
ExFreePool(*PartitionBuffer);
01907 *PartitionBuffer =
NULL;
01908
return status;
01909 }
01910
01911
01912
01913
01914
01915
01916
01917
01918
01919 endSector = maxOffset;
01920
01921 maxSector = maxOffset * 2;
01922
01923
DebugPrint((2,
"MaxOffset = %#I64x, maxSector = %#I64x\n",
01924 maxOffset, maxSector));
01925
01926
01927
01928
01929
01930
01931 primaryPartitionTable =
TRUE;
01932
01933
01934
01935
01936
01937 volumeStartOffset.QuadPart = 0;
01938
01939
01940
01941
01942
01943 partitionNumber = -1;
01944
01945
01946
01947
01948
01949 readBuffer =
ExAllocatePoolWithTag( NonPagedPoolCacheAligned,
01950 PAGE_SIZE,
01951 'btsF' );
01952
01953
if (readBuffer ==
NULL) {
01954
ExFreePool( *PartitionBuffer );
01955
return STATUS_INSUFFICIENT_RESOURCES;
01956 }
01957
01958
01959
01960
01961
01962
01963
01964
do {
01965
01966 BOOLEAN tableIsValid;
01967 ULONG containerPartitionCount;
01968
01969 tableIsValid =
TRUE;
01970
01971
01972
01973
01974
01975
01976
01977
01978
KeInitializeEvent( &event, NotificationEvent, FALSE );
01979
01980
01981
01982
01983
01984
01985 RtlZeroMemory(readBuffer, readSize);
01986
01987 irp =
IoBuildSynchronousFsdRequest( IRP_MJ_READ,
01988 DeviceObject,
01989 readBuffer,
01990 readSize,
01991 &partitionTableOffset,
01992 &event,
01993 &ioStatus );
01994
01995
if (!irp) {
01996 status = STATUS_INSUFFICIENT_RESOURCES;
01997
break;
01998 }
else {
01999
PIO_STACK_LOCATION irpStack;
02000 irpStack =
IoGetNextIrpStackLocation(irp);
02001 irpStack->
Flags |=
SL_OVERRIDE_VERIFY_VOLUME;
02002 }
02003
02004 status =
IoCallDriver( DeviceObject, irp );
02005
02006
if (status == STATUS_PENDING) {
02007 (
VOID)
KeWaitForSingleObject( &event,
02008 Executive,
02009 KernelMode,
02010 FALSE,
02011 (PLARGE_INTEGER) NULL);
02012 status = ioStatus.Status;
02013 }
02014
02015
02016
02017
02018
02019
02020
02021
if(status == STATUS_NO_DATA_DETECTED) {
02022 status = STATUS_SUCCESS;
02023 }
02024
02025
if (!
NT_SUCCESS( status )) {
02026
break;
02027 }
02028
02029
02030
02031
02032
02033
02034
02035
02036
if (foundEZHooker && (partitionTableOffset.QuadPart == 512)) {
02037
02038 partitionTableOffset.QuadPart = 0;
02039
02040 }
02041
02042
02043
02044
02045
02046
if (((
PUSHORT) readBuffer)[
BOOT_SIGNATURE_OFFSET] !=
BOOT_RECORD_SIGNATURE) {
02047
02048
DebugPrint((1,
"xHalIoReadPT: No 0xaa55 found in partition table %d\n",
02049 partitionTableCounter + 1));
02050
02051
break;
02052
02053 }
else {
02054 mbrSignatureFound =
TRUE;
02055 }
02056
02057
02058
02059
02060
02061
if (partitionTableOffset.QuadPart == 0) {
02062 (*PartitionBuffer)->Signature = ((PULONG) readBuffer)[
PARTITION_TABLE_OFFSET/2-1];
02063 }
02064
02065 partitionTableEntry = (
PPARTITION_DESCRIPTOR) &(((
PUSHORT) readBuffer)[
PARTITION_TABLE_OFFSET]);
02066
02067
02068
02069
02070
02071 partitionTableCounter++;
02072
02073
02074
02075
02076
02077
02078
DebugPrint((2,
"Partition Table %d:\n", partitionTableCounter));
02079
02080
for (partitionEntry = 1, containerPartitionCount = 0;
02081 partitionEntry <=
NUM_PARTITION_TABLE_ENTRIES;
02082 partitionEntry++, partitionTableEntry++) {
02083
02084
DebugPrint((2,
"Partition Entry %d,%d: type %#x %s\n",
02085 partitionTableCounter,
02086 partitionEntry,
02087 partitionTableEntry->
PartitionType,
02088 (partitionTableEntry->
ActiveFlag) ?
"Active" :
""));
02089
02090
DebugPrint((2,
"\tOffset %#08lx for %#08lx Sectors\n",
02091
GET_STARTING_SECTOR(partitionTableEntry),
02092
GET_PARTITION_LENGTH(partitionTableEntry)));
02093
02094
02095
02096
02097
02098
if((
HalpIsValidPartitionEntry(partitionTableEntry,
02099 maxOffset,
02100 maxSector) ==
FALSE) &&
02101 (partitionTableCounter == 0)) {
02102
02103
ASSERT(DrivesupBreakIn == FALSE);
02104
DrivesupBreakIn =
FALSE;
02105 tableIsValid =
FALSE;
02106
break;
02107
02108 }
02109
02110
02111
02112
02113
02114
if(IsContainerPartition(partitionTableEntry->
PartitionType)) {
02115
02116 containerPartitionCount++;
02117
02118
if(containerPartitionCount != 1) {
02119
02120
DebugPrint((1,
"Multiple container partitions found in "
02121
"partition table %d\n - table is invalid\n",
02122 partitionTableCounter));
02123 tableIsValid =
FALSE;
02124
break;
02125 }
02126
02127 }
02128
02129
if(emptyPartitionTable) {
02130
02131
if((
GET_STARTING_SECTOR(partitionTableEntry) != 0) ||
02132 (
GET_PARTITION_LENGTH(partitionTableEntry) != 0)) {
02133
02134
02135
02136
02137
02138
02139 emptyPartitionTable =
FALSE;
02140 }
02141 }
02142
02143
02144
02145
02146
02147
02148
02149
if (ReturnRecognizedPartitions) {
02150
02151
02152
02153
02154
02155
02156
02157
if ((partitionTableEntry->
PartitionType == PARTITION_ENTRY_UNUSED) ||
02158 IsContainerPartition(partitionTableEntry->
PartitionType)) {
02159
02160
continue;
02161 }
02162 }
02163
02164
02165
02166
02167
02168 partitionNumber++;
02169
02170
if (((partitionNumber *
sizeof( PARTITION_INFORMATION )) +
02171
sizeof( DRIVE_LAYOUT_INFORMATION )) >
02172 (ULONG) partitionBufferSize) {
02173
02174
02175
02176
02177
02178
02179
02180
02181 newPartitionBuffer =
ExAllocatePoolWithTag( NonPagedPool,
02182 partitionBufferSize << 1,
02183 'btsF' );
02184
02185
if (newPartitionBuffer ==
NULL) {
02186 --partitionNumber;
02187 status = STATUS_INSUFFICIENT_RESOURCES;
02188
break;
02189 }
02190
02191 RtlMoveMemory( newPartitionBuffer,
02192 *PartitionBuffer,
02193 partitionBufferSize );
02194
02195
ExFreePool( *PartitionBuffer );
02196
02197
02198
02199
02200
02201
02202 *PartitionBuffer = newPartitionBuffer;
02203 partitionBufferSize <<= 1;
02204 }
02205
02206
02207
02208
02209
02210
02211
02212
02213 partitionInfo = &(*PartitionBuffer)->PartitionEntry[partitionNumber];
02214
02215 partitionInfo->PartitionType = partitionTableEntry->
PartitionType;
02216
02217 partitionInfo->RewritePartition =
FALSE;
02218
02219
if (partitionTableEntry->
PartitionType != PARTITION_ENTRY_UNUSED) {
02220 LONGLONG startOffset;
02221
02222 partitionInfo->BootIndicator =
02223 partitionTableEntry->
ActiveFlag &
PARTITION_ACTIVE_FLAG ?
02224 (BOOLEAN)
TRUE : (BOOLEAN)
FALSE;
02225
02226
if (IsContainerPartition(partitionTableEntry->
PartitionType)) {
02227 partitionInfo->RecognizedPartition =
FALSE;
02228 startOffset = volumeStartOffset.QuadPart;
02229 }
else {
02230 partitionInfo->RecognizedPartition =
TRUE;
02231 startOffset = partitionTableOffset.QuadPart;
02232 }
02233
02234 partitionInfo->StartingOffset.QuadPart = startOffset +
02235 UInt32x32To64(
GET_STARTING_SECTOR(partitionTableEntry),
02236 SectorSize);
02237 tempInt.QuadPart = (partitionInfo->StartingOffset.QuadPart -
02238 startOffset) /
SectorSize;
02239 partitionInfo->HiddenSectors = tempInt.LowPart;
02240
02241 partitionInfo->PartitionLength.QuadPart =
02242 UInt32x32To64(
GET_PARTITION_LENGTH(partitionTableEntry),
02243 SectorSize);
02244
02245 }
else {
02246
02247
02248
02249
02250
02251
02252
02253
02254
02255 partitionInfo->BootIndicator =
FALSE;
02256 partitionInfo->RecognizedPartition =
FALSE;
02257 partitionInfo->StartingOffset.QuadPart = 0;
02258 partitionInfo->PartitionLength.QuadPart = 0;
02259 partitionInfo->HiddenSectors = 0;
02260 }
02261
02262 }
02263
02264
DebugPrint((2,
"\n"));
02265
02266
02267
02268
02269
02270
if (!
NT_SUCCESS( status )) {
02271
break;
02272 }
02273
02274
if(tableIsValid ==
FALSE) {
02275
02276
02277
02278
02279
02280
02281
02282 partitionTableCounter--;
02283
break;
02284 }
02285
02286
02287
02288
02289
02290
02291
02292
02293 partitionTableEntry = (
PPARTITION_DESCRIPTOR) &(((
PUSHORT) readBuffer)[
PARTITION_TABLE_OFFSET]);
02294
02295
02296
02297
02298
02299 partitionTableOffset.QuadPart = 0;
02300
02301
for (partitionEntry = 1;
02302 partitionEntry <=
NUM_PARTITION_TABLE_ENTRIES;
02303 partitionEntry++, partitionTableEntry++) {
02304
02305
if (IsContainerPartition(partitionTableEntry->
PartitionType)) {
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316 partitionTableOffset.QuadPart = volumeStartOffset.QuadPart +
02317 UInt32x32To64(
GET_STARTING_SECTOR(partitionTableEntry),
02318 SectorSize);
02319
02320
02321
02322
02323
02324
02325
02326
02327
if (primaryPartitionTable) {
02328 volumeStartOffset = partitionTableOffset;
02329 }
02330
02331
02332
02333
02334
02335
02336 maxSector =
GET_PARTITION_LENGTH(partitionTableEntry);
02337
02338
DebugPrint((2,
"MaxSector now = %#08lx\n", maxSector));
02339
02340
02341
02342
02343
02344
02345
break;
02346 }
02347 }
02348
02349
02350
02351
02352
02353
02354 primaryPartitionTable =
FALSE;
02355
02356
02357 }
while (partitionTableOffset.HighPart | partitionTableOffset.LowPart);
02358
02359
02360
02361
02362
02363
02364
02365
02366
02367
DebugPrint((4,
"xHalIoReadPartitionTable: RM %d PTC %d MBR %d EPT %d\n",
02368 diskGeometry.MediaType,
02369 partitionTableCounter,
02370 mbrSignatureFound,
02371 emptyPartitionTable));
02372
02373
if((diskGeometry.MediaType == RemovableMedia) &&
02374 (partitionTableCounter == 0) &&
02375 (mbrSignatureFound ==
TRUE) &&
02376 (emptyPartitionTable ==
TRUE)) {
02377
02378
PBOOT_SECTOR_INFO bootSector = (
PBOOT_SECTOR_INFO) readBuffer;
02379
02380
if((bootSector->
JumpByte[0] == 0xeb) ||
02381 (bootSector->
JumpByte[0] == 0xe9)) {
02382
02383
02384
02385
02386
02387
DebugPrint((1,
"xHalIoReadPartitionTable: Jump byte %#x found "
02388
"along with empty partition table - disk is a "
02389
"super floppy and has no valid MBR\n",
02390 bootSector->
JumpByte));
02391
02392 partitionTableCounter = -1;
02393 }
02394 }
02395
02396
02397
02398
02399
02400
02401
02402
if(partitionTableCounter == -1) {
02403
02404
if((mbrSignatureFound ==
TRUE) ||
02405 (diskGeometry.MediaType == RemovableMedia)) {
02406
02407
02408
02409
02410
02411
02412
02413
02414
DebugPrint((1,
"xHalIoReadPartitionTable: Drive %#p has no valid MBR. "
02415
"Make it into a super-floppy\n", DeviceObject));
02416
02417
DebugPrint((1,
"xHalIoReadPartitionTable: Drive has %#08lx sectors "
02418
"and is %#016I64x bytes large\n",
02419 endSector, endSector * diskGeometry.BytesPerSector));
02420
02421
if (endSector > 0) {
02422
02423 partitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
02424
02425 partitionInfo->RewritePartition =
FALSE;
02426 partitionInfo->RecognizedPartition =
TRUE;
02427 partitionInfo->PartitionType = PARTITION_FAT_16;
02428 partitionInfo->BootIndicator =
FALSE;
02429
02430 partitionInfo->HiddenSectors = 0;
02431
02432 partitionInfo->StartingOffset.QuadPart = 0;
02433
02434 partitionInfo->PartitionLength.QuadPart =
02435 (endSector * diskGeometry.BytesPerSector);
02436
02437 (*PartitionBuffer)->Signature = 1;
02438
02439 partitionNumber = 0;
02440 }
02441 }
else {
02442
02443
02444
02445
02446
02447
02448 partitionNumber = -1;
02449 }
02450 }
02451
02452
02453
02454
02455
02456
02457 (*PartitionBuffer)->PartitionCount = ++partitionNumber;
02458
02459
if (!partitionNumber) {
02460
02461
02462
02463
02464
02465 (*PartitionBuffer)->Signature = 0;
02466 }
02467
02468
02469
02470
02471
02472
if (readBuffer !=
NULL) {
02473
ExFreePool( readBuffer );
02474 }
02475
02476
if (!
NT_SUCCESS(status)) {
02477
ExFreePool(*PartitionBuffer);
02478 *PartitionBuffer =
NULL;
02479 }
02480
return status;
02481 }