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