5c20c4bf36c80eb7e3eff554ed4394cd70cb837c
[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 if (IsRecognizedPartition(PartEntry->PartitionType) ||
346 (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
347 PartEntry->SectorCount.QuadPart != 0LL))
348 {
349 if (Letter <= L'Z')
350 {
351 PartEntry->DriveLetter = Letter;
352 Letter++;
353 }
354 }
355 }
356 }
357 }
358
359 /* Assign drive letters to logical drives */
360 for (Entry1 = List->DiskListHead.Flink;
361 Entry1 != &List->DiskListHead;
362 Entry1 = Entry1->Flink)
363 {
364 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
365
366 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
367 Entry2 != &DiskEntry->LogicalPartListHead;
368 Entry2 = Entry2->Flink)
369 {
370 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
371
372 PartEntry->DriveLetter = 0;
373
374 if (PartEntry->IsPartitioned)
375 {
376 if (IsRecognizedPartition(PartEntry->PartitionType) ||
377 (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
378 PartEntry->SectorCount.QuadPart != 0LL))
379 {
380 if (Letter <= L'Z')
381 {
382 PartEntry->DriveLetter = Letter;
383 Letter++;
384 }
385 }
386 }
387 }
388 }
389 }
390
391 static NTSTATUS
392 NTAPI
393 DiskIdentifierQueryRoutine(
394 PWSTR ValueName,
395 ULONG ValueType,
396 PVOID ValueData,
397 ULONG ValueLength,
398 PVOID Context,
399 PVOID EntryContext)
400 {
401 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
402 UNICODE_STRING NameU;
403
404 if (ValueType == REG_SZ &&
405 ValueLength == 20 * sizeof(WCHAR))
406 {
407 NameU.Buffer = (PWCHAR)ValueData;
408 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
409 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
410
411 NameU.Buffer = (PWCHAR)ValueData + 9;
412 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
413
414 return STATUS_SUCCESS;
415 }
416
417 return STATUS_UNSUCCESSFUL;
418 }
419
420 static NTSTATUS
421 NTAPI
422 DiskConfigurationDataQueryRoutine(
423 PWSTR ValueName,
424 ULONG ValueType,
425 PVOID ValueData,
426 ULONG ValueLength,
427 PVOID Context,
428 PVOID EntryContext)
429 {
430 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
431 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
432 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
433 ULONG i;
434
435 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
436 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
437 return STATUS_UNSUCCESSFUL;
438
439 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
440
441 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
442 #if 0
443 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
444 FullResourceDescriptor->PartialResourceList.Revision != 1)
445 return STATUS_UNSUCCESSFUL;
446 #endif
447
448 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
449 {
450 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
451 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
452 continue;
453
454 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
455 BiosDiskEntry->DiskGeometry = *DiskGeometry;
456
457 return STATUS_SUCCESS;
458 }
459
460 return STATUS_UNSUCCESSFUL;
461 }
462
463 static NTSTATUS
464 NTAPI
465 SystemConfigurationDataQueryRoutine(
466 PWSTR ValueName,
467 ULONG ValueType,
468 PVOID ValueData,
469 ULONG ValueLength,
470 PVOID Context,
471 PVOID EntryContext)
472 {
473 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
474 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
475 ULONG i;
476
477 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
478 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
479 return STATUS_UNSUCCESSFUL;
480
481 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
482
483 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
484 #if 0
485 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
486 FullResourceDescriptor->PartialResourceList.Revision != 1)
487 return STATUS_UNSUCCESSFUL;
488 #endif
489
490 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
491 {
492 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
493 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
494 continue;
495
496 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
497 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
498 if (*Int13Drives == NULL)
499 return STATUS_NO_MEMORY;
500
501 memcpy(*Int13Drives,
502 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
503 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
504 return STATUS_SUCCESS;
505 }
506
507 return STATUS_UNSUCCESSFUL;
508 }
509
510
511 static VOID
512 EnumerateBiosDiskEntries(
513 IN PPARTLIST PartList)
514 {
515 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
516 WCHAR Name[120];
517 ULONG AdapterCount;
518 ULONG DiskCount;
519 NTSTATUS Status;
520 PCM_INT13_DRIVE_PARAMETER Int13Drives;
521 PBIOSDISKENTRY BiosDiskEntry;
522
523 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
524
525 memset(QueryTable, 0, sizeof(QueryTable));
526
527 QueryTable[1].Name = L"Configuration Data";
528 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
529 Int13Drives = NULL;
530 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
531 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
532 &QueryTable[1],
533 (PVOID)&Int13Drives,
534 NULL);
535 if (!NT_SUCCESS(Status))
536 {
537 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
538 return;
539 }
540
541 AdapterCount = 0;
542 while (TRUE)
543 {
544 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
545 L"%s\\%lu",
546 ROOT_NAME, AdapterCount);
547 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
548 Name,
549 &QueryTable[2],
550 NULL,
551 NULL);
552 if (!NT_SUCCESS(Status))
553 {
554 break;
555 }
556
557 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
558 L"%s\\%lu\\DiskController",
559 ROOT_NAME, AdapterCount);
560 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
561 Name,
562 &QueryTable[2],
563 NULL,
564 NULL);
565 if (NT_SUCCESS(Status))
566 {
567 while (TRUE)
568 {
569 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
570 L"%s\\%lu\\DiskController\\0",
571 ROOT_NAME, AdapterCount);
572 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
573 Name,
574 &QueryTable[2],
575 NULL,
576 NULL);
577 if (!NT_SUCCESS(Status))
578 {
579 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
580 return;
581 }
582
583 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
584 L"%s\\%lu\\DiskController\\0\\DiskPeripheral",
585 ROOT_NAME, AdapterCount);
586 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
587 Name,
588 &QueryTable[2],
589 NULL,
590 NULL);
591 if (NT_SUCCESS(Status))
592 {
593 QueryTable[0].Name = L"Identifier";
594 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
595 QueryTable[1].Name = L"Configuration Data";
596 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
597
598 DiskCount = 0;
599 while (TRUE)
600 {
601 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
602 if (BiosDiskEntry == NULL)
603 {
604 break;
605 }
606
607 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
608 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
609 ROOT_NAME, AdapterCount, DiskCount);
610 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
611 Name,
612 QueryTable,
613 (PVOID)BiosDiskEntry,
614 NULL);
615 if (!NT_SUCCESS(Status))
616 {
617 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
618 break;
619 }
620
621 BiosDiskEntry->DiskNumber = DiskCount;
622 BiosDiskEntry->Recognized = FALSE;
623
624 if (DiskCount < Int13Drives[0].NumberDrives)
625 {
626 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
627 }
628 else
629 {
630 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
631 }
632
633 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
634
635 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
636 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
637 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
638 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
639 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
640 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
641 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
642 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
643 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
644 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
645 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
646
647 DiskCount++;
648 }
649 }
650
651 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
652 return;
653 }
654 }
655
656 AdapterCount++;
657 }
658
659 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
660
661 #undef ROOT_NAME
662 }
663
664
665
666 /*
667 * Inserts the disk region represented by PartEntry into either the primary
668 * or the logical partition list of the given disk.
669 * The lists are kept sorted by increasing order of start sectors.
670 * Of course no disk region should overlap at all with one another.
671 */
672 static
673 VOID
674 InsertDiskRegion(
675 IN PDISKENTRY DiskEntry,
676 IN PPARTENTRY PartEntry,
677 IN BOOLEAN LogicalPartition)
678 {
679 PLIST_ENTRY List;
680 PLIST_ENTRY Entry;
681 PPARTENTRY PartEntry2;
682
683 /* Use the correct partition list */
684 if (LogicalPartition)
685 List = &DiskEntry->LogicalPartListHead;
686 else
687 List = &DiskEntry->PrimaryPartListHead;
688
689 /* Find the first disk region before which we need to insert the new one */
690 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
691 {
692 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
693
694 /* Ignore any unused empty region */
695 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
696 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
697 {
698 continue;
699 }
700
701 /* If the current region ends before the one to be inserted, try again */
702 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
703 continue;
704
705 /*
706 * One of the disk region boundaries crosses the desired region
707 * (it starts after the desired region, or ends before the end
708 * of the desired region): this is an impossible situation because
709 * disk regions (partitions) cannot overlap!
710 * Throw an error and bail out.
711 */
712 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
713 <=
714 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
715 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
716 {
717 DPRINT1("Disk region overlap problem, stopping there!\n"
718 "Partition to be inserted:\n"
719 " StartSector = %I64u ; EndSector = %I64u\n"
720 "Existing disk region:\n"
721 " StartSector = %I64u ; EndSector = %I64u\n",
722 PartEntry->StartSector.QuadPart,
723 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
724 PartEntry2->StartSector.QuadPart,
725 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
726 return;
727 }
728
729 /* We have found the first region before which the new one has to be inserted */
730 break;
731 }
732
733 /* Insert the disk region */
734 InsertTailList(Entry, &PartEntry->ListEntry);
735 }
736
737 static
738 PPARTENTRY
739 CreateInsertBlankRegion(
740 IN PDISKENTRY DiskEntry,
741 IN OUT PLIST_ENTRY ListHead,
742 IN ULONGLONG StartSector,
743 IN ULONGLONG SectorCount,
744 IN BOOLEAN LogicalSpace)
745 {
746 PPARTENTRY NewPartEntry;
747
748 NewPartEntry = RtlAllocateHeap(ProcessHeap,
749 HEAP_ZERO_MEMORY,
750 sizeof(PARTENTRY));
751 if (NewPartEntry == NULL)
752 return NULL;
753
754 NewPartEntry->DiskEntry = DiskEntry;
755
756 NewPartEntry->StartSector.QuadPart = StartSector;
757 NewPartEntry->SectorCount.QuadPart = SectorCount;
758
759 NewPartEntry->IsPartitioned = FALSE;
760 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
761 NewPartEntry->FormatState = Unformatted;
762 NewPartEntry->FileSystem[0] = L'\0';
763
764 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
765 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
766 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
767
768 /* Insert the new entry into the list */
769 InsertTailList(ListHead, &NewPartEntry->ListEntry);
770
771 return NewPartEntry;
772 }
773
774 static
775 // BOOLEAN
776 PPARTENTRY
777 InitializePartitionEntry(
778 IN PDISKENTRY DiskEntry,
779 IN PPARTENTRY PartEntry,
780 IN ULONGLONG SectorCount,
781 IN BOOLEAN AutoCreate)
782 {
783 PPARTENTRY NewPartEntry;
784
785 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
786
787 if ((AutoCreate != FALSE) ||
788 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
789 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
790 {
791 DPRINT1("Convert existing partition entry\n");
792
793 NewPartEntry = PartEntry;
794 NewPartEntry->AutoCreate = AutoCreate;
795 }
796 else
797 {
798 DPRINT1("Add new partition entry\n");
799
800 /* Insert and initialize a new partition entry */
801 NewPartEntry = RtlAllocateHeap(ProcessHeap,
802 HEAP_ZERO_MEMORY,
803 sizeof(PARTENTRY));
804 if (NewPartEntry == NULL)
805 return NULL;
806
807 NewPartEntry->DiskEntry = DiskEntry;
808
809 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
810 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
811 NewPartEntry->StartSector.QuadPart;
812
813 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
814 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
815
816 /* Insert the new entry into the list */
817 InsertTailList(&PartEntry->ListEntry, &NewPartEntry->ListEntry);
818 }
819
820 /* Create entry as 'New (Unformatted)' */
821 NewPartEntry->New = TRUE;
822 NewPartEntry->IsPartitioned = TRUE;
823
824 NewPartEntry->PartitionType = FileSystemToPartitionType(L"RAW", &NewPartEntry->StartSector, &NewPartEntry->SectorCount);
825 ASSERT(NewPartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
826
827 NewPartEntry->FormatState = Unformatted;
828 NewPartEntry->FileSystem[0] = L'\0';
829 // NewPartEntry->AutoCreate = AutoCreate;
830 NewPartEntry->BootIndicator = FALSE;
831 NewPartEntry->LogicalPartition = FALSE;
832
833 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
834 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
835 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
836
837 return NewPartEntry;
838 }
839
840
841 static
842 VOID
843 AddPartitionToDisk(
844 IN ULONG DiskNumber,
845 IN PDISKENTRY DiskEntry,
846 IN ULONG PartitionIndex,
847 IN BOOLEAN LogicalPartition)
848 {
849 NTSTATUS Status;
850 PPARTITION_INFORMATION PartitionInfo;
851 PPARTENTRY PartEntry;
852 HANDLE PartitionHandle;
853 OBJECT_ATTRIBUTES ObjectAttributes;
854 IO_STATUS_BLOCK IoStatusBlock;
855 WCHAR PathBuffer[MAX_PATH];
856 UNICODE_STRING Name;
857 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
858 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer;
859
860 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
861
862 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
863 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
864 {
865 return;
866 }
867
868 PartEntry = RtlAllocateHeap(ProcessHeap,
869 HEAP_ZERO_MEMORY,
870 sizeof(PARTENTRY));
871 if (PartEntry == NULL)
872 return;
873
874 PartEntry->DiskEntry = DiskEntry;
875
876 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
877 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
878
879 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
880 PartEntry->PartitionType = PartitionInfo->PartitionType;
881 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
882
883 PartEntry->LogicalPartition = LogicalPartition;
884 PartEntry->IsPartitioned = TRUE;
885 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
886 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
887 PartEntry->PartitionIndex = PartitionIndex;
888
889 /* Specify the partition as initially unformatted */
890 PartEntry->FormatState = Unformatted;
891 PartEntry->FileSystem[0] = L'\0';
892
893 /* Initialize the partition volume label */
894 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
895
896 if (IsContainerPartition(PartEntry->PartitionType))
897 {
898 PartEntry->FormatState = Unformatted;
899
900 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
901 DiskEntry->ExtendedPartition = PartEntry;
902 }
903 else if (IsRecognizedPartition(PartEntry->PartitionType))
904 {
905 ASSERT(PartitionInfo->RecognizedPartition);
906
907 /* Open the volume, ignore any errors */
908 RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
909 L"\\Device\\Harddisk%lu\\Partition%lu",
910 DiskEntry->DiskNumber,
911 PartEntry->PartitionNumber);
912 RtlInitUnicodeString(&Name, PathBuffer);
913
914 InitializeObjectAttributes(&ObjectAttributes,
915 &Name,
916 OBJ_CASE_INSENSITIVE,
917 NULL,
918 NULL);
919
920 PartitionHandle = NULL;
921 Status = NtOpenFile(&PartitionHandle,
922 FILE_READ_DATA | SYNCHRONIZE,
923 &ObjectAttributes,
924 &IoStatusBlock,
925 FILE_SHARE_READ | FILE_SHARE_WRITE,
926 FILE_SYNCHRONOUS_IO_NONALERT);
927 if (!NT_SUCCESS(Status))
928 {
929 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
930 }
931
932 if (/* NT_SUCCESS(Status) && */ PartitionHandle)
933 {
934 /* We don't have a FS, try to guess one */
935 Status = InferFileSystemByHandle(PartitionHandle,
936 PartEntry->PartitionType,
937 PartEntry->FileSystem,
938 sizeof(PartEntry->FileSystem));
939 if (!NT_SUCCESS(Status))
940 DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status);
941 }
942 if (*PartEntry->FileSystem)
943 {
944 if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
945 PartEntry->FormatState = Unformatted;
946 else
947 PartEntry->FormatState = Preformatted;
948 }
949 else
950 {
951 PartEntry->FormatState = UnknownFormat;
952 }
953
954 /* Retrieve the partition volume label */
955 if (PartitionHandle)
956 {
957 Status = NtQueryVolumeInformationFile(PartitionHandle,
958 &IoStatusBlock,
959 &LabelBuffer,
960 sizeof(LabelBuffer),
961 FileFsVolumeInformation);
962 if (NT_SUCCESS(Status))
963 {
964 /* Copy the (possibly truncated) volume label and NULL-terminate it */
965 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
966 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
967 }
968 else
969 {
970 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
971 }
972 }
973
974 /* Close the partition */
975 if (PartitionHandle)
976 NtClose(PartitionHandle);
977 }
978 else
979 {
980 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
981 PartEntry->FormatState = UnknownFormat;
982 }
983
984 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
985 }
986
987 static
988 VOID
989 ScanForUnpartitionedDiskSpace(
990 IN PDISKENTRY DiskEntry)
991 {
992 ULONGLONG StartSector;
993 ULONGLONG SectorCount;
994 ULONGLONG LastStartSector;
995 ULONGLONG LastSectorCount;
996 ULONGLONG LastUnusedSectorCount;
997 PPARTENTRY PartEntry;
998 PPARTENTRY NewPartEntry;
999 PLIST_ENTRY Entry;
1000
1001 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1002
1003 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1004 {
1005 DPRINT1("No primary partition!\n");
1006
1007 /* Create a partition entry that represents the empty disk */
1008
1009 if (DiskEntry->SectorAlignment < 2048)
1010 StartSector = 2048ULL;
1011 else
1012 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1013 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
1014
1015 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1016 &DiskEntry->PrimaryPartListHead,
1017 StartSector,
1018 SectorCount,
1019 FALSE);
1020 if (NewPartEntry == NULL)
1021 DPRINT1("Failed to create a new empty region for full disk space!\n");
1022
1023 return;
1024 }
1025
1026 /* Start partition at head 1, cylinder 0 */
1027 if (DiskEntry->SectorAlignment < 2048)
1028 LastStartSector = 2048ULL;
1029 else
1030 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1031 LastSectorCount = 0ULL;
1032 LastUnusedSectorCount = 0ULL;
1033
1034 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1035 Entry != &DiskEntry->PrimaryPartListHead;
1036 Entry = Entry->Flink)
1037 {
1038 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1039
1040 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1041 PartEntry->SectorCount.QuadPart != 0ULL)
1042 {
1043 LastUnusedSectorCount =
1044 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1045
1046 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1047 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1048 {
1049 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1050
1051 StartSector = LastStartSector + LastSectorCount;
1052 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1053
1054 /* Insert the table into the list */
1055 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1056 &PartEntry->ListEntry,
1057 StartSector,
1058 SectorCount,
1059 FALSE);
1060 if (NewPartEntry == NULL)
1061 {
1062 DPRINT1("Failed to create a new empty region for disk space!\n");
1063 return;
1064 }
1065 }
1066
1067 LastStartSector = PartEntry->StartSector.QuadPart;
1068 LastSectorCount = PartEntry->SectorCount.QuadPart;
1069 }
1070 }
1071
1072 /* Check for trailing unpartitioned disk space */
1073 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1074 {
1075 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1076
1077 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1078 {
1079 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1080
1081 StartSector = LastStartSector + LastSectorCount;
1082 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1083
1084 /* Append the table to the list */
1085 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1086 &DiskEntry->PrimaryPartListHead,
1087 StartSector,
1088 SectorCount,
1089 FALSE);
1090 if (NewPartEntry == NULL)
1091 {
1092 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1093 return;
1094 }
1095 }
1096 }
1097
1098 if (DiskEntry->ExtendedPartition != NULL)
1099 {
1100 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1101 {
1102 DPRINT1("No logical partition!\n");
1103
1104 /* Create a partition entry that represents the empty extended partition */
1105
1106 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1107 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
1108
1109 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1110 &DiskEntry->LogicalPartListHead,
1111 StartSector,
1112 SectorCount,
1113 TRUE);
1114 if (NewPartEntry == NULL)
1115 {
1116 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1117 return;
1118 }
1119 NewPartEntry->LogicalPartition = TRUE;
1120
1121 return;
1122 }
1123
1124 /* Start partition at head 1, cylinder 0 */
1125 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1126 LastSectorCount = 0ULL;
1127 LastUnusedSectorCount = 0ULL;
1128
1129 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1130 Entry != &DiskEntry->LogicalPartListHead;
1131 Entry = Entry->Flink)
1132 {
1133 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1134
1135 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1136 PartEntry->SectorCount.QuadPart != 0ULL)
1137 {
1138 LastUnusedSectorCount =
1139 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1140
1141 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1142 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1143 {
1144 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1145
1146 StartSector = LastStartSector + LastSectorCount;
1147 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1148
1149 /* Insert the table into the list */
1150 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1151 &PartEntry->ListEntry,
1152 StartSector,
1153 SectorCount,
1154 TRUE);
1155 if (NewPartEntry == NULL)
1156 {
1157 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1158 return;
1159 }
1160 NewPartEntry->LogicalPartition = TRUE;
1161 }
1162
1163 LastStartSector = PartEntry->StartSector.QuadPart;
1164 LastSectorCount = PartEntry->SectorCount.QuadPart;
1165 }
1166 }
1167
1168 /* Check for trailing unpartitioned disk space */
1169 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1170 {
1171 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1172 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1173 DiskEntry->SectorAlignment);
1174
1175 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1176 {
1177 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1178
1179 StartSector = LastStartSector + LastSectorCount;
1180 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1181
1182 /* Append the table to the list */
1183 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1184 &DiskEntry->LogicalPartListHead,
1185 StartSector,
1186 SectorCount,
1187 TRUE);
1188 if (NewPartEntry == NULL)
1189 {
1190 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1191 return;
1192 }
1193 NewPartEntry->LogicalPartition = TRUE;
1194 }
1195 }
1196 }
1197
1198 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1199 }
1200
1201 static
1202 VOID
1203 SetDiskSignature(
1204 IN PPARTLIST List,
1205 IN PDISKENTRY DiskEntry)
1206 {
1207 LARGE_INTEGER SystemTime;
1208 TIME_FIELDS TimeFields;
1209 PLIST_ENTRY Entry2;
1210 PDISKENTRY DiskEntry2;
1211 PUCHAR Buffer;
1212
1213 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1214 {
1215 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1216 return;
1217 }
1218
1219 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1220
1221 while (TRUE)
1222 {
1223 NtQuerySystemTime(&SystemTime);
1224 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1225
1226 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1227 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1228 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1229 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1230
1231 if (DiskEntry->LayoutBuffer->Signature == 0)
1232 {
1233 continue;
1234 }
1235
1236 /* Check if the signature already exist */
1237 /* FIXME:
1238 * Check also signatures from disks, which are
1239 * not visible (bootable) by the bios.
1240 */
1241 for (Entry2 = List->DiskListHead.Flink;
1242 Entry2 != &List->DiskListHead;
1243 Entry2 = Entry2->Flink)
1244 {
1245 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1246
1247 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
1248 {
1249 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1250 continue;
1251 }
1252
1253 if (DiskEntry != DiskEntry2 &&
1254 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1255 break;
1256 }
1257
1258 if (Entry2 == &List->DiskListHead)
1259 break;
1260 }
1261 }
1262
1263 static
1264 VOID
1265 UpdateDiskSignatures(
1266 IN PPARTLIST List)
1267 {
1268 PLIST_ENTRY Entry;
1269 PDISKENTRY DiskEntry;
1270
1271 /* Update each disk */
1272 for (Entry = List->DiskListHead.Flink;
1273 Entry != &List->DiskListHead;
1274 Entry = Entry->Flink)
1275 {
1276 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1277
1278 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1279 {
1280 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1281 continue;
1282 }
1283
1284 if (DiskEntry->LayoutBuffer &&
1285 DiskEntry->LayoutBuffer->Signature == 0)
1286 {
1287 SetDiskSignature(List, DiskEntry);
1288 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1289 }
1290 }
1291 }
1292
1293 static
1294 VOID
1295 AddDiskToList(
1296 IN HANDLE FileHandle,
1297 IN ULONG DiskNumber,
1298 IN PPARTLIST List)
1299 {
1300 DISK_GEOMETRY DiskGeometry;
1301 SCSI_ADDRESS ScsiAddress;
1302 PDISKENTRY DiskEntry;
1303 IO_STATUS_BLOCK Iosb;
1304 NTSTATUS Status;
1305 PPARTITION_SECTOR Mbr;
1306 PULONG Buffer;
1307 LARGE_INTEGER FileOffset;
1308 WCHAR Identifier[20];
1309 ULONG Checksum;
1310 ULONG Signature;
1311 ULONG i;
1312 PLIST_ENTRY ListEntry;
1313 PBIOSDISKENTRY BiosDiskEntry;
1314 ULONG LayoutBufferSize;
1315 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1316
1317 /* Retrieve the drive geometry */
1318 Status = NtDeviceIoControlFile(FileHandle,
1319 NULL,
1320 NULL,
1321 NULL,
1322 &Iosb,
1323 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1324 NULL,
1325 0,
1326 &DiskGeometry,
1327 sizeof(DiskGeometry));
1328 if (!NT_SUCCESS(Status))
1329 return;
1330
1331 if (DiskGeometry.MediaType != FixedMedia &&
1332 DiskGeometry.MediaType != RemovableMedia)
1333 {
1334 return;
1335 }
1336
1337 /*
1338 * FIXME: Here we suppose the disk is always SCSI. What if it is
1339 * of another type? To check this we need to retrieve the name of
1340 * the driver the disk device belongs to.
1341 */
1342 Status = NtDeviceIoControlFile(FileHandle,
1343 NULL,
1344 NULL,
1345 NULL,
1346 &Iosb,
1347 IOCTL_SCSI_GET_ADDRESS,
1348 NULL,
1349 0,
1350 &ScsiAddress,
1351 sizeof(ScsiAddress));
1352 if (!NT_SUCCESS(Status))
1353 return;
1354
1355 /*
1356 * Check whether the disk is initialized, by looking at its MBR.
1357 * NOTE that this must be generalized to GPT disks as well!
1358 */
1359
1360 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1361 0,
1362 DiskGeometry.BytesPerSector);
1363 if (Mbr == NULL)
1364 return;
1365
1366 FileOffset.QuadPart = 0;
1367 Status = NtReadFile(FileHandle,
1368 NULL,
1369 NULL,
1370 NULL,
1371 &Iosb,
1372 (PVOID)Mbr,
1373 DiskGeometry.BytesPerSector,
1374 &FileOffset,
1375 NULL);
1376 if (!NT_SUCCESS(Status))
1377 {
1378 RtlFreeHeap(ProcessHeap, 0, Mbr);
1379 DPRINT1("NtReadFile failed, status=%x\n", Status);
1380 return;
1381 }
1382 Signature = Mbr->Signature;
1383
1384 /* Calculate the MBR checksum */
1385 Checksum = 0;
1386 Buffer = (PULONG)Mbr;
1387 for (i = 0; i < 128; i++)
1388 {
1389 Checksum += Buffer[i];
1390 }
1391 Checksum = ~Checksum + 1;
1392
1393 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1394 L"%08x-%08x-A", Checksum, Signature);
1395 DPRINT("Identifier: %S\n", Identifier);
1396
1397 DiskEntry = RtlAllocateHeap(ProcessHeap,
1398 HEAP_ZERO_MEMORY,
1399 sizeof(DISKENTRY));
1400 if (DiskEntry == NULL)
1401 {
1402 RtlFreeHeap(ProcessHeap, 0, Mbr);
1403 DPRINT1("Failed to allocate a new disk entry.\n");
1404 return;
1405 }
1406
1407 // DiskEntry->Checksum = Checksum;
1408 // DiskEntry->Signature = Signature;
1409 DiskEntry->BiosFound = FALSE;
1410
1411 /*
1412 * Check if this disk has a valid MBR: verify its signature,
1413 * and whether its two first bytes are a valid instruction
1414 * (related to this, see IsThereAValidBootSector() in partlist.c).
1415 *
1416 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1417 */
1418
1419 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1420
1421 /* If we have not the 0xAA55 then it's raw partition */
1422 if (Mbr->Magic != PARTITION_MAGIC)
1423 {
1424 DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
1425 }
1426 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1427 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
1428 Mbr->Partition[1].PartitionType == 0 &&
1429 Mbr->Partition[2].PartitionType == 0 &&
1430 Mbr->Partition[3].PartitionType == 0)
1431 {
1432 DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
1433 }
1434 /* Otherwise, partition table is in MBR */
1435 else
1436 {
1437 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
1438 }
1439
1440 /* Free the MBR sector buffer */
1441 RtlFreeHeap(ProcessHeap, 0, Mbr);
1442
1443
1444 for (ListEntry = List->BiosDiskListHead.Flink;
1445 ListEntry != &List->BiosDiskListHead;
1446 ListEntry = ListEntry->Flink)
1447 {
1448 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1449 /* FIXME:
1450 * Compare the size from bios and the reported size from driver.
1451 * If we have more than one disk with a zero or with the same signature
1452 * we must create new signatures and reboot. After the reboot,
1453 * it is possible to identify the disks.
1454 */
1455 if (BiosDiskEntry->Signature == Signature &&
1456 BiosDiskEntry->Checksum == Checksum &&
1457 !BiosDiskEntry->Recognized)
1458 {
1459 if (!DiskEntry->BiosFound)
1460 {
1461 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1462 DiskEntry->BiosFound = TRUE;
1463 BiosDiskEntry->Recognized = TRUE;
1464 }
1465 else
1466 {
1467 // FIXME: What to do?
1468 }
1469 }
1470 }
1471
1472 if (!DiskEntry->BiosFound)
1473 {
1474 #if 0
1475 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1476 return;
1477 #else
1478 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1479 #endif
1480 }
1481
1482 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1483 InitializeListHead(&DiskEntry->LogicalPartListHead);
1484
1485 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1486 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1487 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1488 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1489
1490 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1491 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1492 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1493 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1494
1495 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1496 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1497 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1498
1499 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1500 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1501 DiskGeometry.SectorsPerTrack;
1502
1503 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1504 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1505
1506 DiskEntry->DiskNumber = DiskNumber;
1507 DiskEntry->Port = ScsiAddress.PortNumber;
1508 DiskEntry->Bus = ScsiAddress.PathId;
1509 DiskEntry->Id = ScsiAddress.TargetId;
1510
1511 GetDriverName(DiskEntry);
1512 /*
1513 * Actually it would be more correct somehow to use:
1514 *
1515 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1516 * ULONG ReturnedLength;
1517 *
1518 * Status = NtQueryObject(SomeHandleToTheDisk,
1519 * ObjectNameInformation,
1520 * &NameInfo,
1521 * sizeof(NameInfo),
1522 * &ReturnedLength);
1523 * etc...
1524 *
1525 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1526 */
1527
1528 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1529
1530
1531 /*
1532 * We now retrieve the disk partition layout
1533 */
1534
1535 /*
1536 * Stop there now if the disk is GPT-partitioned,
1537 * since we currently do not support such disks.
1538 */
1539 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1540 {
1541 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1542 return;
1543 }
1544
1545 /* Allocate a layout buffer with 4 partition entries first */
1546 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1547 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1548 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1549 HEAP_ZERO_MEMORY,
1550 LayoutBufferSize);
1551 if (DiskEntry->LayoutBuffer == NULL)
1552 {
1553 DPRINT1("Failed to allocate the disk layout buffer!\n");
1554 return;
1555 }
1556
1557 /* Keep looping while the drive layout buffer is too small */
1558 for (;;)
1559 {
1560 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1561 Status = NtDeviceIoControlFile(FileHandle,
1562 NULL,
1563 NULL,
1564 NULL,
1565 &Iosb,
1566 IOCTL_DISK_GET_DRIVE_LAYOUT,
1567 NULL,
1568 0,
1569 DiskEntry->LayoutBuffer,
1570 LayoutBufferSize);
1571 if (NT_SUCCESS(Status))
1572 break;
1573
1574 if (Status != STATUS_BUFFER_TOO_SMALL)
1575 {
1576 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1577 return;
1578 }
1579
1580 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1581 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1582 HEAP_ZERO_MEMORY,
1583 DiskEntry->LayoutBuffer,
1584 LayoutBufferSize);
1585 if (NewLayoutBuffer == NULL)
1586 {
1587 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1588 return;
1589 }
1590
1591 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1592 }
1593
1594 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1595
1596 #ifdef DUMP_PARTITION_TABLE
1597 DumpPartitionTable(DiskEntry);
1598 #endif
1599
1600 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1601 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1602 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
1603 {
1604 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1605 {
1606 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1607 }
1608 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1609 {
1610 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1611 }
1612 else
1613 {
1614 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1615 }
1616 }
1617 else
1618 {
1619 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1620 }
1621
1622 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1623 {
1624 DiskEntry->NewDisk = TRUE;
1625 DiskEntry->LayoutBuffer->PartitionCount = 4;
1626
1627 for (i = 0; i < 4; i++)
1628 {
1629 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1630 }
1631 }
1632 else
1633 {
1634 /* Enumerate and add the first four primary partitions */
1635 for (i = 0; i < 4; i++)
1636 {
1637 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1638 }
1639
1640 /* Enumerate and add the remaining partitions as logical ones */
1641 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1642 {
1643 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1644 }
1645 }
1646
1647 ScanForUnpartitionedDiskSpace(DiskEntry);
1648 }
1649
1650 PPARTLIST
1651 CreatePartitionList(VOID)
1652 {
1653 PPARTLIST List;
1654 OBJECT_ATTRIBUTES ObjectAttributes;
1655 SYSTEM_DEVICE_INFORMATION Sdi;
1656 IO_STATUS_BLOCK Iosb;
1657 ULONG ReturnSize;
1658 NTSTATUS Status;
1659 ULONG DiskNumber;
1660 WCHAR Buffer[MAX_PATH];
1661 UNICODE_STRING Name;
1662 HANDLE FileHandle;
1663
1664 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1665 0,
1666 sizeof(PARTLIST));
1667 if (List == NULL)
1668 return NULL;
1669
1670 List->CurrentDisk = NULL;
1671 List->CurrentPartition = NULL;
1672
1673 List->SystemPartition = NULL;
1674 List->OriginalSystemPartition = NULL;
1675
1676 InitializeListHead(&List->DiskListHead);
1677 InitializeListHead(&List->BiosDiskListHead);
1678
1679 /*
1680 * Enumerate the disks seen by the BIOS; this will be used later
1681 * to map drives seen by NTOS with their corresponding BIOS names.
1682 */
1683 EnumerateBiosDiskEntries(List);
1684
1685 /* Enumerate disks seen by NTOS */
1686 Status = NtQuerySystemInformation(SystemDeviceInformation,
1687 &Sdi,
1688 sizeof(Sdi),
1689 &ReturnSize);
1690 if (!NT_SUCCESS(Status))
1691 {
1692 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
1693 RtlFreeHeap(ProcessHeap, 0, List);
1694 return NULL;
1695 }
1696
1697 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1698 {
1699 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1700 L"\\Device\\Harddisk%lu\\Partition0",
1701 DiskNumber);
1702 RtlInitUnicodeString(&Name, Buffer);
1703
1704 InitializeObjectAttributes(&ObjectAttributes,
1705 &Name,
1706 OBJ_CASE_INSENSITIVE,
1707 NULL,
1708 NULL);
1709
1710 Status = NtOpenFile(&FileHandle,
1711 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1712 &ObjectAttributes,
1713 &Iosb,
1714 FILE_SHARE_READ | FILE_SHARE_WRITE,
1715 FILE_SYNCHRONOUS_IO_NONALERT);
1716 if (NT_SUCCESS(Status))
1717 {
1718 AddDiskToList(FileHandle, DiskNumber, List);
1719 NtClose(FileHandle);
1720 }
1721 }
1722
1723 UpdateDiskSignatures(List);
1724
1725 AssignDriveLetters(List);
1726
1727 /* Search for first usable disk and partition */
1728 if (IsListEmpty(&List->DiskListHead))
1729 {
1730 List->CurrentDisk = NULL;
1731 List->CurrentPartition = NULL;
1732 }
1733 else
1734 {
1735 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1736 DISKENTRY,
1737 ListEntry);
1738
1739 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1740 {
1741 List->CurrentPartition = NULL;
1742 }
1743 else
1744 {
1745 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1746 PARTENTRY,
1747 ListEntry);
1748 }
1749 }
1750
1751 return List;
1752 }
1753
1754 VOID
1755 DestroyPartitionList(
1756 IN PPARTLIST List)
1757 {
1758 PDISKENTRY DiskEntry;
1759 PBIOSDISKENTRY BiosDiskEntry;
1760 PPARTENTRY PartEntry;
1761 PLIST_ENTRY Entry;
1762
1763 /* Release disk and partition info */
1764 while (!IsListEmpty(&List->DiskListHead))
1765 {
1766 Entry = RemoveHeadList(&List->DiskListHead);
1767 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1768
1769 /* Release driver name */
1770 RtlFreeUnicodeString(&DiskEntry->DriverName);
1771
1772 /* Release primary partition list */
1773 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1774 {
1775 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1776 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1777
1778 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1779 }
1780
1781 /* Release logical partition list */
1782 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1783 {
1784 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1785 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1786
1787 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1788 }
1789
1790 /* Release layout buffer */
1791 if (DiskEntry->LayoutBuffer != NULL)
1792 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1793
1794 /* Release disk entry */
1795 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1796 }
1797
1798 /* Release the bios disk info */
1799 while (!IsListEmpty(&List->BiosDiskListHead))
1800 {
1801 Entry = RemoveHeadList(&List->BiosDiskListHead);
1802 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1803
1804 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1805 }
1806
1807 /* Release list head */
1808 RtlFreeHeap(ProcessHeap, 0, List);
1809 }
1810
1811 PDISKENTRY
1812 GetDiskByBiosNumber(
1813 IN PPARTLIST List,
1814 IN ULONG BiosDiskNumber)
1815 {
1816 PDISKENTRY DiskEntry;
1817 PLIST_ENTRY Entry;
1818
1819 /* Loop over the disks and find the correct one */
1820 for (Entry = List->DiskListHead.Flink;
1821 Entry != &List->DiskListHead;
1822 Entry = Entry->Flink)
1823 {
1824 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1825
1826 if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
1827 {
1828 /* Disk found */
1829 return DiskEntry;
1830 }
1831 }
1832
1833 /* Disk not found, stop there */
1834 return NULL;
1835 }
1836
1837 PDISKENTRY
1838 GetDiskByNumber(
1839 IN PPARTLIST List,
1840 IN ULONG DiskNumber)
1841 {
1842 PDISKENTRY DiskEntry;
1843 PLIST_ENTRY Entry;
1844
1845 /* Loop over the disks and find the correct one */
1846 for (Entry = List->DiskListHead.Flink;
1847 Entry != &List->DiskListHead;
1848 Entry = Entry->Flink)
1849 {
1850 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1851
1852 if (DiskEntry->DiskNumber == DiskNumber)
1853 {
1854 /* Disk found */
1855 return DiskEntry;
1856 }
1857 }
1858
1859 /* Disk not found, stop there */
1860 return NULL;
1861 }
1862
1863 PDISKENTRY
1864 GetDiskBySCSI(
1865 IN PPARTLIST List,
1866 IN USHORT Port,
1867 IN USHORT Bus,
1868 IN USHORT Id)
1869 {
1870 PDISKENTRY DiskEntry;
1871 PLIST_ENTRY Entry;
1872
1873 /* Loop over the disks and find the correct one */
1874 for (Entry = List->DiskListHead.Flink;
1875 Entry != &List->DiskListHead;
1876 Entry = Entry->Flink)
1877 {
1878 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1879
1880 if (DiskEntry->Port == Port &&
1881 DiskEntry->Bus == Bus &&
1882 DiskEntry->Id == Id)
1883 {
1884 /* Disk found */
1885 return DiskEntry;
1886 }
1887 }
1888
1889 /* Disk not found, stop there */
1890 return NULL;
1891 }
1892
1893 PDISKENTRY
1894 GetDiskBySignature(
1895 IN PPARTLIST List,
1896 IN ULONG Signature)
1897 {
1898 PDISKENTRY DiskEntry;
1899 PLIST_ENTRY Entry;
1900
1901 /* Loop over the disks and find the correct one */
1902 for (Entry = List->DiskListHead.Flink;
1903 Entry != &List->DiskListHead;
1904 Entry = Entry->Flink)
1905 {
1906 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1907
1908 if (DiskEntry->LayoutBuffer->Signature == Signature)
1909 {
1910 /* Disk found */
1911 return DiskEntry;
1912 }
1913 }
1914
1915 /* Disk not found, stop there */
1916 return NULL;
1917 }
1918
1919 PPARTENTRY
1920 GetPartition(
1921 // IN PPARTLIST List,
1922 IN PDISKENTRY DiskEntry,
1923 IN ULONG PartitionNumber)
1924 {
1925 PPARTENTRY PartEntry;
1926 PLIST_ENTRY Entry;
1927
1928 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1929 {
1930 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1931 return NULL;
1932 }
1933
1934 /* Disk found, loop over the primary partitions first... */
1935 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1936 Entry != &DiskEntry->PrimaryPartListHead;
1937 Entry = Entry->Flink)
1938 {
1939 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1940
1941 if (PartEntry->PartitionNumber == PartitionNumber)
1942 {
1943 /* Partition found */
1944 return PartEntry;
1945 }
1946 }
1947
1948 /* ... then over the logical partitions if needed */
1949 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1950 Entry != &DiskEntry->LogicalPartListHead;
1951 Entry = Entry->Flink)
1952 {
1953 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1954
1955 if (PartEntry->PartitionNumber == PartitionNumber)
1956 {
1957 /* Partition found */
1958 return PartEntry;
1959 }
1960 }
1961
1962 /* The partition was not found on the disk, stop there */
1963 return NULL;
1964 }
1965
1966 BOOLEAN
1967 GetDiskOrPartition(
1968 IN PPARTLIST List,
1969 IN ULONG DiskNumber,
1970 IN ULONG PartitionNumber OPTIONAL,
1971 OUT PDISKENTRY* pDiskEntry,
1972 OUT PPARTENTRY* pPartEntry OPTIONAL)
1973 {
1974 PDISKENTRY DiskEntry;
1975 PPARTENTRY PartEntry = NULL;
1976
1977 /* Find the disk */
1978 DiskEntry = GetDiskByNumber(List, DiskNumber);
1979 if (!DiskEntry)
1980 return FALSE;
1981
1982 /* If we have a partition (PartitionNumber != 0), find it */
1983 if (PartitionNumber != 0)
1984 {
1985 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1986 {
1987 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1988 return FALSE;
1989 }
1990
1991 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1992 if (!PartEntry)
1993 return FALSE;
1994 ASSERT(PartEntry->DiskEntry == DiskEntry);
1995 }
1996
1997 /* Return the disk (and optionally the partition) */
1998 *pDiskEntry = DiskEntry;
1999 if (pPartEntry) *pPartEntry = PartEntry;
2000 return TRUE;
2001 }
2002
2003 //
2004 // NOTE: Was introduced broken in r6258 by Casper
2005 //
2006 BOOLEAN
2007 SelectPartition(
2008 IN PPARTLIST List,
2009 IN ULONG DiskNumber,
2010 IN ULONG PartitionNumber)
2011 {
2012 PDISKENTRY DiskEntry;
2013 PPARTENTRY PartEntry;
2014
2015 DiskEntry = GetDiskByNumber(List, DiskNumber);
2016 if (!DiskEntry)
2017 return FALSE;
2018
2019 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
2020 if (!PartEntry)
2021 return FALSE;
2022
2023 ASSERT(PartEntry->DiskEntry == DiskEntry);
2024 ASSERT(DiskEntry->DiskNumber == DiskNumber);
2025 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
2026
2027 List->CurrentDisk = DiskEntry;
2028 List->CurrentPartition = PartEntry;
2029 return TRUE;
2030 }
2031
2032 PPARTENTRY
2033 GetNextPartition(
2034 IN PPARTLIST List)
2035 {
2036 PLIST_ENTRY DiskListEntry;
2037 PLIST_ENTRY PartListEntry;
2038 PDISKENTRY DiskEntry;
2039 PPARTENTRY PartEntry;
2040
2041 /* Fail if no disks are available */
2042 if (IsListEmpty(&List->DiskListHead))
2043 return NULL;
2044
2045 /* Check for next usable entry on current disk */
2046 if (List->CurrentPartition != NULL)
2047 {
2048 if (List->CurrentPartition->LogicalPartition)
2049 {
2050 /* Logical partition */
2051
2052 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2053 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2054 {
2055 /* Next logical partition */
2056 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2057
2058 List->CurrentPartition = PartEntry;
2059 return List->CurrentPartition;
2060 }
2061 else
2062 {
2063 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
2064 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2065 {
2066 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2067
2068 List->CurrentPartition = PartEntry;
2069 return List->CurrentPartition;
2070 }
2071 }
2072 }
2073 else
2074 {
2075 /* Primary or extended partition */
2076
2077 if (List->CurrentPartition->IsPartitioned &&
2078 IsContainerPartition(List->CurrentPartition->PartitionType))
2079 {
2080 /* First logical partition */
2081 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
2082 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2083 {
2084 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2085
2086 List->CurrentPartition = PartEntry;
2087 return List->CurrentPartition;
2088 }
2089 }
2090 else
2091 {
2092 /* Next primary partition */
2093 PartListEntry = List->CurrentPartition->ListEntry.Flink;
2094 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2095 {
2096 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2097
2098 List->CurrentPartition = PartEntry;
2099 return List->CurrentPartition;
2100 }
2101 }
2102 }
2103 }
2104
2105 /* Search for the first partition entry on the next disk */
2106 for (DiskListEntry = List->CurrentDisk->ListEntry.Flink;
2107 DiskListEntry != &List->DiskListHead;
2108 DiskListEntry = DiskListEntry->Flink)
2109 {
2110 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2111
2112 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2113 {
2114 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2115 continue;
2116 }
2117
2118 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
2119 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2120 {
2121 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2122
2123 List->CurrentDisk = DiskEntry;
2124 List->CurrentPartition = PartEntry;
2125 return List->CurrentPartition;
2126 }
2127 }
2128
2129 return NULL;
2130 }
2131
2132 PPARTENTRY
2133 GetPrevPartition(
2134 IN PPARTLIST List)
2135 {
2136 PLIST_ENTRY DiskListEntry;
2137 PLIST_ENTRY PartListEntry;
2138 PDISKENTRY DiskEntry;
2139 PPARTENTRY PartEntry;
2140
2141 /* Fail if no disks are available */
2142 if (IsListEmpty(&List->DiskListHead))
2143 return NULL;
2144
2145 /* Check for previous usable entry on current disk */
2146 if (List->CurrentPartition != NULL)
2147 {
2148 if (List->CurrentPartition->LogicalPartition)
2149 {
2150 /* Logical partition */
2151 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2152 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
2153 {
2154 /* Previous logical partition */
2155 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2156 }
2157 else
2158 {
2159 /* Extended partition */
2160 PartEntry = List->CurrentDisk->ExtendedPartition;
2161 }
2162
2163 List->CurrentPartition = PartEntry;
2164 return List->CurrentPartition;
2165 }
2166 else
2167 {
2168 /* Primary or extended partition */
2169
2170 PartListEntry = List->CurrentPartition->ListEntry.Blink;
2171 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
2172 {
2173 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2174
2175 if (PartEntry->IsPartitioned &&
2176 IsContainerPartition(PartEntry->PartitionType))
2177 {
2178 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
2179 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2180 }
2181
2182 List->CurrentPartition = PartEntry;
2183 return List->CurrentPartition;
2184 }
2185 }
2186 }
2187
2188 /* Search for the last partition entry on the previous disk */
2189 for (DiskListEntry = List->CurrentDisk->ListEntry.Blink;
2190 DiskListEntry != &List->DiskListHead;
2191 DiskListEntry = DiskListEntry->Blink)
2192 {
2193 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2194
2195 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2196 {
2197 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2198 continue;
2199 }
2200
2201 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
2202 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
2203 {
2204 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2205
2206 if (PartEntry->IsPartitioned &&
2207 IsContainerPartition(PartEntry->PartitionType))
2208 {
2209 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
2210 if (PartListEntry != &DiskEntry->LogicalPartListHead)
2211 {
2212 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2213
2214 List->CurrentDisk = DiskEntry;
2215 List->CurrentPartition = PartEntry;
2216 return List->CurrentPartition;
2217 }
2218 }
2219 else
2220 {
2221 List->CurrentDisk = DiskEntry;
2222 List->CurrentPartition = PartEntry;
2223 return List->CurrentPartition;
2224 }
2225 }
2226 }
2227
2228 return NULL;
2229 }
2230
2231 // static
2232 FORCEINLINE
2233 BOOLEAN
2234 IsEmptyLayoutEntry(
2235 IN PPARTITION_INFORMATION PartitionInfo)
2236 {
2237 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2238 PartitionInfo->PartitionLength.QuadPart == 0)
2239 {
2240 return TRUE;
2241 }
2242
2243 return FALSE;
2244 }
2245
2246 // static
2247 FORCEINLINE
2248 BOOLEAN
2249 IsSamePrimaryLayoutEntry(
2250 IN PPARTITION_INFORMATION PartitionInfo,
2251 IN PDISKENTRY DiskEntry,
2252 IN PPARTENTRY PartEntry)
2253 {
2254 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2255 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2256 // PartitionInfo->PartitionType == PartEntry->PartitionType
2257 {
2258 return TRUE;
2259 }
2260
2261 return FALSE;
2262 }
2263
2264 static
2265 ULONG
2266 GetPrimaryPartitionCount(
2267 IN PDISKENTRY DiskEntry)
2268 {
2269 PLIST_ENTRY Entry;
2270 PPARTENTRY PartEntry;
2271 ULONG Count = 0;
2272
2273 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2274 {
2275 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2276 return 0;
2277 }
2278
2279 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2280 Entry != &DiskEntry->PrimaryPartListHead;
2281 Entry = Entry->Flink)
2282 {
2283 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2284 if (PartEntry->IsPartitioned)
2285 Count++;
2286 }
2287
2288 return Count;
2289 }
2290
2291 static
2292 ULONG
2293 GetLogicalPartitionCount(
2294 IN PDISKENTRY DiskEntry)
2295 {
2296 PLIST_ENTRY ListEntry;
2297 PPARTENTRY PartEntry;
2298 ULONG Count = 0;
2299
2300 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2301 {
2302 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2303 return 0;
2304 }
2305
2306 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2307 ListEntry != &DiskEntry->LogicalPartListHead;
2308 ListEntry = ListEntry->Flink)
2309 {
2310 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2311 if (PartEntry->IsPartitioned)
2312 Count++;
2313 }
2314
2315 return Count;
2316 }
2317
2318 static
2319 BOOLEAN
2320 ReAllocateLayoutBuffer(
2321 IN PDISKENTRY DiskEntry)
2322 {
2323 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2324 ULONG NewPartitionCount;
2325 ULONG CurrentPartitionCount = 0;
2326 ULONG LayoutBufferSize;
2327 ULONG i;
2328
2329 DPRINT1("ReAllocateLayoutBuffer()\n");
2330
2331 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2332
2333 if (DiskEntry->LayoutBuffer)
2334 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2335
2336 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2337 CurrentPartitionCount, NewPartitionCount);
2338
2339 if (CurrentPartitionCount == NewPartitionCount)
2340 return TRUE;
2341
2342 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2343 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2344 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2345 HEAP_ZERO_MEMORY,
2346 DiskEntry->LayoutBuffer,
2347 LayoutBufferSize);
2348 if (NewLayoutBuffer == NULL)
2349 {
2350 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2351 return FALSE;
2352 }
2353
2354 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2355
2356 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2357 if (NewPartitionCount > CurrentPartitionCount)
2358 {
2359 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2360 {
2361 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2362 }
2363 }
2364
2365 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2366
2367 return TRUE;
2368 }
2369
2370 static
2371 VOID
2372 UpdateDiskLayout(
2373 IN PDISKENTRY DiskEntry)
2374 {
2375 PPARTITION_INFORMATION PartitionInfo;
2376 PPARTITION_INFORMATION LinkInfo = NULL;
2377 PLIST_ENTRY ListEntry;
2378 PPARTENTRY PartEntry;
2379 LARGE_INTEGER HiddenSectors64;
2380 ULONG Index;
2381 ULONG PartitionNumber = 1;
2382
2383 DPRINT1("UpdateDiskLayout()\n");
2384
2385 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2386 {
2387 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2388 return;
2389 }
2390
2391 /* Resize the layout buffer if necessary */
2392 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2393 {
2394 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2395 return;
2396 }
2397
2398 /* Update the primary partition table */
2399 Index = 0;
2400 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2401 ListEntry != &DiskEntry->PrimaryPartListHead;
2402 ListEntry = ListEntry->Flink)
2403 {
2404 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2405
2406 if (PartEntry->IsPartitioned)
2407 {
2408 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2409 PartEntry->PartitionIndex = Index;
2410
2411 /* Reset the current partition number only for newly-created partitions */
2412 if (PartEntry->New)
2413 PartEntry->PartitionNumber = 0;
2414
2415 PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2416
2417 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2418 {
2419 DPRINT1("Updating primary partition entry %lu\n", Index);
2420
2421 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2422 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2423 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2424 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2425 PartitionInfo->PartitionType = PartEntry->PartitionType;
2426 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2427 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2428 PartitionInfo->RewritePartition = TRUE;
2429 }
2430
2431 if (!IsContainerPartition(PartEntry->PartitionType))
2432 PartitionNumber++;
2433
2434 Index++;
2435 }
2436 }
2437
2438 ASSERT(Index <= 4);
2439
2440 /* Update the logical partition table */
2441 Index = 4;
2442 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2443 ListEntry != &DiskEntry->LogicalPartListHead;
2444 ListEntry = ListEntry->Flink)
2445 {
2446 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2447
2448 if (PartEntry->IsPartitioned)
2449 {
2450 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2451 PartEntry->PartitionIndex = Index;
2452
2453 DPRINT1("Updating logical partition entry %lu\n", Index);
2454
2455 /* Reset the current partition number only for newly-created partitions */
2456 if (PartEntry->New)
2457 PartEntry->PartitionNumber = 0;
2458
2459 PartEntry->OnDiskPartitionNumber = PartitionNumber;
2460
2461 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2462 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2463 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2464 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2465 PartitionInfo->PartitionType = PartEntry->PartitionType;
2466 PartitionInfo->BootIndicator = FALSE;
2467 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2468 PartitionInfo->RewritePartition = TRUE;
2469
2470 /* Fill the link entry of the previous partition entry */
2471 if (LinkInfo != NULL)
2472 {
2473 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2474 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2475 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2476 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2477 LinkInfo->PartitionNumber = 0;
2478 LinkInfo->PartitionType = PARTITION_EXTENDED;
2479 LinkInfo->BootIndicator = FALSE;
2480 LinkInfo->RecognizedPartition = FALSE;
2481 LinkInfo->RewritePartition = TRUE;
2482 }
2483
2484 /* Save a pointer to the link entry of the current partition entry */
2485 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2486
2487 PartitionNumber++;
2488 Index += 4;
2489 }
2490 }
2491
2492 /* Wipe unused primary partition entries */
2493 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2494 {
2495 DPRINT1("Primary partition entry %lu\n", Index);
2496
2497 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2498
2499 if (!IsEmptyLayoutEntry(PartitionInfo))
2500 {
2501 DPRINT1("Wiping primary partition entry %lu\n", Index);
2502
2503 PartitionInfo->StartingOffset.QuadPart = 0;
2504 PartitionInfo->PartitionLength.QuadPart = 0;
2505 PartitionInfo->HiddenSectors = 0;
2506 PartitionInfo->PartitionNumber = 0;
2507 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2508 PartitionInfo->BootIndicator = FALSE;
2509 PartitionInfo->RecognizedPartition = FALSE;
2510 PartitionInfo->RewritePartition = TRUE;
2511 }
2512 }
2513
2514 /* Wipe unused logical partition entries */
2515 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2516 {
2517 if (Index % 4 >= 2)
2518 {
2519 DPRINT1("Logical partition entry %lu\n", Index);
2520
2521 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2522
2523 if (!IsEmptyLayoutEntry(PartitionInfo))
2524 {
2525 DPRINT1("Wiping partition entry %lu\n", Index);
2526
2527 PartitionInfo->StartingOffset.QuadPart = 0;
2528 PartitionInfo->PartitionLength.QuadPart = 0;
2529 PartitionInfo->HiddenSectors = 0;
2530 PartitionInfo->PartitionNumber = 0;
2531 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2532 PartitionInfo->BootIndicator = FALSE;
2533 PartitionInfo->RecognizedPartition = FALSE;
2534 PartitionInfo->RewritePartition = TRUE;
2535 }
2536 }
2537 }
2538
2539 DiskEntry->Dirty = TRUE;
2540
2541 #ifdef DUMP_PARTITION_TABLE
2542 DumpPartitionTable(DiskEntry);
2543 #endif
2544 }
2545
2546 static
2547 PPARTENTRY
2548 GetPrevUnpartitionedEntry(
2549 IN PDISKENTRY DiskEntry,
2550 IN PPARTENTRY PartEntry)
2551 {
2552 PPARTENTRY PrevPartEntry;
2553 PLIST_ENTRY ListHead;
2554
2555 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2556 {
2557 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2558 return NULL;
2559 }
2560
2561 if (PartEntry->LogicalPartition)
2562 ListHead = &DiskEntry->LogicalPartListHead;
2563 else
2564 ListHead = &DiskEntry->PrimaryPartListHead;
2565
2566 if (PartEntry->ListEntry.Blink != ListHead)
2567 {
2568 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2569 PARTENTRY,
2570 ListEntry);
2571 if (PrevPartEntry->IsPartitioned == FALSE)
2572 return PrevPartEntry;
2573 }
2574
2575 return NULL;
2576 }
2577
2578 static
2579 PPARTENTRY
2580 GetNextUnpartitionedEntry(
2581 IN PDISKENTRY DiskEntry,
2582 IN PPARTENTRY PartEntry)
2583 {
2584 PPARTENTRY NextPartEntry;
2585 PLIST_ENTRY ListHead;
2586
2587 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2588 {
2589 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2590 return NULL;
2591 }
2592
2593 if (PartEntry->LogicalPartition)
2594 ListHead = &DiskEntry->LogicalPartListHead;
2595 else
2596 ListHead = &DiskEntry->PrimaryPartListHead;
2597
2598 if (PartEntry->ListEntry.Flink != ListHead)
2599 {
2600 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2601 PARTENTRY,
2602 ListEntry);
2603 if (NextPartEntry->IsPartitioned == FALSE)
2604 return NextPartEntry;
2605 }
2606
2607 return NULL;
2608 }
2609
2610 BOOLEAN
2611 CreatePrimaryPartition(
2612 IN PPARTLIST List,
2613 IN ULONGLONG SectorCount,
2614 IN BOOLEAN AutoCreate)
2615 {
2616 ERROR_NUMBER Error;
2617 PDISKENTRY DiskEntry;
2618 PPARTENTRY PartEntry;
2619
2620 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2621
2622 if (List == NULL ||
2623 List->CurrentDisk == NULL ||
2624 List->CurrentPartition == NULL ||
2625 List->CurrentPartition->IsPartitioned)
2626 {
2627 return FALSE;
2628 }
2629
2630 Error = PrimaryPartitionCreationChecks(List);
2631 if (Error != NOT_AN_ERROR)
2632 {
2633 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
2634 return FALSE;
2635 }
2636
2637 DiskEntry = List->CurrentDisk;
2638 PartEntry = List->CurrentPartition;
2639
2640 /* Convert the current entry, or insert and initialize a new partition entry */
2641 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, AutoCreate);
2642 if (PartEntry == NULL)
2643 return FALSE;
2644
2645 UpdateDiskLayout(DiskEntry);
2646
2647 AssignDriveLetters(List);
2648
2649 return TRUE;
2650 }
2651
2652 static
2653 VOID
2654 AddLogicalDiskSpace(
2655 IN PDISKENTRY DiskEntry)
2656 {
2657 ULONGLONG StartSector;
2658 ULONGLONG SectorCount;
2659 PPARTENTRY NewPartEntry;
2660
2661 DPRINT1("AddLogicalDiskSpace()\n");
2662
2663 /* Create a partition entry that represents the empty space in the container partition */
2664
2665 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2666 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2667
2668 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
2669 &DiskEntry->LogicalPartListHead,
2670 StartSector,
2671 SectorCount,
2672 TRUE);
2673 if (NewPartEntry == NULL)
2674 {
2675 DPRINT1("Failed to create a new empty region for extended partition space!\n");
2676 return;
2677 }
2678 NewPartEntry->LogicalPartition = TRUE;
2679 }
2680
2681 BOOLEAN
2682 CreateExtendedPartition(
2683 IN PPARTLIST List,
2684 IN ULONGLONG SectorCount)
2685 {
2686 ERROR_NUMBER Error;
2687 PDISKENTRY DiskEntry;
2688 PPARTENTRY PartEntry;
2689
2690 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2691
2692 if (List == NULL ||
2693 List->CurrentDisk == NULL ||
2694 List->CurrentPartition == NULL ||
2695 List->CurrentPartition->IsPartitioned)
2696 {
2697 return FALSE;
2698 }
2699
2700 Error = ExtendedPartitionCreationChecks(List);
2701 if (Error != NOT_AN_ERROR)
2702 {
2703 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
2704 return FALSE;
2705 }
2706
2707 DiskEntry = List->CurrentDisk;
2708 PartEntry = List->CurrentPartition;
2709
2710 /* Convert the current entry, or insert and initialize a new partition entry */
2711 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, FALSE);
2712 if (PartEntry == NULL)
2713 return FALSE;
2714
2715 if (PartEntry->StartSector.QuadPart < 1450560)
2716 {
2717 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2718 PartEntry->PartitionType = PARTITION_EXTENDED;
2719 }
2720 else
2721 {
2722 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2723 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2724 }
2725
2726 // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2727 PartEntry->New = FALSE;
2728 PartEntry->FormatState = Formatted;
2729
2730 DiskEntry->ExtendedPartition = PartEntry;
2731
2732 AddLogicalDiskSpace(DiskEntry);
2733
2734 UpdateDiskLayout(DiskEntry);
2735
2736 AssignDriveLetters(List);
2737
2738 return TRUE;
2739 }
2740
2741 BOOLEAN
2742 CreateLogicalPartition(
2743 IN PPARTLIST List,
2744 IN ULONGLONG SectorCount,
2745 IN BOOLEAN AutoCreate)
2746 {
2747 ERROR_NUMBER Error;
2748 PDISKENTRY DiskEntry;
2749 PPARTENTRY PartEntry;
2750
2751 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2752
2753 if (List == NULL ||
2754 List->CurrentDisk == NULL ||
2755 List->CurrentPartition == NULL ||
2756 List->CurrentPartition->IsPartitioned)
2757 {
2758 return FALSE;
2759 }
2760
2761 Error = LogicalPartitionCreationChecks(List);
2762 if (Error != NOT_AN_ERROR)
2763 {
2764 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
2765 return FALSE;
2766 }
2767
2768 DiskEntry = List->CurrentDisk;
2769 PartEntry = List->CurrentPartition;
2770
2771 /* Convert the current entry, or insert and initialize a new partition entry */
2772 PartEntry = InitializePartitionEntry(DiskEntry, PartEntry, SectorCount, AutoCreate);
2773 if (PartEntry == NULL)
2774 return FALSE;
2775
2776 PartEntry->LogicalPartition = TRUE;
2777
2778 UpdateDiskLayout(DiskEntry);
2779
2780 AssignDriveLetters(List);
2781
2782 return TRUE;
2783 }
2784
2785 static
2786 NTSTATUS
2787 DismountVolume(
2788 IN PPARTENTRY PartEntry)
2789 {
2790 NTSTATUS Status;
2791 NTSTATUS LockStatus;
2792 UNICODE_STRING Name;
2793 OBJECT_ATTRIBUTES ObjectAttributes;
2794 IO_STATUS_BLOCK IoStatusBlock;
2795 HANDLE PartitionHandle;
2796 WCHAR Buffer[MAX_PATH];
2797
2798 /* Check whether the partition is valid and may have been mounted in the system */
2799 if (!PartEntry->IsPartitioned ||
2800 PartEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
2801 IsContainerPartition(PartEntry->PartitionType) ||
2802 !IsRecognizedPartition(PartEntry->PartitionType) ||
2803 PartEntry->FormatState == Unformatted /* || PartEntry->FormatState == UnknownFormat */ ||
2804 !*PartEntry->FileSystem ||
2805 PartEntry->PartitionNumber == 0)
2806 {
2807 /* The partition is not mounted, so just return success */
2808 return STATUS_SUCCESS;
2809 }
2810
2811 /* Open the volume */
2812 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
2813 L"\\Device\\Harddisk%lu\\Partition%lu",
2814 PartEntry->DiskEntry->DiskNumber,
2815 PartEntry->PartitionNumber);
2816 RtlInitUnicodeString(&Name, Buffer);
2817
2818 InitializeObjectAttributes(&ObjectAttributes,
2819 &Name,
2820 OBJ_CASE_INSENSITIVE,
2821 NULL,
2822 NULL);
2823
2824 Status = NtOpenFile(&PartitionHandle,
2825 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
2826 &ObjectAttributes,
2827 &IoStatusBlock,
2828 FILE_SHARE_READ | FILE_SHARE_WRITE,
2829 FILE_SYNCHRONOUS_IO_NONALERT);
2830 if (!NT_SUCCESS(Status))
2831 {
2832 DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
2833 return Status;
2834 }
2835
2836 /* Lock the volume */
2837 LockStatus = NtFsControlFile(PartitionHandle,
2838 NULL,
2839 NULL,
2840 NULL,
2841 &IoStatusBlock,
2842 FSCTL_LOCK_VOLUME,
2843 NULL,
2844 0,
2845 NULL,
2846 0);
2847 if (!NT_SUCCESS(LockStatus))
2848 {
2849 DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
2850 }
2851
2852 /* Dismount the volume */
2853 Status = NtFsControlFile(PartitionHandle,
2854 NULL,
2855 NULL,
2856 NULL,
2857 &IoStatusBlock,
2858 FSCTL_DISMOUNT_VOLUME,
2859 NULL,
2860 0,
2861 NULL,
2862 0);
2863 if (!NT_SUCCESS(Status))
2864 {
2865 DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
2866 }
2867
2868 /* Unlock the volume */
2869 LockStatus = NtFsControlFile(PartitionHandle,
2870 NULL,
2871 NULL,
2872 NULL,
2873 &IoStatusBlock,
2874 FSCTL_UNLOCK_VOLUME,
2875 NULL,
2876 0,
2877 NULL,
2878 0);
2879 if (!NT_SUCCESS(LockStatus))
2880 {
2881 DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
2882 }
2883
2884 /* Close the volume */
2885 NtClose(PartitionHandle);
2886
2887 return Status;
2888 }
2889
2890 VOID
2891 DeleteCurrentPartition(
2892 IN PPARTLIST List)
2893 {
2894 PDISKENTRY DiskEntry;
2895 PPARTENTRY PartEntry;
2896 PPARTENTRY PrevPartEntry;
2897 PPARTENTRY NextPartEntry;
2898 PPARTENTRY LogicalPartEntry;
2899 PLIST_ENTRY Entry;
2900
2901 if (List == NULL ||
2902 List->CurrentDisk == NULL ||
2903 List->CurrentPartition == NULL ||
2904 List->CurrentPartition->IsPartitioned == FALSE)
2905 {
2906 return;
2907 }
2908
2909 /* Clear the system disk and partition pointers if the system partition is being deleted */
2910 if (List->SystemPartition == List->CurrentPartition)
2911 {
2912 List->SystemPartition = NULL;
2913 }
2914
2915 DiskEntry = List->CurrentDisk;
2916 PartEntry = List->CurrentPartition;
2917
2918 /* Check which type of partition (primary/logical or extended) is being deleted */
2919 if (DiskEntry->ExtendedPartition == PartEntry)
2920 {
2921 /* An extended partition is being deleted: delete all logical partition entries */
2922 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2923 {
2924 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2925 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2926
2927 /* Dismount the logical partition */
2928 DismountVolume(LogicalPartEntry);
2929
2930 /* Delete it */
2931 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2932 }
2933
2934 DiskEntry->ExtendedPartition = NULL;
2935 }
2936 else
2937 {
2938 /* A primary partition is being deleted: dismount it */
2939 DismountVolume(PartEntry);
2940 }
2941
2942 /* Adjust unpartitioned disk space entries */
2943
2944 /* Get pointer to previous and next unpartitioned entries */
2945 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2946 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2947
2948 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2949 {
2950 /* Merge previous, current and next unpartitioned entry */
2951
2952 /* Adjust the previous entries length */
2953 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2954
2955 /* Remove the current entry */
2956 RemoveEntryList(&PartEntry->ListEntry);
2957 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2958
2959 /* Remove the next entry */
2960 RemoveEntryList(&NextPartEntry->ListEntry);
2961 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2962
2963 /* Update current partition */
2964 List->CurrentPartition = PrevPartEntry;
2965 }
2966 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2967 {
2968 /* Merge current and previous unpartitioned entry */
2969
2970 /* Adjust the previous entries length */
2971 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2972
2973 /* Remove the current entry */
2974 RemoveEntryList(&PartEntry->ListEntry);
2975 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2976
2977 /* Update current partition */
2978 List->CurrentPartition = PrevPartEntry;
2979 }
2980 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2981 {
2982 /* Merge current and next unpartitioned entry */
2983
2984 /* Adjust the next entries offset and length */
2985 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2986 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2987
2988 /* Remove the current entry */
2989 RemoveEntryList(&PartEntry->ListEntry);
2990 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2991
2992 /* Update current partition */
2993 List->CurrentPartition = NextPartEntry;
2994 }
2995 else
2996 {
2997 /* Nothing to merge but change current entry */
2998 PartEntry->IsPartitioned = FALSE;
2999 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3000 PartEntry->FormatState = Unformatted;
3001 PartEntry->FileSystem[0] = L'\0';
3002 PartEntry->DriveLetter = 0;
3003 PartEntry->OnDiskPartitionNumber = 0;
3004 PartEntry->PartitionNumber = 0;
3005 // PartEntry->PartitionIndex = 0;
3006 }
3007
3008 UpdateDiskLayout(DiskEntry);
3009
3010 AssignDriveLetters(List);
3011 }
3012
3013 static
3014 BOOLEAN
3015 IsSupportedActivePartition(
3016 IN PPARTENTRY PartEntry)
3017 {
3018 /* Check the type and the filesystem of this partition */
3019
3020 /*
3021 * We do not support extended partition containers (on MBR disks) marked
3022 * as active, and containing code inside their extended boot records.
3023 */
3024 if (IsContainerPartition(PartEntry->PartitionType))
3025 {
3026 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3027 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3028 return FALSE;
3029 }
3030
3031 /*
3032 * ADDITIONAL CHECKS / BIG HACK:
3033 *
3034 * Retrieve its file system and check whether we have
3035 * write support for it. If that is the case we are fine
3036 * and we can use it directly. However if we don't have
3037 * write support we will need to change the active system
3038 * partition.
3039 *
3040 * NOTE that this is completely useless on architectures
3041 * where a real system partition is required, as on these
3042 * architectures the partition uses the FAT FS, for which
3043 * we do have write support.
3044 * NOTE also that for those architectures looking for a
3045 * partition boot indicator is insufficient.
3046 */
3047 if ((PartEntry->FormatState == Unformatted ) ||
3048 (PartEntry->FormatState == Preformatted) ||
3049 (PartEntry->FormatState == Formatted ))
3050 {
3051 ASSERT(*PartEntry->FileSystem);
3052
3053 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3054 if (wcsicmp(PartEntry->FileSystem, L"FAT") == 0 ||
3055 wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 ||
3056 // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3057 wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0 ||
3058 wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
3059 {
3060 return TRUE;
3061 }
3062 else
3063 {
3064 // WARNING: We cannot write on this FS yet!
3065 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3066 PartEntry->FileSystem);
3067 return FALSE;
3068 }
3069 }
3070 else // if (PartEntry->FormatState == UnknownFormat)
3071 {
3072 ASSERT(!*PartEntry->FileSystem);
3073
3074 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3075 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3076 return FALSE;
3077 }
3078
3079 // HACK: WARNING: We cannot write on this FS yet!
3080 // See fsutil.c:InferFileSystem()
3081 if (PartEntry->PartitionType == PARTITION_IFS)
3082 {
3083 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3084 PartEntry->FileSystem);
3085 return FALSE;
3086 }
3087
3088 return TRUE;
3089 }
3090
3091 VOID
3092 CheckActiveSystemPartition(
3093 IN PPARTLIST List)
3094 {
3095 PDISKENTRY DiskEntry;
3096 PPARTENTRY PartEntry;
3097 PLIST_ENTRY ListEntry;
3098
3099 /* Check for empty disk list */
3100 if (IsListEmpty(&List->DiskListHead))
3101 {
3102 List->SystemPartition = NULL;
3103 List->OriginalSystemPartition = NULL;
3104 return;
3105 }
3106
3107 /* Choose the currently selected disk */
3108 DiskEntry = List->CurrentDisk;
3109
3110 /* Check for empty partition list */
3111 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
3112 {
3113 List->SystemPartition = NULL;
3114 List->OriginalSystemPartition = NULL;
3115 return;
3116 }
3117
3118 if (List->SystemPartition != NULL)
3119 {
3120 /* We already have an active system partition */
3121 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3122 List->SystemPartition->PartitionNumber,
3123 List->SystemPartition->DiskEntry->DiskNumber,
3124 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3125 return;
3126 }
3127
3128 DPRINT("We are here (1)!\n");
3129
3130 List->SystemPartition = NULL;
3131 List->OriginalSystemPartition = NULL;
3132
3133 /* Retrieve the first partition of the disk */
3134 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3135 PARTENTRY,
3136 ListEntry);
3137 ASSERT(DiskEntry == PartEntry->DiskEntry);
3138 List->SystemPartition = PartEntry;
3139
3140 //
3141 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3142 //
3143
3144 /* Check if the disk is new and if so, use its first partition as the active system partition */
3145 if (DiskEntry->NewDisk)
3146 {
3147 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
3148 {
3149 ASSERT(DiskEntry == PartEntry->DiskEntry);
3150 List->SystemPartition = PartEntry;
3151
3152 List->OriginalSystemPartition = List->SystemPartition;
3153
3154 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3155 List->SystemPartition->PartitionNumber,
3156 List->SystemPartition->DiskEntry->DiskNumber,
3157 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3158
3159 goto SetSystemPartition;
3160 }
3161
3162 // FIXME: What to do??
3163 DPRINT1("NewDisk TRUE but first partition is used?\n");
3164 }
3165
3166 DPRINT("We are here (2)!\n");
3167
3168 /*
3169 * The disk is not new, check if any partition is initialized;
3170 * if not, the first one becomes the system partition.
3171 */
3172 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3173 ListEntry != &DiskEntry->PrimaryPartListHead;
3174 ListEntry = ListEntry->Flink)
3175 {
3176 /* Retrieve the partition */
3177 PartEntry = CONTAINING_RECORD(ListEntry,
3178 PARTENTRY,
3179 ListEntry);
3180
3181 /* Check if the partition is partitioned and is used */
3182 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
3183 {
3184 break;
3185 }
3186 }
3187 if (ListEntry == &DiskEntry->PrimaryPartListHead)
3188 {
3189 /*
3190 * OK we haven't encountered any used and active partition,
3191 * so use the first one as the system partition.
3192 */
3193 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
3194 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
3195
3196 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3197 List->SystemPartition->PartitionNumber,
3198 List->SystemPartition->DiskEntry->DiskNumber,
3199 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3200
3201 goto SetSystemPartition;
3202 }
3203
3204 List->SystemPartition = NULL;
3205 List->OriginalSystemPartition = NULL;
3206
3207 DPRINT("We are here (3)!\n");
3208
3209 /* The disk is not new, scan all partitions to find the (active) system partition */
3210 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3211 ListEntry != &DiskEntry->PrimaryPartListHead;
3212 ListEntry = ListEntry->Flink)
3213 {
3214 /* Retrieve the partition */
3215 PartEntry = CONTAINING_RECORD(ListEntry,
3216 PARTENTRY,
3217 ListEntry);
3218
3219 /* Check if the partition is partitioned and used */
3220 if (PartEntry->IsPartitioned &&
3221 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
3222 {
3223 /* Check if the partition is active */
3224 if (PartEntry->BootIndicator)
3225 {
3226 /* Yes, we found it */
3227 ASSERT(DiskEntry == PartEntry->DiskEntry);
3228 List->SystemPartition = PartEntry;
3229
3230 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
3231 PartEntry->PartitionNumber,
3232 DiskEntry->DiskNumber,
3233 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
3234 break;
3235 }
3236 }
3237 }
3238
3239 /* Check if we have found the system partition */
3240 if (List->SystemPartition == NULL)
3241 {
3242 /* Nothing, use the alternative system partition */
3243 DPRINT1("No system partition found, use the alternative partition!\n");
3244 goto UseAlternativeSystemPartition;
3245 }
3246
3247 /* Save it */
3248 List->OriginalSystemPartition = List->SystemPartition;
3249
3250 /* If we get a candidate active partition, validate it */
3251 if (!IsSupportedActivePartition(List->OriginalSystemPartition))
3252 {
3253 goto FindAndUseAlternativeSystemPartition;
3254 }
3255
3256 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3257 List->SystemPartition->PartitionNumber,
3258 List->SystemPartition->DiskEntry->DiskNumber,
3259 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3260
3261 return;
3262
3263 FindAndUseAlternativeSystemPartition:
3264 /*
3265 * We are here because we have not found any (active) candidate
3266 * system partition that we know how to support. What we are going
3267 * to do is to change the existing system partition and use the
3268 * partition on which we install ReactOS as the new system partition,
3269 * and then we will need to add in FreeLdr's entry a boot entry to boot
3270 * from the original system partition.
3271 */
3272
3273 /* Unset the old system partition */
3274 List->SystemPartition->BootIndicator = FALSE;
3275 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
3276 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3277 List->SystemPartition->DiskEntry->Dirty = TRUE;
3278
3279 UseAlternativeSystemPartition:
3280 List->SystemPartition = List->CurrentPartition;
3281
3282 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3283 List->SystemPartition->PartitionNumber,
3284 List->SystemPartition->DiskEntry->DiskNumber,
3285 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3286
3287 SetSystemPartition:
3288 /* Set the new active system partition */
3289 List->SystemPartition->BootIndicator = TRUE;
3290 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3291 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3292 List->SystemPartition->DiskEntry->Dirty = TRUE;
3293 }
3294
3295 static
3296 NTSTATUS
3297 WritePartitions(
3298 IN PPARTLIST List,
3299 IN PDISKENTRY DiskEntry)
3300 {
3301 NTSTATUS Status;
3302 OBJECT_ATTRIBUTES ObjectAttributes;
3303 UNICODE_STRING Name;
3304 HANDLE FileHandle;
3305 IO_STATUS_BLOCK Iosb;
3306 ULONG BufferSize;
3307 PPARTITION_INFORMATION PartitionInfo;
3308 ULONG PartitionCount;
3309 PLIST_ENTRY ListEntry;
3310 PPARTENTRY PartEntry;
3311 WCHAR DstPath[MAX_PATH];
3312
3313 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3314
3315 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
3316 L"\\Device\\Harddisk%lu\\Partition0",
3317 DiskEntry->DiskNumber);
3318 RtlInitUnicodeString(&Name, DstPath);
3319
3320 InitializeObjectAttributes(&ObjectAttributes,
3321 &Name,
3322 OBJ_CASE_INSENSITIVE,
3323 NULL,
3324 NULL);
3325
3326 Status = NtOpenFile(&FileHandle,
3327 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3328 &ObjectAttributes,
3329 &Iosb,
3330 0,
3331 FILE_SYNCHRONOUS_IO_NONALERT);
3332 if (!NT_SUCCESS(Status))
3333 {
3334 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3335 return Status;
3336 }
3337
3338 #ifdef DUMP_PARTITION_TABLE
3339 DumpPartitionTable(DiskEntry);
3340 #endif
3341
3342 //
3343 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3344 // the disk in MBR or GPT format in case the disk was not initialized!!
3345 // For this we must ask the user which format to use.
3346 //
3347
3348 /* Save the original partition count to be restored later (see comment below) */
3349 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
3350
3351 /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3352 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3353 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3354 Status = NtDeviceIoControlFile(FileHandle,
3355 NULL,
3356 NULL,
3357 NULL,
3358 &Iosb,
3359 IOCTL_DISK_SET_DRIVE_LAYOUT,
3360 DiskEntry->LayoutBuffer,
3361 BufferSize,
3362 DiskEntry->LayoutBuffer,
3363 BufferSize);
3364 NtClose(FileHandle);
3365
3366 /*
3367 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3368 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3369 * where such a table is expected to enumerate up to 4 partitions:
3370 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3371 * Due to this we need to restore the original PartitionCount number.
3372 */
3373 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
3374
3375 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3376 if (!NT_SUCCESS(Status))
3377 {
3378 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3379 return Status;
3380 }
3381
3382 #ifdef DUMP_PARTITION_TABLE
3383 DumpPartitionTable(DiskEntry);
3384 #endif
3385
3386 /* Update the partition numbers */
3387
3388 /* Update the primary partition table */
3389 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3390 ListEntry != &DiskEntry->PrimaryPartListHead;
3391 ListEntry = ListEntry->Flink)
3392 {
3393 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3394
3395 if (PartEntry->IsPartitioned)
3396 {
3397 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3398 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3399 }
3400 }
3401
3402 /* Update the logical partition table */
3403 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
3404 ListEntry != &DiskEntry->LogicalPartListHead;
3405 ListEntry = ListEntry->Flink)
3406 {
3407 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3408
3409 if (PartEntry->IsPartitioned)
3410 {
3411 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3412 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3413 }
3414 }
3415
3416 //
3417 // NOTE: Originally (see r40437), we used to install here also a new MBR
3418 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3419 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3420 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3421 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3422 // was called too, the installation test was modified by checking whether
3423 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3424 //
3425
3426 // DiskEntry->Dirty = FALSE;
3427
3428 return Status;
3429 }
3430
3431 BOOLEAN
3432 WritePartitionsToDisk(
3433 IN PPARTLIST List)
3434 {
3435 PLIST_ENTRY Entry;
3436 PDISKENTRY DiskEntry;
3437
3438 if (List == NULL)
3439 return TRUE;
3440
3441 for (Entry = List->DiskListHead.Flink;
3442 Entry != &List->DiskListHead;
3443 Entry = Entry->Flink)
3444 {
3445 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3446
3447 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3448 {
3449 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3450 continue;
3451 }
3452
3453 if (DiskEntry->Dirty != FALSE)
3454 {
3455 WritePartitions(List, DiskEntry);
3456 DiskEntry->Dirty = FALSE;
3457 }
3458 }
3459
3460 return TRUE;
3461 }
3462
3463 BOOLEAN
3464 SetMountedDeviceValue(
3465 IN WCHAR Letter,
3466 IN ULONG Signature,
3467 IN LARGE_INTEGER StartingOffset)
3468 {
3469 OBJECT_ATTRIBUTES ObjectAttributes;
3470 WCHAR ValueNameBuffer[16];
3471 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3472 UNICODE_STRING ValueName;
3473 REG_DISK_MOUNT_INFO MountInfo;
3474 NTSTATUS Status;
3475 HANDLE KeyHandle;
3476
3477 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3478 L"\\DosDevices\\%c:", Letter);
3479 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3480
3481 InitializeObjectAttributes(&ObjectAttributes,
3482 &KeyName,
3483 OBJ_CASE_INSENSITIVE,
3484 NULL,
3485 NULL);
3486
3487 Status = NtOpenKey(&KeyHandle,
3488 KEY_ALL_ACCESS,
3489 &ObjectAttributes);
3490 if (!NT_SUCCESS(Status))
3491 {
3492 Status = NtCreateKey(&KeyHandle,
3493 KEY_ALL_ACCESS,
3494 &ObjectAttributes,
3495 0,
3496 NULL,
3497 REG_OPTION_NON_VOLATILE,
3498 NULL);
3499 }
3500
3501 if (!NT_SUCCESS(Status))
3502 {
3503 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3504 return FALSE;
3505 }
3506
3507 MountInfo.Signature = Signature;
3508 MountInfo.StartingOffset = StartingOffset;
3509 Status = NtSetValueKey(KeyHandle,
3510 &ValueName,
3511 0,
3512 REG_BINARY,
3513 (PVOID)&MountInfo,
3514 sizeof(MountInfo));
3515 NtClose(KeyHandle);
3516 if (!NT_SUCCESS(Status))
3517 {
3518 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3519 return FALSE;
3520 }
3521
3522 return TRUE;
3523 }
3524
3525 BOOLEAN
3526 SetMountedDeviceValues(
3527 IN PPARTLIST List)
3528 {
3529 PLIST_ENTRY Entry1, Entry2;
3530 PDISKENTRY DiskEntry;
3531 PPARTENTRY PartEntry;
3532 LARGE_INTEGER StartingOffset;
3533
3534 if (List == NULL)
3535 return FALSE;
3536
3537 for (Entry1 = List->DiskListHead.Flink;
3538 Entry1 != &List->DiskListHead;
3539 Entry1 = Entry1->Flink)
3540 {
3541 DiskEntry = CONTAINING_RECORD(Entry1,
3542 DISKENTRY,
3543 ListEntry);
3544
3545 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3546 {
3547 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3548 continue;
3549 }
3550
3551 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3552 Entry2 != &DiskEntry->PrimaryPartListHead;
3553 Entry2 = Entry2->Flink)
3554 {
3555 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3556 if (PartEntry->IsPartitioned)
3557 {
3558 /* Assign a "\DosDevices\#:" mount point to this partition */
3559 if (PartEntry->DriveLetter)
3560 {
3561 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3562 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3563 DiskEntry->LayoutBuffer->Signature,
3564 StartingOffset))
3565 {
3566 return FALSE;
3567 }
3568 }
3569 }
3570 }
3571
3572 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3573 Entry2 != &DiskEntry->LogicalPartListHead;
3574 Entry2 = Entry2->Flink)
3575 {
3576 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3577 if (PartEntry->IsPartitioned)
3578 {
3579 /* Assign a "\DosDevices\#:" mount point to this partition */
3580 if (PartEntry->DriveLetter)
3581 {
3582 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3583 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3584 DiskEntry->LayoutBuffer->Signature,
3585 StartingOffset))
3586 {
3587 return FALSE;
3588 }
3589 }
3590 }
3591 }
3592 }
3593
3594 return TRUE;
3595 }
3596
3597 VOID
3598 SetPartitionType(
3599 IN PPARTENTRY PartEntry,
3600 IN UCHAR PartitionType)
3601 {
3602 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3603
3604 PartEntry->PartitionType = PartitionType;
3605
3606 DiskEntry->Dirty = TRUE;
3607 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
3608 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
3609 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3610 }
3611
3612 ERROR_NUMBER
3613 PrimaryPartitionCreationChecks(
3614 IN PPARTLIST List)
3615 {
3616 PDISKENTRY DiskEntry;
3617 PPARTENTRY PartEntry;
3618
3619 DiskEntry = List->CurrentDisk;
3620 PartEntry = List->CurrentPartition;
3621
3622 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3623 {
3624 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3625 return ERROR_WARN_PARTITION;
3626 }
3627
3628 /* Fail if the partition is already in use */
3629 if (PartEntry->IsPartitioned)
3630 return ERROR_NEW_PARTITION;
3631
3632 /* Fail if there are already 4 primary partitions in the list */
3633 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3634 return ERROR_PARTITION_TABLE_FULL;
3635
3636 return ERROR_SUCCESS;
3637 }
3638
3639 ERROR_NUMBER
3640 ExtendedPartitionCreationChecks(
3641 IN PPARTLIST List)
3642 {
3643 PDISKENTRY DiskEntry;
3644 PPARTENTRY PartEntry;
3645
3646 DiskEntry = List->CurrentDisk;
3647 PartEntry = List->CurrentPartition;
3648
3649 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3650 {
3651 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3652 return ERROR_WARN_PARTITION;
3653 }
3654
3655 /* Fail if the partition is already in use */
3656 if (PartEntry->IsPartitioned)
3657 return ERROR_NEW_PARTITION;
3658
3659 /* Fail if there are already 4 primary partitions in the list */
3660 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3661 return ERROR_PARTITION_TABLE_FULL;
3662
3663 /* Fail if there is another extended partition in the list */
3664 if (DiskEntry->ExtendedPartition != NULL)
3665 return ERROR_ONLY_ONE_EXTENDED;
3666
3667 return ERROR_SUCCESS;
3668 }
3669
3670 ERROR_NUMBER
3671 LogicalPartitionCreationChecks(
3672 IN PPARTLIST List)
3673 {
3674 PDISKENTRY DiskEntry;
3675 PPARTENTRY PartEntry;
3676
3677 DiskEntry = List->CurrentDisk;
3678 PartEntry = List->CurrentPartition;
3679
3680 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3681 {
3682 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3683 return ERROR_WARN_PARTITION;
3684 }
3685
3686 /* Fail if the partition is already in use */
3687 if (PartEntry->IsPartitioned)
3688 return ERROR_NEW_PARTITION;
3689
3690 return ERROR_SUCCESS;
3691 }
3692
3693 BOOLEAN
3694 GetNextUnformattedPartition(
3695 IN PPARTLIST List,
3696 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3697 OUT PPARTENTRY *pPartEntry)
3698 {
3699 PLIST_ENTRY Entry1, Entry2;
3700 PDISKENTRY DiskEntry;
3701 PPARTENTRY PartEntry;
3702
3703 for (Entry1 = List->DiskListHead.Flink;
3704 Entry1 != &List->DiskListHead;
3705 Entry1 = Entry1->Flink)
3706 {
3707 DiskEntry = CONTAINING_RECORD(Entry1,
3708 DISKENTRY,
3709 ListEntry);
3710
3711 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3712 {
3713 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3714 continue;
3715 }
3716
3717 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3718 Entry2 != &DiskEntry->PrimaryPartListHead;
3719 Entry2 = Entry2->Flink)
3720 {
3721 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3722 if (PartEntry->IsPartitioned && PartEntry->New)
3723 {
3724 ASSERT(DiskEntry == PartEntry->DiskEntry);
3725 if (pDiskEntry) *pDiskEntry = DiskEntry;
3726 *pPartEntry = PartEntry;
3727 return TRUE;
3728 }
3729 }
3730
3731 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3732 Entry2 != &DiskEntry->LogicalPartListHead;
3733 Entry2 = Entry2->Flink)
3734 {
3735 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3736 if (PartEntry->IsPartitioned && PartEntry->New)
3737 {
3738 ASSERT(DiskEntry == PartEntry->DiskEntry);
3739 if (pDiskEntry) *pDiskEntry = DiskEntry;
3740 *pPartEntry = PartEntry;
3741 return TRUE;
3742 }
3743 }
3744 }
3745
3746 if (pDiskEntry) *pDiskEntry = NULL;
3747 *pPartEntry = NULL;
3748
3749 return FALSE;
3750 }
3751
3752 BOOLEAN
3753 GetNextUncheckedPartition(
3754 IN PPARTLIST List,
3755 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3756 OUT PPARTENTRY *pPartEntry)
3757 {
3758 PLIST_ENTRY Entry1, Entry2;
3759 PDISKENTRY DiskEntry;
3760 PPARTENTRY PartEntry;
3761
3762 for (Entry1 = List->DiskListHead.Flink;
3763 Entry1 != &List->DiskListHead;
3764 Entry1 = Entry1->Flink)
3765 {
3766 DiskEntry = CONTAINING_RECORD(Entry1,
3767 DISKENTRY,
3768 ListEntry);
3769
3770 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3771 {
3772 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3773 continue;
3774 }
3775
3776 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3777 Entry2 != &DiskEntry->PrimaryPartListHead;
3778 Entry2 = Entry2->Flink)
3779 {
3780 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3781 if (PartEntry->NeedsCheck == TRUE)
3782 {
3783 ASSERT(DiskEntry == PartEntry->DiskEntry);
3784 if (pDiskEntry) *pDiskEntry = DiskEntry;
3785 *pPartEntry = PartEntry;
3786 return TRUE;
3787 }
3788 }
3789
3790 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
3791 Entry2 != &DiskEntry->LogicalPartListHead;
3792 Entry2 = Entry2->Flink)
3793 {
3794 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3795 if (PartEntry->NeedsCheck == TRUE)
3796 {
3797 ASSERT(DiskEntry == PartEntry->DiskEntry);
3798 if (pDiskEntry) *pDiskEntry = DiskEntry;
3799 *pPartEntry = PartEntry;
3800 return TRUE;
3801 }
3802 }
3803 }
3804
3805 if (pDiskEntry) *pDiskEntry = NULL;
3806 *pPartEntry = NULL;
3807
3808 return FALSE;
3809 }
3810
3811 /* EOF */