ReactOS  0.4.13-dev-249-gcba1a2f
partition.c
Go to the documentation of this file.
1 /*
2  * FreeLoader
3  * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4  *
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.
9  *
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.
14  *
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.
18  */
19 
20 /*
21  * TODO: This is here where we should add support for GPT partitions
22  * as well as partitionless disks!
23  */
24 
25 #ifndef _M_ARM
26 #include <freeldr.h>
27 
28 #include <debug.h>
29 
31 
32 /* This function serves to retrieve a partition entry for devices that handle partitions differently */
34 
36  PPARTITION_TABLE_ENTRY PartitionTableEntry,
37  ULONG *ActivePartition)
38 {
39  ULONG BootablePartitionCount = 0;
40  ULONG CurrentPartitionNumber;
41  ULONG Index;
42  MASTER_BOOT_RECORD MasterBootRecord;
43  PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
44 
45  *ActivePartition = 0;
46 
47  // Read master boot record
48  if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
49  {
50  return FALSE;
51  }
52 
53  CurrentPartitionNumber = 0;
54  for (Index=0; Index<4; Index++)
55  {
56  ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
57 
58  if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
59  ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
60  ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
61  {
62  CurrentPartitionNumber++;
63 
64  // Test if this is the bootable partition
65  if (ThisPartitionTableEntry->BootIndicator == 0x80)
66  {
67  BootablePartitionCount++;
68  *ActivePartition = CurrentPartitionNumber;
69 
70  // Copy the partition table entry
71  RtlCopyMemory(PartitionTableEntry,
72  ThisPartitionTableEntry,
73  sizeof(PARTITION_TABLE_ENTRY));
74  }
75  }
76  }
77 
78  // Make sure there was only one bootable partition
79  if (BootablePartitionCount == 0)
80  {
81  ERR("No bootable (active) partitions found.\n");
82  return FALSE;
83  }
84  else if (BootablePartitionCount != 1)
85  {
86  ERR("Too many bootable (active) partitions found.\n");
87  return FALSE;
88  }
89 
90  return TRUE;
91 }
92 
94 {
95  MASTER_BOOT_RECORD MasterBootRecord;
96  PARTITION_TABLE_ENTRY ExtendedPartitionTableEntry;
97  ULONG ExtendedPartitionNumber;
98  ULONG ExtendedPartitionOffset;
99  ULONG Index;
100  ULONG CurrentPartitionNumber;
101  PPARTITION_TABLE_ENTRY ThisPartitionTableEntry;
102 
103  // Read master boot record
104  if (!DiskReadBootRecord(DriveNumber, 0, &MasterBootRecord))
105  {
106  return FALSE;
107  }
108 
109  CurrentPartitionNumber = 0;
110  for (Index=0; Index<4; Index++)
111  {
112  ThisPartitionTableEntry = &MasterBootRecord.PartitionTable[Index];
113 
114  if (ThisPartitionTableEntry->SystemIndicator != PARTITION_ENTRY_UNUSED &&
115  ThisPartitionTableEntry->SystemIndicator != PARTITION_EXTENDED &&
116  ThisPartitionTableEntry->SystemIndicator != PARTITION_XINT13_EXTENDED)
117  {
118  CurrentPartitionNumber++;
119  }
120 
121  if (PartitionNumber == CurrentPartitionNumber)
122  {
123  RtlCopyMemory(PartitionTableEntry, ThisPartitionTableEntry, sizeof(PARTITION_TABLE_ENTRY));
124  return TRUE;
125  }
126  }
127 
128  // They want an extended partition entry so we will need
129  // to loop through all the extended partitions on the disk
130  // and return the one they want.
131 
132  ExtendedPartitionNumber = PartitionNumber - CurrentPartitionNumber - 1;
133 
134  // Set the initial relative starting sector to 0
135  // This is because extended partition starting
136  // sectors a numbered relative to their parent
137  ExtendedPartitionOffset = 0;
138 
139  for (Index=0; Index<=ExtendedPartitionNumber; Index++)
140  {
141  // Get the extended partition table entry
142  if (!DiskGetFirstExtendedPartitionEntry(&MasterBootRecord, &ExtendedPartitionTableEntry))
143  {
144  return FALSE;
145  }
146 
147  // Adjust the relative starting sector of the partition
148  ExtendedPartitionTableEntry.SectorCountBeforePartition += ExtendedPartitionOffset;
149  if (ExtendedPartitionOffset == 0)
150  {
151  // Set the start of the parrent extended partition
152  ExtendedPartitionOffset = ExtendedPartitionTableEntry.SectorCountBeforePartition;
153  }
154  // Read the partition boot record
155  if (!DiskReadBootRecord(DriveNumber, ExtendedPartitionTableEntry.SectorCountBeforePartition, &MasterBootRecord))
156  {
157  return FALSE;
158  }
159 
160  // Get the first real partition table entry
161  if (!DiskGetFirstPartitionEntry(&MasterBootRecord, PartitionTableEntry))
162  {
163  return FALSE;
164  }
165 
166  // Now correct the start sector of the partition
167  PartitionTableEntry->SectorCountBeforePartition += ExtendedPartitionTableEntry.SectorCountBeforePartition;
168  }
169 
170  // When we get here we should have the correct entry
171  // already stored in PartitionTableEntry
172  // so just return TRUE
173  return TRUE;
174 }
175 
177 {
178  ULONG Index;
179 
180  for (Index=0; Index<4; Index++)
181  {
182  // Check the system indicator
183  // If it's not an extended or unused partition
184  // then we're done
185  if ((MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_ENTRY_UNUSED) &&
186  (MasterBootRecord->PartitionTable[Index].SystemIndicator != PARTITION_EXTENDED) &&
188  {
189  RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
190  return TRUE;
191  }
192  }
193 
194  return FALSE;
195 }
196 
198 {
199  ULONG Index;
200 
201  for (Index=0; Index<4; Index++)
202  {
203  // Check the system indicator
204  // If it an extended partition then we're done
205  if ((MasterBootRecord->PartitionTable[Index].SystemIndicator == PARTITION_EXTENDED) ||
207  {
208  RtlCopyMemory(PartitionTableEntry, &MasterBootRecord->PartitionTable[Index], sizeof(PARTITION_TABLE_ENTRY));
209  return TRUE;
210  }
211  }
212 
213  return FALSE;
214 }
215 
216 BOOLEAN DiskReadBootRecord(UCHAR DriveNumber, ULONGLONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
217 {
218  ULONG Index;
219 
220  // Read master boot record
221  if (!MachDiskReadLogicalSectors(DriveNumber, LogicalSectorNumber, 1, DiskReadBuffer))
222  {
223  return FALSE;
224  }
225  RtlCopyMemory(BootRecord, DiskReadBuffer, sizeof(MASTER_BOOT_RECORD));
226 
227  TRACE("Dumping partition table for drive 0x%x:\n", DriveNumber);
228  TRACE("Boot record logical start sector = %d\n", LogicalSectorNumber);
229  TRACE("sizeof(MASTER_BOOT_RECORD) = 0x%x.\n", sizeof(MASTER_BOOT_RECORD));
230 
231  for (Index=0; Index<4; Index++)
232  {
233  TRACE("-------------------------------------------\n");
234  TRACE("Partition %d\n", (Index + 1));
235  TRACE("BootIndicator: 0x%x\n", BootRecord->PartitionTable[Index].BootIndicator);
236  TRACE("StartHead: 0x%x\n", BootRecord->PartitionTable[Index].StartHead);
237  TRACE("StartSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].StartSector);
238  TRACE("StartCylinder: 0x%x\n", BootRecord->PartitionTable[Index].StartCylinder);
239  TRACE("SystemIndicator: 0x%x\n", BootRecord->PartitionTable[Index].SystemIndicator);
240  TRACE("EndHead: 0x%x\n", BootRecord->PartitionTable[Index].EndHead);
241  TRACE("EndSector (Plus 2 cylinder bits): 0x%x\n", BootRecord->PartitionTable[Index].EndSector);
242  TRACE("EndCylinder: 0x%x\n", BootRecord->PartitionTable[Index].EndCylinder);
243  TRACE("SectorCountBeforePartition: 0x%x\n", BootRecord->PartitionTable[Index].SectorCountBeforePartition);
244  TRACE("PartitionSectorCount: 0x%x\n", BootRecord->PartitionTable[Index].PartitionSectorCount);
245  }
246 
247  // Check the partition table magic value
248  if (BootRecord->MasterBootRecordMagic != 0xaa55)
249  {
250  return FALSE;
251  }
252 
253  return TRUE;
254 }
255 
256 #ifndef _M_AMD64
257 NTSTATUS
258 NTAPI
261  IN ULONGLONG LogicalSectorNumber,
263  OUT PMASTER_BOOT_RECORD BootRecord)
264 {
265  ULONG_PTR FileId = (ULONG_PTR)DeviceObject;
269 
270  Position.QuadPart = LogicalSectorNumber * SectorSize;
271  Status = ArcSeek(FileId, &Position, SeekAbsolute);
272  if (Status != ESUCCESS)
273  return STATUS_IO_DEVICE_ERROR;
274 
275  Status = ArcRead(FileId, BootRecord, SectorSize, &BytesRead);
276  if (Status != ESUCCESS || BytesRead != SectorSize)
277  return STATUS_IO_DEVICE_ERROR;
278 
279  return STATUS_SUCCESS;
280 }
281 
282 BOOLEAN
283 NTAPI
287  IN PPARTITION_TABLE_ENTRY PartitionTableEntry,
288  OUT PARTITION_INFORMATION *PartitionEntry)
289 {
290  BOOLEAN IsRecognized;
291 
292  IsRecognized = TRUE; /* FIXME */
293  if (!IsRecognized && ReturnRecognizedPartitions)
294  return FALSE;
295 
296  PartitionEntry->StartingOffset.QuadPart = (ULONGLONG)PartitionTableEntry->SectorCountBeforePartition * SectorSize;
297  PartitionEntry->PartitionLength.QuadPart = (ULONGLONG)PartitionTableEntry->PartitionSectorCount * SectorSize;
298  PartitionEntry->HiddenSectors = 0;
299  PartitionEntry->PartitionNumber = 0; /* Will be filled later */
300  PartitionEntry->PartitionType = PartitionTableEntry->SystemIndicator;
301  PartitionEntry->BootIndicator = (PartitionTableEntry->BootIndicator & 0x80) ? TRUE : FALSE;
302  PartitionEntry->RecognizedPartition = IsRecognized;
303  PartitionEntry->RewritePartition = FALSE;
304 
305  return TRUE;
306 }
307 
308 NTSTATUS
309 FASTCALL
315 {
316  PMASTER_BOOT_RECORD MasterBootRecord;
317  PDRIVE_LAYOUT_INFORMATION Partitions;
318  ULONG NbPartitions, i, Size;
319  NTSTATUS ret;
320 
322 
323  if (SectorSize < sizeof(MASTER_BOOT_RECORD))
324  return STATUS_NOT_SUPPORTED;
325 
326  MasterBootRecord = ExAllocatePool(NonPagedPool, SectorSize);
327  if (!MasterBootRecord)
328  return STATUS_NO_MEMORY;
329 
330  /* Read disk MBR */
331  ret = IopReadBootRecord(DeviceObject, 0, SectorSize, MasterBootRecord);
332  if (!NT_SUCCESS(ret))
333  {
334  ExFreePool(MasterBootRecord);
335  return ret;
336  }
337 
338  /* Check validity of boot record */
339  if (MasterBootRecord->MasterBootRecordMagic != 0xaa55)
340  {
341  ExFreePool(MasterBootRecord);
342  return STATUS_NOT_SUPPORTED;
343  }
344 
345  /* Count number of partitions */
346  NbPartitions = 0;
347  for (i = 0; i < 4; i++)
348  {
349  NbPartitions++;
350 
351  if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
353  {
354  /* FIXME: unhandled case; count number of partitions */
356  }
357  }
358 
359  if (NbPartitions == 0)
360  {
361  ExFreePool(MasterBootRecord);
362  return STATUS_NOT_SUPPORTED;
363  }
364 
365  /* Allocation space to store partitions */
366  Size = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
367  NbPartitions * sizeof(PARTITION_INFORMATION);
368  Partitions = ExAllocatePool(NonPagedPool, Size);
369  if (!Partitions)
370  {
371  ExFreePool(MasterBootRecord);
372  return STATUS_NO_MEMORY;
373  }
374 
375  /* Count number of partitions */
376  NbPartitions = 0;
377  for (i = 0; i < 4; i++)
378  {
380  SectorSize,
381  &MasterBootRecord->PartitionTable[i],
382  &Partitions->PartitionEntry[NbPartitions]))
383  {
384  Partitions->PartitionEntry[NbPartitions].PartitionNumber = NbPartitions + 1;
385  NbPartitions++;
386  }
387 
388  if (MasterBootRecord->PartitionTable[i].SystemIndicator == PARTITION_EXTENDED ||
390  {
391  /* FIXME: unhandled case; copy partitions */
393  }
394  }
395 
396  Partitions->PartitionCount = NbPartitions;
397  Partitions->Signature = MasterBootRecord->Signature;
398  ExFreePool(MasterBootRecord);
399 
400  *PartitionBuffer = Partitions;
401  return STATUS_SUCCESS;
402 }
403 #endif // _M_AMD64
404 #endif
ULONG Signature
Definition: disk.h:75
#define MachDiskReadLogicalSectors(Drive, Start, Count, Buf)
Definition: machine.h:120
BOOLEAN(* DISK_GET_PARTITION_ENTRY)(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: disk.h:150
#define IN
Definition: typedefs.h:38
USHORT MasterBootRecordMagic
Definition: disk.h:78
Definition: disk.h:53
DISK_GET_PARTITION_ENTRY DiskGetPartitionEntry
Definition: partition.c:33
BOOLEAN DiskGetFirstExtendedPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:197
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
UCHAR StartCylinder
Definition: parttest.c:79
BOOLEAN DiskGetActivePartitionEntry(UCHAR DriveNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry, ULONG *ActivePartition)
Definition: partition.c:35
UCHAR StartSector
Definition: parttest.c:78
Definition: arc.h:32
UCHAR EndHead
Definition: parttest.c:81
ULONG PartitionSectorCount
Definition: parttest.c:85
static COORD Position
Definition: mouse.c:34
#define DiskReadBuffer
Definition: hardware.h:33
UCHAR SystemIndicator
Definition: disk.h:60
LONG NTSTATUS
Definition: precomp.h:26
ULONG ARC_STATUS
Definition: arc.h:4
NTSTATUS NTAPI IopReadBootRecord(IN PDEVICE_OBJECT DeviceObject, IN ULONGLONG LogicalSectorNumber, IN ULONG SectorSize, OUT PMASTER_BOOT_RECORD BootRecord)
Definition: partition.c:259
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2056
ULONG SectorCountBeforePartition
Definition: parttest.c:84
struct _PARTITION_INFORMATION PARTITION_INFORMATION
#define FASTCALL
Definition: nt_native.h:50
uint32_t ULONG_PTR
Definition: typedefs.h:63
#define STATUS_IO_DEVICE_ERROR
Definition: udferr_usr.h:179
UCHAR SystemIndicator
Definition: parttest.c:80
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:86
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
BOOLEAN DiskGetFirstPartitionEntry(PMASTER_BOOT_RECORD MasterBootRecord, PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:176
_In_ ULONG _In_ BOOLEAN _Out_ struct _DRIVE_LAYOUT_INFORMATION ** PartitionBuffer
Definition: iofuncs.h:2048
BOOLEAN DiskGetMbrPartitionEntry(UCHAR DriveNumber, ULONG PartitionNumber, PPARTITION_TABLE_ENTRY PartitionTableEntry)
Definition: partition.c:93
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
DBG_DEFAULT_CHANNEL(DISK)
ULONG SectorCountBeforePartition
Definition: disk.h:64
#define PARTITION_EXTENDED
Definition: disk.h:91
#define TRACE(s)
Definition: solgame.cpp:4
BOOLEAN NTAPI IopCopyPartitionRecord(IN BOOLEAN ReturnRecognizedPartitions, IN ULONG SectorSize, IN PPARTITION_TABLE_ENTRY PartitionTableEntry, OUT PARTITION_INFORMATION *PartitionEntry)
Definition: partition.c:284
UCHAR BootIndicator
Definition: parttest.c:76
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
UCHAR StartHead
Definition: parttest.c:77
uint64_t ULONGLONG
Definition: typedefs.h:65
static const UCHAR Index[8]
Definition: usbohci.c:18
Definition: parttest.c:75
UCHAR EndCylinder
Definition: parttest.c:83
UCHAR BootIndicator
Definition: disk.h:55
PARTITION_TABLE_ENTRY PartitionTable[4]
Definition: disk.h:77
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:237
unsigned char UCHAR
Definition: xmlstorage.h:181
int ret
#define ExAllocatePool(type, size)
Definition: fbtusb.h:44
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:244
_In_ ULONG _In_ BOOLEAN ReturnRecognizedPartitions
Definition: iofuncs.h:2046
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
#define PARTITION_XINT13_EXTENDED
Definition: disk.h:98
NTSTATUS FASTCALL IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN BOOLEAN ReturnRecognizedPartitions, OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
Definition: partition.c:310
Status
Definition: gdiplustypes.h:24
#define ERR(fmt,...)
Definition: debug.h:109
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
#define OUT
Definition: typedefs.h:39
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:409
BOOLEAN DiskReadBootRecord(UCHAR DriveNumber, ULONGLONG LogicalSectorNumber, PMASTER_BOOT_RECORD BootRecord)
Definition: partition.c:216
unsigned int ULONG
Definition: retypes.h:1
#define UNIMPLEMENTED
Definition: debug.h:114
#define ULONG_PTR
Definition: config.h:101
PARTITION_TABLE_ENTRY PartitionTable[4]
Definition: parttest.c:92
_In_ ULONG SectorSize
Definition: halfuncs.h:291
return STATUS_SUCCESS
Definition: btrfs.c:2745
UCHAR EndSector
Definition: parttest.c:82
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
#define ExFreePool(addr)
Definition: env_spec_w32.h:352