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