[SETUPLIB][USETUP] Minor improvements.
[reactos.git] / base / setup / lib / utils / partlist.c
1 /*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2019 Hermes Belusca-Maito
7 */
8
9 #include "precomp.h"
10 #include <ntddscsi.h>
11
12 #include "partlist.h"
13 #include "fsutil.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18 //#define DUMP_PARTITION_TABLE
19
20 #include <pshpack1.h>
21
22 typedef struct _REG_DISK_MOUNT_INFO
23 {
24 ULONG Signature;
25 LARGE_INTEGER StartingOffset;
26 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
27
28 #include <poppack.h>
29
30
31 /* HELPERS FOR PARTITION TYPES **********************************************/
32
33 /*
34 * This partition type list was ripped from the kernelDisk.c module of
35 * the Visopsys Operating System (see license below), and completed with
36 * information from Paragon Hard-Disk Manager, and the following websites:
37 * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
38 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
39 */
40 /*
41 * kernelDisk.c
42 *
43 * Visopsys Operating System
44 * Copyright (C) 1998-2015 J. Andrew McLaughlin
45 *
46 * This program is free software; you can redistribute it and/or modify it
47 * under the terms of the GNU General Public License as published by the Free
48 * Software Foundation; either version 2 of the License, or (at your option)
49 * any later version.
50 *
51 * This program is distributed in the hope that it will be useful, but
52 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
53 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
54 * for more details.
55 *
56 * You should have received a copy of the GNU General Public License along
57 * with this program; if not, write to the Free Software Foundation, Inc.,
58 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
59 */
60
61 /* This is a table for keeping known partition type codes and descriptions */
62 PARTITION_TYPE PartitionTypes[NUM_PARTITION_TYPE_ENTRIES] =
63 {
64 { 0x00, "(Empty)" },
65 { 0x01, "FAT12" },
66 { 0x02, "XENIX root" },
67 { 0x03, "XENIX usr" },
68 { 0x04, "FAT16 (< 32 MB)" },
69 { 0x05, "Extended" },
70 { 0x06, "FAT16" },
71 { 0x07, "NTFS/HPFS/exFAT" },
72 { 0x08, "OS/2 or AIX boot" },
73 { 0x09, "AIX data" },
74 { 0x0A, "OS/2 Boot Manager" },
75 { 0x0B, "FAT32" },
76 { 0x0C, "FAT32 (LBA)" },
77 { 0x0E, "FAT16 (LBA)" },
78 { 0x0F, "Extended (LBA)" },
79 { 0x10, "OPUS" },
80 { 0x11, "Hidden FAT12" },
81 { 0x12, "FAT diagnostic (Compaq)" },
82 { 0x13, "BTRON" },
83 { 0x14, "Hidden FAT16 (< 32 MB)" },
84 { 0x16, "Hidden FAT16" },
85 { 0x17, "Hidden HPFS or NTFS" },
86 { 0x18, "AST SmartSleep" },
87 { 0x1B, "Hidden FAT32" },
88 { 0x1C, "Hidden FAT32 (LBA)" },
89 { 0x1E, "Hidden FAT16 (LBA)" },
90 { 0x24, "NEC DOS 3.x" },
91 { 0x27, "Hidden WinRE NTFS" },
92 { 0x2A, "AtheOS File System (AFS)" },
93 { 0x2B, "SyllableSecure (SylStor)" },
94 { 0x32, "NOS" },
95 { 0x35, "JFS on OS/2 or eCS" },
96 { 0x38, "THEOS v3.2 2GB partition" },
97 { 0x39, "Plan 9" },
98 { 0x3A, "THEOS v4 4GB partition" },
99 { 0x3B, "THEOS v4 extended partition" },
100 { 0x3C, "PartitionMagic recovery partition" },
101 { 0x3D, "Hidden NetWare" },
102 { 0x40, "Lynx" },
103 { 0x41, "PowerPC PReP boot" },
104 { 0x42, "Win2K Dynamic Volume extended" },
105 { 0x43, "Old Linux" },
106 { 0x44, "GoBack" },
107 { 0x45, "Priam or Boot-US Boot Manager" },
108 { 0x4D, "QNX4.x" },
109 { 0x4E, "QNX4.x 2nd partition" },
110 { 0x4F, "QNX4.x 3rd partition" },
111 { 0x50, "OnTrack Disk Manager R/O" },
112 { 0x51, "OnTrack Disk Manager R/W or Novell" },
113 { 0x52, "CP/M" },
114 { 0x53, "OnTrack DM6 Aux3" },
115 { 0x54, "OnTrack DM6 Dynamic Drive Overlay" },
116 { 0x55, "EZ-Drive" },
117 { 0x56, "Golden Bow VFeature Partitioned Volume" },
118 { 0x5C, "Priam EDisk" },
119 { 0x61, "SpeedStor" },
120 { 0x62, "Pick" },
121 { 0x63, "GNU HURD or Unix System V (SCO, ISC Unix, UnixWare)" },
122 { 0x64, "Novell NetWare 286, 2.xx" },
123 { 0x65, "Novell NetWare 386, 3.xx or 4.xx" },
124 { 0x66, "Novell NetWare SMS Partition" },
125 { 0x67, "Novell" },
126 { 0x68, "Novell" },
127 { 0x69, "Novell NetWare 5+" },
128 { 0x70, "DiskSecure Multi-Boot" },
129 { 0x75, "IBM PC/IX" },
130 { 0x7E, "Veritas VxVM public" },
131 { 0x7F, "Veritas VxVM private" },
132 { 0x80, "Old MINIX" },
133 { 0x81, "Linux or MINIX" },
134 { 0x82, "Linux swap or Solaris" },
135 { 0x83, "Linux Native" },
136 { 0x84, "Hibernate" },
137 { 0x85, "Extended Linux" },
138 { 0x86, "FAT16 mirrored" },
139 { 0x87, "HPFS or NTFS mirrored" },
140 { 0x88, "Linux plaintext partition table" },
141 { 0x8B, "FAT32 mirrored" },
142 { 0x8C, "FAT32 (LBA) mirrored" },
143 { 0x8E, "Linux LVM" },
144 { 0x93, "Hidden Linux" },
145 { 0x94, "Amoeba BBT" },
146 { 0x96, "CDFS/ISO-9660" },
147 { 0x9F, "BSD/OS" },
148 { 0xA0, "Laptop Hibernate" },
149 { 0xA1, "Laptop Hibernate (NEC 6000H)" },
150 { 0xA5, "BSD, NetBSD, FreeBSD" },
151 { 0xA6, "OpenBSD" },
152 { 0xA7, "NeXTStep" },
153 { 0xA8, "Darwin UFS" }, // Also known as "OS-X"
154 { 0xA9, "NetBSD" },
155 { 0xAB, "Darwin boot" },
156 { 0xAF, "Apple HFS" },
157 { 0xB6, "NT FAT16 corrupt mirror" },
158 { 0xB7, "BSDI BSD/386 FS" }, // Alternatively, "NT NTFS corrupt mirror"
159 { 0xB8, "BSDI BSD/386 swap" },
160 { 0xBB, "Boot Wizard hidden" },
161 { 0xBC, "Paragon Backup capsule" },
162 { 0xBE, "Solaris 8 boot partition" },
163 { 0xBF, "Solaris 10 x86" },
164 { 0xC0, "NTFT" }, // Alternatively, "CTOS" or "REAL/32 or DR-DOS or Novell-DOS secure partition"
165 { 0xC1, "DR-DOS FAT12" },
166 { 0xC2, "Hidden Linux" },
167 { 0xC3, "Hidden Linux swap" },
168 { 0xC4, "DR-DOS FAT16 (< 32 MB)" },
169 { 0xC5, "DR-DOS Extended" },
170 { 0xC6, "DR-DOS FAT16" },
171 { 0xC7, "HPFS mirrored" }, // Alternatively, "Syrinx boot"
172 { 0xCB, "DR-DOS FAT32" },
173 { 0xCC, "DR-DOS FAT32 (LBA)" },
174 { 0xCE, "DR-DOS FAT16 (LBA)" },
175 { 0xD0, "MDOS" },
176 { 0xD1, "MDOS FAT12" },
177 { 0xD4, "MDOS FAT16 (< 32 MB)" },
178 { 0xD5, "MDOS Extended" },
179 { 0xD6, "MDOS FAT16" },
180 { 0xD8, "CP/M-86" },
181 { 0xDB, "Digital Research CP/M" },
182 { 0xDE, "Dell OEM" },
183 { 0xDF, "BootIt EMBRM (FAT16/32)" },
184 { 0xE1, "SpeedStor FAT12" },
185 { 0xE3, "SpeedStor (0xE3)" },
186 { 0xE4, "SpeedStor FAT16" },
187 { 0xE5, "Tandy MSDOS" },
188 { 0xE6, "SpeedStor (0xE6)" },
189 { 0xE8, "Linux Unified Key Setup partition" },
190 { 0xEA, "Rufus private partition" },
191 { 0xEB, "BeOS BFS" },
192 { 0xEC, "SkyOS SkyFS" },
193 { 0xEE, "EFI GPT protective" },
194 { 0xEF, "EFI System partition" },
195 { 0xF0, "Linux/PA-RISC boot loader" },
196 { 0xF1, "SpeedStor (0xF1)" },
197 { 0xF2, "DOS 3.3+ second" },
198 { 0xF4, "SpeedStor (0xF4)" },
199 { 0xF5, "SpeedStor (0xF5)" },
200 { 0xF6, "SpeedStor (0xF6)" },
201 { 0xFA, "Bochs" },
202 { 0xFB, "VMware FS" },
203 { 0xFC, "VMware swap" },
204 { 0xFD, "Linux RAID auto" },
205 { 0xFE, "NT hidden partition" },
206 { 0xFF, "XENIX Bad Block Table" },
207 };
208
209
210 /* FUNCTIONS ****************************************************************/
211
212 #ifdef DUMP_PARTITION_TABLE
213 static
214 VOID
215 DumpPartitionTable(
216 PDISKENTRY DiskEntry)
217 {
218 PPARTITION_INFORMATION PartitionInfo;
219 ULONG i;
220
221 DbgPrint("\n");
222 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
223 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
224
225 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
226 {
227 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
228 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
229 i,
230 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
231 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
232 PartitionInfo->HiddenSectors,
233 PartitionInfo->PartitionNumber,
234 PartitionInfo->PartitionType,
235 PartitionInfo->BootIndicator ? '*': ' ',
236 PartitionInfo->RewritePartition ? 'Y': 'N');
237 }
238
239 DbgPrint("\n");
240 }
241 #endif
242
243
244 ULONGLONG
245 AlignDown(
246 IN ULONGLONG Value,
247 IN ULONG Alignment)
248 {
249 ULONGLONG Temp;
250
251 Temp = Value / Alignment;
252
253 return Temp * Alignment;
254 }
255
256 ULONGLONG
257 AlignUp(
258 IN ULONGLONG Value,
259 IN ULONG Alignment)
260 {
261 ULONGLONG Temp, Result;
262
263 Temp = Value / Alignment;
264
265 Result = Temp * Alignment;
266 if (Value % Alignment)
267 Result += Alignment;
268
269 return Result;
270 }
271
272 ULONGLONG
273 RoundingDivide(
274 IN ULONGLONG Dividend,
275 IN ULONGLONG Divisor)
276 {
277 return (Dividend + Divisor / 2) / Divisor;
278 }
279
280
281 static
282 VOID
283 GetDriverName(
284 IN PDISKENTRY DiskEntry)
285 {
286 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
287 WCHAR KeyName[32];
288 NTSTATUS Status;
289
290 RtlInitUnicodeString(&DiskEntry->DriverName, NULL);
291
292 RtlStringCchPrintfW(KeyName, ARRAYSIZE(KeyName),
293 L"\\Scsi\\Scsi Port %hu",
294 DiskEntry->Port);
295
296 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
297
298 QueryTable[0].Name = L"Driver";
299 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
300 QueryTable[0].EntryContext = &DiskEntry->DriverName;
301
302 /* This will allocate DiskEntry->DriverName if needed */
303 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
304 KeyName,
305 QueryTable,
306 NULL,
307 NULL);
308 if (!NT_SUCCESS(Status))
309 {
310 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
311 }
312 }
313
314 static
315 VOID
316 AssignDriveLetters(
317 IN PPARTLIST List)
318 {
319 PDISKENTRY DiskEntry;
320 PPARTENTRY PartEntry;
321 PLIST_ENTRY Entry1;
322 PLIST_ENTRY Entry2;
323 WCHAR Letter;
324
325 Letter = L'C';
326
327 /* Assign drive letters to primary partitions */
328 for (Entry1 = List->DiskListHead.Flink;
329 Entry1 != &List->DiskListHead;
330 Entry1 = Entry1->Flink)
331 {
332 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
333
334 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
335 Entry2 != &DiskEntry->PrimaryPartListHead;
336 Entry2 = Entry2->Flink)
337 {
338 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
339
340 PartEntry->DriveLetter = 0;
341
342 if (PartEntry->IsPartitioned &&
343 !IsContainerPartition(PartEntry->PartitionType))
344 {
345 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
346
347 if (IsRecognizedPartition(PartEntry->PartitionType) ||
348 PartEntry->SectorCount.QuadPart != 0LL)
349 {
350 if (Letter <= L'Z')
351 {
352 PartEntry->DriveLetter = Letter;
353 Letter++;
354 }
355 }
356 }
357 }
358 }
359
360 /* Assign drive letters to logical drives */
361 for (Entry1 = List->DiskListHead.Flink;
362 Entry1 != &List->DiskListHead;
363 Entry1 = Entry1->Flink)
364 {
365 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
366
367 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
368 Entry2 != &DiskEntry->LogicalPartListHead;
369 Entry2 = Entry2->Flink)
370 {
371 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
372
373 PartEntry->DriveLetter = 0;
374
375 if (PartEntry->IsPartitioned)
376 {
377 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
378
379 if (IsRecognizedPartition(PartEntry->PartitionType) ||
380 PartEntry->SectorCount.QuadPart != 0LL)
381 {
382 if (Letter <= L'Z')
383 {
384 PartEntry->DriveLetter = Letter;
385 Letter++;
386 }
387 }
388 }
389 }
390 }
391 }
392
393 static NTSTATUS
394 NTAPI
395 DiskIdentifierQueryRoutine(
396 PWSTR ValueName,
397 ULONG ValueType,
398 PVOID ValueData,
399 ULONG ValueLength,
400 PVOID Context,
401 PVOID EntryContext)
402 {
403 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
404 UNICODE_STRING NameU;
405
406 if (ValueType == REG_SZ &&
407 ValueLength == 20 * sizeof(WCHAR))
408 {
409 NameU.Buffer = (PWCHAR)ValueData;
410 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
411 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
412
413 NameU.Buffer = (PWCHAR)ValueData + 9;
414 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
415
416 return STATUS_SUCCESS;
417 }
418
419 return STATUS_UNSUCCESSFUL;
420 }
421
422 static NTSTATUS
423 NTAPI
424 DiskConfigurationDataQueryRoutine(
425 PWSTR ValueName,
426 ULONG ValueType,
427 PVOID ValueData,
428 ULONG ValueLength,
429 PVOID Context,
430 PVOID EntryContext)
431 {
432 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
433 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
434 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
435 ULONG i;
436
437 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
438 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
439 return STATUS_UNSUCCESSFUL;
440
441 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
442
443 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
444 #if 0
445 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
446 FullResourceDescriptor->PartialResourceList.Revision != 1)
447 return STATUS_UNSUCCESSFUL;
448 #endif
449
450 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
451 {
452 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
453 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
454 continue;
455
456 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
457 BiosDiskEntry->DiskGeometry = *DiskGeometry;
458
459 return STATUS_SUCCESS;
460 }
461
462 return STATUS_UNSUCCESSFUL;
463 }
464
465 static NTSTATUS
466 NTAPI
467 SystemConfigurationDataQueryRoutine(
468 PWSTR ValueName,
469 ULONG ValueType,
470 PVOID ValueData,
471 ULONG ValueLength,
472 PVOID Context,
473 PVOID EntryContext)
474 {
475 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
476 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
477 ULONG i;
478
479 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
480 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
481 return STATUS_UNSUCCESSFUL;
482
483 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
484
485 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
486 #if 0
487 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
488 FullResourceDescriptor->PartialResourceList.Revision != 1)
489 return STATUS_UNSUCCESSFUL;
490 #endif
491
492 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
493 {
494 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
495 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
496 continue;
497
498 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
499 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
500 if (*Int13Drives == NULL)
501 return STATUS_NO_MEMORY;
502
503 memcpy(*Int13Drives,
504 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
505 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
506 return STATUS_SUCCESS;
507 }
508
509 return STATUS_UNSUCCESSFUL;
510 }
511
512
513 static VOID
514 EnumerateBiosDiskEntries(
515 IN PPARTLIST PartList)
516 {
517 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
518 WCHAR Name[120];
519 ULONG AdapterCount;
520 ULONG DiskCount;
521 NTSTATUS Status;
522 PCM_INT13_DRIVE_PARAMETER Int13Drives;
523 PBIOSDISKENTRY BiosDiskEntry;
524
525 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
526
527 memset(QueryTable, 0, sizeof(QueryTable));
528
529 QueryTable[1].Name = L"Configuration Data";
530 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
531 Int13Drives = NULL;
532 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
533 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
534 &QueryTable[1],
535 (PVOID)&Int13Drives,
536 NULL);
537 if (!NT_SUCCESS(Status))
538 {
539 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
540 return;
541 }
542
543 AdapterCount = 0;
544 while (TRUE)
545 {
546 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
547 L"%s\\%lu",
548 ROOT_NAME, AdapterCount);
549 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
550 Name,
551 &QueryTable[2],
552 NULL,
553 NULL);
554 if (!NT_SUCCESS(Status))
555 {
556 break;
557 }
558
559 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
560 L"%s\\%lu\\DiskController",
561 ROOT_NAME, AdapterCount);
562 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
563 Name,
564 &QueryTable[2],
565 NULL,
566 NULL);
567 if (NT_SUCCESS(Status))
568 {
569 while (TRUE)
570 {
571 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
572 L"%s\\%lu\\DiskController\\0",
573 ROOT_NAME, AdapterCount);
574 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
575 Name,
576 &QueryTable[2],
577 NULL,
578 NULL);
579 if (!NT_SUCCESS(Status))
580 {
581 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
582 return;
583 }
584
585 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
586 L"%s\\%lu\\DiskController\\0\\DiskPeripheral",
587 ROOT_NAME, AdapterCount);
588 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
589 Name,
590 &QueryTable[2],
591 NULL,
592 NULL);
593 if (NT_SUCCESS(Status))
594 {
595 QueryTable[0].Name = L"Identifier";
596 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
597 QueryTable[1].Name = L"Configuration Data";
598 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
599
600 DiskCount = 0;
601 while (TRUE)
602 {
603 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
604 if (BiosDiskEntry == NULL)
605 {
606 break;
607 }
608
609 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
610 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
611 ROOT_NAME, AdapterCount, DiskCount);
612 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
613 Name,
614 QueryTable,
615 (PVOID)BiosDiskEntry,
616 NULL);
617 if (!NT_SUCCESS(Status))
618 {
619 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
620 break;
621 }
622
623 BiosDiskEntry->DiskNumber = DiskCount;
624 BiosDiskEntry->Recognized = FALSE;
625
626 if (DiskCount < Int13Drives[0].NumberDrives)
627 {
628 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
629 }
630 else
631 {
632 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
633 }
634
635 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
636
637 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
638 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
639 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
640 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
641 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
642 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
643 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
644 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
645 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
646 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
647 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
648
649 DiskCount++;
650 }
651 }
652
653 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
654 return;
655 }
656 }
657
658 AdapterCount++;
659 }
660
661 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
662
663 #undef ROOT_NAME
664 }
665
666
667
668 /*
669 * Inserts the disk region represented by PartEntry into either the primary
670 * or the logical partition list of the given disk.
671 * The lists are kept sorted by increasing order of start sectors.
672 * Of course no disk region should overlap at all with one another.
673 */
674 static
675 VOID
676 InsertDiskRegion(
677 IN PDISKENTRY DiskEntry,
678 IN PPARTENTRY PartEntry,
679 IN BOOLEAN LogicalPartition)
680 {
681 PLIST_ENTRY List;
682 PLIST_ENTRY Entry;
683 PPARTENTRY PartEntry2;
684
685 /* Use the correct partition list */
686 if (LogicalPartition)
687 List = &DiskEntry->LogicalPartListHead;
688 else
689 List = &DiskEntry->PrimaryPartListHead;
690
691 /* Find the first disk region before which we need to insert the new one */
692 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
693 {
694 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
695
696 /* Ignore any unused empty region */
697 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
698 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
699 {
700 continue;
701 }
702
703 /* If the current region ends before the one to be inserted, try again */
704 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
705 continue;
706
707 /*
708 * One of the disk region boundaries crosses the desired region
709 * (it starts after the desired region, or ends before the end
710 * of the desired region): this is an impossible situation because
711 * disk regions (partitions) cannot overlap!
712 * Throw an error and bail out.
713 */
714 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
715 <=
716 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
717 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
718 {
719 DPRINT1("Disk region overlap problem, stopping there!\n"
720 "Partition to be inserted:\n"
721 " StartSector = %I64u ; EndSector = %I64u\n"
722 "Existing disk region:\n"
723 " StartSector = %I64u ; EndSector = %I64u\n",
724 PartEntry->StartSector.QuadPart,
725 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
726 PartEntry2->StartSector.QuadPart,
727 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
728 return;
729 }
730
731 /* We have found the first region before which the new one has to be inserted */
732 break;
733 }
734
735 /* Insert the disk region */
736 InsertTailList(Entry, &PartEntry->ListEntry);
737 }
738
739 static
740 PPARTENTRY
741 CreateInsertBlankRegion(
742 IN PDISKENTRY DiskEntry,
743 IN OUT PLIST_ENTRY ListHead,
744 IN ULONGLONG StartSector,
745 IN ULONGLONG SectorCount,
746 IN BOOLEAN LogicalSpace)
747 {
748 PPARTENTRY NewPartEntry;
749
750 NewPartEntry = RtlAllocateHeap(ProcessHeap,
751 HEAP_ZERO_MEMORY,
752 sizeof(PARTENTRY));
753 if (NewPartEntry == NULL)
754 return NULL;
755
756 NewPartEntry->DiskEntry = DiskEntry;
757
758 NewPartEntry->StartSector.QuadPart = StartSector;
759 NewPartEntry->SectorCount.QuadPart = SectorCount;
760
761 NewPartEntry->IsPartitioned = FALSE;
762 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
763 NewPartEntry->FormatState = Unformatted;
764 NewPartEntry->FileSystem[0] = L'\0';
765
766 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
767 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
768 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
769
770 /* Insert the new entry into the list */
771 InsertTailList(ListHead, &NewPartEntry->ListEntry);
772
773 return NewPartEntry;
774 }
775
776 static
777 // BOOLEAN
778 PPARTENTRY
779 InitializePartitionEntry(
780 IN PDISKENTRY DiskEntry,
781 IN PPARTENTRY PartEntry,
782 IN ULONGLONG SectorCount,
783 IN BOOLEAN AutoCreate)
784 {
785 PPARTENTRY NewPartEntry;
786
787 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
788
789 if ((AutoCreate != FALSE) ||
790 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
791 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
792 {
793 DPRINT1("Convert existing partition entry\n");
794
795 NewPartEntry = PartEntry;
796 NewPartEntry->AutoCreate = AutoCreate;
797 }
798 else
799 {
800 DPRINT1("Add new partition entry\n");
801
802 /* Insert and initialize a new partition entry */
803 NewPartEntry = RtlAllocateHeap(ProcessHeap,
804 HEAP_ZERO_MEMORY,
805 sizeof(PARTENTRY));
806 if (NewPartEntry == NULL)
807 return NULL;
808
809 NewPartEntry->DiskEntry = DiskEntry;
810
811 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
812 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
813 NewPartEntry->StartSector.QuadPart;
814
815 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
816 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
817
818 /* Insert the new entry into the list */
819 InsertTailList(&PartEntry->ListEntry, &NewPartEntry->ListEntry);
820 }
821
822 /* Create entry as 'New (Unformatted)' */
823 NewPartEntry->New = TRUE;
824 NewPartEntry->IsPartitioned = TRUE;
825
826 NewPartEntry->PartitionType = FileSystemToPartitionType(L"RAW", &NewPartEntry->StartSector, &NewPartEntry->SectorCount);
827 ASSERT(NewPartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
828
829 NewPartEntry->FormatState = Unformatted;
830 NewPartEntry->FileSystem[0] = L'\0';
831 // NewPartEntry->AutoCreate = AutoCreate;
832 NewPartEntry->BootIndicator = FALSE;
833 NewPartEntry->LogicalPartition = FALSE;
834
835 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
836 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
837 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
838
839 return NewPartEntry;
840 }
841
842
843 static
844 VOID
845 AddPartitionToDisk(
846 IN ULONG DiskNumber,
847 IN PDISKENTRY DiskEntry,
848 IN ULONG PartitionIndex,
849 IN BOOLEAN LogicalPartition)
850 {
851 NTSTATUS Status;
852 PPARTITION_INFORMATION PartitionInfo;
853 PPARTENTRY PartEntry;
854 HANDLE PartitionHandle;
855 OBJECT_ATTRIBUTES ObjectAttributes;
856 IO_STATUS_BLOCK IoStatusBlock;
857 WCHAR PathBuffer[MAX_PATH];
858 UNICODE_STRING Name;
859 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
860 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer;
861
862 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
863
864 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
865 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
866 {
867 return;
868 }
869
870 PartEntry = RtlAllocateHeap(ProcessHeap,
871 HEAP_ZERO_MEMORY,
872 sizeof(PARTENTRY));
873 if (PartEntry == NULL)
874 return;
875
876 PartEntry->DiskEntry = DiskEntry;
877
878 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
879 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
880
881 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
882 PartEntry->PartitionType = PartitionInfo->PartitionType;
883 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
884
885 PartEntry->LogicalPartition = LogicalPartition;
886 PartEntry->IsPartitioned = TRUE;
887 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
888 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
889 PartEntry->PartitionIndex = PartitionIndex;
890
891 /* Specify the partition as initially unformatted */
892 PartEntry->FormatState = Unformatted;
893 PartEntry->FileSystem[0] = L'\0';
894
895 /* Initialize the partition volume label */
896 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
897
898 if (IsContainerPartition(PartEntry->PartitionType))
899 {
900 PartEntry->FormatState = Unformatted;
901
902 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
903 DiskEntry->ExtendedPartition = PartEntry;
904 }
905 else if (IsRecognizedPartition(PartEntry->PartitionType))
906 {
907 ASSERT(PartitionInfo->RecognizedPartition);
908 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
909
910 /* Open the volume, ignore any errors */
911 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
912 L"\\Device\\Harddisk%lu\\Partition%lu",
913 DiskEntry->DiskNumber,
914 PartEntry->PartitionNumber);
915 RtlInitUnicodeString(&Name, PathBuffer);
916
917 InitializeObjectAttributes(&ObjectAttributes,
918 &Name,
919 OBJ_CASE_INSENSITIVE,
920 NULL,
921 NULL);
922
923 PartitionHandle = NULL;
924 Status = NtOpenFile(&PartitionHandle,
925 FILE_READ_DATA | SYNCHRONIZE,
926 &ObjectAttributes,
927 &IoStatusBlock,
928 FILE_SHARE_READ | FILE_SHARE_WRITE,
929 FILE_SYNCHRONOUS_IO_NONALERT);
930 if (!NT_SUCCESS(Status))
931 {
932 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
933 }
934
935 if (/* NT_SUCCESS(Status) && */ PartitionHandle)
936 {
937 /* We don't have a FS, try to guess one */
938 Status = InferFileSystemByHandle(PartitionHandle,
939 PartEntry->PartitionType,
940 PartEntry->FileSystem,
941 sizeof(PartEntry->FileSystem));
942 if (!NT_SUCCESS(Status))
943 DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status);
944 }
945 if (*PartEntry->FileSystem)
946 {
947 if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
948 PartEntry->FormatState = Unformatted;
949 else
950 PartEntry->FormatState = Preformatted;
951 }
952 else
953 {
954 PartEntry->FormatState = UnknownFormat;
955 }
956
957 /* Retrieve the partition volume label */
958 if (PartitionHandle)
959 {
960 Status = NtQueryVolumeInformationFile(PartitionHandle,
961 &IoStatusBlock,
962 &LabelBuffer,
963 sizeof(LabelBuffer),
964 FileFsVolumeInformation);
965 if (NT_SUCCESS(Status))
966 {
967 /* Copy the (possibly truncated) volume label and NULL-terminate it */
968 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
969 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
970 }
971 else
972 {
973 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
974 }
975 }
976
977 /* Close the partition */
978 if (PartitionHandle)
979 NtClose(PartitionHandle);
980 }
981 else
982 {
983 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
984 PartEntry->FormatState = UnknownFormat;
985 }
986
987 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
988 }
989
990 static
991 VOID
992 ScanForUnpartitionedDiskSpace(
993 IN PDISKENTRY DiskEntry)
994 {
995 ULONGLONG StartSector;
996 ULONGLONG SectorCount;
997 ULONGLONG LastStartSector;
998 ULONGLONG LastSectorCount;
999 ULONGLONG LastUnusedSectorCount;
1000 PPARTENTRY PartEntry;
1001 PPARTENTRY NewPartEntry;
1002 PLIST_ENTRY Entry;
1003
1004 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1005
1006 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1007 {
1008 DPRINT1("No primary partition!\n");
1009
1010 /* Create a partition entry that represents the empty disk */
1011
1012 if (DiskEntry->SectorAlignment < 2048)
1013 StartSector = 2048ULL;
1014 else
1015 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1016 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
1017
1018 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1019 &DiskEntry->PrimaryPartListHead,
1020 StartSector,
1021 SectorCount,
1022 FALSE);
1023 if (NewPartEntry == NULL)
1024 DPRINT1("Failed to create a new empty region for full disk space!\n");
1025
1026 return;
1027 }
1028
1029 /* Start partition at head 1, cylinder 0 */
1030 if (DiskEntry->SectorAlignment < 2048)
1031 LastStartSector = 2048ULL;
1032 else
1033 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1034 LastSectorCount = 0ULL;
1035 LastUnusedSectorCount = 0ULL;
1036
1037 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1038 Entry != &DiskEntry->PrimaryPartListHead;
1039 Entry = Entry->Flink)
1040 {
1041 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1042
1043 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1044 PartEntry->SectorCount.QuadPart != 0ULL)
1045 {
1046 LastUnusedSectorCount =
1047 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1048
1049 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1050 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1051 {
1052 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1053
1054 StartSector = LastStartSector + LastSectorCount;
1055 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1056
1057 /* Insert the table into the list */
1058 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1059 &PartEntry->ListEntry,
1060 StartSector,
1061 SectorCount,
1062 FALSE);
1063 if (NewPartEntry == NULL)
1064 {
1065 DPRINT1("Failed to create a new empty region for disk space!\n");
1066 return;
1067 }
1068 }
1069
1070 LastStartSector = PartEntry->StartSector.QuadPart;
1071 LastSectorCount = PartEntry->SectorCount.QuadPart;
1072 }
1073 }
1074
1075 /* Check for trailing unpartitioned disk space */
1076 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1077 {
1078 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1079
1080 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1081 {
1082 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1083
1084 StartSector = LastStartSector + LastSectorCount;
1085 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1086
1087 /* Append the table to the list */
1088 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1089 &DiskEntry->PrimaryPartListHead,
1090 StartSector,
1091 SectorCount,
1092 FALSE);
1093 if (NewPartEntry == NULL)
1094 {
1095 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1096 return;
1097 }
1098 }
1099 }
1100
1101 if (DiskEntry->ExtendedPartition != NULL)
1102 {
1103 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1104 {
1105 DPRINT1("No logical partition!\n");
1106
1107 /* Create a partition entry that represents the empty extended partition */
1108
1109 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1110 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
1111
1112 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1113 &DiskEntry->LogicalPartListHead,
1114 StartSector,
1115 SectorCount,
1116 TRUE);
1117 if (NewPartEntry == NULL)
1118 {
1119 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1120 return;
1121 }
1122 NewPartEntry->LogicalPartition = TRUE;
1123
1124 return;
1125 }
1126
1127 /* Start partition at head 1, cylinder 0 */
1128 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1129 LastSectorCount = 0ULL;
1130 LastUnusedSectorCount = 0ULL;
1131
1132 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1133 Entry != &DiskEntry->LogicalPartListHead;
1134 Entry = Entry->Flink)
1135 {
1136 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1137
1138 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1139 PartEntry->SectorCount.QuadPart != 0ULL)
1140 {
1141 LastUnusedSectorCount =
1142 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1143
1144 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1145 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1146 {
1147 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1148
1149 StartSector = LastStartSector + LastSectorCount;
1150 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1151
1152 /* Insert the table into the list */
1153 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1154 &PartEntry->ListEntry,
1155 StartSector,
1156 SectorCount,
1157 TRUE);
1158 if (NewPartEntry == NULL)
1159 {
1160 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1161 return;
1162 }
1163 NewPartEntry->LogicalPartition = TRUE;
1164 }
1165
1166 LastStartSector = PartEntry->StartSector.QuadPart;
1167 LastSectorCount = PartEntry->SectorCount.QuadPart;
1168 }
1169 }
1170
1171 /* Check for trailing unpartitioned disk space */
1172 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1173 {
1174 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1175 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1176 DiskEntry->SectorAlignment);
1177
1178 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1179 {
1180 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1181
1182 StartSector = LastStartSector + LastSectorCount;
1183 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1184
1185 /* Append the table to the list */
1186 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1187 &DiskEntry->LogicalPartListHead,
1188 StartSector,
1189 SectorCount,
1190 TRUE);
1191 if (NewPartEntry == NULL)
1192 {
1193 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1194 return;
1195 }
1196 NewPartEntry->LogicalPartition = TRUE;
1197 }
1198 }
1199 }
1200
1201 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1202 }
1203
1204 static
1205 VOID
1206 SetDiskSignature(
1207 IN PPARTLIST List,
1208 IN PDISKENTRY DiskEntry)
1209 {
1210 LARGE_INTEGER SystemTime;
1211 TIME_FIELDS TimeFields;
1212 PLIST_ENTRY Entry2;
1213 PDISKENTRY DiskEntry2;
1214 PUCHAR Buffer;
1215
1216 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1217 {
1218 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1219 return;
1220 }
1221
1222 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1223
1224 while (TRUE)
1225 {
1226 NtQuerySystemTime(&SystemTime);
1227 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1228
1229 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1230 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1231 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1232 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1233
1234 if (DiskEntry->LayoutBuffer->Signature == 0)
1235 {
1236 continue;
1237 }
1238
1239 /* Check if the signature already exist */
1240 /* FIXME:
1241 * Check also signatures from disks, which are
1242 * not visible (bootable) by the bios.
1243 */
1244 for (Entry2 = List->DiskListHead.Flink;
1245 Entry2 != &List->DiskListHead;
1246 Entry2 = Entry2->Flink)
1247 {
1248 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1249
1250 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
1251 {
1252 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1253 continue;
1254 }
1255
1256 if (DiskEntry != DiskEntry2 &&
1257 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1258 break;
1259 }
1260
1261 if (Entry2 == &List->DiskListHead)
1262 break;
1263 }
1264 }
1265
1266 static
1267 VOID
1268 UpdateDiskSignatures(
1269 IN PPARTLIST List)
1270 {
1271 PLIST_ENTRY Entry;
1272 PDISKENTRY DiskEntry;
1273
1274 /* Update each disk */
1275 for (Entry = List->DiskListHead.Flink;
1276 Entry != &List->DiskListHead;
1277 Entry = Entry->Flink)
1278 {
1279 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1280
1281 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1282 {
1283 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1284 continue;
1285 }
1286
1287 if (DiskEntry->LayoutBuffer &&
1288 DiskEntry->LayoutBuffer->Signature == 0)
1289 {
1290 SetDiskSignature(List, DiskEntry);
1291 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1292 }
1293 }
1294 }
1295
1296 static
1297 VOID
1298 AddDiskToList(
1299 IN HANDLE FileHandle,
1300 IN ULONG DiskNumber,
1301 IN PPARTLIST List)
1302 {
1303 DISK_GEOMETRY DiskGeometry;
1304 SCSI_ADDRESS ScsiAddress;
1305 PDISKENTRY DiskEntry;
1306 IO_STATUS_BLOCK Iosb;
1307 NTSTATUS Status;
1308 PPARTITION_SECTOR Mbr;
1309 PULONG Buffer;
1310 LARGE_INTEGER FileOffset;
1311 WCHAR Identifier[20];
1312 ULONG Checksum;
1313 ULONG Signature;
1314 ULONG i;
1315 PLIST_ENTRY ListEntry;
1316 PBIOSDISKENTRY BiosDiskEntry;
1317 ULONG LayoutBufferSize;
1318 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1319
1320 /* Retrieve the drive geometry */
1321 Status = NtDeviceIoControlFile(FileHandle,
1322 NULL,
1323 NULL,
1324 NULL,
1325 &Iosb,
1326 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1327 NULL,
1328 0,
1329 &DiskGeometry,
1330 sizeof(DiskGeometry));
1331 if (!NT_SUCCESS(Status))
1332 return;
1333
1334 if (DiskGeometry.MediaType != FixedMedia &&
1335 DiskGeometry.MediaType != RemovableMedia)
1336 {
1337 return;
1338 }
1339
1340 /*
1341 * FIXME: Here we suppose the disk is always SCSI. What if it is
1342 * of another type? To check this we need to retrieve the name of
1343 * the driver the disk device belongs to.
1344 */
1345 Status = NtDeviceIoControlFile(FileHandle,
1346 NULL,
1347 NULL,
1348 NULL,
1349 &Iosb,
1350 IOCTL_SCSI_GET_ADDRESS,
1351 NULL,
1352 0,
1353 &ScsiAddress,
1354 sizeof(ScsiAddress));
1355 if (!NT_SUCCESS(Status))
1356 return;
1357
1358 /*
1359 * Check whether the disk is initialized, by looking at its MBR.
1360 * NOTE that this must be generalized to GPT disks as well!
1361 */
1362
1363 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1364 0,
1365 DiskGeometry.BytesPerSector);
1366 if (Mbr == NULL)
1367 return;
1368
1369 FileOffset.QuadPart = 0;
1370 Status = NtReadFile(FileHandle,
1371 NULL,
1372 NULL,
1373 NULL,
1374 &Iosb,
1375 (PVOID)Mbr,
1376 DiskGeometry.BytesPerSector,
1377 &FileOffset,
1378 NULL);
1379 if (!NT_SUCCESS(Status))
1380 {
1381 RtlFreeHeap(ProcessHeap, 0, Mbr);
1382 DPRINT1("NtReadFile failed, status=%x\n", Status);
1383 return;
1384 }
1385 Signature = Mbr->Signature;
1386
1387 /* Calculate the MBR checksum */
1388 Checksum = 0;
1389 Buffer = (PULONG)Mbr;
1390 for (i = 0; i < 128; i++)
1391 {
1392 Checksum += Buffer[i];
1393 }
1394 Checksum = ~Checksum + 1;
1395
1396 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1397 L"%08x-%08x-A", Checksum, Signature);
1398 DPRINT("Identifier: %S\n", Identifier);
1399
1400 DiskEntry = RtlAllocateHeap(ProcessHeap,
1401 HEAP_ZERO_MEMORY,
1402 sizeof(DISKENTRY));
1403 if (DiskEntry == NULL)
1404 {
1405 RtlFreeHeap(ProcessHeap, 0, Mbr);
1406 DPRINT1("Failed to allocate a new disk entry.\n");
1407 return;
1408 }
1409
1410 // DiskEntry->Checksum = Checksum;
1411 // DiskEntry->Signature = Signature;
1412 DiskEntry->BiosFound = FALSE;
1413
1414 /*
1415 * Check if this disk has a valid MBR: verify its signature,
1416 * and whether its two first bytes are a valid instruction
1417 * (related to this, see IsThereAValidBootSector() in partlist.c).
1418 *
1419 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1420 */
1421
1422 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1423
1424 /* If we have not the 0xAA55 then it's raw partition */
1425 if (Mbr->Magic != PARTITION_MAGIC)
1426 {
1427 DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
1428 }
1429 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1430 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
1431 Mbr->Partition[1].PartitionType == 0 &&
1432 Mbr->Partition[2].PartitionType == 0 &&
1433 Mbr->Partition[3].PartitionType == 0)
1434 {
1435 DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
1436 }
1437 /* Otherwise, partition table is in MBR */
1438 else
1439 {
1440 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
1441 }
1442
1443 /* Free the MBR sector buffer */
1444 RtlFreeHeap(ProcessHeap, 0, Mbr);
1445
1446
1447 for (ListEntry = List->BiosDiskListHead.Flink;
1448 ListEntry != &List->BiosDiskListHead;
1449 ListEntry = ListEntry->Flink)
1450 {
1451 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1452 /* FIXME:
1453 * Compare the size from bios and the reported size from driver.
1454 * If we have more than one disk with a zero or with the same signature
1455 * we must create new signatures and reboot. After the reboot,
1456 * it is possible to identify the disks.
1457 */
1458 if (BiosDiskEntry->Signature == Signature &&
1459 BiosDiskEntry->Checksum == Checksum &&
1460 !BiosDiskEntry->Recognized)
1461 {
1462 if (!DiskEntry->BiosFound)
1463 {
1464 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1465 DiskEntry->BiosFound = TRUE;
1466 BiosDiskEntry->Recognized = TRUE;
1467 }
1468 else
1469 {
1470 // FIXME: What to do?
1471 }
1472 }
1473 }
1474
1475 if (!DiskEntry->BiosFound)
1476 {
1477 #if 0
1478 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1479 return;
1480 #else
1481 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1482 #endif
1483 }
1484
1485 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1486 InitializeListHead(&DiskEntry->LogicalPartListHead);
1487
1488 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1489 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1490 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1491 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1492
1493 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1494 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1495 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1496 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1497
1498 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1499 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1500 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1501
1502 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1503 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1504 DiskGeometry.SectorsPerTrack;
1505
1506 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1507 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1508
1509 DiskEntry->DiskNumber = DiskNumber;
1510 DiskEntry->Port = ScsiAddress.PortNumber;
1511 DiskEntry->Bus = ScsiAddress.PathId;
1512 DiskEntry->Id = ScsiAddress.TargetId;
1513
1514 GetDriverName(DiskEntry);
1515 /*
1516 * Actually it would be more correct somehow to use:
1517 *
1518 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1519 * ULONG ReturnedLength;
1520 *
1521 * Status = NtQueryObject(SomeHandleToTheDisk,
1522 * ObjectNameInformation,
1523 * &NameInfo,
1524 * sizeof(NameInfo),
1525 * &ReturnedLength);
1526 * etc...
1527 *
1528 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1529 */
1530
1531 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1532
1533
1534 /*
1535 * We now retrieve the disk partition layout
1536 */
1537
1538 /*
1539 * Stop there now if the disk is GPT-partitioned,
1540 * since we currently do not support such disks.
1541 */
1542 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1543 {
1544 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1545 return;
1546 }
1547
1548 /* Allocate a layout buffer with 4 partition entries first */
1549 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1550 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1551 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1552 HEAP_ZERO_MEMORY,
1553 LayoutBufferSize);
1554 if (DiskEntry->LayoutBuffer == NULL)
1555 {
1556 DPRINT1("Failed to allocate the disk layout buffer!\n");
1557 return;
1558 }
1559
1560 /* Keep looping while the drive layout buffer is too small */
1561 for (;;)
1562 {
1563 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1564 Status = NtDeviceIoControlFile(FileHandle,
1565 NULL,
1566 NULL,
1567 NULL,
1568 &Iosb,
1569 IOCTL_DISK_GET_DRIVE_LAYOUT,
1570 NULL,
1571 0,
1572 DiskEntry->LayoutBuffer,
1573 LayoutBufferSize);
1574 if (NT_SUCCESS(Status))
1575 break;
1576
1577 if (Status != STATUS_BUFFER_TOO_SMALL)
1578 {
1579 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1580 return;
1581 }
1582
1583 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1584 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1585 HEAP_ZERO_MEMORY,
1586 DiskEntry->LayoutBuffer,
1587 LayoutBufferSize);
1588 if (NewLayoutBuffer == NULL)
1589 {
1590 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1591 return;
1592 }
1593
1594 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1595 }
1596
1597 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1598
1599 #ifdef DUMP_PARTITION_TABLE
1600 DumpPartitionTable(DiskEntry);
1601 #endif
1602
1603 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1604 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1605 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
1606 {
1607 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1608 {
1609 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1610 }
1611 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1612 {
1613 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1614 }
1615 else
1616 {
1617 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1618 }
1619 }
1620 else
1621 {
1622 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1623 }
1624
1625 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1626 {
1627 DiskEntry->NewDisk = TRUE;
1628 DiskEntry->LayoutBuffer->PartitionCount = 4;
1629
1630 for (i = 0; i < 4; i++)
1631 {
1632 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1633 }
1634 }
1635 else
1636 {
1637 /* Enumerate and add the first four primary partitions */
1638 for (i = 0; i < 4; i++)
1639 {
1640 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1641 }
1642
1643 /* Enumerate and add the remaining partitions as logical ones */
1644 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1645 {
1646 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1647 }
1648 }
1649
1650 ScanForUnpartitionedDiskSpace(DiskEntry);
1651 }
1652
1653 PPARTLIST
1654 CreatePartitionList(VOID)
1655 {
1656 PPARTLIST List;
1657 OBJECT_ATTRIBUTES ObjectAttributes;
1658 SYSTEM_DEVICE_INFORMATION Sdi;
1659 IO_STATUS_BLOCK Iosb;
1660 ULONG ReturnSize;
1661 NTSTATUS Status;
1662 ULONG DiskNumber;
1663 WCHAR Buffer[MAX_PATH];
1664 UNICODE_STRING Name;
1665 HANDLE FileHandle;
1666
1667 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1668 0,
1669 sizeof(PARTLIST));
1670 if (List == NULL)
1671 return NULL;
1672
1673 List->CurrentDisk = NULL;
1674 List->CurrentPartition = NULL;
1675
1676 List->SystemPartition = NULL;
1677 List->OriginalSystemPartition = NULL;
1678
1679 InitializeListHead(&List->DiskListHead);
1680 InitializeListHead(&List->BiosDiskListHead);
1681
1682 /*
1683 * Enumerate the disks seen by the BIOS; this will be used later
1684 * to map drives seen by NTOS with their corresponding BIOS names.
1685 */
1686 EnumerateBiosDiskEntries(List);
1687
1688 /* Enumerate disks seen by NTOS */
1689 Status = NtQuerySystemInformation(SystemDeviceInformation,
1690 &Sdi,
1691 sizeof(Sdi),
1692 &ReturnSize);
1693 if (!NT_SUCCESS(Status))
1694 {
1695 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
1696 RtlFreeHeap(ProcessHeap, 0, List);
1697 return NULL;
1698 }
1699
1700 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1701 {
1702 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1703 L"\\Device\\Harddisk%lu\\Partition0",
1704 DiskNumber);
1705 RtlInitUnicodeString(&Name, Buffer);
1706
1707 InitializeObjectAttributes(&ObjectAttributes,
1708 &Name,
1709 OBJ_CASE_INSENSITIVE,
1710 NULL,
1711 NULL);
1712
1713 Status = NtOpenFile(&FileHandle,
1714 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1715 &ObjectAttributes,
1716 &Iosb,
1717 FILE_SHARE_READ | FILE_SHARE_WRITE,
1718 FILE_SYNCHRONOUS_IO_NONALERT);
1719 if (NT_SUCCESS(Status))
1720 {
1721 AddDiskToList(FileHandle, DiskNumber, List);
1722 NtClose(FileHandle);
1723 }
1724 }
1725
1726 UpdateDiskSignatures(List);
1727
1728 AssignDriveLetters(List);
1729
1730 /* Search for first usable disk and partition */
1731 if (IsListEmpty(&List->DiskListHead))
1732 {
1733 List->CurrentDisk = NULL;
1734 List->CurrentPartition = NULL;
1735 }
1736 else
1737 {
1738 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1739 DISKENTRY,
1740 ListEntry);
1741
1742 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1743 {
1744 List->CurrentPartition = NULL;
1745 }
1746 else
1747 {
1748 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1749 PARTENTRY,
1750 ListEntry);
1751 }
1752 }
1753
1754 return List;
1755 }
1756
1757 VOID
1758 DestroyPartitionList(
1759 IN PPARTLIST List)
1760 {
1761 PDISKENTRY DiskEntry;
1762 PBIOSDISKENTRY BiosDiskEntry;
1763 PPARTENTRY PartEntry;
1764 PLIST_ENTRY Entry;
1765
1766 /* Release disk and partition info */
1767 while (!IsListEmpty(&List->DiskListHead))
1768 {
1769 Entry = RemoveHeadList(&List->DiskListHead);
1770 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1771
1772 /* Release driver name */
1773 RtlFreeUnicodeString(&DiskEntry->DriverName);
1774
1775 /* Release primary partition list */
1776 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1777 {
1778 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1779 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1780
1781 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1782 }
1783
1784 /* Release logical partition list */
1785 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1786 {
1787 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1788 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1789
1790 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1791 }
1792
1793 /* Release layout buffer */
1794 if (DiskEntry->LayoutBuffer != NULL)
1795 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1796
1797 /* Release disk entry */
1798 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1799 }
1800
1801 /* Release the bios disk info */
1802 while (!IsListEmpty(&List->BiosDiskListHead))
1803 {
1804 Entry = RemoveHeadList(&List->BiosDiskListHead);
1805 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1806
1807 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1808 }
1809
1810 /* Release list head */
1811 RtlFreeHeap(ProcessHeap, 0, List);
1812 }
1813
1814 PDISKENTRY
1815 GetDiskByBiosNumber(
1816 IN PPARTLIST List,
1817 IN ULONG BiosDiskNumber)
1818 {
1819 PDISKENTRY DiskEntry;
1820 PLIST_ENTRY Entry;
1821
1822 /* Loop over the disks and find the correct one */
1823 for (Entry = List->DiskListHead.Flink;
1824 Entry != &List->DiskListHead;
1825 Entry = Entry->Flink)
1826 {
1827 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1828
1829 if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
1830 {
1831 /* Disk found */
1832 return DiskEntry;
1833 }
1834 }
1835
1836 /* Disk not found, stop there */
1837 return NULL;
1838 }
1839
1840 PDISKENTRY
1841 GetDiskByNumber(
1842 IN PPARTLIST List,
1843 IN ULONG DiskNumber)
1844 {
1845 PDISKENTRY DiskEntry;
1846 PLIST_ENTRY Entry;
1847
1848 /* Loop over the disks and find the correct one */
1849 for (Entry = List->DiskListHead.Flink;
1850 Entry != &List->DiskListHead;
1851 Entry = Entry->Flink)
1852 {
1853 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1854
1855 if (DiskEntry->DiskNumber == DiskNumber)
1856 {
1857 /* Disk found */
1858 return DiskEntry;
1859 }
1860 }
1861
1862 /* Disk not found, stop there */
1863 return NULL;
1864 }
1865
1866 PDISKENTRY
1867 GetDiskBySCSI(
1868 IN PPARTLIST List,
1869 IN USHORT Port,
1870 IN USHORT Bus,
1871 IN USHORT Id)
1872 {
1873 PDISKENTRY DiskEntry;
1874 PLIST_ENTRY Entry;
1875
1876 /* Loop over the disks and find the correct one */
1877 for (Entry = List->DiskListHead.Flink;
1878 Entry != &List->DiskListHead;
1879 Entry = Entry->Flink)
1880 {
1881 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1882
1883 if (DiskEntry->Port == Port &&
1884 DiskEntry->Bus == Bus &&
1885 DiskEntry->Id == Id)
1886 {
1887 /* Disk found */
1888 return DiskEntry;
1889 }
1890 }
1891
1892 /* Disk not found, stop there */
1893 return NULL;
1894 }
1895
1896 PDISKENTRY
1897 GetDiskBySignature(
1898 IN PPARTLIST List,
1899 IN ULONG Signature)
1900 {
1901 PDISKENTRY DiskEntry;
1902 PLIST_ENTRY Entry;
1903
1904 /* Loop over the disks and find the correct one */
1905 for (Entry = List->DiskListHead.Flink;
1906 Entry != &List->DiskListHead;
1907 Entry = Entry->Flink)
1908 {
1909 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1910
1911 if (DiskEntry->LayoutBuffer->Signature == Signature)
1912 {
1913 /* Disk found */
1914 return DiskEntry;
1915 }
1916 }
1917
1918 /* Disk not found, stop there */
1919 return NULL;
1920 }
1921
1922 PPARTENTRY
1923 GetPartition(
1924 // IN PPARTLIST List,
1925 IN PDISKENTRY DiskEntry,
1926 IN ULONG PartitionNumber)
1927 {
1928 PPARTENTRY PartEntry;
1929 PLIST_ENTRY Entry;
1930
1931 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1932 {
1933 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1934 return NULL;
1935 }
1936
1937 /* Disk found, loop over the primary partitions first... */
1938 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1939 Entry != &DiskEntry->PrimaryPartListHead;
1940 Entry = Entry->Flink)
1941 {
1942 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1943
1944 if (PartEntry->PartitionNumber == PartitionNumber)
1945 {
1946 /* Partition found */
1947 return PartEntry;
1948 }
1949 }
1950
1951 /* ... then over the logical partitions if needed */
1952 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1953 Entry != &DiskEntry->LogicalPartListHead;
1954 Entry = Entry->Flink)
1955 {
1956 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1957
1958 if (PartEntry->PartitionNumber == PartitionNumber)
1959 {
1960 /* Partition found */
1961 return PartEntry;
1962 }
1963 }
1964
1965 /* The partition was not found on the disk, stop there */
1966 return NULL;
1967 }
1968
1969 BOOLEAN
1970 GetDiskOrPartition(
1971 IN PPARTLIST List,
1972 IN ULONG DiskNumber,
1973 IN ULONG PartitionNumber OPTIONAL,
1974 OUT PDISKENTRY* pDiskEntry,
1975 OUT PPARTENTRY* pPartEntry OPTIONAL)
1976 {
1977 PDISKENTRY DiskEntry;
1978 PPARTENTRY PartEntry = NULL;
1979
1980 /* Find the disk */
1981 DiskEntry = GetDiskByNumber(List, DiskNumber);
1982 if (!DiskEntry)
1983 return FALSE;
1984
1985 /* If we have a partition (PartitionNumber != 0), find it */
1986 if (PartitionNumber != 0)
1987 {
1988 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1989 {
1990 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1991 return FALSE;
1992 }
1993
1994 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1995 if (!PartEntry)
1996 return FALSE;
1997 ASSERT(PartEntry->DiskEntry == DiskEntry);
1998 }
1999
2000 /* Return the disk (and optionally the partition) */
2001 *pDiskEntry = DiskEntry;
2002 if (pPartEntry) *pPartEntry = PartEntry;
2003 return TRUE;
2004 }
2005
2006 //
2007 // NOTE: Was introduced broken in r6258 by Casper
2008 //
2009 BOOLEAN
2010 SelectPartition(
2011 IN PPARTLIST List,
2012 IN ULONG DiskNumber,
2013 IN ULONG PartitionNumber)
2014 {
2015 PDISKENTRY DiskEntry;
2016 PPARTENTRY PartEntry;
2017
2018 DiskEntry = GetDiskByNumber(List, DiskNumber);
2019 if (!DiskEntry)
2020 return FALSE;
2021
2022 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
2023 if (!PartEntry)
2024 return FALSE;
2025
2026 ASSERT(PartEntry->DiskEntry == DiskEntry);
2027 ASSERT(DiskEntry->DiskNumber == DiskNumber);
2028 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
2029
2030 List->CurrentDisk = DiskEntry;
2031 List->CurrentPartition = PartEntry;
2032 return TRUE;
2033 }
2034
2035 PPARTENTRY
2036 GetNextPartition(
2037 IN PPARTLIST List)
2038 {
2039 PLIST_ENTRY DiskListEntry;
2040 PLIST_ENTRY PartListEntry;
2041 PDISKENTRY DiskEntry;
2042 PPARTENTRY PartEntry;
2043
2044 /* Fail if no disks are available */
2045 if (IsListEmpty(&List->DiskListHead))
2046 return NULL;
2047
2048 /* Check for next usable entry on current disk */
2049 if (List->CurrentPartition != NULL)
2050 {
2051 if (List->CurrentPartition->LogicalPartition)
2052 {
2053 /* Logical partition */
2054
2055 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2056 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2057 {
2058 /* Next logical partition */
2059 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2060
2061 List->CurrentPartition = PartEntry;
2062 return List->CurrentPartition;
2063 }
2064 else
2065 {
2066 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2067 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2068 {
2069 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2070
2071 List->CurrentPartition = PartEntry;
2072 return List->CurrentPartition;
2073 }
2074 }
2075 }
2076 else
2077 {
2078 /* Primary or extended partition */
2079
2080 if (List->CurrentPartition->IsPartitioned &&
2081 IsContainerPartition(List->CurrentPartition->PartitionType))
2082 {
2083 /* First logical partition */
2084 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2085 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2086 {
2087 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2088
2089 List->CurrentPartition = PartEntry;
2090 return List->CurrentPartition;
2091 }
2092 }
2093 else
2094 {
2095 /* Next primary partition */
2096 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2097 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2098 {
2099 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2100
2101 List->CurrentPartition = PartEntry;
2102 return List->CurrentPartition;
2103 }
2104 }
2105 }
2106 }
2107
2108 /* Search for the first partition entry on the next disk */
2109 for (DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2110 DiskListEntry != &List->DiskListHead;
2111 DiskListEntry = DiskListEntry->Flink)
2112 {
2113 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2114
2115 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2116 {
2117 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2118 continue;
2119 }
2120
2121 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2122 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2123 {
2124 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2125
2126 List->CurrentDisk = DiskEntry;
2127 List->CurrentPartition = PartEntry;
2128 return List->CurrentPartition;
2129 }
2130 }
2131
2132 return NULL;
2133 }
2134
2135 PPARTENTRY
2136 GetPrevPartition(
2137 IN PPARTLIST List)
2138 {
2139 PLIST_ENTRY DiskListEntry;
2140 PLIST_ENTRY PartListEntry;
2141 PDISKENTRY DiskEntry;
2142 PPARTENTRY PartEntry;
2143
2144 /* Fail if no disks are available */
2145 if (IsListEmpty(&List->DiskListHead))
2146 return NULL;
2147
2148 /* Check for previous usable entry on current disk */
2149 if (List->CurrentPartition != NULL)
2150 {
2151 if (List->CurrentPartition->LogicalPartition)
2152 {
2153 /* Logical partition */
2154 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2155 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2156 {
2157 /* Previous logical partition */
2158 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2159 }
2160 else
2161 {
2162 /* Extended partition */
2163 PartEntry = List->CurrentDisk->ExtendedPartition;
2164 }
2165
2166 List->CurrentPartition = PartEntry;
2167 return List->CurrentPartition;
2168 }
2169 else
2170 {
2171 /* Primary or extended partition */
2172
2173 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2174 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2175 {
2176 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2177
2178 if (PartEntry->IsPartitioned &&
2179 IsContainerPartition(PartEntry->PartitionType))
2180 {
2181 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2182 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2183 }
2184
2185 List->CurrentPartition = PartEntry;
2186 return List->CurrentPartition;
2187 }
2188 }
2189 }
2190
2191 /* Search for the last partition entry on the previous disk */
2192 for (DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2193 DiskListEntry != &List->DiskListHead;
2194 DiskListEntry = DiskListEntry->Blink)
2195 {
2196 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2197
2198 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2199 {
2200 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2201 continue;
2202 }
2203
2204 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2205 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2206 {
2207 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2208
2209 if (PartEntry->IsPartitioned &&
2210 IsContainerPartition(PartEntry->PartitionType))
2211 {
2212 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2213 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2214 {
2215 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2216
2217 List->CurrentDisk = DiskEntry;
2218 List->CurrentPartition = PartEntry;
2219 return List->CurrentPartition;
2220 }
2221 }
2222 else
2223 {
2224 List->CurrentDisk = DiskEntry;
2225 List->CurrentPartition = PartEntry;
2226 return List->CurrentPartition;
2227 }
2228 }
2229 }
2230
2231 return NULL;
2232 }
2233
2234 // static
2235 FORCEINLINE
2236 BOOLEAN
2237 IsEmptyLayoutEntry(
2238 IN PPARTITION_INFORMATION PartitionInfo)
2239 {
2240 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2241 PartitionInfo->PartitionLength.QuadPart == 0)
2242 {
2243 return TRUE;
2244 }
2245
2246 return FALSE;
2247 }
2248
2249 // static
2250 FORCEINLINE
2251 BOOLEAN
2252 IsSamePrimaryLayoutEntry(
2253 IN PPARTITION_INFORMATION PartitionInfo,
2254 IN PDISKENTRY DiskEntry,
2255 IN PPARTENTRY PartEntry)
2256 {
2257 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2258 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2259 // PartitionInfo->PartitionType == PartEntry->PartitionType
2260 {
2261 return TRUE;
2262 }
2263
2264 return FALSE;
2265 }
2266
2267 static
2268 ULONG
2269 GetPrimaryPartitionCount(
2270 IN PDISKENTRY DiskEntry)
2271 {
2272 PLIST_ENTRY Entry;
2273 PPARTENTRY PartEntry;
2274 ULONG Count = 0;
2275
2276 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2277 {
2278 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2279 return 0;
2280 }
2281
2282 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2283 Entry != &DiskEntry->PrimaryPartListHead;
2284 Entry = Entry->Flink)
2285 {
2286 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2287 if (PartEntry->IsPartitioned)
2288 Count++;
2289 }
2290
2291 return Count;
2292 }
2293
2294 static
2295 ULONG
2296 GetLogicalPartitionCount(
2297 IN PDISKENTRY DiskEntry)
2298 {
2299 PLIST_ENTRY ListEntry;
2300 PPARTENTRY PartEntry;
2301 ULONG Count = 0;
2302
2303 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2304 {
2305 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2306 return 0;
2307 }
2308
2309 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2310 ListEntry != &DiskEntry->LogicalPartListHead;
2311 ListEntry = ListEntry->Flink)
2312 {
2313 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2314 if (PartEntry->IsPartitioned)
2315 Count++;
2316 }
2317
2318 return Count;
2319 }
2320
2321 static
2322 BOOLEAN
2323 ReAllocateLayoutBuffer(
2324 IN PDISKENTRY DiskEntry)
2325 {
2326 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2327 ULONG NewPartitionCount;
2328 ULONG CurrentPartitionCount = 0;
2329 ULONG LayoutBufferSize;
2330 ULONG i;
2331
2332 DPRINT1("ReAllocateLayoutBuffer()\n");
2333
2334 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2335
2336 if (DiskEntry->LayoutBuffer)
2337 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2338
2339 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2340 CurrentPartitionCount, NewPartitionCount);
2341
2342 if (CurrentPartitionCount == NewPartitionCount)
2343 return TRUE;
2344
2345 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2346 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2347 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2348 HEAP_ZERO_MEMORY,
2349 DiskEntry->LayoutBuffer,
2350 LayoutBufferSize);
2351 if (NewLayoutBuffer == NULL)
2352 {
2353 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2354 return FALSE;
2355 }
2356
2357 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2358
2359 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2360 if (NewPartitionCount > CurrentPartitionCount)
2361 {
2362 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2363 {
2364 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2365 }
2366 }
2367
2368 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2369
2370 return TRUE;
2371 }
2372
2373 static
2374 VOID
2375 UpdateDiskLayout(
2376 IN PDISKENTRY DiskEntry)
2377 {
2378 PPARTITION_INFORMATION PartitionInfo;
2379 PPARTITION_INFORMATION LinkInfo = NULL;
2380 PLIST_ENTRY ListEntry;
2381 PPARTENTRY PartEntry;
2382 LARGE_INTEGER HiddenSectors64;
2383 ULONG Index;
2384 ULONG PartitionNumber = 1;
2385
2386 DPRINT1("UpdateDiskLayout()\n");
2387
2388 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2389 {
2390 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2391 return;
2392 }
2393
2394 /* Resize the layout buffer if necessary */
2395 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2396 {
2397 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2398 return;
2399 }
2400
2401 /* Update the primary partition table */
2402 Index = 0;
2403 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2404 ListEntry != &DiskEntry->PrimaryPartListHead;
2405 ListEntry = ListEntry->Flink)
2406 {
2407 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2408
2409 if (PartEntry->IsPartitioned)
2410 {
2411 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
2412
2413 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2414 PartEntry->PartitionIndex = Index;
2415
2416 /* Reset the current partition number only for newly-created (unmounted) partitions */
2417 if (PartEntry->New)
2418 PartEntry->PartitionNumber = 0;
2419
2420 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0);
2421
2422 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2423 {
2424 DPRINT1("Updating primary partition entry %lu\n", Index);
2425
2426 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2427 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2428 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2429 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2430 PartitionInfo->PartitionType = PartEntry->PartitionType;
2431 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2432 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2433 PartitionInfo->RewritePartition = TRUE;
2434 }
2435
2436 if (!IsContainerPartition(PartEntry->PartitionType))
2437 PartitionNumber++;
2438
2439 Index++;
2440 }
2441 }
2442
2443 ASSERT(Index <= 4);
2444
2445 /* Update the logical partition table */
2446 Index = 4;
2447 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2448 ListEntry != &DiskEntry->LogicalPartListHead;
2449 ListEntry = ListEntry->Flink)
2450 {
2451 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2452
2453 if (PartEntry->IsPartitioned)
2454 {
2455 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
2456
2457 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2458 PartEntry->PartitionIndex = Index;
2459
2460 /* Reset the current partition number only for newly-created (unmounted) partitions */
2461 if (PartEntry->New)
2462 PartEntry->PartitionNumber = 0;
2463
2464 PartEntry->OnDiskPartitionNumber = PartitionNumber;
2465
2466 DPRINT1("Updating logical partition entry %lu\n", Index);
2467
2468 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2469 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2470 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2471 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2472 PartitionInfo->PartitionType = PartEntry->PartitionType;
2473 PartitionInfo->BootIndicator = FALSE;
2474 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2475 PartitionInfo->RewritePartition = TRUE;
2476
2477 /* Fill the link entry of the previous partition entry */
2478 if (LinkInfo != NULL)
2479 {
2480 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2481 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2482 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2483 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2484 LinkInfo->PartitionNumber = 0;
2485 LinkInfo->PartitionType = PARTITION_EXTENDED;
2486 LinkInfo->BootIndicator = FALSE;
2487 LinkInfo->RecognizedPartition = FALSE;
2488 LinkInfo->RewritePartition = TRUE;
2489 }
2490
2491 /* Save a pointer to the link entry of the current partition entry */
2492 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2493
2494 PartitionNumber++;
2495 Index += 4;
2496 }
2497 }
2498
2499 /* Wipe unused primary partition entries */
2500 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2501 {
2502 DPRINT1("Primary partition entry %lu\n", Index);
2503
2504 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2505
2506 if (!IsEmptyLayoutEntry(PartitionInfo))
2507 {
2508 DPRINT1("Wiping primary partition entry %lu\n", Index);
2509
2510 PartitionInfo->StartingOffset.QuadPart = 0;
2511 PartitionInfo->PartitionLength.QuadPart = 0;
2512 PartitionInfo->HiddenSectors = 0;
2513 PartitionInfo->PartitionNumber = 0;
2514 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2515 PartitionInfo->BootIndicator = FALSE;
2516 PartitionInfo->RecognizedPartition = FALSE;
2517 PartitionInfo->RewritePartition = TRUE;
2518 }
2519 }
2520
2521 /* Wipe unused logical partition entries */
2522 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2523 {
2524 if (Index % 4 >= 2)
2525 {
2526 DPRINT1("Logical partition entry %lu\n", Index);
2527
2528 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2529
2530 if (!IsEmptyLayoutEntry(PartitionInfo))
2531 {
2532 DPRINT1("Wiping partition entry %lu\n", Index);
2533
2534 PartitionInfo->StartingOffset.QuadPart = 0;
2535 PartitionInfo->PartitionLength.QuadPart = 0;
2536 PartitionInfo->HiddenSectors = 0;
2537 PartitionInfo->PartitionNumber = 0;
2538 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2539 PartitionInfo->BootIndicator = FALSE;
2540 PartitionInfo->RecognizedPartition = FALSE;
2541 PartitionInfo->RewritePartition = TRUE;
2542 }
2543 }
2544 }
2545
2546 DiskEntry->Dirty = TRUE;
2547
2548 #ifdef DUMP_PARTITION_TABLE
2549 DumpPartitionTable(DiskEntry);
2550 #endif
2551 }
2552
2553 static
2554 PPARTENTRY
2555 GetPrevUnpartitionedEntry(
2556 IN PDISKENTRY DiskEntry,
2557 IN PPARTENTRY PartEntry)
2558 {
2559 PPARTENTRY PrevPartEntry;
2560 PLIST_ENTRY ListHead;
2561
2562 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2563 {
2564 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2565 return NULL;
2566 }
2567
2568 if (PartEntry->LogicalPartition)
2569 ListHead = &DiskEntry->LogicalPartListHead;
2570 else
2571 ListHead = &DiskEntry->PrimaryPartListHead;
2572
2573 if (PartEntry->ListEntry.Blink != ListHead)
2574 {
2575 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2576 PARTENTRY,
2577 ListEntry);
2578 if (PrevPartEntry->IsPartitioned == FALSE)
2579 {
2580 ASSERT(PrevPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2581 return PrevPartEntry;
2582 }
2583 }
2584
2585 return NULL;
2586 }
2587
2588 static
2589 PPARTENTRY
2590 GetNextUnpartitionedEntry(
2591 IN PDISKENTRY DiskEntry,
2592 IN PPARTENTRY PartEntry)
2593 {
2594 PPARTENTRY NextPartEntry;
2595 PLIST_ENTRY ListHead;
2596
2597 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2598 {
2599 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2600 return NULL;
2601 }
2602
2603 if (PartEntry->LogicalPartition)
2604 ListHead = &DiskEntry->LogicalPartListHead;
2605 else
2606 ListHead = &DiskEntry->PrimaryPartListHead;
2607
2608 if (PartEntry->ListEntry.Flink != ListHead)
2609 {
2610 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2611 PARTENTRY,
2612 ListEntry);
2613 if (NextPartEntry->IsPartitioned == FALSE)
2614 {
2615 ASSERT(NextPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2616 return NextPartEntry;
2617 }
2618 }
2619
2620 return NULL;
2621 }
2622
2623 BOOLEAN
2624 CreatePrimaryPartition(
2625 IN PPARTLIST List,
2626 IN PPARTENTRY SelectedEntry,
2627 IN ULONGLONG SectorCount,
2628 IN BOOLEAN AutoCreate)
2629 {
2630 ERROR_NUMBER Error;
2631 PPARTENTRY PartEntry;
2632
2633 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2634
2635 if (List == NULL ||
2636 SelectedEntry == NULL ||
2637 SelectedEntry->DiskEntry == NULL ||
2638 SelectedEntry->IsPartitioned)
2639 {
2640 return FALSE;
2641 }
2642
2643 Error = PrimaryPartitionCreationChecks(SelectedEntry);
2644 if (Error != NOT_AN_ERROR)
2645 {
2646 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
2647 return FALSE;
2648 }
2649
2650 /* Convert the current entry, or insert and initialize a new partition entry */
2651 PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, AutoCreate);
2652 if (PartEntry == NULL)
2653 return FALSE;
2654
2655 UpdateDiskLayout(PartEntry->DiskEntry);
2656
2657 AssignDriveLetters(List);
2658
2659 return TRUE;
2660 }
2661
2662 static
2663 VOID
2664 AddLogicalDiskSpace(
2665 IN PDISKENTRY DiskEntry)
2666 {
2667 ULONGLONG StartSector;
2668 ULONGLONG SectorCount;
2669 PPARTENTRY NewPartEntry;
2670
2671 DPRINT1("AddLogicalDiskSpace()\n");
2672
2673 /* Create a partition entry that represents the empty space in the container partition */
2674
2675 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2676 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2677
2678 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
2679 &DiskEntry->LogicalPartListHead,
2680 StartSector,
2681 SectorCount,
2682 TRUE);
2683 if (NewPartEntry == NULL)
2684 {
2685 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2686 return;
2687 }
2688 NewPartEntry->LogicalPartition = TRUE;
2689 }
2690
2691 BOOLEAN
2692 CreateExtendedPartition(
2693 IN PPARTLIST List,
2694 IN PPARTENTRY SelectedEntry,
2695 IN ULONGLONG SectorCount)
2696 {
2697 ERROR_NUMBER Error;
2698 PPARTENTRY PartEntry;
2699
2700 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2701
2702 if (List == NULL ||
2703 SelectedEntry == NULL ||
2704 SelectedEntry->DiskEntry == NULL ||
2705 SelectedEntry->IsPartitioned)
2706 {
2707 return FALSE;
2708 }
2709
2710 Error = ExtendedPartitionCreationChecks(SelectedEntry);
2711 if (Error != NOT_AN_ERROR)
2712 {
2713 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
2714 return FALSE;
2715 }
2716
2717 /* Convert the current entry, or insert and initialize a new partition entry */
2718 PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, FALSE);
2719 if (PartEntry == NULL)
2720 return FALSE;
2721
2722 if (PartEntry->StartSector.QuadPart < 1450560)
2723 {
2724 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2725 PartEntry->PartitionType = PARTITION_EXTENDED;
2726 }
2727 else
2728 {
2729 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2730 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2731 }
2732
2733 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2734 PartEntry->New = FALSE;
2735 PartEntry->FormatState = Formatted;
2736
2737 PartEntry->DiskEntry->ExtendedPartition = PartEntry;
2738
2739 AddLogicalDiskSpace(PartEntry->DiskEntry);
2740
2741 UpdateDiskLayout(PartEntry->DiskEntry);
2742
2743 AssignDriveLetters(List);
2744
2745 return TRUE;
2746 }
2747
2748 BOOLEAN
2749 CreateLogicalPartition(
2750 IN PPARTLIST List,
2751 IN PPARTENTRY SelectedEntry,
2752 IN ULONGLONG SectorCount,
2753 IN BOOLEAN AutoCreate)
2754 {
2755 ERROR_NUMBER Error;
2756 PPARTENTRY PartEntry;
2757
2758 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2759
2760 if (List == NULL ||
2761 SelectedEntry == NULL ||
2762 SelectedEntry->DiskEntry == NULL ||
2763 SelectedEntry->IsPartitioned)
2764 {
2765 return FALSE;
2766 }
2767
2768 Error = LogicalPartitionCreationChecks(SelectedEntry);
2769 if (Error != NOT_AN_ERROR)
2770 {
2771 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
2772 return FALSE;
2773 }
2774
2775 /* Convert the current entry, or insert and initialize a new partition entry */
2776 PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, AutoCreate);
2777 if (PartEntry == NULL)
2778 return FALSE;
2779
2780 PartEntry->LogicalPartition = TRUE;
2781
2782 UpdateDiskLayout(PartEntry->DiskEntry);
2783
2784 AssignDriveLetters(List);
2785
2786 return TRUE;
2787 }
2788
2789 static
2790 NTSTATUS
2791 DismountVolume(
2792 IN PPARTENTRY PartEntry)
2793 {
2794 NTSTATUS Status;
2795 NTSTATUS LockStatus;
2796 UNICODE_STRING Name;
2797 OBJECT_ATTRIBUTES ObjectAttributes;
2798 IO_STATUS_BLOCK IoStatusBlock;
2799 HANDLE PartitionHandle;
2800 WCHAR Buffer[MAX_PATH];
2801
2802 /* Check whether the partition is valid and was mounted by the system */
2803 if (!PartEntry->IsPartitioned ||
2804 IsContainerPartition(PartEntry->PartitionType) ||
2805 !IsRecognizedPartition(PartEntry->PartitionType) ||
2806 PartEntry->FormatState == Unformatted /* || PartEntry->FormatState == UnknownFormat */ ||
2807 !*PartEntry->FileSystem ||
2808 PartEntry->PartitionNumber == 0)
2809 {
2810 /* The partition is not mounted, so just return success */
2811 return STATUS_SUCCESS;
2812 }
2813
2814 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
2815
2816 /* Open the volume */
2817 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
2818 L"\\Device\\Harddisk%lu\\Partition%lu",
2819 PartEntry->DiskEntry->DiskNumber,
2820 PartEntry->PartitionNumber);
2821 RtlInitUnicodeString(&Name, Buffer);
2822
2823 InitializeObjectAttributes(&ObjectAttributes,
2824 &Name,
2825 OBJ_CASE_INSENSITIVE,
2826 NULL,
2827 NULL);
2828
2829 Status = NtOpenFile(&PartitionHandle,
2830 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2831 &ObjectAttributes,
2832 &IoStatusBlock,
2833 FILE_SHARE_READ | FILE_SHARE_WRITE,
2834 FILE_SYNCHRONOUS_IO_NONALERT);
2835 if (!NT_SUCCESS(Status))
2836 {
2837 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
2838 return Status;
2839 }
2840
2841 /* Lock the volume */
2842 LockStatus = NtFsControlFile(PartitionHandle,
2843 NULL,
2844 NULL,
2845 NULL,
2846 &IoStatusBlock,
2847 FSCTL_LOCK_VOLUME,
2848 NULL,
2849 0,
2850 NULL,
2851 0);
2852 if (!NT_SUCCESS(LockStatus))
2853 {
2854 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
2855 }
2856
2857 /* Dismount the volume */
2858 Status = NtFsControlFile(PartitionHandle,
2859 NULL,
2860 NULL,
2861 NULL,
2862 &IoStatusBlock,
2863 FSCTL_DISMOUNT_VOLUME,
2864 NULL,
2865 0,
2866 NULL,
2867 0);
2868 if (!NT_SUCCESS(Status))
2869 {
2870 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
2871 }
2872
2873 /* Unlock the volume */
2874 LockStatus = NtFsControlFile(PartitionHandle,
2875 NULL,
2876 NULL,
2877 NULL,
2878 &IoStatusBlock,
2879 FSCTL_UNLOCK_VOLUME,
2880 NULL,
2881 0,
2882 NULL,
2883 0);
2884 if (!NT_SUCCESS(LockStatus))
2885 {
2886 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
2887 }
2888
2889 /* Close the volume */
2890 NtClose(PartitionHandle);
2891
2892 return Status;
2893 }
2894
2895 VOID
2896 DeletePartition(
2897 IN PPARTLIST List,
2898 IN PPARTENTRY PartEntry)
2899 {
2900 PDISKENTRY DiskEntry;
2901 PPARTENTRY PrevPartEntry;
2902 PPARTENTRY NextPartEntry;
2903 PPARTENTRY LogicalPartEntry;
2904 PLIST_ENTRY Entry;
2905
2906 if (List == NULL ||
2907 PartEntry == NULL ||
2908 PartEntry->DiskEntry == NULL ||
2909 PartEntry->IsPartitioned == FALSE)
2910 {
2911 return;
2912 }
2913
2914 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
2915
2916 /* Clear the system partition pointers if it is being deleted */
2917 if (List->SystemPartition == PartEntry)
2918 {
2919 ASSERT(List->SystemPartition);
2920
2921 if (List->SystemPartition == List->OriginalSystemPartition)
2922 List->OriginalSystemPartition = NULL;
2923 List->SystemPartition = NULL;
2924 }
2925
2926 DiskEntry = PartEntry->DiskEntry;
2927
2928 /* Check which type of partition (primary/logical or extended) is being deleted */
2929 if (DiskEntry->ExtendedPartition == PartEntry)
2930 {
2931 /* An extended partition is being deleted: delete all logical partition entries */
2932 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2933 {
2934 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2935 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2936
2937 /* Dismount the logical partition */
2938 DismountVolume(LogicalPartEntry);
2939
2940 /* Delete it */
2941 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2942 }
2943
2944 DiskEntry->ExtendedPartition = NULL;
2945 }
2946 else
2947 {
2948 /* A primary partition is being deleted: dismount it */
2949 DismountVolume(PartEntry);
2950 }
2951
2952 /* Adjust unpartitioned disk space entries */
2953
2954 /* Get pointer to previous and next unpartitioned entries */
2955 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2956 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2957
2958 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2959 {
2960 /* Merge previous, current and next unpartitioned entry */
2961
2962 /* Adjust the previous entries length */
2963 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2964
2965 /* Remove the current entry */
2966 RemoveEntryList(&PartEntry->ListEntry);
2967 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2968
2969 /* Remove the next entry */
2970 RemoveEntryList(&NextPartEntry->ListEntry);
2971 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2972
2973 /* Update current partition */
2974 if (List->CurrentPartition == PartEntry ||
2975 List->CurrentPartition == NextPartEntry)
2976 {
2977 List->CurrentPartition = PrevPartEntry;
2978 }
2979 }
2980 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2981 {
2982 /* Merge current and previous unpartitioned entry */
2983
2984 /* Adjust the previous entries length */
2985 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2986
2987 /* Remove the current entry */
2988 RemoveEntryList(&PartEntry->ListEntry);
2989 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2990
2991 /* Update current partition */
2992 if (List->CurrentPartition == PartEntry)
2993 {
2994 List->CurrentPartition = PrevPartEntry;
2995 }
2996 }
2997 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2998 {
2999 /* Merge current and next unpartitioned entry */
3000
3001 /* Adjust the next entries offset and length */
3002 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3003 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3004
3005 /* Remove the current entry */
3006 RemoveEntryList(&PartEntry->ListEntry);
3007 RtlFreeHeap(ProcessHeap, 0, PartEntry);
3008
3009 /* Update current partition */
3010 if (List->CurrentPartition == PartEntry)
3011 {
3012 List->CurrentPartition = NextPartEntry;
3013 }
3014 }
3015 else
3016 {
3017 /* Nothing to merge but change current entry */
3018 PartEntry->IsPartitioned = FALSE;
3019 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3020 PartEntry->FormatState = Unformatted;
3021 PartEntry->FileSystem[0] = L'\0';
3022 PartEntry->DriveLetter = 0;
3023 PartEntry->OnDiskPartitionNumber = 0;
3024 PartEntry->PartitionNumber = 0;
3025 // PartEntry->PartitionIndex = 0;
3026 }
3027
3028 UpdateDiskLayout(DiskEntry);
3029
3030 AssignDriveLetters(List);
3031 }
3032
3033 VOID
3034 DeleteCurrentPartition(
3035 IN PPARTLIST List)
3036 {
3037 DeletePartition(List, List->CurrentPartition);
3038 }
3039
3040 static
3041 BOOLEAN
3042 IsSupportedActivePartition(
3043 IN PPARTENTRY PartEntry)
3044 {
3045 /* Check the type and the filesystem of this partition */
3046
3047 /*
3048 * We do not support extended partition containers (on MBR disks) marked
3049 * as active, and containing code inside their extended boot records.
3050 */
3051 if (IsContainerPartition(PartEntry->PartitionType))
3052 {
3053 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3054 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3055 return FALSE;
3056 }
3057
3058 /*
3059 * ADDITIONAL CHECKS / BIG HACK:
3060 *
3061 * Retrieve its file system and check whether we have
3062 * write support for it. If that is the case we are fine
3063 * and we can use it directly. However if we don't have
3064 * write support we will need to change the active system
3065 * partition.
3066 *
3067 * NOTE that this is completely useless on architectures
3068 * where a real system partition is required, as on these
3069 * architectures the partition uses the FAT FS, for which
3070 * we do have write support.
3071 * NOTE also that for those architectures looking for a
3072 * partition boot indicator is insufficient.
3073 */
3074 if ((PartEntry->FormatState == Unformatted ) ||
3075 (PartEntry->FormatState == Preformatted) ||
3076 (PartEntry->FormatState == Formatted ))
3077 {
3078 ASSERT(*PartEntry->FileSystem);
3079
3080 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3081 if (wcsicmp(PartEntry->FileSystem, L"FAT") == 0 ||
3082 wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 ||
3083 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3084 wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0 ||
3085 wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
3086 {
3087 return TRUE;
3088 }
3089 else
3090 {
3091 // WARNING: We cannot write on this FS yet!
3092 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3093 PartEntry->FileSystem);
3094 return FALSE;
3095 }
3096 }
3097 else // if (PartEntry->FormatState == UnknownFormat)
3098 {
3099 ASSERT(!*PartEntry->FileSystem);
3100
3101 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3102 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3103 return FALSE;
3104 }
3105
3106 // HACK: WARNING: We cannot write on this FS yet!
3107 // See fsutil.c:InferFileSystem()
3108 if (PartEntry->PartitionType == PARTITION_IFS)
3109 {
3110 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3111 PartEntry->FileSystem);
3112 return FALSE;
3113 }
3114
3115 return TRUE;
3116 }
3117
3118 VOID
3119 CheckActiveSystemPartition(
3120 IN PPARTLIST List)
3121 {
3122 PDISKENTRY DiskEntry;
3123 PPARTENTRY PartEntry;
3124 PLIST_ENTRY ListEntry;
3125
3126 /* Check for empty disk list */
3127 if (IsListEmpty(&List->DiskListHead))
3128 {
3129 List->SystemPartition = NULL;
3130 List->OriginalSystemPartition = NULL;
3131 return;
3132 }
3133
3134 /* Choose the currently selected disk */
3135 DiskEntry = List->CurrentDisk;
3136
3137 /* Check for empty partition list */
3138 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
3139 {
3140 List->SystemPartition = NULL;
3141 List->OriginalSystemPartition = NULL;
3142 return;
3143 }
3144
3145 if (List->SystemPartition != NULL)
3146 {
3147 /* We already have an active system partition */
3148 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3149 List->SystemPartition->PartitionNumber,
3150 List->SystemPartition->DiskEntry->DiskNumber,
3151 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3152 return;
3153 }
3154
3155 DPRINT("We are here (1)!\n");
3156
3157 List->SystemPartition = NULL;
3158 List->OriginalSystemPartition = NULL;
3159
3160 /* Retrieve the first partition of the disk */
3161 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3162 PARTENTRY,
3163 ListEntry);
3164 ASSERT(DiskEntry == PartEntry->DiskEntry);
3165 List->SystemPartition = PartEntry;
3166
3167 //
3168 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3169 //
3170
3171 /* Check if the disk is new and if so, use its first partition as the active system partition */
3172 if (DiskEntry->NewDisk)
3173 {
3174 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
3175 {
3176 ASSERT(DiskEntry == PartEntry->DiskEntry);
3177 List->SystemPartition = PartEntry;
3178
3179 List->OriginalSystemPartition = List->SystemPartition;
3180
3181 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3182 List->SystemPartition->PartitionNumber,
3183 List->SystemPartition->DiskEntry->DiskNumber,
3184 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3185
3186 goto SetSystemPartition;
3187 }
3188
3189 // FIXME: What to do??
3190 DPRINT1("NewDisk TRUE but first partition is used?\n");
3191 }
3192
3193 DPRINT("We are here (2)!\n");
3194
3195 /*
3196 * The disk is not new, check if any partition is initialized;
3197 * if not, the first one becomes the system partition.
3198 */
3199 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3200 ListEntry != &DiskEntry->PrimaryPartListHead;
3201 ListEntry = ListEntry->Flink)
3202 {
3203 /* Retrieve the partition */
3204 PartEntry = CONTAINING_RECORD(ListEntry,
3205 PARTENTRY,
3206 ListEntry);
3207
3208 /* Check if the partition is partitioned and is used */
3209 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
3210 {
3211 break;
3212 }
3213 }
3214 if (ListEntry == &DiskEntry->PrimaryPartListHead)
3215 {
3216 /*
3217 * OK we haven't encountered any used and active partition,
3218 * so use the first one as the system partition.
3219 */
3220 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
3221 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
3222
3223 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3224 List->SystemPartition->PartitionNumber,
3225 List->SystemPartition->DiskEntry->DiskNumber,
3226 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3227
3228 goto SetSystemPartition;
3229 }
3230
3231 List->SystemPartition = NULL;
3232 List->OriginalSystemPartition = NULL;
3233
3234 DPRINT("We are here (3)!\n");
3235
3236 /* The disk is not new, scan all partitions to find the (active) system partition */
3237 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3238 ListEntry != &DiskEntry->PrimaryPartListHead;
3239 ListEntry = ListEntry->Flink)
3240 {
3241 /* Retrieve the partition */
3242 PartEntry = CONTAINING_RECORD(ListEntry,
3243 PARTENTRY,
3244 ListEntry);
3245
3246 /* Check if the partition is partitioned and used */
3247 if (PartEntry->IsPartitioned &&
3248 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
3249 {
3250 /* Check if the partition is active */
3251 if (PartEntry->BootIndicator)
3252 {
3253 /* Yes, we found it */
3254 ASSERT(DiskEntry == PartEntry->DiskEntry);
3255 List->SystemPartition = PartEntry;
3256
3257 DPRINT1("Found active system partition %