3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 BOOLEAN
DiskGetActivePartitionEntry(ULONG DriveNumber
,
25 PPARTITION_TABLE_ENTRY PartitionTableEntry
,
26 ULONG
*ActivePartition
)
28 ULONG BootablePartitionCount
= 0;
29 MASTER_BOOT_RECORD MasterBootRecord
;
32 // Read master boot record
33 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
38 // Count the bootable partitions
39 if (MasterBootRecord
.PartitionTable
[0].BootIndicator
== 0x80)
41 BootablePartitionCount
++;
44 if (MasterBootRecord
.PartitionTable
[1].BootIndicator
== 0x80)
46 BootablePartitionCount
++;
49 if (MasterBootRecord
.PartitionTable
[2].BootIndicator
== 0x80)
51 BootablePartitionCount
++;
54 if (MasterBootRecord
.PartitionTable
[3].BootIndicator
== 0x80)
56 BootablePartitionCount
++;
60 // Make sure there was only one bootable partition
61 if (BootablePartitionCount
== 0)
63 DPRINTM(DPRINT_DISK
, "No bootable (active) partitions found.\n");
66 else if (BootablePartitionCount
!= 1)
68 DPRINTM(DPRINT_DISK
, "Too many bootable (active) partitions found.\n");
72 // Copy the partition table entry
73 RtlCopyMemory(PartitionTableEntry
,
74 &MasterBootRecord
.PartitionTable
[*ActivePartition
- 1],
75 sizeof(PARTITION_TABLE_ENTRY
));
80 BOOLEAN
DiskGetPartitionEntry(ULONG DriveNumber
, ULONG PartitionNumber
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
82 MASTER_BOOT_RECORD MasterBootRecord
;
83 PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry
;
84 ULONG ExtendedPartitionNumber
;
85 ULONG ExtendedPartitionOffset
;
88 // Read master boot record
89 if (!DiskReadBootRecord(DriveNumber
, 0, &MasterBootRecord
))
94 // If they are asking for a primary
95 // partition then things are easy
96 if (PartitionNumber
< 5)
98 // PartitionNumber is one-based and we need it zero-based
101 // Copy the partition table entry
102 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
.PartitionTable
[PartitionNumber
], sizeof(PARTITION_TABLE_ENTRY
));
108 // They want an extended partition entry so we will need
109 // to loop through all the extended partitions on the disk
110 // and return the one they want.
112 ExtendedPartitionNumber
= PartitionNumber
- 5;
114 // Set the initial relative starting sector to 0
115 // This is because extended partition starting
116 // sectors a numbered relative to their parent
117 ExtendedPartitionOffset
= 0;
119 for (Index
=0; Index
<=ExtendedPartitionNumber
; Index
++)
121 // Get the extended partition table entry
122 if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord
, &ExtendedPartitionTableEntry
))
127 // Adjust the relative starting sector of the partition
128 ExtendedPartitionTableEntry
.SectorCountBeforePartition
+= ExtendedPartitionOffset
;
129 if (ExtendedPartitionOffset
== 0)
131 // Set the start of the parrent extended partition
132 ExtendedPartitionOffset
= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
134 // Read the partition boot record
135 if (!DiskReadBootRecord(DriveNumber
, ExtendedPartitionTableEntry
.SectorCountBeforePartition
, &MasterBootRecord
))
140 // Get the first real partition table entry
141 if (!DiskGetFirstPartitionEntry(&MasterBootRecord
, PartitionTableEntry
))
146 // Now correct the start sector of the partition
147 PartitionTableEntry
->SectorCountBeforePartition
+= ExtendedPartitionTableEntry
.SectorCountBeforePartition
;
150 // When we get here we should have the correct entry
151 // already stored in PartitionTableEntry
152 // so just return TRUE
158 BOOLEAN
DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
162 for (Index
=0; Index
<4; Index
++)
164 // Check the system indicator
165 // If it's not an extended or unused partition
167 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_ENTRY_UNUSED
) &&
168 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_EXTENDED
) &&
169 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
!= PARTITION_XINT13_EXTENDED
))
171 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
179 BOOLEAN
DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord
, PPARTITION_TABLE_ENTRY PartitionTableEntry
)
183 for (Index
=0; Index
<4; Index
++)
185 // Check the system indicator
186 // If it an extended partition then we're done
187 if ((MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_EXTENDED
) ||
188 (MasterBootRecord
->PartitionTable
[Index
].SystemIndicator
== PARTITION_XINT13_EXTENDED
))
190 RtlCopyMemory(PartitionTableEntry
, &MasterBootRecord
->PartitionTable
[Index
], sizeof(PARTITION_TABLE_ENTRY
));
198 BOOLEAN
DiskReadBootRecord(ULONG DriveNumber
, ULONGLONG LogicalSectorNumber
, PMASTER_BOOT_RECORD BootRecord
)
203 // Read master boot record
204 if (!MachDiskReadLogicalSectors(DriveNumber
, LogicalSectorNumber
, 1, (PVOID
)DISKREADBUFFER
))
208 RtlCopyMemory(BootRecord
, (PVOID
)DISKREADBUFFER
, sizeof(MASTER_BOOT_RECORD
));
211 DPRINTM(DPRINT_DISK
, "Dumping partition table for drive 0x%x:\n", DriveNumber
);
212 DPRINTM(DPRINT_DISK
, "Boot record logical start sector = %d\n", LogicalSectorNumber
);
213 DPRINTM(DPRINT_DISK
, "sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD
));
215 for (Index
=0; Index
<4; Index
++)
217 DPRINTM(DPRINT_DISK
, "-------------------------------------------\n");
218 DPRINTM(DPRINT_DISK
, "Partition %d\n", (Index
+ 1));
219 DPRINTM(DPRINT_DISK
, "BootIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].BootIndicator
);
220 DPRINTM(DPRINT_DISK
, "StartHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartHead
);
221 DPRINTM(DPRINT_DISK
, "StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].StartSector
);
222 DPRINTM(DPRINT_DISK
, "StartCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].StartCylinder
);
223 DPRINTM(DPRINT_DISK
, "SystemIndicator: 0x%x\n", BootRecord
->PartitionTable
[Index
].SystemIndicator
);
224 DPRINTM(DPRINT_DISK
, "EndHead: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndHead
);
225 DPRINTM(DPRINT_DISK
, "EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord
->PartitionTable
[Index
].EndSector
);
226 DPRINTM(DPRINT_DISK
, "EndCylinder: 0x%x\n", BootRecord
->PartitionTable
[Index
].EndCylinder
);
227 DPRINTM(DPRINT_DISK
, "SectorCountBeforePartition: 0x%x\n", BootRecord
->PartitionTable
[Index
].SectorCountBeforePartition
);
228 DPRINTM(DPRINT_DISK
, "PartitionSectorCount: 0x%x\n", BootRecord
->PartitionTable
[Index
].PartitionSectorCount
);
231 // Check the partition table magic value
232 if (BootRecord
->MasterBootRecordMagic
!= 0xaa55)
234 sprintf(ErrMsg
, "Invalid partition table magic 0x%x found on drive 0x%lx",
235 BootRecord
->MasterBootRecordMagic
, DriveNumber
);
236 DiskError(ErrMsg
, 0);
246 IN PDEVICE_OBJECT DeviceObject
,
247 IN ULONGLONG LogicalSectorNumber
,
249 OUT PMASTER_BOOT_RECORD BootRecord
)
251 ULONG FileId
= (ULONG
)DeviceObject
;
252 LARGE_INTEGER Position
;
256 Position
.QuadPart
= LogicalSectorNumber
* SectorSize
;
257 Status
= ArcSeek(FileId
, &Position
, SeekAbsolute
);
258 if (Status
!= ESUCCESS
)
259 return STATUS_IO_DEVICE_ERROR
;
261 Status
= ArcRead(FileId
, BootRecord
, SectorSize
, &BytesRead
);
262 if (Status
!= ESUCCESS
|| BytesRead
!= SectorSize
)
263 return STATUS_IO_DEVICE_ERROR
;
265 return STATUS_SUCCESS
;
270 IopCopyPartitionRecord(
271 IN BOOLEAN ReturnRecognizedPartitions
,
273 IN PPARTITION_TABLE_ENTRY PartitionTableEntry
,
274 OUT PARTITION_INFORMATION
*PartitionEntry
)
276 BOOLEAN IsRecognized
;
278 IsRecognized
= TRUE
; /* FIXME */
279 if (!IsRecognized
&& ReturnRecognizedPartitions
)
282 PartitionEntry
->StartingOffset
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->SectorCountBeforePartition
* SectorSize
;
283 PartitionEntry
->PartitionLength
.QuadPart
= (ULONGLONG
)PartitionTableEntry
->PartitionSectorCount
* SectorSize
;
284 PartitionEntry
->HiddenSectors
= 0;
285 PartitionEntry
->PartitionNumber
= 0; /* Will be filled later */
286 PartitionEntry
->PartitionType
= PartitionTableEntry
->SystemIndicator
;
287 PartitionEntry
->BootIndicator
= (PartitionTableEntry
->BootIndicator
& 0x80) ? TRUE
: FALSE
;
288 PartitionEntry
->RecognizedPartition
= IsRecognized
;
289 PartitionEntry
->RewritePartition
= FALSE
;
297 IoReadPartitionTable(
298 IN PDEVICE_OBJECT DeviceObject
,
300 IN BOOLEAN ReturnRecognizedPartitions
,
301 OUT PDRIVE_LAYOUT_INFORMATION
*PartitionBuffer
)
303 PMASTER_BOOT_RECORD MasterBootRecord
;
304 PDRIVE_LAYOUT_INFORMATION Partitions
;
305 ULONG NbPartitions
, i
, Size
;
308 *PartitionBuffer
= NULL
;
310 if (SectorSize
< sizeof(MASTER_BOOT_RECORD
))
311 return STATUS_NOT_SUPPORTED
;
313 MasterBootRecord
= ExAllocatePool(NonPagedPool
, SectorSize
);
314 if (!MasterBootRecord
)
315 return STATUS_NO_MEMORY
;
318 ret
= IopReadBootRecord(DeviceObject
, 0, SectorSize
, MasterBootRecord
);
319 if (!NT_SUCCESS(ret
))
321 ExFreePool(MasterBootRecord
);
325 /* Check validity of boot record */
326 if (MasterBootRecord
->MasterBootRecordMagic
!= 0xaa55)
328 ExFreePool(MasterBootRecord
);
329 return STATUS_NOT_SUPPORTED
;
332 /* Count number of partitions */
334 for (i
= 0; i
< 4; i
++)
338 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
339 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
341 /* FIXME: unhandled case; count number of partitions */
346 if (NbPartitions
== 0)
348 ExFreePool(MasterBootRecord
);
349 return STATUS_NOT_SUPPORTED
;
352 /* Allocation space to store partitions */
353 Size
= FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION
, PartitionEntry
) +
354 NbPartitions
* sizeof(PARTITION_INFORMATION
);
355 Partitions
= ExAllocatePool(NonPagedPool
, Size
);
358 ExFreePool(MasterBootRecord
);
359 return STATUS_NO_MEMORY
;
362 /* Count number of partitions */
364 for (i
= 0; i
< 4; i
++)
366 if (IopCopyPartitionRecord(ReturnRecognizedPartitions
,
368 &MasterBootRecord
->PartitionTable
[i
],
369 &Partitions
->PartitionEntry
[NbPartitions
]))
371 Partitions
->PartitionEntry
[NbPartitions
].PartitionNumber
= NbPartitions
+ 1;
375 if (MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_EXTENDED
||
376 MasterBootRecord
->PartitionTable
[i
].SystemIndicator
== PARTITION_XINT13_EXTENDED
)
378 /* FIXME: unhandled case; copy partitions */
383 Partitions
->PartitionCount
= NbPartitions
;
384 Partitions
->Signature
= MasterBootRecord
->Signature
;
385 ExFreePool(MasterBootRecord
);
387 *PartitionBuffer
= Partitions
;
388 return STATUS_SUCCESS
;