ReactOS 0.4.16-dev-2491-g3dc6630
partlist.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Partition list functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2018-2024 Hermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
7 */
8
9#include "precomp.h"
10#include <ntddscsi.h>
11#include <mountdev.h> // For IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
12
13#include "partlist.h"
14#include "volutil.h"
15#include "fsrec.h" // For FileSystemToMBRPartitionType()
16#include "devutils.h"
17
18#include "registry.h"
19
20#define NDEBUG
21#include <debug.h>
22
23// #define DUMP_PARTITION_TABLE
24
25#include <pshpack1.h>
27{
31#include <poppack.h>
32
33
34/* FUNCTIONS ****************************************************************/
35
36#ifdef DUMP_PARTITION_TABLE
37static
38VOID
39DumpPartitionTable(
40 PDISKENTRY DiskEntry)
41{
43 ULONG i;
44
45 DbgPrint("\n");
46 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
47 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
48
49 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
50 {
52 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
53 i,
54 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
55 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
56 PartitionInfo->HiddenSectors,
57 PartitionInfo->PartitionNumber,
58 PartitionInfo->PartitionType,
59 PartitionInfo->BootIndicator ? '*': ' ',
60 PartitionInfo->RewritePartition ? 'Y': 'N');
61 }
62
63 DbgPrint("\n");
64}
65#endif
66
67
72{
73 ULONGLONG Temp;
74
75 Temp = Value / Alignment;
76
77 return Temp * Alignment;
78}
79
84{
85 ULONGLONG Temp, Result;
86
87 Temp = Value / Alignment;
88
89 Result = Temp * Alignment;
90 if (Value % Alignment)
92
93 return Result;
94}
95
98 IN ULONGLONG Dividend,
100{
101 return (Dividend + Divisor / 2) / Divisor;
102}
103
104
105static
106VOID
108 IN PDISKENTRY DiskEntry)
109{
111 WCHAR KeyName[32];
113
114 RtlInitUnicodeString(&DiskEntry->DriverName, NULL);
115
117 L"\\Scsi\\Scsi Port %hu",
118 DiskEntry->Port);
119
121
122 QueryTable[0].Name = L"Driver";
124 QueryTable[0].EntryContext = &DiskEntry->DriverName;
125
126 /* This will allocate DiskEntry->DriverName if needed */
128 KeyName,
130 NULL,
131 NULL);
132 if (!NT_SUCCESS(Status))
133 {
134 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
135 }
136}
137
138static
139VOID
142{
143 PDISKENTRY DiskEntry;
144 PPARTENTRY PartEntry;
145 PLIST_ENTRY Entry1;
146 PLIST_ENTRY Entry2;
148
149 Letter = L'C';
150
151 /* Assign drive letters to primary partitions */
152 for (Entry1 = List->DiskListHead.Flink;
153 Entry1 != &List->DiskListHead;
154 Entry1 = Entry1->Flink)
155 {
156 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
157
158 for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
159 Entry2 != &DiskEntry->PrimaryPartListHead;
160 Entry2 = Entry2->Flink)
161 {
162 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
163
164 if (!PartEntry->Volume)
165 continue;
166 PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
167
168 if (PartEntry->IsPartitioned &&
169 !IsContainerPartition(PartEntry->PartitionType) &&
171 PartEntry->SectorCount.QuadPart != 0LL))
172 {
173 if (Letter <= L'Z')
174 PartEntry->Volume->Info.DriveLetter = Letter++;
175 }
176 }
177 }
178
179 /* Assign drive letters to logical drives */
180 for (Entry1 = List->DiskListHead.Flink;
181 Entry1 != &List->DiskListHead;
182 Entry1 = Entry1->Flink)
183 {
184 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
185
186 for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
187 Entry2 != &DiskEntry->LogicalPartListHead;
188 Entry2 = Entry2->Flink)
189 {
190 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
191
192 if (!PartEntry->Volume)
193 continue;
194 PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
195
196 if (PartEntry->IsPartitioned &&
198 PartEntry->SectorCount.QuadPart != 0LL))
199 {
200 if (Letter <= L'Z')
201 PartEntry->Volume->Info.DriveLetter = Letter++;
202 }
203 }
204 }
205}
206
207static NTSTATUS
208NTAPI
216{
217 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
218 UNICODE_STRING NameU;
219
220 if (ValueType == REG_SZ &&
221 ValueLength == 20 * sizeof(WCHAR) &&
222 ((PWCHAR)ValueData)[8] == L'-')
223 {
224 NameU.Buffer = (PWCHAR)ValueData;
225 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
226 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
227
228 NameU.Buffer = (PWCHAR)ValueData + 9;
229 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
230
231 return STATUS_SUCCESS;
232 }
233
234 return STATUS_UNSUCCESSFUL;
235}
236
237static NTSTATUS
238NTAPI
246{
247 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
248 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
250 ULONG i;
251
254 return STATUS_UNSUCCESSFUL;
255
256 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
257
258 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
259#if 0
260 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
261 FullResourceDescriptor->PartialResourceList.Revision != 1)
262 return STATUS_UNSUCCESSFUL;
263#endif
264
265 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
266 {
269 continue;
270
271 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
272 BiosDiskEntry->DiskGeometry = *DiskGeometry;
273
274 return STATUS_SUCCESS;
275 }
276
277 return STATUS_UNSUCCESSFUL;
278}
279
280static NTSTATUS
281NTAPI
289{
290 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
292 ULONG i;
293
296 return STATUS_UNSUCCESSFUL;
297
298 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
299
300 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
301#if 0
302 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
303 FullResourceDescriptor->PartialResourceList.Revision != 1)
304 return STATUS_UNSUCCESSFUL;
305#endif
306
307 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
308 {
310 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
311 continue;
312
314 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
315 if (*Int13Drives == NULL)
316 return STATUS_NO_MEMORY;
317
318 memcpy(*Int13Drives,
319 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
320 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
321 return STATUS_SUCCESS;
322 }
323
324 return STATUS_UNSUCCESSFUL;
325}
326
327
328static VOID
330 IN PPARTLIST PartList)
331{
333 WCHAR Name[120];
334 ULONG AdapterCount;
336 ULONG DiskCount;
338 PCM_INT13_DRIVE_PARAMETER Int13Drives;
339 PBIOSDISKENTRY BiosDiskEntry;
340
341#define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
342
343 memset(QueryTable, 0, sizeof(QueryTable));
344
345 QueryTable[1].Name = L"Configuration Data";
347 Int13Drives = NULL;
349 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
350 &QueryTable[1],
351 (PVOID)&Int13Drives,
352 NULL);
353 if (!NT_SUCCESS(Status))
354 {
355 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
356 return;
357 }
358
359 for (AdapterCount = 0; ; ++AdapterCount)
360 {
362 L"%s\\%lu",
363 ROOT_NAME, AdapterCount);
365 Name,
366 &QueryTable[2],
367 NULL,
368 NULL);
369 if (!NT_SUCCESS(Status))
370 {
371 break;
372 }
373
375 L"%s\\%lu\\DiskController",
376 ROOT_NAME, AdapterCount);
378 Name,
379 &QueryTable[2],
380 NULL,
381 NULL);
382 if (NT_SUCCESS(Status))
383 {
384 for (ControllerCount = 0; ; ++ControllerCount)
385 {
387 L"%s\\%lu\\DiskController\\%lu",
388 ROOT_NAME, AdapterCount, ControllerCount);
390 Name,
391 &QueryTable[2],
392 NULL,
393 NULL);
394 if (!NT_SUCCESS(Status))
395 {
396 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
397 return;
398 }
399
401 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral",
402 ROOT_NAME, AdapterCount, ControllerCount);
404 Name,
405 &QueryTable[2],
406 NULL,
407 NULL);
408 if (NT_SUCCESS(Status))
409 {
410 QueryTable[0].Name = L"Identifier";
412 QueryTable[1].Name = L"Configuration Data";
414
415 for (DiskCount = 0; ; ++DiskCount)
416 {
418 if (BiosDiskEntry == NULL)
419 {
420 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
421 return;
422 }
423
425 L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu",
426 ROOT_NAME, AdapterCount, ControllerCount, DiskCount);
428 Name,
430 (PVOID)BiosDiskEntry,
431 NULL);
432 if (!NT_SUCCESS(Status))
433 {
434 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
435 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
436 return;
437 }
438
439 BiosDiskEntry->AdapterNumber = 0; // And NOT "AdapterCount" as it needs to be hardcoded for BIOS!
440 BiosDiskEntry->ControllerNumber = ControllerCount;
441 BiosDiskEntry->DiskNumber = DiskCount;
442 BiosDiskEntry->DiskEntry = NULL;
443
444 if (DiskCount < Int13Drives[0].NumberDrives)
445 {
446 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
447 }
448 else
449 {
450 DPRINT1("Didn't find Int13 drive data for disk %u\n", DiskCount);
451 }
452
453 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
454
455 DPRINT("--->\n");
456 DPRINT("AdapterNumber: %lu\n", BiosDiskEntry->AdapterNumber);
457 DPRINT("ControllerNumber: %lu\n", BiosDiskEntry->ControllerNumber);
458 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
459 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
460 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
461 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
462 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
463 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
464 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
465 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
466 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
467 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
468 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
469 DPRINT("<---\n");
470 }
471 }
472 }
473 }
474 }
475
476 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
477
478#undef ROOT_NAME
479}
480
481
482/*
483 * Detects whether a disk is a "super-floppy", i.e. an unpartitioned
484 * disk with only a valid VBR, as reported by IoReadPartitionTable()
485 * and IoWritePartitionTable():
486 * only one single partition starting at offset zero and spanning the
487 * whole disk, without hidden sectors, whose type is FAT16 non-bootable.
488 *
489 * Accessing \Device\HarddiskN\Partition0 or Partition1 on such disks
490 * returns the same data.
491 */
494 _In_ const DISK_PARTITION_INFO* DiskInfo,
495 _In_opt_ const ULONGLONG* DiskSize,
497{
498 /* Structure size must be valid */
499 if (DiskInfo->SizeOfPartitionInfo < RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr))
500 return FALSE;
501
502 /* The layout must be MBR */
503 if (DiskInfo->PartitionStyle != PARTITION_STYLE_MBR)
504 return FALSE;
505
506 /* The single partition must start at the beginning of the disk */
507 if (!(PartitionInfo->StartingOffset.QuadPart == 0 &&
508 PartitionInfo->HiddenSectors == 0))
509 {
510 return FALSE;
511 }
512
513 /* The disk signature is usually set to 1; warn in case it's not */
514 if (DiskInfo->Mbr.Signature != 1)
515 {
516 DPRINT1("Super-Floppy signature %08x != 1\n", DiskInfo->Mbr.Signature);
517 }
518
519 /* The partition must be recognized and report as FAT16 non-bootable */
520 if ((PartitionInfo->RecognizedPartition != TRUE) ||
521 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
522 (PartitionInfo->BootIndicator != FALSE))
523 {
524 DPRINT1("Super-Floppy does not return default settings:\n"
525 " RecognizedPartition = %s, expected TRUE\n"
526 " PartitionType = 0x%02x, expected 0x04 (PARTITION_FAT_16)\n"
527 " BootIndicator = %s, expected FALSE\n",
528 PartitionInfo->RecognizedPartition ? "TRUE" : "FALSE",
529 PartitionInfo->PartitionType,
530 PartitionInfo->BootIndicator ? "TRUE" : "FALSE");
531 }
532
533 /* The partition and disk sizes should agree */
534 if (DiskSize && (PartitionInfo->PartitionLength.QuadPart != *DiskSize))
535 {
536 DPRINT1("PartitionLength = %I64u is different from DiskSize = %I64u\n",
537 PartitionInfo->PartitionLength.QuadPart, *DiskSize);
538 }
539
540 return TRUE;
541}
542
545 _In_ const DRIVE_LAYOUT_INFORMATION* Layout,
546 _In_opt_ const ULONGLONG* DiskSize)
547{
548 DISK_PARTITION_INFO DiskInfo;
549
550 /* The layout must contain only one partition */
551 if (Layout->PartitionCount != 1)
552 return FALSE;
553
554 /* Build the disk partition info */
555 DiskInfo.SizeOfPartitionInfo = RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr);
556 DiskInfo.PartitionStyle = PARTITION_STYLE_MBR;
557 DiskInfo.Mbr.Signature = Layout->Signature;
558 DiskInfo.Mbr.CheckSum = 0; // Dummy value
559
560 /* Call the helper on the single partition entry */
561 return IsDiskSuperFloppy2(&DiskInfo, DiskSize, Layout->PartitionEntry);
562}
563
566 _In_ const DRIVE_LAYOUT_INFORMATION_EX* LayoutEx,
567 _In_opt_ const ULONGLONG* DiskSize)
568{
569 DISK_PARTITION_INFO DiskInfo;
570 const PARTITION_INFORMATION_EX* PartitionInfoEx;
572
573 /* The layout must be MBR and contain only one partition */
574 if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
575 return FALSE;
576 if (LayoutEx->PartitionCount != 1)
577 return FALSE;
578
579 /* Build the disk partition info */
580 DiskInfo.SizeOfPartitionInfo = RTL_SIZEOF_THROUGH_FIELD(DISK_PARTITION_INFO, Mbr);
581 DiskInfo.PartitionStyle = PARTITION_STYLE_MBR; // LayoutEx->PartitionStyle;
582 DiskInfo.Mbr.Signature = LayoutEx->Mbr.Signature;
583 DiskInfo.Mbr.CheckSum = 0; // Dummy value
584
585 /* Convert the single partition entry */
586 PartitionInfoEx = LayoutEx->PartitionEntry;
587
588 PartitionInfo.StartingOffset = PartitionInfoEx->StartingOffset;
589 PartitionInfo.PartitionLength = PartitionInfoEx->PartitionLength;
590 PartitionInfo.HiddenSectors = PartitionInfoEx->Mbr.HiddenSectors;
591 PartitionInfo.PartitionNumber = PartitionInfoEx->PartitionNumber;
592 PartitionInfo.PartitionType = PartitionInfoEx->Mbr.PartitionType;
593 PartitionInfo.BootIndicator = PartitionInfoEx->Mbr.BootIndicator;
594 PartitionInfo.RecognizedPartition = PartitionInfoEx->Mbr.RecognizedPartition;
595 PartitionInfo.RewritePartition = PartitionInfoEx->RewritePartition;
596
597 /* Call the helper on the single partition entry */
598 return IsDiskSuperFloppy2(&DiskInfo, DiskSize, &PartitionInfo);
599}
600
603 _In_ PDISKENTRY DiskEntry)
604{
605 ULONGLONG DiskSize;
606
607 /* No layout buffer: we cannot say anything yet */
608 if (!DiskEntry->LayoutBuffer)
609 return FALSE;
610
611 /* The disk must be MBR */
612 if (DiskEntry->DiskStyle != PARTITION_STYLE_MBR)
613 return FALSE;
614
615 DiskSize = GetDiskSizeInBytes(DiskEntry);
616 return IsDiskSuperFloppy(DiskEntry->LayoutBuffer, &DiskSize);
617}
618
619
620/*
621 * Inserts the disk region represented by PartEntry into either
622 * the primary or the logical partition list of the given disk.
623 * The lists are kept sorted by increasing order of start sectors.
624 * Of course no disk region should overlap at all with one another.
625 */
626static
629 IN PDISKENTRY DiskEntry,
630 IN PPARTENTRY PartEntry,
632{
635 PPARTENTRY PartEntry2;
636
637 /* Use the correct partition list */
639 List = &DiskEntry->LogicalPartListHead;
640 else
641 List = &DiskEntry->PrimaryPartListHead;
642
643 /* Find the first disk region before which we need to insert the new one */
644 for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
645 {
646 PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
647
648 /* Ignore any unused empty region */
649 if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
650 PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
651 {
652 continue;
653 }
654
655 /* If the current region ends before the one to be inserted, try again */
656 if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
657 continue;
658
659 /*
660 * One of the disk region boundaries crosses the desired region
661 * (it starts after the desired region, or ends before the end
662 * of the desired region): this is an impossible situation because
663 * disk regions (partitions) cannot overlap!
664 * Throw an error and bail out.
665 */
666 if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
667 <=
668 min( PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
669 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
670 {
671 DPRINT1("Disk region overlap problem, stopping there!\n"
672 "Partition to be inserted:\n"
673 " StartSector = %I64u ; EndSector = %I64u\n"
674 "Existing disk region:\n"
675 " StartSector = %I64u ; EndSector = %I64u\n",
676 PartEntry->StartSector.QuadPart,
677 PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1,
678 PartEntry2->StartSector.QuadPart,
679 PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
680 return FALSE;
681 }
682
683 /* We have found the first region before which the new one has to be inserted */
684 break;
685 }
686
687 /* Insert the disk region */
688 InsertTailList(Entry, &PartEntry->ListEntry);
689 return TRUE;
690}
691
692static
695 IN PDISKENTRY DiskEntry,
696 IN OUT PLIST_ENTRY ListHead,
697 IN ULONGLONG StartSector,
699 IN BOOLEAN LogicalSpace)
700{
701 PPARTENTRY NewPartEntry;
702
703 NewPartEntry = RtlAllocateHeap(ProcessHeap,
705 sizeof(PARTENTRY));
706 if (!NewPartEntry)
707 return NULL;
708
709 NewPartEntry->DiskEntry = DiskEntry;
710
711 NewPartEntry->StartSector.QuadPart = StartSector;
712 NewPartEntry->SectorCount.QuadPart = SectorCount;
713
714 NewPartEntry->LogicalPartition = LogicalSpace;
715 NewPartEntry->IsPartitioned = FALSE;
717 NewPartEntry->Volume = NULL;
718
719 DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
720 DPRINT1("Last Sector : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
721 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
722
723 /* Insert the new entry into the list */
724 InsertTailList(ListHead, &NewPartEntry->ListEntry);
725
726 return NewPartEntry;
727}
728
729static
730VOID
732 _Inout_ PPARTENTRY PartEntry)
733{
734 // RemoveEntryList(&PartEntry->Volume->ListEntry);
735 if (PartEntry->Volume)
736 RtlFreeHeap(ProcessHeap, 0, PartEntry->Volume);
737 RtlFreeHeap(ProcessHeap, 0, PartEntry);
738}
739
740static
741VOID
743 _In_ PDISKENTRY DiskEntry)
744{
745 ULONGLONG StartSector;
747 PPARTENTRY NewPartEntry;
748
749 DPRINT("AddLogicalDiskSpace()\n");
750
751 /* Create a partition entry that represents the empty space in the container partition */
752
753 StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
754 SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
755
756 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
757 &DiskEntry->LogicalPartListHead,
758 StartSector,
760 TRUE);
761 if (!NewPartEntry)
762 DPRINT1("Failed to create a new empty region for full extended partition space!\n");
763}
764
765// TODO: Improve upon the PartitionInfo parameter later
766// (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example)
767// So far we only use it as the optional type of the partition to create.
768//
769// See also CreatePartition().
770static
773 _Inout_ PPARTENTRY PartEntry,
774 _In_opt_ ULONGLONG SizeBytes,
776{
777 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
780
781 DPRINT1("Current entry sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
782
783 /* The entry must not be already partitioned and not be void */
784 ASSERT(!PartEntry->IsPartitioned);
785 ASSERT(PartEntry->SectorCount.QuadPart);
786 ASSERT(!PartEntry->Volume);
787
788 /* Either we create a primary/logical partition, or we create an
789 * extended partition but the entry must not be logical space */
790 ASSERT(!isContainer || !PartEntry->LogicalPartition);
791
792 /* Convert the size in bytes to sector count. SizeBytes being
793 * zero means the caller wants to use all the empty space. */
794 if ((SizeBytes == 0) || (SizeBytes == GetPartEntrySizeInBytes(PartEntry)))
795 {
796 /* Use all of the unpartitioned disk space */
797 SectorCount = PartEntry->SectorCount.QuadPart;
798 }
799 else
800 {
801 SectorCount = SizeBytes / DiskEntry->BytesPerSector;
802 if (SectorCount == 0)
803 {
804 /* SizeBytes was certainly less than the minimal size, so fail */
805 DPRINT1("Partition size %I64u too small\n", SizeBytes);
806 return FALSE;
807 }
808 }
809 DPRINT1(" New sector count: %I64u\n", SectorCount);
810
811 /* Fail if we request more sectors than what the entry actually contains */
812 if (SectorCount > PartEntry->SectorCount.QuadPart)
813 return FALSE;
814
815 if ((SectorCount == 0) ||
816 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
817 PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
818 {
819 /* Reuse the whole current entry */
820 }
821 else
822 {
823 ULONGLONG StartSector;
824 ULONGLONG SectorCount2;
825 PPARTENTRY NewPartEntry;
826
827 /* Create a partition entry that represents the remaining space
828 * after the partition to be initialized */
829
830 StartSector = AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment);
831 SectorCount2 = PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - StartSector;
832
833 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
834 PartEntry->ListEntry.Flink,
835 StartSector,
836 SectorCount2,
837 PartEntry->LogicalPartition);
838 if (!NewPartEntry)
839 {
840 DPRINT1("Failed to create a new empty region for disk space!\n");
841 return FALSE;
842 }
843
844 /* Resize down the partition entry; its StartSector remains the same */
845 PartEntry->SectorCount.QuadPart = StartSector - PartEntry->StartSector.QuadPart;
846 }
847
848 /* Convert to a new partition entry */
849 PartEntry->New = TRUE;
850 PartEntry->IsPartitioned = TRUE;
851
852 PartEntry->BootIndicator = FALSE;
853 if (PartitionInfo)
854 {
855 if (!isContainer)
856 {
857 PartEntry->PartitionType = (UCHAR)PartitionInfo;
858 }
859 else
860 {
861 /* Set the correct extended container partition type,
862 * depending on whether it is contained below or above
863 * the 1024-cylinder (usually 8.4GB/7.8GiB) boundary:
864 * - below: INT13h CHS partition;
865 * - above: Extended INT13h LBA partition. */
866 if ((PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1)
867 / (DiskEntry->TracksPerCylinder * DiskEntry->SectorsPerTrack) < 1024)
868 {
869 PartEntry->PartitionType = PARTITION_EXTENDED;
870 }
871 else
872 {
873 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
874 }
875 }
876 }
877 else
878 {
879// FIXME: Use FileSystemToMBRPartitionType() only for MBR, otherwise use PARTITION_BASIC_DATA_GUID.
880 ASSERT(!isContainer);
881 PartEntry->PartitionType = FileSystemToMBRPartitionType(L"RAW",
882 PartEntry->StartSector.QuadPart,
883 PartEntry->SectorCount.QuadPart);
884 }
885 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
886
887 if (isContainer)
888 {
889 DiskEntry->ExtendedPartition = PartEntry;
890 AddLogicalDiskSpace(DiskEntry);
891 }
892
893 DPRINT1("First Sector : %I64u\n", PartEntry->StartSector.QuadPart);
894 DPRINT1("Last Sector : %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
895 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
896
897 return TRUE;
898}
899
900static
901VOID
903 _Inout_ PPARTENTRY PartEntry)
904{
906
907 /* Ignore if this is a container partition */
908 if (IsContainerPartition(PartEntry->PartitionType))
909 return;
910 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
911
912 /* Make a device name for the partition */
913 Status = RtlStringCchPrintfW(PartEntry->DeviceName,
914 _countof(PartEntry->DeviceName),
915 L"\\Device\\Harddisk%lu\\Partition%lu",
916 PartEntry->DiskEntry->DiskNumber,
917 PartEntry->PartitionNumber);
919}
920
921static
925 _In_opt_ PCWSTR AltDeviceName)
926{
930 /*
931 * This variable is used to store the device name for
932 * the output buffer to IOCTL_MOUNTDEV_QUERY_DEVICE_NAME.
933 * It's based on MOUNTDEV_NAME (mountmgr.h).
934 * Doing it this way prevents memory allocation.
935 * The device name won't be longer.
936 */
937 struct
938 {
939 USHORT NameLength;
940 WCHAR Name[256];
941 } DeviceName;
942
943 /* If the volume already has a device name, do nothing more */
944 if (*Volume->Info.DeviceName)
945 return STATUS_SUCCESS;
946
947 if (!AltDeviceName)
948 {
949 PPARTENTRY PartEntry = Volume->PartEntry;
950 ASSERT(PartEntry);
951 ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
952 AltDeviceName = PartEntry->DeviceName;
953 }
954
955 /* Make a temporary volume device name */
956 Status = RtlStringCchCopyW(Volume->Info.DeviceName,
957 _countof(Volume->Info.DeviceName),
958 AltDeviceName);
960
961 /* Try to open the volume (if it is valid, this will also mount it) */
962 Status = pOpenDevice(Volume->Info.DeviceName, &VolumeHandle);
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT1("pOpenDevice() failed, Status 0x%08lx\n", Status);
966 return Status;
967 }
968
969 /* Retrieve the non-persistent volume device name */
971 NULL, NULL, NULL,
974 NULL, 0,
975 &DeviceName, sizeof(DeviceName));
977
978 // NOTE: If a memory allocation were needed, Status would be
979 // equal to STATUS_BUFFER_OVERFLOW, and one would allocate
980 // a buffer of size
981 // FIELD_OFFSET(MOUNTDEV_NAME, Name[0]) + DeviceName.NameLength
982 // before calling the IOCTL again on the new buffer and size.
983
984 if (!NT_SUCCESS(Status))
985 {
986 DPRINT1("IOCTL_MOUNTDEV_QUERY_DEVICE_NAME failed, Status 0x%08lx\n", Status);
987 return Status;
988 }
989
990 /* Copy the volume device name */
991 Status = RtlStringCchCopyNW(Volume->Info.DeviceName,
992 _countof(Volume->Info.DeviceName),
993 DeviceName.Name,
994 DeviceName.NameLength / sizeof(WCHAR));
996 return STATUS_SUCCESS;
997}
998
999static
1003 _In_opt_ PPARTENTRY PartEntry)
1004{
1006
1009 sizeof(VOLENTRY));
1010 if (!Volume)
1011 return NULL;
1012
1013 /* Reset some volume information */
1014
1015 /* No device name for now */
1016 Volume->Info.DeviceName[0] = UNICODE_NULL;
1017 // Volume->Info.VolumeName[0] = UNICODE_NULL;
1018
1019 /* Initialize the volume letter and label */
1020 Volume->Info.DriveLetter = UNICODE_NULL;
1021 Volume->Info.VolumeLabel[0] = UNICODE_NULL;
1022
1023 /* Specify the volume as initially unformatted */
1024 Volume->Info.FileSystem[0] = UNICODE_NULL;
1025 Volume->FormatState = Unformatted;
1026 Volume->NeedsCheck = FALSE;
1027 Volume->New = TRUE;
1028
1029 if (PartEntry)
1030 {
1031 ASSERT(PartEntry->DiskEntry->PartList == List);
1032 Volume->PartEntry = PartEntry;
1033 }
1034 InsertTailList(&List->VolumesList, &Volume->ListEntry);
1035 return Volume;
1036}
1037
1038static
1039VOID
1041 IN ULONG DiskNumber,
1042 IN PDISKENTRY DiskEntry,
1043 IN ULONG PartitionIndex,
1045{
1047 PPARTENTRY PartEntry;
1048
1049 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
1050
1051 /* Ignore empty partitions */
1052 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED)
1053 return;
1054 /* Request must be consistent, though! */
1056
1057 PartEntry = RtlAllocateHeap(ProcessHeap,
1059 sizeof(PARTENTRY));
1060 if (!PartEntry)
1061 return;
1062
1063 PartEntry->DiskEntry = DiskEntry;
1064
1065 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
1066 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
1067
1068 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
1069 PartEntry->PartitionType = PartitionInfo->PartitionType;
1070
1072 PartEntry->IsPartitioned = TRUE;
1073 PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
1074 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
1075 PartEntry->PartitionIndex = PartitionIndex;
1076 InitPartitionDeviceName(PartEntry);
1077
1078 /* No volume initially */
1079 PartEntry->Volume = NULL;
1080
1081 if (IsContainerPartition(PartEntry->PartitionType))
1082 {
1083 if (!LogicalPartition && DiskEntry->ExtendedPartition == NULL)
1084 DiskEntry->ExtendedPartition = PartEntry;
1085 }
1086 else if (IsRecognizedPartition(PartEntry->PartitionType) || // PartitionInfo->RecognizedPartition
1087 IsOEMPartition(PartEntry->PartitionType))
1088 {
1091
1092 ASSERT(PartEntry->PartitionNumber != 0);
1093
1094 /* The PARTMGR should have notified the MOUNTMGR that a volume
1095 * associated with this partition had to be created */
1096 Volume = InitVolume(DiskEntry->PartList, PartEntry);
1097 if (!Volume)
1098 {
1099 DPRINT1("Couldn't allocate a volume for device '%S'\n",
1100 PartEntry->DeviceName);
1101 goto SkipVolume;
1102 }
1103 PartEntry->Volume = Volume;
1105 Volume->New = FALSE;
1106
1107 /* Attach and mount the volume */
1108 Status = MountVolume(&Volume->Info, PartEntry->PartitionType);
1109 if (!NT_SUCCESS(Status))
1110 {
1111 DPRINT1("Failed to mount volume '%S', Status 0x%08lx\n",
1112 Volume->Info.DeviceName, Status);
1113 }
1114
1115 //
1116 // FIXME: TEMP Backward-compatibility: Set the FormatState
1117 // flag in accordance with the FileSystem volume value.
1118 //
1119 /*
1120 * MountVolume() determines whether the given volume is actually
1121 * unformatted, if it was mounted with RawFS and the partition
1122 * type has specific values for FAT volumes. If so, the volume
1123 * stays mounted with RawFS (the FileSystem is "RAW"). However,
1124 * if the partition type has different values, the volume is
1125 * considered as having an unknown format (it may or may not be
1126 * formatted) and the FileSystem value has been emptied.
1127 */
1128 if (IsUnknown(&Volume->Info))
1129 Volume->FormatState = UnknownFormat;
1130 else if (IsUnformatted(&Volume->Info)) // FileSystem is "RAW"
1131 Volume->FormatState = Unformatted;
1132 else // !IsUnknown && !IsUnformatted == IsFormatted
1133 Volume->FormatState = Formatted;
1134SkipVolume:;
1135 }
1136 else
1137 {
1138 /* Unknown partition (may or may not be actually formatted):
1139 * the partition is hidden, hence no volume */
1140 DPRINT1("Disk %lu Partition %lu is not recognized (Type 0x%02x)\n",
1141 DiskEntry->DiskNumber, PartEntry->PartitionNumber,
1142 PartEntry->PartitionType);
1143 }
1144
1145 InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
1146}
1147
1148static
1149VOID
1151 IN PDISKENTRY DiskEntry)
1152{
1153 ULONGLONG StartSector;
1155 ULONGLONG LastStartSector;
1156 ULONGLONG LastSectorCount;
1157 ULONGLONG LastUnusedSectorCount;
1158 PPARTENTRY PartEntry;
1159 PPARTENTRY NewPartEntry;
1161
1162 DPRINT("ScanForUnpartitionedDiskSpace()\n");
1163
1164 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1165 {
1166 DPRINT1("No primary partition!\n");
1167
1168 /* Create a partition entry that represents the empty disk */
1169
1170 if (DiskEntry->SectorAlignment < 2048)
1171 StartSector = 2048ULL;
1172 else
1173 StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1174 SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
1175
1176 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1177 &DiskEntry->PrimaryPartListHead,
1178 StartSector,
1180 FALSE);
1181 if (!NewPartEntry)
1182 DPRINT1("Failed to create a new empty region for full disk space!\n");
1183
1184 return;
1185 }
1186
1187 /* Start partition at head 1, cylinder 0 */
1188 if (DiskEntry->SectorAlignment < 2048)
1189 LastStartSector = 2048ULL;
1190 else
1191 LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1192 LastSectorCount = 0ULL;
1193 LastUnusedSectorCount = 0ULL;
1194
1195 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1196 Entry != &DiskEntry->PrimaryPartListHead;
1197 Entry = Entry->Flink)
1198 {
1199 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1200
1201 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1202 PartEntry->SectorCount.QuadPart != 0ULL)
1203 {
1204 LastUnusedSectorCount =
1205 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1206
1207 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1208 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1209 {
1210 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1211
1212 StartSector = LastStartSector + LastSectorCount;
1213 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1214
1215 /* Insert the table into the list */
1216 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1217 &PartEntry->ListEntry,
1218 StartSector,
1220 FALSE);
1221 if (!NewPartEntry)
1222 {
1223 DPRINT1("Failed to create a new empty region for disk space!\n");
1224 return;
1225 }
1226 }
1227
1228 LastStartSector = PartEntry->StartSector.QuadPart;
1229 LastSectorCount = PartEntry->SectorCount.QuadPart;
1230 }
1231 }
1232
1233 /* Check for trailing unpartitioned disk space */
1234 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1235 {
1236 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1237
1238 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1239 {
1240 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1241
1242 StartSector = LastStartSector + LastSectorCount;
1243 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1244
1245 /* Append the table to the list */
1246 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1247 &DiskEntry->PrimaryPartListHead,
1248 StartSector,
1250 FALSE);
1251 if (!NewPartEntry)
1252 {
1253 DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1254 return;
1255 }
1256 }
1257 }
1258
1259 if (DiskEntry->ExtendedPartition != NULL)
1260 {
1261 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1262 {
1263 DPRINT1("No logical partition!\n");
1264
1265 /* Create a partition entry that represents the empty extended partition */
1266 AddLogicalDiskSpace(DiskEntry);
1267 return;
1268 }
1269
1270 /* Start partition at head 1, cylinder 0 */
1271 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1272 LastSectorCount = 0ULL;
1273 LastUnusedSectorCount = 0ULL;
1274
1275 for (Entry = DiskEntry->LogicalPartListHead.Flink;
1276 Entry != &DiskEntry->LogicalPartListHead;
1277 Entry = Entry->Flink)
1278 {
1279 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1280
1281 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1282 PartEntry->SectorCount.QuadPart != 0ULL)
1283 {
1284 LastUnusedSectorCount =
1285 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1286
1287 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1288 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1289 {
1290 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1291
1292 StartSector = LastStartSector + LastSectorCount;
1293 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1294
1295 /* Insert the table into the list */
1296 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1297 &PartEntry->ListEntry,
1298 StartSector,
1300 TRUE);
1301 if (!NewPartEntry)
1302 {
1303 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1304 return;
1305 }
1306 }
1307
1308 LastStartSector = PartEntry->StartSector.QuadPart;
1309 LastSectorCount = PartEntry->SectorCount.QuadPart;
1310 }
1311 }
1312
1313 /* Check for trailing unpartitioned disk space */
1314 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1315 {
1316 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1317 DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1318 DiskEntry->SectorAlignment);
1319
1320 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1321 {
1322 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1323
1324 StartSector = LastStartSector + LastSectorCount;
1325 SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1326
1327 /* Append the table to the list */
1328 NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1329 &DiskEntry->LogicalPartListHead,
1330 StartSector,
1332 TRUE);
1333 if (!NewPartEntry)
1334 {
1335 DPRINT1("Failed to create a new empty region for extended partition space!\n");
1336 return;
1337 }
1338 }
1339 }
1340 }
1341
1342 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1343}
1344
1345static
1346VOID
1349 IN PDISKENTRY DiskEntry)
1350{
1351 LARGE_INTEGER SystemTime;
1353 PLIST_ENTRY Entry2;
1354 PDISKENTRY DiskEntry2;
1355 PUCHAR Buffer;
1356
1357 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1358 {
1359 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1360 return;
1361 }
1362
1363 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1364
1365 while (TRUE)
1366 {
1367 NtQuerySystemTime(&SystemTime);
1368 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1369
1370 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1371 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1372 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1373 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1374
1375 if (DiskEntry->LayoutBuffer->Signature == 0)
1376 {
1377 continue;
1378 }
1379
1380 /* Check if the signature already exist */
1381 /* FIXME:
1382 * Check also signatures from disks, which are
1383 * not visible (bootable) by the BIOS.
1384 */
1385 for (Entry2 = List->DiskListHead.Flink;
1386 Entry2 != &List->DiskListHead;
1387 Entry2 = Entry2->Flink)
1388 {
1389 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1390
1391 if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
1392 {
1393 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1394 continue;
1395 }
1396
1397 if (DiskEntry != DiskEntry2 &&
1398 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1399 break;
1400 }
1401
1402 if (Entry2 == &List->DiskListHead)
1403 break;
1404 }
1405}
1406
1407static
1408VOID
1411{
1413 PDISKENTRY DiskEntry;
1414
1415 /* Update each disk */
1416 for (Entry = List->DiskListHead.Flink;
1417 Entry != &List->DiskListHead;
1418 Entry = Entry->Flink)
1419 {
1420 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1421
1422 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1423 {
1424 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1425 continue;
1426 }
1427
1428 if (DiskEntry->LayoutBuffer &&
1429 DiskEntry->LayoutBuffer->Signature == 0)
1430 {
1431 SetDiskSignature(List, DiskEntry);
1433 }
1434 }
1435}
1436
1437static
1438VOID
1441{
1442 PLIST_ENTRY ListEntry;
1443 PBIOSDISKENTRY BiosDiskEntry;
1444 PDISKENTRY DiskEntry;
1445 ULONG HwAdapterNumber = 0;
1446 ULONG HwControllerNumber = 0;
1447 ULONG RemovableDiskCount = 0;
1448
1449 /*
1450 * Enumerate the disks recognized by the BIOS and recompute the disk
1451 * numbers on the system when *ALL* removable disks are not connected.
1452 * The entries are inserted in increasing order of AdapterNumber,
1453 * ControllerNumber and DiskNumber.
1454 */
1455 for (ListEntry = List->BiosDiskListHead.Flink;
1456 ListEntry != &List->BiosDiskListHead;
1457 ListEntry = ListEntry->Flink)
1458 {
1459 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1460 DiskEntry = BiosDiskEntry->DiskEntry;
1461
1462 /*
1463 * If the adapter or controller numbers change, update them and reset
1464 * the number of removable disks on this adapter/controller.
1465 */
1466 if (HwAdapterNumber != BiosDiskEntry->AdapterNumber ||
1467 HwControllerNumber != BiosDiskEntry->ControllerNumber)
1468 {
1469 HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1470 HwControllerNumber = BiosDiskEntry->ControllerNumber;
1471 RemovableDiskCount = 0;
1472 }
1473
1474 /* Adjust the actual hardware disk number */
1475 if (DiskEntry)
1476 {
1477 ASSERT(DiskEntry->HwDiskNumber == BiosDiskEntry->DiskNumber);
1478
1479 if (DiskEntry->MediaType == RemovableMedia)
1480 {
1481 /* Increase the number of removable disks and set the disk number to zero */
1482 ++RemovableDiskCount;
1483 DiskEntry->HwFixedDiskNumber = 0;
1484 }
1485 else // if (DiskEntry->MediaType == FixedMedia)
1486 {
1487 /* Adjust the fixed disk number, offset by the number of removable disks found before this one */
1488 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber - RemovableDiskCount;
1489 }
1490 }
1491 else
1492 {
1493 DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry->DiskNumber);
1494 }
1495 }
1496}
1497
1498static
1499VOID
1502 IN ULONG DiskNumber,
1504{
1505 DISK_GEOMETRY DiskGeometry;
1506 SCSI_ADDRESS ScsiAddress;
1507 PDISKENTRY DiskEntry;
1511 PULONG Buffer;
1513 WCHAR Identifier[20];
1514 ULONG Checksum;
1516 ULONG i;
1517 PLIST_ENTRY ListEntry;
1518 PBIOSDISKENTRY BiosDiskEntry;
1519 ULONG LayoutBufferSize;
1520 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1521
1522 /* Retrieve the drive geometry */
1524 NULL,
1525 NULL,
1526 NULL,
1527 &Iosb,
1529 NULL,
1530 0,
1531 &DiskGeometry,
1532 sizeof(DiskGeometry));
1533 if (!NT_SUCCESS(Status))
1534 return;
1535
1536 if (DiskGeometry.MediaType != FixedMedia &&
1537 DiskGeometry.MediaType != RemovableMedia)
1538 {
1539 return;
1540 }
1541
1542 /*
1543 * FIXME: Here we suppose the disk is always SCSI. What if it is
1544 * of another type? To check this we need to retrieve the name of
1545 * the driver the disk device belongs to.
1546 */
1548 NULL,
1549 NULL,
1550 NULL,
1551 &Iosb,
1553 NULL,
1554 0,
1555 &ScsiAddress,
1556 sizeof(ScsiAddress));
1557 if (!NT_SUCCESS(Status))
1558 return;
1559
1560 /*
1561 * Check whether the disk is initialized, by looking at its MBR.
1562 * NOTE that this must be generalized to GPT disks as well!
1563 */
1564
1566 0,
1567 DiskGeometry.BytesPerSector);
1568 if (Mbr == NULL)
1569 return;
1570
1571 FileOffset.QuadPart = 0;
1573 NULL,
1574 NULL,
1575 NULL,
1576 &Iosb,
1577 (PVOID)Mbr,
1578 DiskGeometry.BytesPerSector,
1579 &FileOffset,
1580 NULL);
1581 if (!NT_SUCCESS(Status))
1582 {
1583 RtlFreeHeap(ProcessHeap, 0, Mbr);
1584 DPRINT1("NtReadFile failed, status=%x\n", Status);
1585 return;
1586 }
1587 Signature = Mbr->Signature;
1588
1589 /* Calculate the MBR checksum */
1590 Checksum = 0;
1591 Buffer = (PULONG)Mbr;
1592 for (i = 0; i < 128; i++)
1593 {
1594 Checksum += Buffer[i];
1595 }
1596 Checksum = ~Checksum + 1;
1597
1599 L"%08x-%08x-%c",
1600 Checksum, Signature,
1601 (Mbr->Magic == PARTITION_MAGIC) ? L'A' : L'X');
1602 DPRINT("Identifier: %S\n", Identifier);
1603
1604 DiskEntry = RtlAllocateHeap(ProcessHeap,
1606 sizeof(DISKENTRY));
1607 if (DiskEntry == NULL)
1608 {
1609 RtlFreeHeap(ProcessHeap, 0, Mbr);
1610 DPRINT1("Failed to allocate a new disk entry.\n");
1611 return;
1612 }
1613
1614 DiskEntry->PartList = List;
1615
1616#if 0
1617 {
1618 FILE_FS_DEVICE_INFORMATION FileFsDevice;
1619
1620 /* Query the device for its type */
1622 &Iosb,
1623 &FileFsDevice,
1624 sizeof(FileFsDevice),
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber, Identifier);
1629 }
1630 else
1631 {
1632 DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber, FileFsDevice.DeviceType, FileFsDevice.Characteristics);
1633 }
1634 }
1635 // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation).
1636#endif
1637 DiskEntry->MediaType = DiskGeometry.MediaType;
1638 if (DiskEntry->MediaType == RemovableMedia)
1639 {
1640 DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber, Identifier);
1641 }
1642 else // if (DiskEntry->MediaType == FixedMedia)
1643 {
1644 DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber, Identifier);
1645 }
1646
1647// DiskEntry->Checksum = Checksum;
1648// DiskEntry->Signature = Signature;
1649 DiskEntry->BiosFound = FALSE;
1650
1651 /*
1652 * Check if this disk has a valid MBR: verify its signature,
1653 * and whether its two first bytes are a valid instruction
1654 * (related to this, see IsThereAValidBootSector() in partlist.c).
1655 *
1656 * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1657 */
1658
1659 // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1660
1661 /* If we have not the 0xAA55 then it's raw partition */
1662 if (Mbr->Magic != PARTITION_MAGIC)
1663 {
1664 DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
1665 }
1666 /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1667 else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
1668 Mbr->Partition[1].PartitionType == 0 &&
1669 Mbr->Partition[2].PartitionType == 0 &&
1670 Mbr->Partition[3].PartitionType == 0)
1671 {
1672 DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
1673 }
1674 /* Otherwise, partition table is in MBR */
1675 else
1676 {
1677 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
1678 }
1679
1680 /* Free the MBR sector buffer */
1681 RtlFreeHeap(ProcessHeap, 0, Mbr);
1682
1683
1684 for (ListEntry = List->BiosDiskListHead.Flink;
1685 ListEntry != &List->BiosDiskListHead;
1686 ListEntry = ListEntry->Flink)
1687 {
1688 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1689 /* FIXME:
1690 * Compare the size from BIOS and the reported size from driver.
1691 * If we have more than one disk with a zero or with the same signature
1692 * we must create new signatures and reboot. After the reboot,
1693 * it is possible to identify the disks.
1694 */
1695 if (BiosDiskEntry->Signature == Signature &&
1696 BiosDiskEntry->Checksum == Checksum &&
1697 BiosDiskEntry->DiskEntry == NULL)
1698 {
1699 if (!DiskEntry->BiosFound)
1700 {
1701 DiskEntry->HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1702 DiskEntry->HwControllerNumber = BiosDiskEntry->ControllerNumber;
1703 DiskEntry->HwDiskNumber = BiosDiskEntry->DiskNumber;
1704
1705 if (DiskEntry->MediaType == RemovableMedia)
1706 {
1707 /* Set the removable disk number to zero */
1708 DiskEntry->HwFixedDiskNumber = 0;
1709 }
1710 else // if (DiskEntry->MediaType == FixedMedia)
1711 {
1712 /* The fixed disk number will later be adjusted using the number of removable disks */
1713 DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber;
1714 }
1715
1716 DiskEntry->BiosFound = TRUE;
1717 BiosDiskEntry->DiskEntry = DiskEntry;
1718 break;
1719 }
1720 else
1721 {
1722 // FIXME: What to do?
1723 DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber, Identifier);
1724 }
1725 }
1726 }
1727
1728 if (!DiskEntry->BiosFound)
1729 {
1730 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber);
1731 }
1732
1733 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1734 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1735 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1736 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1737
1738 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1739 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1740 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1741 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1742
1743 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1744 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1745 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1746
1747 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1748 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1749 DiskGeometry.SectorsPerTrack;
1750
1751 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1752 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1753
1754 DiskEntry->DiskNumber = DiskNumber;
1755 DiskEntry->Port = ScsiAddress.PortNumber;
1756 DiskEntry->Bus = ScsiAddress.PathId;
1757 DiskEntry->Id = ScsiAddress.TargetId;
1758
1759 GetDriverName(DiskEntry);
1760 /*
1761 * Actually it would be more correct somehow to use:
1762 *
1763 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1764 * ULONG ReturnedLength;
1765 *
1766 * Status = NtQueryObject(SomeHandleToTheDisk,
1767 * ObjectNameInformation,
1768 * &NameInfo,
1769 * sizeof(NameInfo),
1770 * &ReturnedLength);
1771 * etc...
1772 *
1773 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1774 */
1775
1778
1779 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1780
1781
1782 /*
1783 * We now retrieve the disk partition layout
1784 */
1785
1786 /*
1787 * Stop there now if the disk is GPT-partitioned,
1788 * since we currently do not support such disks.
1789 */
1790 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1791 {
1792 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1793 return;
1794 }
1795
1796 /* Allocate a layout buffer with 4 partition entries first */
1797 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1798 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1801 LayoutBufferSize);
1802 if (DiskEntry->LayoutBuffer == NULL)
1803 {
1804 DPRINT1("Failed to allocate the disk layout buffer!\n");
1805 return;
1806 }
1807
1808 /* Keep looping while the drive layout buffer is too small */
1809 for (;;)
1810 {
1811 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1813 NULL,
1814 NULL,
1815 NULL,
1816 &Iosb,
1818 NULL,
1819 0,
1820 DiskEntry->LayoutBuffer,
1821 LayoutBufferSize);
1822 if (NT_SUCCESS(Status))
1823 break;
1824
1826 {
1827 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1828 return;
1829 }
1830
1831 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1832 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1834 DiskEntry->LayoutBuffer,
1835 LayoutBufferSize);
1836 if (NewLayoutBuffer == NULL)
1837 {
1838 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1839 return;
1840 }
1841
1842 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1843 }
1844
1845 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1846
1847#ifdef DUMP_PARTITION_TABLE
1848 DumpPartitionTable(DiskEntry);
1849#endif
1850
1851 if (IsSuperFloppy(DiskEntry))
1852 DPRINT1("Disk %lu is a super-floppy\n", DiskNumber);
1853
1854 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1857 {
1858 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1859 {
1860 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1861 }
1862 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1863 {
1864 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1865 }
1866 else
1867 {
1868 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1869 }
1870 }
1871 else
1872 {
1873 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1874 }
1875
1876 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1877 {
1878 DiskEntry->NewDisk = TRUE;
1879 DiskEntry->LayoutBuffer->PartitionCount = 4;
1880
1881 for (i = 0; i < 4; i++)
1882 {
1884 }
1885 }
1886 else
1887 {
1888 /* Enumerate and add the first four primary partitions */
1889 for (i = 0; i < 4; i++)
1890 {
1891 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1892 }
1893
1894 /* Enumerate and add the remaining partitions as logical ones */
1895 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1896 {
1897 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1898 }
1899 }
1900
1902}
1903
1904/*
1905 * Retrieve the system disk, i.e. the fixed disk that is accessible by the
1906 * firmware during boot time and where the system partition resides.
1907 * If no system partition has been determined, we retrieve the first disk
1908 * that verifies the mentioned criteria above.
1909 */
1910static
1914{
1916 PDISKENTRY DiskEntry;
1917
1918 /* Check for empty disk list */
1919 if (IsListEmpty(&List->DiskListHead))
1920 return NULL;
1921
1922 /*
1923 * If we already have a system partition, the system disk
1924 * is the one on which the system partition resides.
1925 */
1926 if (List->SystemPartition)
1927 return List->SystemPartition->DiskEntry;
1928
1929 /* Loop over the disks and find the correct one */
1930 for (Entry = List->DiskListHead.Flink;
1931 Entry != &List->DiskListHead;
1932 Entry = Entry->Flink)
1933 {
1934 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1935
1936 /* The disk must be a fixed disk and be found by the firmware */
1937 if (DiskEntry->MediaType == FixedMedia && DiskEntry->BiosFound)
1938 {
1939 break;
1940 }
1941 }
1942 if (Entry == &List->DiskListHead)
1943 {
1944 /* We haven't encountered any suitable disk */
1945 return NULL;
1946 }
1947
1948 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1949 {
1950 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
1951 }
1952
1953 return DiskEntry;
1954}
1955
1956/*
1957 * Retrieve the actual "active" partition of the given disk.
1958 * On MBR disks, partition with the Active/Boot flag set;
1959 * on GPT disks, partition with the correct GUID.
1960 */
1961BOOLEAN
1963 IN PPARTENTRY PartEntry)
1964{
1965 // TODO: Support for GPT disks!
1966
1967 if (IsContainerPartition(PartEntry->PartitionType))
1968 return FALSE;
1969
1970 /* Check if the partition is partitioned, used and active */
1971 if (PartEntry->IsPartitioned &&
1972 // !IsContainerPartition(PartEntry->PartitionType) &&
1973 PartEntry->BootIndicator)
1974 {
1975 /* Yes it is */
1976 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
1977 return TRUE;
1978 }
1979
1980 return FALSE;
1981}
1982
1983static
1986 IN PDISKENTRY DiskEntry)
1987{
1988 PLIST_ENTRY ListEntry;
1989 PPARTENTRY PartEntry;
1990 PPARTENTRY ActivePartition = NULL;
1991
1992 /* Check for empty disk list */
1993 // ASSERT(DiskEntry);
1994 if (!DiskEntry)
1995 return NULL;
1996
1997 /* Check for empty partition list */
1998 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1999 return NULL;
2000
2001 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2002 {
2003 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2004 return NULL;
2005 }
2006
2007 /* Scan all (primary) partitions to find the active disk partition */
2008 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2009 ListEntry != &DiskEntry->PrimaryPartListHead;
2010 ListEntry = ListEntry->Flink)
2011 {
2012 /* Retrieve the partition */
2013 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2014 if (IsPartitionActive(PartEntry))
2015 {
2016 /* Yes, we've found it */
2017 ASSERT(DiskEntry == PartEntry->DiskEntry);
2018 ASSERT(PartEntry->IsPartitioned);
2019 ASSERT(PartEntry->Volume);
2020
2021 ActivePartition = PartEntry;
2022
2023 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
2024 PartEntry->PartitionNumber, DiskEntry->DiskNumber,
2025 !PartEntry->Volume->Info.DriveLetter ? L'-' : PartEntry->Volume->Info.DriveLetter);
2026 break;
2027 }
2028 }
2029
2030 /* Check if the disk is new and if so, use its first partition as the active system partition */
2031 if (DiskEntry->NewDisk && ActivePartition != NULL)
2032 {
2033 // FIXME: What to do??
2034 DPRINT1("NewDisk TRUE but already existing active partition?\n");
2035 }
2036
2037 /* Return the active partition found (or none) */
2038 return ActivePartition;
2039}
2040
2042NTAPI
2044{
2046 PDISKENTRY SystemDisk;
2050 ULONG ReturnSize;
2052 ULONG DiskNumber;
2056
2058 0,
2059 sizeof(PARTLIST));
2060 if (!List)
2061 return NULL;
2062
2063 List->SystemPartition = NULL;
2064
2065 InitializeListHead(&List->DiskListHead);
2066 InitializeListHead(&List->BiosDiskListHead);
2067 InitializeListHead(&List->VolumesList);
2068 InitializeListHead(&List->PendingUnmountVolumesList);
2069
2070 /*
2071 * Enumerate the disks seen by the BIOS; this will be used later
2072 * to map drives seen by NTOS with their corresponding BIOS names.
2073 */
2075
2076 /* Enumerate disks seen by NTOS */
2078 &Sdi,
2079 sizeof(Sdi),
2080 &ReturnSize);
2081 if (!NT_SUCCESS(Status))
2082 {
2083 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx\n", Status);
2085 return NULL;
2086 }
2087
2088 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
2089 {
2091 L"\\Device\\Harddisk%lu\\Partition0",
2092 DiskNumber);
2094
2096 &Name,
2098 NULL,
2099 NULL);
2100
2104 &Iosb,
2107 if (NT_SUCCESS(Status))
2108 {
2109 AddDiskToList(FileHandle, DiskNumber, List);
2111 }
2112 }
2113
2117
2118 /*
2119 * Retrieve the system partition: the active partition on the system
2120 * disk (the one that will be booted by default by the hardware).
2121 */
2122 SystemDisk = GetSystemDisk(List);
2123 List->SystemPartition = (SystemDisk ? GetActiveDiskPartition(SystemDisk) : NULL);
2124
2125 return List;
2126}
2127
2128VOID
2129NTAPI
2132{
2133 PDISKENTRY DiskEntry;
2134 PBIOSDISKENTRY BiosDiskEntry;
2135 PPARTENTRY PartEntry;
2136 PVOLENTRY VolumeEntry;
2138
2139 /* Release disk and partition info */
2140 while (!IsListEmpty(&List->DiskListHead))
2141 {
2142 Entry = RemoveHeadList(&List->DiskListHead);
2143 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2144
2145 /* Release driver name */
2146 RtlFreeUnicodeString(&DiskEntry->DriverName);
2147
2148 /* Release primary partition list */
2149 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
2150 {
2152 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2153 DestroyRegion(PartEntry);
2154 }
2155
2156 /* Release logical partition list */
2157 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2158 {
2160 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2161 DestroyRegion(PartEntry);
2162 }
2163
2164 /* Release layout buffer */
2165 if (DiskEntry->LayoutBuffer != NULL)
2166 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
2167
2168 /* Release disk entry */
2169 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
2170 }
2171
2172 /* Release the BIOS disk info */
2173 while (!IsListEmpty(&List->BiosDiskListHead))
2174 {
2175 Entry = RemoveHeadList(&List->BiosDiskListHead);
2176 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
2177 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
2178 }
2179
2180 /* Release the pending volumes info */
2181 while (!IsListEmpty(&List->PendingUnmountVolumesList))
2182 {
2183 Entry = RemoveHeadList(&List->PendingUnmountVolumesList);
2184 VolumeEntry = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
2185 RtlFreeHeap(ProcessHeap, 0, VolumeEntry);
2186 }
2187
2188 /* Release list head */
2190}
2191
2195 _In_ ULONG HwDiskNumber)
2196{
2197 PDISKENTRY DiskEntry;
2199
2200 /* Loop over the disks and find the correct one */
2201 for (Entry = List->DiskListHead.Flink;
2202 Entry != &List->DiskListHead;
2203 Entry = Entry->Flink)
2204 {
2205 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2206
2207 if (DiskEntry->HwDiskNumber == HwDiskNumber)
2208 return DiskEntry; /* Disk found, return it */
2209 }
2210
2211 /* Disk not found, stop there */
2212 return NULL;
2213}
2214
2218 _In_ ULONG DiskNumber)
2219{
2220 PDISKENTRY DiskEntry;
2222
2223 /* Loop over the disks and find the correct one */
2224 for (Entry = List->DiskListHead.Flink;
2225 Entry != &List->DiskListHead;
2226 Entry = Entry->Flink)
2227 {
2228 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2229
2230 if (DiskEntry->DiskNumber == DiskNumber)
2231 return DiskEntry; /* Disk found, return it */
2232 }
2233
2234 /* Disk not found, stop there */
2235 return NULL;
2236}
2237
2242 _In_ USHORT Bus,
2243 _In_ USHORT Id)
2244{
2245 PDISKENTRY DiskEntry;
2247
2248 /* Loop over the disks and find the correct one */
2249 for (Entry = List->DiskListHead.Flink;
2250 Entry != &List->DiskListHead;
2251 Entry = Entry->Flink)
2252 {
2253 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2254
2255 if (DiskEntry->Port == Port &&
2256 DiskEntry->Bus == Bus &&
2257 DiskEntry->Id == Id)
2258 {
2259 /* Disk found, return it */
2260 return DiskEntry;
2261 }
2262 }
2263
2264 /* Disk not found, stop there */
2265 return NULL;
2266}
2267
2272{
2273 PDISKENTRY DiskEntry;
2275
2276 /* Loop over the disks and find the correct one */
2277 for (Entry = List->DiskListHead.Flink;
2278 Entry != &List->DiskListHead;
2279 Entry = Entry->Flink)
2280 {
2281 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2282
2283 if (DiskEntry->LayoutBuffer->Signature == Signature)
2284 return DiskEntry; /* Disk found, return it */
2285 }
2286
2287 /* Disk not found, stop there */
2288 return NULL;
2289}
2290
2293 _In_ PDISKENTRY DiskEntry,
2295{
2296 PPARTENTRY PartEntry;
2298
2299 /* Forbid whole-disk or extended container partition access */
2300 if (PartitionNumber == 0)
2301 return NULL;
2302
2303 /* Loop over the primary partitions first... */
2304 for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2305 Entry != &DiskEntry->PrimaryPartListHead;
2306 Entry = Entry->Flink)
2307 {
2308 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2309
2310 if (PartEntry->PartitionNumber == PartitionNumber)
2311 return PartEntry; /* Partition found, return it */
2312 }
2313
2314 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2315 return NULL;
2316
2317 /* ... then over the logical partitions if needed */
2318 for (Entry = DiskEntry->LogicalPartListHead.Flink;
2319 Entry != &DiskEntry->LogicalPartListHead;
2320 Entry = Entry->Flink)
2321 {
2322 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2323
2324 if (PartEntry->PartitionNumber == PartitionNumber)
2325 return PartEntry; /* Partition found, return it */
2326 }
2327
2328 /* The partition was not found on the disk, stop there */
2329 return NULL;
2330}
2331
2335 _In_ ULONG DiskNumber,
2337{
2338 PDISKENTRY DiskEntry;
2339 PPARTENTRY PartEntry;
2340
2341 /* Find the disk */
2342 DiskEntry = GetDiskByNumber(List, DiskNumber);
2343 if (!DiskEntry)
2344 return NULL;
2345 ASSERT(DiskEntry->DiskNumber == DiskNumber);
2346
2347 /* Find the partition */
2348 PartEntry = GetPartition(DiskEntry, PartitionNumber);
2349 if (!PartEntry)
2350 return NULL;
2351 ASSERT(PartEntry->DiskEntry == DiskEntry);
2352 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
2353
2354 return PartEntry;
2355}
2356
2358NTAPI
2361 IN PPARTENTRY CurrentPart OPTIONAL)
2362{
2363 PLIST_ENTRY DiskListEntry;
2364 PLIST_ENTRY PartListEntry;
2366
2367 /* Fail if no disks are available */
2368 if (IsListEmpty(&List->DiskListHead))
2369 return NULL;
2370
2371 /* Check for the next usable entry on the current partition's disk */
2372 if (CurrentPart != NULL)
2373 {
2374 CurrentDisk = CurrentPart->DiskEntry;
2375
2376 if (CurrentPart->LogicalPartition)
2377 {
2378 /* Logical partition */
2379
2380 PartListEntry = CurrentPart->ListEntry.Flink;
2381 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2382 {
2383 /* Next logical partition */
2384 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2385 return CurrentPart;
2386 }
2387 else
2388 {
2389 PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink;
2390 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2391 {
2392 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2393 return CurrentPart;
2394 }
2395 }
2396 }
2397 else
2398 {
2399 /* Primary or extended partition */
2400
2401 if (CurrentPart->IsPartitioned &&
2402 IsContainerPartition(CurrentPart->PartitionType))
2403 {
2404 /* First logical partition */
2405 PartListEntry = CurrentDisk->LogicalPartListHead.Flink;
2406 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2407 {
2408 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2409 return CurrentPart;
2410 }
2411 }
2412 else
2413 {
2414 /* Next primary partition */
2415 PartListEntry = CurrentPart->ListEntry.Flink;
2416 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2417 {
2418 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2419 return CurrentPart;
2420 }
2421 }
2422 }
2423 }
2424
2425 /* Search for the first partition entry on the next disk */
2426 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink
2427 : List->DiskListHead.Flink);
2428 DiskListEntry != &List->DiskListHead;
2429 DiskListEntry = DiskListEntry->Flink)
2430 {
2431 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2432
2434 {
2435 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2436 continue;
2437 }
2438
2439 PartListEntry = CurrentDisk->PrimaryPartListHead.Flink;
2440 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2441 {
2442 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2443 return CurrentPart;
2444 }
2445 }
2446
2447 return NULL;
2448}
2449
2451NTAPI
2454 IN PPARTENTRY CurrentPart OPTIONAL)
2455{
2456 PLIST_ENTRY DiskListEntry;
2457 PLIST_ENTRY PartListEntry;
2459
2460 /* Fail if no disks are available */
2461 if (IsListEmpty(&List->DiskListHead))
2462 return NULL;
2463
2464 /* Check for the previous usable entry on the current partition's disk */
2465 if (CurrentPart != NULL)
2466 {
2467 CurrentDisk = CurrentPart->DiskEntry;
2468
2469 if (CurrentPart->LogicalPartition)
2470 {
2471 /* Logical partition */
2472
2473 PartListEntry = CurrentPart->ListEntry.Blink;
2474 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2475 {
2476 /* Previous logical partition */
2477 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2478 }
2479 else
2480 {
2481 /* Extended partition */
2482 CurrentPart = CurrentDisk->ExtendedPartition;
2483 }
2484 return CurrentPart;
2485 }
2486 else
2487 {
2488 /* Primary or extended partition */
2489
2490 PartListEntry = CurrentPart->ListEntry.Blink;
2491 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2492 {
2493 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2494
2495 if (CurrentPart->IsPartitioned &&
2496 IsContainerPartition(CurrentPart->PartitionType))
2497 {
2498 PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2499 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2500 }
2501
2502 return CurrentPart;
2503 }
2504 }
2505 }
2506
2507 /* Search for the last partition entry on the previous disk */
2508 for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink
2509 : List->DiskListHead.Blink);
2510 DiskListEntry != &List->DiskListHead;
2511 DiskListEntry = DiskListEntry->Blink)
2512 {
2513 CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2514
2516 {
2517 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2518 continue;
2519 }
2520
2521 PartListEntry = CurrentDisk->PrimaryPartListHead.Blink;
2522 if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2523 {
2524 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2525
2526 if (CurrentPart->IsPartitioned &&
2527 IsContainerPartition(CurrentPart->PartitionType))
2528 {
2529 PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2530 if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2531 {
2532 CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2533 return CurrentPart;
2534 }
2535 }
2536 else
2537 {
2538 return CurrentPart;
2539 }
2540 }
2541 }
2542
2543 return NULL;
2544}
2545
2546static inline
2547BOOLEAN
2550{
2551 return (PartitionInfo->StartingOffset.QuadPart == 0 &&
2552 PartitionInfo->PartitionLength.QuadPart == 0);
2553}
2554
2555static inline
2556BOOLEAN
2559 _In_ PPARTENTRY PartEntry)
2560{
2561 return ((PartitionInfo->StartingOffset.QuadPart == GetPartEntryOffsetInBytes(PartEntry)) &&
2562 (PartitionInfo->PartitionLength.QuadPart == GetPartEntrySizeInBytes(PartEntry)));
2563// PartitionInfo->PartitionType == PartEntry->PartitionType
2564}
2565
2566
2571static
2572ULONG
2574 _In_ PLIST_ENTRY PartListHead)
2575{
2577 PPARTENTRY PartEntry;
2578 ULONG Count = 0;
2579
2580 for (Entry = PartListHead->Flink;
2581 Entry != PartListHead;
2582 Entry = Entry->Flink)
2583 {
2584 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2585 if (PartEntry->IsPartitioned)
2586 ++Count;
2587 }
2588
2589 return Count;
2590}
2591
2592#define GetPrimaryPartitionCount(DiskEntry) \
2593 GetPartitionCount(&(DiskEntry)->PrimaryPartListHead)
2594
2595#define GetLogicalPartitionCount(DiskEntry) \
2596 (((DiskEntry)->DiskStyle == PARTITION_STYLE_MBR) \
2597 ? GetPartitionCount(&(DiskEntry)->LogicalPartListHead) : 0)
2598
2599
2600static
2601BOOLEAN
2603 IN PDISKENTRY DiskEntry)
2604{
2605 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2606 ULONG NewPartitionCount;
2607 ULONG CurrentPartitionCount = 0;
2608 ULONG LayoutBufferSize;
2609 ULONG i;
2610
2611 DPRINT1("ReAllocateLayoutBuffer()\n");
2612
2613 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2614
2615 if (DiskEntry->LayoutBuffer)
2616 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2617
2618 DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2619 CurrentPartitionCount, NewPartitionCount);
2620
2621 if (CurrentPartitionCount == NewPartitionCount)
2622 return TRUE;
2623
2624 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2625 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2626 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2628 DiskEntry->LayoutBuffer,
2629 LayoutBufferSize);
2630 if (NewLayoutBuffer == NULL)
2631 {
2632 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2633 return FALSE;
2634 }
2635
2636 NewLayoutBuffer->PartitionCount = NewPartitionCount;
2637
2638 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2639 if (NewPartitionCount > CurrentPartitionCount)
2640 {
2641 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2642 {
2643 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2644 }
2645 }
2646
2647 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2648
2649 return TRUE;
2650}
2651
2652static
2653VOID
2655 IN PDISKENTRY DiskEntry)
2656{
2658 PPARTITION_INFORMATION LinkInfo;
2659 PLIST_ENTRY ListEntry;
2660 PPARTENTRY PartEntry;
2661 LARGE_INTEGER HiddenSectors64;
2662 ULONG Index;
2664
2665 DPRINT1("UpdateDiskLayout()\n");
2666
2667 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2668 {
2669 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2670 return;
2671 }
2672
2673 /* Resize the layout buffer if necessary */
2674 if (!ReAllocateLayoutBuffer(DiskEntry))
2675 {
2676 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2677 return;
2678 }
2679
2680 /* Update the primary partition table */
2681 Index = 0;
2682 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2683 ListEntry != &DiskEntry->PrimaryPartListHead;
2684 ListEntry = ListEntry->Flink)
2685 {
2686 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2687
2688 if (PartEntry->IsPartitioned)
2689 {
2691
2692 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2693 PartEntry->PartitionIndex = Index;
2694
2695 /* Reset the current partition number only for not-yet written partitions */
2696 if (PartEntry->New)
2697 PartEntry->PartitionNumber = 0;
2698
2700
2701 if (!IsSamePrimaryLayoutEntry(PartitionInfo, PartEntry))
2702 {
2703 DPRINT1("Updating primary partition entry %lu\n", Index);
2704
2705 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry);
2706 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry);
2707 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2708 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2709 PartitionInfo->PartitionType = PartEntry->PartitionType;
2710 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2711 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2712 PartitionInfo->RewritePartition = TRUE;
2713 }
2714
2715 if (!IsContainerPartition(PartEntry->PartitionType))
2717
2718 Index++;
2719 }
2720 }
2721
2722 ASSERT(Index <= 4);
2723
2724 /* Update the logical partition table */
2725 LinkInfo = NULL;
2726 Index = 4;
2727 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2728 ListEntry != &DiskEntry->LogicalPartListHead;
2729 ListEntry = ListEntry->Flink)
2730 {
2731 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2732
2733 if (PartEntry->IsPartitioned)
2734 {
2736
2737 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2738 PartEntry->PartitionIndex = Index;
2739
2740 /* Reset the current partition number only for not-yet written partitions */
2741 if (PartEntry->New)
2742 PartEntry->PartitionNumber = 0;
2743
2745
2746 DPRINT1("Updating logical partition entry %lu\n", Index);
2747
2748 PartitionInfo->StartingOffset.QuadPart = GetPartEntryOffsetInBytes(PartEntry);
2749 PartitionInfo->PartitionLength.QuadPart = GetPartEntrySizeInBytes(PartEntry);
2750 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2751 PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2752 PartitionInfo->PartitionType = PartEntry->PartitionType;
2753 PartitionInfo->BootIndicator = FALSE;
2754 PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2755 PartitionInfo->RewritePartition = TRUE;
2756
2757 /* Fill the link entry of the previous partition entry */
2758 if (LinkInfo)
2759 {
2760 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2761 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2762 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2763 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2764 LinkInfo->PartitionNumber = 0;
2765
2766 /* Extended partition links only use type 0x05, as observed
2767 * on Windows NT. Alternatively they could inherit the type
2768 * of the main extended container. */
2769 LinkInfo->PartitionType = PARTITION_EXTENDED; // DiskEntry->ExtendedPartition->PartitionType;
2770
2771 LinkInfo->BootIndicator = FALSE;
2772 LinkInfo->RecognizedPartition = FALSE;
2773 LinkInfo->RewritePartition = TRUE;
2774 }
2775
2776 /* Save a pointer to the link entry of the current partition entry */
2777 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2778
2780 Index += 4;
2781 }
2782 }
2783
2784 /* Wipe unused primary partition entries */
2785 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2786 {
2787 DPRINT1("Primary partition entry %lu\n", Index);
2788
2789 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2790
2792 {
2793 DPRINT1("Wiping primary partition entry %lu\n", Index);
2794
2795 PartitionInfo->StartingOffset.QuadPart = 0;
2796 PartitionInfo->PartitionLength.QuadPart = 0;
2797 PartitionInfo->HiddenSectors = 0;
2798 PartitionInfo->PartitionNumber = 0;
2799 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2800 PartitionInfo->BootIndicator = FALSE;
2801 PartitionInfo->RecognizedPartition = FALSE;
2802 PartitionInfo->RewritePartition = TRUE;
2803 }
2804 }
2805
2806 /* Wipe unused logical partition entries */
2807 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2808 {
2809 if (Index % 4 >= 2)
2810 {
2811 DPRINT1("Logical partition entry %lu\n", Index);
2812
2813 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2814
2816 {
2817 DPRINT1("Wiping partition entry %lu\n", Index);
2818
2819 PartitionInfo->StartingOffset.QuadPart = 0;
2820 PartitionInfo->PartitionLength.QuadPart = 0;
2821 PartitionInfo->HiddenSectors = 0;
2822 PartitionInfo->PartitionNumber = 0;
2823 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2824 PartitionInfo->BootIndicator = FALSE;
2825 PartitionInfo->RecognizedPartition = FALSE;
2826 PartitionInfo->RewritePartition = TRUE;
2827 }
2828 }
2829 }
2830
2831 // HACK: See the FIXMEs in WritePartitions(): (Re)set the PartitionStyle to MBR.
2832 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
2833
2834 DiskEntry->Dirty = TRUE;
2835
2836#ifdef DUMP_PARTITION_TABLE
2837 DumpPartitionTable(DiskEntry);
2838#endif
2839}
2840
2855NTAPI
2857 _In_ PPARTENTRY PartEntry,
2859{
2860 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2861 PLIST_ENTRY ListHead, AdjEntry;
2862
2863 /* In case of MBR disks only, check the logical partitions if necessary */
2864 if ((DiskEntry->DiskStyle == PARTITION_STYLE_MBR) &&
2865 PartEntry->LogicalPartition)
2866 {
2867 ListHead = &DiskEntry->LogicalPartListHead;
2868 }
2869 else
2870 {
2871 ListHead = &DiskEntry->PrimaryPartListHead;
2872 }
2873
2874 if (Direction)
2875 AdjEntry = PartEntry->ListEntry.Flink; // Next region.
2876 else
2877 AdjEntry = PartEntry->ListEntry.Blink; // Previous region.
2878
2879 if (AdjEntry != ListHead)
2880 {
2881 PartEntry = CONTAINING_RECORD(AdjEntry, PARTENTRY, ListEntry);
2882 if (!PartEntry->IsPartitioned)
2883 {
2884 ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2885 return PartEntry;
2886 }
2887 }
2888 return NULL;
2889}
2890
2891static ERROR_NUMBER
2893 _In_ PPARTENTRY PartEntry,
2894 _In_opt_ ULONGLONG SizeBytes,
2896{
2897 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2899
2900 // TODO: Re-enable once we initialize unpartitioned disks before using them.
2901 // ASSERT(DiskEntry->DiskStyle == PARTITION_STYLE_MBR);
2902 ASSERT(!PartEntry->IsPartitioned);
2903
2904 if (isContainer)
2905 {
2906 /* Cannot create an extended partition within logical partition space */
2907 if (PartEntry->LogicalPartition)
2909
2910 /* Fail if there is another extended partition in the list */
2911 if (DiskEntry->ExtendedPartition)
2913 }
2914
2915 /*
2916 * Primary or Extended partitions
2917 */
2918 if (!PartEntry->LogicalPartition || isContainer)
2919 {
2920 /* Only one primary partition is allowed on super-floppy */
2921 if (IsSuperFloppy(DiskEntry))
2923
2924 /* Fail if there are too many primary partitions */
2925 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
2927 }
2928 /*
2929 * Logical partitions
2930 */
2931 else
2932 {
2933 // TODO: Check that we are inside an extended partition!
2934 // Then the following check will be useless.
2935
2936 /* Only one (primary) partition is allowed on super-floppy */
2937 if (IsSuperFloppy(DiskEntry))
2939 }
2940
2941 return ERROR_SUCCESS;
2942}
2943
2945NTAPI
2947 _In_ PPARTENTRY PartEntry,
2948 _In_opt_ ULONGLONG SizeBytes,
2950{
2951 // PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2952
2953 /* Fail if the partition is already in use */
2954 if (PartEntry->IsPartitioned)
2955 return ERROR_NEW_PARTITION;
2956
2957 // TODO: Re-enable once we initialize unpartitioned disks before
2958 // using them; because such disks would be mistook as GPT otherwise.
2959 // if (DiskEntry->DiskStyle == PARTITION_STYLE_MBR)
2960 return MBRPartitionCreateChecks(PartEntry, SizeBytes, PartitionInfo);
2961#if 0
2962 else // if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2963 {
2964 DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2965 return ERROR_WARN_PARTITION;
2966 }
2967#endif
2968}
2969
2970// TODO: Improve upon the PartitionInfo parameter later
2971// (see VDS::CREATE_PARTITION_PARAMETERS and PPARTITION_INFORMATION_MBR/GPT for example)
2972// So far we only use it as the optional type of the partition to create.
2973BOOLEAN
2974NTAPI
2977 _Inout_ PPARTENTRY PartEntry,
2978 _In_opt_ ULONGLONG SizeBytes,
2980{
2983 PDISKENTRY DiskEntry;
2984 PCSTR mainType = "Primary";
2985
2986 if (isContainer)
2987 mainType = "Extended";
2988 else if (PartEntry && PartEntry->LogicalPartition)
2989 mainType = "Logical";
2990
2991 DPRINT1("CreatePartition(%s, %I64u bytes)\n", mainType, SizeBytes);
2992
2993 if (!List || !PartEntry ||
2994 !PartEntry->DiskEntry || PartEntry->IsPartitioned)
2995 {
2996 return FALSE;
2997 }
2998
2999 Error = PartitionCreateChecks(PartEntry, SizeBytes, PartitionInfo);
3000 if (Error != NOT_AN_ERROR)
3001 {
3002 DPRINT1("PartitionCreateChecks(%s) failed with error %lu\n", mainType, Error);
3003 return FALSE;
3004 }
3005
3006 /* Initialize the partition entry, inserting a new blank region if needed */
3007 if (!InitializePartitionEntry(PartEntry, SizeBytes, PartitionInfo))
3008 return FALSE;
3009
3010 DiskEntry = PartEntry->DiskEntry;
3011 UpdateDiskLayout(DiskEntry);
3012
3013 ASSERT(!PartEntry->Volume);
3014 if (!isContainer)
3015 {
3016 /* We create a primary/logical partition: initialize a new basic
3017 * volume entry. When the partition will actually be written onto
3018 * the disk, the PARTMGR will notify the MOUNTMGR that a volume
3019 * associated with this partition has to be created. */
3020 PartEntry->Volume = InitVolume(DiskEntry->PartList, PartEntry);
3021 ASSERT(PartEntry->Volume);
3022 }
3023
3025
3026 return TRUE;
3027}
3028
3029static NTSTATUS
3032 _In_ PPARTENTRY PartEntry)
3033{
3034 PVOLENTRY Volume = PartEntry->Volume;
3035
3036 ASSERT(PartEntry->DiskEntry->PartList == List);
3037
3038 if (Volume)
3039 {
3040 /* Partition validation checks */
3041 ASSERT(Volume->PartEntry == PartEntry);
3042 ASSERT(PartEntry->IsPartitioned);
3043 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
3044 ASSERT(!IsContainerPartition(PartEntry->PartitionType));
3045
3046 /* Dismount the basic volume: unlink the volume from the list */
3047 PartEntry->Volume = NULL;
3048 Volume->PartEntry = NULL;
3049 RemoveEntryList(&Volume->ListEntry);
3050
3051 /* Check whether the volume was mounted */
3052 // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
3053 // it has usually been mounted with RawFS and thus needs to be dismounted.
3054 if (Volume->New || (Volume->FormatState == UnknownFormat))
3055 {
3056 /* The volume is not mounted and can be deleted */
3058 Volume = NULL;
3059 }
3060 }
3061 if (!Volume)
3062 {
3063 /* The partition is not mounted, so just return success */
3064 return STATUS_SUCCESS;
3065 }
3066
3067 /* Dismount the basic volume, linking it into the list of volumes to unmount */
3068 // return DismountVolume(&Volume->Info, TRUE); // For when immediate operation mode is supported.
3069 InsertTailList(&List->PendingUnmountVolumesList, &Volume->ListEntry);
3070 return STATUS_SUCCESS;
3071}
3072
3073BOOLEAN
3074NTAPI
3077 _In_ PPARTENTRY PartEntry,
3078 _Out_opt_ PPARTENTRY* FreeRegion)
3079{
3080 PDISKENTRY DiskEntry;
3081 PPARTENTRY PrevPartEntry;
3082 PPARTENTRY NextPartEntry;
3083 PPARTENTRY LogicalPartEntry;
3085
3086 if (!List || !PartEntry ||
3087 !PartEntry->DiskEntry || !PartEntry->IsPartitioned)
3088 {
3089 return FALSE;
3090 }
3091
3092 ASSERT(PartEntry->DiskEntry->PartList == List);
3093 ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
3094
3095 /* Clear the system partition if it is being deleted */
3096 if (List->SystemPartition == PartEntry)
3097 {
3098 ASSERT(List->SystemPartition);
3099 List->SystemPartition = NULL;
3100 }
3101
3102 DiskEntry = PartEntry->DiskEntry;
3103
3104 /* Check which type of partition (primary/logical or extended) is being deleted */
3105 if (DiskEntry->ExtendedPartition == PartEntry)
3106 {
3107 /* An extended partition is being deleted: delete all logical partition entries */
3108 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
3109 {
3111 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3112
3113 /* Dismount the logical partition and delete it */
3114 DismountPartition(List, LogicalPartEntry);
3115 DestroyRegion(LogicalPartEntry);
3116 }
3117
3118 DiskEntry->ExtendedPartition = NULL;
3119 }
3120 else
3121 {
3122 /* A primary/logical partition is being deleted: dismount it */
3123 DismountPartition(List, PartEntry);
3124 }
3125
3126 /* Adjust the unpartitioned disk space entries */
3127
3128 /* Get pointer to previous and next unpartitioned entries */
3129 PrevPartEntry = GetAdjUnpartitionedEntry(PartEntry, FALSE);
3130 NextPartEntry = GetAdjUnpartitionedEntry(PartEntry, TRUE);
3131
3132 if (PrevPartEntry != NULL && NextPartEntry != NULL)
3133 {
3134 /* Merge the previous, current and next unpartitioned entries */
3135
3136 /* Adjust the previous entry length */
3137 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
3138
3139 /* Remove the current and next entries */
3140 RemoveEntryList(&PartEntry->ListEntry);
3141 DestroyRegion(PartEntry);
3142 RemoveEntryList(&NextPartEntry->ListEntry);
3143 DestroyRegion(NextPartEntry);
3144
3145 /* Optionally return the freed region */
3146 if (FreeRegion)
3147 *FreeRegion = PrevPartEntry;
3148 }
3149 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
3150 {
3151 /* Merge the current and the previous unpartitioned entries */
3152
3153 /* Adjust the previous entry length */
3154 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3155
3156 /* Remove the current entry */
3157 RemoveEntryList(&PartEntry->ListEntry);
3158 DestroyRegion(PartEntry);
3159
3160 /* Optionally return the freed region */
3161 if (FreeRegion)
3162 *FreeRegion = PrevPartEntry;
3163 }
3164 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
3165 {
3166 /* Merge the current and the next unpartitioned entries */
3167
3168 /* Adjust the next entry offset and length */
3169 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3170 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3171
3172 /* Remove the current entry */
3173 RemoveEntryList(&PartEntry->ListEntry);
3174 DestroyRegion(PartEntry);
3175
3176 /* Optionally return the freed region */
3177 if (FreeRegion)
3178 *FreeRegion = NextPartEntry;
3179 }
3180 else
3181 {
3182 /* Nothing to merge but change the current entry */
3183 PartEntry->New = FALSE;
3184 PartEntry->IsPartitioned = FALSE;
3185 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3186 PartEntry->OnDiskPartitionNumber = 0;
3187 PartEntry->PartitionNumber = 0;
3188 // PartEntry->PartitionIndex = 0;
3189 PartEntry->BootIndicator = FALSE;
3190 PartEntry->DeviceName[0] = UNICODE_NULL;
3191
3192 if (PartEntry->Volume)
3193 {
3194 RemoveEntryList(&PartEntry->Volume->ListEntry);
3195 RtlFreeHeap(ProcessHeap, 0, PartEntry->Volume);
3196 }
3197 PartEntry->Volume = NULL;
3198
3199 /* Optionally return the freed region */
3200 if (FreeRegion)
3201 *FreeRegion = PartEntry;
3202 }
3203
3204 UpdateDiskLayout(DiskEntry);
3206
3207 return TRUE;
3208}
3209
3210static
3211BOOLEAN
3213 IN PPARTENTRY PartEntry)
3214{
3216
3217 /* Check the type and the file system of this partition */
3218
3219 /*
3220 * We do not support extended partition containers (on MBR disks) marked
3221 * as active, and containing code inside their extended boot records.
3222 */
3223 if (IsContainerPartition(PartEntry->PartitionType))
3224 {
3225 DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3226 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3227 return FALSE;
3228 }
3229
3230 Volume = PartEntry->Volume;
3231 if (!Volume)
3232 {
3233 /* Still no recognizable volume mounted: partition not supported */
3234 return FALSE;
3235 }
3236
3237 /*
3238 * ADDITIONAL CHECKS / BIG HACK:
3239 *
3240 * Retrieve its file system and check whether we have
3241 * write support for it. If that is the case we are fine
3242 * and we can use it directly. However if we don't have
3243 * write support we will need to change the active system
3244 * partition.
3245 *
3246 * NOTE that this is completely useless on architectures
3247 * where a real system partition is required, as on these
3248 * architectures the partition uses the FAT FS, for which
3249 * we do have write support.
3250 * NOTE also that for those architectures looking for a
3251 * partition boot indicator is insufficient.
3252 */
3253 if (Volume->FormatState == Unformatted)
3254 {
3255 /* If this partition is mounted, it would use RawFS ("RAW") */
3256 return TRUE;
3257 }
3258 else if (Volume->FormatState == Formatted)
3259 {
3260 ASSERT(*Volume->Info.FileSystem);
3261
3262 /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3263 if (_wcsicmp(Volume->Info.FileSystem, L"FAT") == 0 ||
3264 _wcsicmp(Volume->Info.FileSystem, L"FAT32") == 0 ||
3265 // _wcsicmp(Volume->Info.FileSystem, L"NTFS") == 0 ||
3266 _wcsicmp(Volume->Info.FileSystem, L"BTRFS") == 0)
3267 {
3268 return TRUE;
3269 }
3270 else
3271 {
3272 // WARNING: We cannot write on this FS yet!
3273 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3274 Volume->Info.FileSystem);
3275 return FALSE;
3276 }
3277 }
3278 else // if (Volume->FormatState == UnknownFormat)
3279 {
3280 ASSERT(!*Volume->Info.FileSystem);
3281
3282 DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3283 PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3284 return FALSE;
3285 }
3286
3287 // HACK: WARNING: We cannot write on this FS yet!
3288 // See fsutil.c:InferFileSystem()
3289 if (PartEntry->PartitionType == PARTITION_IFS)
3290 {
3291 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3292 Volume->Info.FileSystem);
3293 return FALSE;
3294 }
3295
3296 return TRUE;
3297}
3298
3302 IN BOOLEAN ForceSelect,
3303 IN PDISKENTRY AlternativeDisk OPTIONAL,
3304 IN PPARTENTRY AlternativePart OPTIONAL)
3305{
3306 PLIST_ENTRY ListEntry;
3307 PDISKENTRY DiskEntry;
3308 PPARTENTRY PartEntry;
3309 PPARTENTRY ActivePartition;
3310 PPARTENTRY CandidatePartition = NULL;
3311
3312 /* Check for empty disk list */
3313 if (IsListEmpty(&List->DiskListHead))
3314 {
3315 /* No system partition! */
3316 ASSERT(List->SystemPartition == NULL);
3317 goto NoSystemPartition;
3318 }
3319
3320 /* Adjust the optional alternative disk if needed */
3321 if (!AlternativeDisk && AlternativePart)
3322 AlternativeDisk = AlternativePart->DiskEntry;
3323
3324 /* Ensure that the alternative partition is on the alternative disk */
3325 if (AlternativePart)
3326 ASSERT(AlternativeDisk && (AlternativePart->DiskEntry == AlternativeDisk));
3327
3328 /* Ensure that the alternative disk is in the list */
3329 if (AlternativeDisk)
3330 ASSERT(AlternativeDisk->PartList == List);
3331
3332 /* Start fresh */
3333 CandidatePartition = NULL;
3334
3335//
3336// Step 1 : Check the system disk.
3337//
3338
3339 /*
3340 * First, check whether the system disk, i.e. the one that will be booted
3341 * by default by the hardware, contains an active partition. If so this
3342 * should be our system partition.
3343 */
3344 DiskEntry = GetSystemDisk(List);
3345 if (!DiskEntry)
3346 {
3347 /* No system disk found, directly go check the alternative disk */
3348 goto UseAlternativeDisk;
3349 }
3350
3351 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3352 {
3353 DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3354 goto UseAlternativeDisk;
3355 }
3356
3357 /* If we have a system partition (in the system disk), validate it */
3358 ActivePartition = List->SystemPartition;
3359 if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3360 {
3361 CandidatePartition = ActivePartition;
3362
3363 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3364 CandidatePartition->PartitionNumber,
3365 CandidatePartition->DiskEntry->DiskNumber,
3366 !CandidatePartition->Volume->Info.DriveLetter ? L'-' : CandidatePartition->Volume->Info.DriveLetter);
3367
3368 /* Return the candidate system partition */
3369 return CandidatePartition;
3370 }
3371
3372 /* If the system disk is not the optional alternative disk, perform the minimal checks */
3373 if (DiskEntry != AlternativeDisk)
3374 {
3375 /*
3376 * No active partition has been recognized. Enumerate all the (primary)
3377 * partitions in the system disk, excluding the possible current active
3378 * partition, to find a new candidate.
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 /* Skip the current active partition */
3388 if (PartEntry == ActivePartition)
3389 continue;
3390
3391 /* Check if the partition is partitioned and used */
3392 if (PartEntry->IsPartitioned &&
3394 {
3396
3397 /* If we get a candidate active partition in the disk, validate it */
3398 if (IsSupportedActivePartition(PartEntry))
3399 {
3400 CandidatePartition = PartEntry;
3401 goto UseAlternativePartition;
3402 }
3403 }
3404
3405#if 0
3406 /* Check if the partition is partitioned and used */
3407 if (!PartEntry->IsPartitioned)
3408 {
3410
3411 // TODO: Check for minimal size!!
3412 CandidatePartition = PartEntry;
3413 goto UseAlternativePartition;
3414 }
3415#endif
3416 }
3417
3418 /*
3419 * Still nothing, look whether there is some free space that we can use
3420 * for the new system partition. We must be sure that the total number
3421 * of partition is less than the maximum allowed, and that the minimal
3422 * size is fine.
3423 */
3424//
3425// TODO: Fix the handling of system partition being created in unpartitioned space!!
3426// --> When to partition it? etc...
3427//
3428 if (GetPrimaryPartitionCount(DiskEntry) < 4)
3429 {
3430 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3431 ListEntry != &DiskEntry->PrimaryPartListHead;
3432 ListEntry = ListEntry->Flink)
3433 {
3434 /* Retrieve the partition */
3435 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3436
3437 /* Skip the current active partition */
3438 if (PartEntry == ActivePartition)
3439 continue;
3440
3441 /* Check for unpartitioned space */
3442 if (!PartEntry->IsPartitioned)
3443 {
3445
3446 // TODO: Check for minimal size!!
3447 CandidatePartition = PartEntry;
3448 goto UseAlternativePartition;
3449 }
3450 }
3451 }
3452 }
3453
3454
3455//
3456// Step 2 : No active partition found: Check the alternative disk if specified.
3457//
3458
3459UseAlternativeDisk:
3460 if (!AlternativeDisk || (!ForceSelect && (DiskEntry != AlternativeDisk)))
3461 goto NoSystemPartition;
3462
3463 if (AlternativeDisk->DiskStyle == PARTITION_STYLE_GPT)
3464 {
3465 DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3466 goto NoSystemPartition;
3467 }
3468
3469 if (DiskEntry != AlternativeDisk)
3470 {
3471 /* Choose the alternative disk */
3472 DiskEntry = AlternativeDisk;
3473
3474 /* If we get a candidate active partition, validate it */
3475 ActivePartition = GetActiveDiskPartition(DiskEntry);
3476 if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3477 {
3478 CandidatePartition = ActivePartition;
3479 goto UseAlternativePartition;
3480 }
3481 }
3482
3483 /* We now may have an unsupported active partition, or none */
3484
3485/***
3486 *** TODO: Improve the selection:
3487 *** - If we want a really separate system partition from the partition where
3488 *** we install, do something similar to what's done below in the code.
3489 *** - Otherwise if we allow for the system partition to be also the partition
3490 *** where we install, just directly fall down to using AlternativePart.
3491 ***/
3492
3493 /* Retrieve the first partition of the disk */
3494 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3495 PARTENTRY, ListEntry);
3496 ASSERT(DiskEntry == PartEntry->DiskEntry);
3497
3498 CandidatePartition = PartEntry;
3499
3500 //
3501 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3502 //
3503
3504 /* Check if the disk is new and if so, use its first partition as the active system partition */
3505 if (DiskEntry->NewDisk)
3506 {
3507 // !IsContainerPartition(PartEntry->PartitionType);
3508 if (!CandidatePartition->IsPartitioned || !CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */
3509 {
3510 ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3511
3512 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3513 CandidatePartition->PartitionNumber,
3514 CandidatePartition->DiskEntry->DiskNumber,
3515 (!CandidatePartition->Volume || !CandidatePartition->Volume->Info.DriveLetter) ?
3516 L'-' : CandidatePartition->Volume->Info.DriveLetter);
3517
3518 /* Return the candidate system partition */
3519 return CandidatePartition;
3520 }
3521
3522 // FIXME: What to do??
3523 DPRINT1("NewDisk TRUE but first partition is used?\n");
3524 }
3525
3526 /*
3527 * The disk is not new, check if any partition is initialized;
3528 * if not, the first one becomes the system partition.
3529 */
3530 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3531 ListEntry != &DiskEntry->PrimaryPartListHead;
3532 ListEntry = ListEntry->Flink)
3533 {
3534 /* Retrieve the partition */
3535 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3536
3537 /* Check if the partition is partitioned and is used */
3538 // !IsContainerPartition(PartEntry->PartitionType);
3539 if (/* PartEntry->IsPartitioned && */
3540 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator)
3541 {
3542 break;
3543 }
3544 }
3545 if (ListEntry == &DiskEntry->PrimaryPartListHead)
3546 {
3547 /*
3548 * OK we haven't encountered any used and active partition,
3549 * so use the first one as the system partition.
3550 */
3551 ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3552
3553 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3554 CandidatePartition->PartitionNumber,
3555 CandidatePartition->DiskEntry->DiskNumber,
3556 (!CandidatePartition->Volume || !CandidatePartition->Volume->Info.DriveLetter) ?
3557 L'-' : CandidatePartition->Volume->Info.DriveLetter);
3558
3559 /* Return the candidate system partition */
3560 return CandidatePartition;
3561 }
3562
3563 /*
3564 * The disk is not new, we did not find any actual active partition,
3565 * or the one we found was not supported, or any possible other candidate
3566 * is not supported. We then use the alternative partition if specified.
3567 */
3568 if (AlternativePart)
3569 {
3570 DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n");
3571 CandidatePartition = AlternativePart;
3572 goto UseAlternativePartition;
3573 }
3574 else
3575 {
3576NoSystemPartition:
3577 DPRINT1("No valid or supported system partition has been found on this system!\n");
3578 return NULL;
3579 }
3580
3581UseAlternativePartition:
3582 /*
3583 * We are here because we did not find any (active) candidate system
3584 * partition that we know how to support. What we are going to do is
3585 * to change the existing system partition and use the alternative partition
3586 * (e.g. on which we install ReactOS) as the new system partition.
3587 * Then we will need to add in FreeLdr's boot menu an entry for booting
3588 * from the original system partition.
3589 */
3590 ASSERT(CandidatePartition);
3591
3592 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3593 CandidatePartition->PartitionNumber,
3594 CandidatePartition->DiskEntry->DiskNumber,
3595 (!CandidatePartition->Volume || !CandidatePartition->Volume->Info.DriveLetter) ?
3596 L'-' : CandidatePartition->Volume->Info.DriveLetter);
3597
3598 /* Return the candidate system partition */
3599 return CandidatePartition;
3600}
3601
3602BOOLEAN
3605 IN PPARTENTRY PartEntry,
3606 IN PPARTENTRY OldActivePart OPTIONAL)
3607{
3608 /* Check for empty disk list */
3609 if (IsListEmpty(&List->DiskListHead))
3610 return FALSE;
3611
3612 /* Validate the partition entry */
3613 if (!PartEntry)
3614 return FALSE;
3615
3616 /*
3617 * If the partition entry is already the system partition, or if it is
3618 * the same as the old active partition hint the user provided (and if
3619 * it is already active), just return success.
3620 */
3621 if ((PartEntry == List->SystemPartition) ||
3622 ((PartEntry == OldActivePart) && IsPartitionActive(OldActivePart)))
3623 {
3624 return TRUE;
3625 }
3626
3627 ASSERT(PartEntry->DiskEntry);
3628
3629 /* Ensure that the partition's disk is in the list */
3630 ASSERT(PartEntry->DiskEntry->PartList == List);
3631
3632 /*
3633 * If the user provided an old active partition hint, verify that it is
3634 * indeed active and belongs to the same disk where the new partition
3635 * belongs. Otherwise determine the current active partition on the disk
3636 * where the new partition belongs.
3637 */
3638 if (!(OldActivePart && IsPartitionActive(OldActivePart) && (OldActivePart->DiskEntry == PartEntry->DiskEntry)))
3639 {
3640 /* It's not, determine the current active partition for the disk */
3641 OldActivePart = GetActiveDiskPartition(PartEntry->DiskEntry);
3642 }
3643
3644 /* Unset the old active partition if it exists */
3645 if (OldActivePart)
3646 {
3647 OldActivePart->BootIndicator = FALSE;
3648 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].BootIndicator = FALSE;
3649 OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].RewritePartition = TRUE;
3650 OldActivePart->DiskEntry->Dirty = TRUE;
3651 }
3652
3653 /* Modify the system partition if the new partition is on the system disk */
3654 if (PartEntry->DiskEntry == GetSystemDisk(List))
3655 List->SystemPartition = PartEntry;
3656
3657 /* Set the new active partition */
3658 PartEntry->BootIndicator = TRUE;
3659 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
3660 PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3661 PartEntry->DiskEntry->Dirty = TRUE;
3662
3663 return TRUE;
3664}
3665
3668 IN PDISKENTRY DiskEntry)
3669{
3677 ULONG PartitionCount;
3678 PLIST_ENTRY ListEntry;
3679 PPARTENTRY PartEntry;
3681
3682 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3683
3684 /* If the disk is not dirty, there is nothing to do */
3685 if (!DiskEntry->Dirty)
3686 return STATUS_SUCCESS;
3687
3689 L"\\Device\\Harddisk%lu\\Partition0",
3690 DiskEntry->DiskNumber);
3692
3694 &Name,
3696 NULL,
3697 NULL);
3698
3702 &Iosb,
3703 0,
3705 if (!NT_SUCCESS(Status))
3706 {
3707 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3708 return Status;
3709 }
3710
3711#ifdef DUMP_PARTITION_TABLE
3712 DumpPartitionTable(DiskEntry);
3713#endif
3714
3715 //
3716 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3717 // the disk in MBR or GPT format in case the disk was not initialized!!
3718 // For this we must ask the user which format to use.
3719 //
3720
3721 /* Save the original partition count to be restored later (see comment below) */
3722 PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
3723
3724 /* Set the new disk layout and retrieve its updated version with
3725 * new partition numbers for the new partitions. The PARTMGR will
3726 * automatically notify the MOUNTMGR of new or deleted volumes. */
3728 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3730 NULL,
3731 NULL,
3732 NULL,
3733 &Iosb,
3735 DiskEntry->LayoutBuffer,
3736 BufferSize,
3737 DiskEntry->LayoutBuffer,
3738 BufferSize);
3740
3741 /*
3742 * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3743 * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3744 * where such a table is expected to enumerate up to 4 partitions:
3745 * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3746 * Due to this we need to restore the original PartitionCount number.
3747 */
3748 DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
3749
3750 /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3751 if (!NT_SUCCESS(Status))
3752 {
3753 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3754 return Status;
3755 }
3756
3757#ifdef DUMP_PARTITION_TABLE
3758 DumpPartitionTable(DiskEntry);
3759#endif
3760
3761 /* Update the partition numbers and device names */
3762
3763 /* Update the primary partition table */
3764 for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3765 ListEntry != &DiskEntry->PrimaryPartListHead;
3766 ListEntry = ListEntry->Flink)
3767 {
3768 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3769 if (!PartEntry->IsPartitioned)
3770 continue;
3772
3773 /*
3774 * Initialize the partition's number and its device name only
3775 * if the partition was new. Note that the partition number
3776 * should not change if this partition has not been deleted
3777 * during repartitioning.
3778 */
3779 // FIXME: Our PartMgr currently returns modified numbers
3780 // in the layout, this needs to be investigated and fixed.
3781 if (PartEntry->New)
3782 {
3783 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3784 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3785 InitPartitionDeviceName(PartEntry);
3786 }
3787 PartEntry->New = FALSE;
3788 }
3789
3790 /* Update the logical partition table */
3791 for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
3792 ListEntry != &DiskEntry->LogicalPartListHead;
3793 ListEntry = ListEntry->Flink)
3794 {
3795 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3796 if (!PartEntry->IsPartitioned)
3797 continue;
3799
3800 /* See comment above */
3801 if (PartEntry->New)
3802 {
3803 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3804 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3805 InitPartitionDeviceName(PartEntry);
3806 }
3807 PartEntry->New = FALSE;
3808 }
3809
3810 //
3811 // NOTE: Originally (see r40437), we used to install here also a new MBR
3812 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3813 // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0.
3814 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3815 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3816 // was called too, the installation test was modified by checking whether
3817 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3818 //
3819
3820 // HACK: Parts of FIXMEs described above: (Re)set the PartitionStyle to MBR.
3821 DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
3822
3823 /* The layout has been successfully updated, the disk is not dirty anymore */
3824 DiskEntry->Dirty = FALSE;
3825
3826 return Status;
3827}
3828
3829BOOLEAN
3832{
3835 PDISKENTRY DiskEntry;
3837
3838 if (!List)
3839 return TRUE;
3840
3841 /* Unmount all the pending volumes */
3843 while (!IsListEmpty(&List->PendingUnmountVolumesList))
3844 {
3845 NTSTATUS UnmountStatus;
3846 Entry = RemoveHeadList(&List->PendingUnmountVolumesList);
3847 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3848 UnmountStatus = DismountVolume(&Volume->Info, TRUE);
3849 if (!NT_SUCCESS(UnmountStatus))
3850 Status = UnmountStatus;
3852 }
3853 if (!NT_SUCCESS(Status))
3854 return FALSE;
3855
3856 /* Write all the partitions to all the disks */
3857 for (Entry = List->DiskListHead.Flink;
3858 Entry != &List->DiskListHead;
3859 Entry = Entry->Flink)
3860 {
3861 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3862
3863 if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3864 {
3865 DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3866 continue;
3867 }
3868
3869 if (DiskEntry->Dirty != FALSE)
3870 {
3871 Status = WritePartitions(DiskEntry);
3872 if (!NT_SUCCESS(Status))
3873 {
3874 DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3875 DiskEntry->DiskNumber, Status);
3876 }
3877 }
3878 }
3879
3880 /* The PARTMGR should have notified the MOUNTMGR that new volumes
3881 * associated with the new partitions had to be created */
3882
3883 /* Assign valid device names to new volumes */
3884 for (Entry = List->VolumesList.Flink;
3885 Entry != &List->VolumesList;
3886 Entry = Entry->Flink)
3887 {
3888 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3890 }
3891
3892 return TRUE;
3893}
3894
3895
3901static BOOLEAN
3904{
3905 PPARTENTRY PartEntry = Volume->PartEntry;
3906 WCHAR Letter = Volume->Info.DriveLetter;
3909 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices");
3911 WCHAR Buffer[16];
3913 REG_DISK_MOUNT_INFO MountInfo;
3914
3915 /* Ignore no letter */
3916 if (!Letter)
3917 return TRUE;
3918
3920 L"\\DosDevices\\%c:", Letter);
3922
3924 &KeyName,
3927 NULL);
3928
3932 if (!NT_SUCCESS(Status))
3933 {
3937 0,
3938 NULL,
3940 NULL);
3941 }
3942 if (!NT_SUCCESS(Status))
3943 {
3944 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3945 return FALSE;
3946 }
3947
3948 MountInfo.Signature = PartEntry->DiskEntry->LayoutBuffer->Signature;
3949 MountInfo.StartingOffset = GetPartEntryOffsetInBytes(PartEntry);
3951 &ValueName,
3952 0,
3953 REG_BINARY,
3954 (PVOID)&MountInfo,
3955 sizeof(MountInfo));
3957 if (!NT_SUCCESS(Status))
3958 {
3959 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3960 return FALSE;
3961 }
3962
3963 return TRUE;
3964}
3965
3966BOOLEAN
3969{
3972
3973 if (!List)
3974 return FALSE;
3975
3976 for (Entry = List->VolumesList.Flink;
3977 Entry != &List->VolumesList;
3978 Entry = Entry->Flink)
3979 {
3980 Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
3981
3982 /* Assign a "\DosDevices\#:" mount point to this volume */
3984 return FALSE;
3985 }
3986
3987 return TRUE;
3988}
3989
3990VOID
3992 IN PPARTENTRY PartEntry,
3994{
3995 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3996
3997 ASSERT(DiskEntry->DiskStyle == PARTITION_STYLE_MBR);
3998
3999 /* Nothing to do if we assign the same type */
4000 if (PartitionType == PartEntry->PartitionType)
4001 return;
4002
4003 // TODO: We might need to remount the associated basic volume...
4004
4005 PartEntry->PartitionType = PartitionType;
4006
4007 DiskEntry->Dirty = TRUE;
4008 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
4009 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
4010 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
4011}
4012
4013/* EOF */
DWORD Id
WCHAR Letter
unsigned char BOOLEAN
Definition: actypes.h:127
@ Identifier
Definition: asmpp.cpp:95
LONG NTSTATUS
Definition: precomp.h:26
HANDLE ProcessHeap
Definition: servman.c:15
#define DPRINT1
Definition: precomp.h:8
HANDLE GetRootKeyByPredefKey(IN HANDLE KeyHandle, OUT PCWSTR *RootKeyMountPoint OPTIONAL)
Definition: registry.c:90
BOOL Error
Definition: chkdsk.c:66
#define PARTITION_IFS
Definition: disk.h:78
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:71
#define PARTITION_EXTENDED
Definition: disk.h:76
#define PARTITION_FAT_16
Definition: disk.h:75
#define PARTITION_XINT13_EXTENDED
Definition: disk.h:83
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:616
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:634
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:160
#define IOCTL_DISK_GET_DRIVE_GEOMETRY
Definition: cdrw_usr.h:169
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define STATUS_NO_MEMORY
Definition: d3dkmdt.h:51
#define BufferSize
Definition: mmc.h:75
#define ERROR_SUCCESS
Definition: deptool.c:10
LPWSTR Name
Definition: desk.c:124
NTSTATUS pOpenDevice(_In_ PCWSTR DevicePath, _Out_ PHANDLE DeviceHandle)
Open an existing device given by its NT-style path, which is assumed to be for a disk device or a par...
Definition: devutils.c:128
PDISKENTRY CurrentDisk
Definition: partlist.c:75
@ LogicalPartition
Definition: disksup.c:48
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define RTL_CONSTANT_STRING(s)
Definition: combase.c:35
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_READ
Definition: compat.h:136
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
_ACRTIMP int __cdecl _wcsicmp(const wchar_t *, const wchar_t *)
Definition: wcs.c:159
static const WCHAR Signature[]
Definition: parser.c:141
#define L(x)
Definition: resources.c:13
return Iosb
Definition: create.c:4403
BOOLEAN RtlTimeToTimeFields(IN PLARGE_INTEGER Time, IN PTIME_FIELDS TimeFields)
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
enum _ERROR_NUMBER ERROR_NUMBER
@ NOT_AN_ERROR
Definition: errorcode.h:17
@ ERROR_WARN_PARTITION
Definition: errorcode.h:33
@ ERROR_NEW_PARTITION
Definition: errorcode.h:34
@ ERROR_ONLY_ONE_EXTENDED
Definition: errorcode.h:59
@ ERROR_PARTITION_TABLE_FULL
Definition: errorcode.h:58
ULONG ControllerCount
Definition: fdc.c:18
@ SystemDeviceInformation
Definition: ntddk_ex.h:18
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
_Must_inspect_result_ _Out_ PHANDLE VolumeHandle
Definition: fltkernel.h:2283
#define FILE_SYNCHRONOUS_IO_NONALERT
Definition: from_kernel.h:31
@ FileFsDeviceInformation
Definition: from_kernel.h:222
UCHAR FileSystemToMBRPartitionType(IN PCWSTR FileSystem, IN ULONGLONG StartSector, IN ULONGLONG SectorCount)
Definition: fsrec.c:333
union Alignment_ Alignment
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define DbgPrint
Definition: hal.h:12
CPPORT Port[4]
Definition: headless.c:38
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:312
#define REG_SZ
Definition: layer.c:22
#define IsOEMPartition(PartitionType)
Definition: partlist.h:22
struct _PARTLIST * PPARTLIST
struct _BIOSDISKENTRY * PBIOSDISKENTRY
@ UnknownFormat
Definition: partlist.h:36
@ Formatted
Definition: partlist.h:37
@ Unformatted
Definition: partlist.h:34
#define GetDiskSizeInBytes(DiskEntry)
Definition: partlist.h:258
#define EFI_PMBR_OSTYPE_EFI
Definition: partlist.h:197
#define PARTITION_MAGIC
Definition: partlist.h:194
#define GetPartEntryOffsetInBytes(PartEntry)
Definition: partlist.h:252
#define GetPartEntrySizeInBytes(PartEntry)
Definition: partlist.h:255
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
#define for
Definition: utility.h:88
#define IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
Definition: imports.h:91
@ PARTITION_STYLE_GPT
Definition: imports.h:202
@ PARTITION_STYLE_MBR
Definition: imports.h:201
#define ULL(a, b)
Definition: format_msg.c:27
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
static PTIME_FIELDS TimeFields
Definition: time.c:104
#define min(a, b)
Definition: monoChain.cc:55
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
_In_ PCWSTR _Inout_ _At_ QueryTable EntryContext
Definition: rtlfuncs.h:4210
_In_ PCWSTR _Inout_ _At_ QueryTable _Pre_unknown_ PRTL_QUERY_REGISTRY_TABLE QueryTable
Definition: rtlfuncs.h:4211
#define _Out_opt_
Definition: no_sal2.h:214
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
int Count
Definition: noreturn.cpp:7
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3953
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:336
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
#define SYNCHRONIZE
Definition: nt_native.h:61
NTSYSAPI NTSTATUS NTAPI NtSetValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex OPTIONAL, IN ULONG Type, IN PVOID Data, IN ULONG DataSize)
Definition: ntapi.c:859
#define REG_BINARY
Definition: nt_native.h:1499
#define FILE_READ_DATA
Definition: nt_native.h:628
#define KEY_ALL_ACCESS
Definition: nt_native.h:1044
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RTL_REGISTRY_ABSOLUTE
Definition: nt_native.h:161
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1060
NTSYSAPI NTSTATUS NTAPI RtlUnicodeStringToInteger(PUNICODE_STRING String, ULONG Base, PULONG Value)
NTSYSAPI NTSTATUS NTAPI NtDeviceIoControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
#define RTL_REGISTRY_DEVICEMAP
Definition: nt_native.h:165
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
#define GENERIC_WRITE
Definition: nt_native.h:90
#define REG_FULL_RESOURCE_DESCRIPTOR
Definition: nt_native.h:1506
NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
Definition: ntapi.c:240
#define UNICODE_NULL
#define RTL_SIZEOF_THROUGH_FIELD(type, field)
Definition: ntbasedef.h:684
#define IOCTL_DISK_SET_DRIVE_LAYOUT
Definition: ntdddisk.h:205
#define IsContainerPartition(PartitionType)
Definition: ntdddisk.h:321
#define IsRecognizedPartition(PartitionType)
Definition: ntdddisk.h:342
#define IOCTL_DISK_GET_DRIVE_LAYOUT
Definition: ntdddisk.h:91
struct _PARTITION_INFORMATION PARTITION_INFORMATION
@ RemovableMedia
Definition: ntdddisk.h:382
@ FixedMedia
Definition: ntdddisk.h:383
struct _DRIVE_LAYOUT_INFORMATION DRIVE_LAYOUT_INFORMATION
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
NTSTATUS NTAPI NtQuerySystemTime(OUT PLARGE_INTEGER SystemTime)
Definition: time.c:569
NTSTRSAFEAPI RtlStringCchCopyNW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_reads_or_z_(cchToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cchToCopy)
Definition: ntstrsafe.h:363
NTSTRSAFEAPI RtlStringCchCopyW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:127
NTSTRSAFEVAPI RtlStringCchPrintfW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ NTSTRSAFE_PCWSTR pszFormat,...)
Definition: ntstrsafe.h:1110
ULONG SectorCount
Definition: part_xbox.c:31
CHAR PartitionType
Definition: part_xbox.c:32
unsigned short USHORT
Definition: pedump.c:61
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
struct _CM_FULL_RESOURCE_DESCRIPTOR * PCM_FULL_RESOURCE_DESCRIPTOR
#define CmResourceTypeDeviceSpecific
Definition: restypes.h:108
#define IOCTL_SCSI_GET_ADDRESS
Definition: scsi_port.h:52
#define memset(x, y, z)
Definition: compat.h:39
IN HANDLE DstPath
Definition: fsutil.h:81
BOOLEAN SetMountedDeviceValues(_In_ PPARTLIST List)
Definition: partlist.c:3967
static VOID AddPartitionToDisk(IN ULONG DiskNumber, IN PDISKENTRY DiskEntry, IN ULONG PartitionIndex, IN BOOLEAN LogicalPartition)
Definition: partlist.c:1040
static NTSTATUS InitVolumeDeviceName(_Inout_ PVOLENTRY Volume, _In_opt_ PCWSTR AltDeviceName)
Definition: partlist.c:923
BOOLEAN IsDiskSuperFloppy2(_In_ const DISK_PARTITION_INFO *DiskInfo, _In_opt_ const ULONGLONG *DiskSize, _In_ const PARTITION_INFORMATION *PartitionInfo)
Definition: partlist.c:493
static ERROR_NUMBER MBRPartitionCreateChecks(_In_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:2892
ERROR_NUMBER NTAPI PartitionCreateChecks(_In_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:2946
static BOOLEAN SetMountedDeviceValue(_In_ PVOLENTRY Volume)
Assign a "\DosDevices\#:" mount point drive letter to a disk partition or volume, specified by a give...
Definition: partlist.c:3902
static VOID GetDriverName(IN PDISKENTRY DiskEntry)
Definition: partlist.c:107
struct _REG_DISK_MOUNT_INFO * PREG_DISK_MOUNT_INFO
static PDISKENTRY GetSystemDisk(IN PPARTLIST List)
Definition: partlist.c:1912
ULONGLONG AlignUp(IN ULONGLONG Value, IN ULONG Alignment)
Definition: partlist.c:81
static VOID UpdateDiskLayout(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2654
static VOID DestroyRegion(_Inout_ PPARTENTRY PartEntry)
Definition: partlist.c:731
BOOLEAN WritePartitionsToDisk(IN PPARTLIST List)
Definition: partlist.c:3830
ULONGLONG RoundingDivide(IN ULONGLONG Dividend, IN ULONGLONG Divisor)
Definition: partlist.c:97
VOID SetMBRPartitionType(IN PPARTENTRY PartEntry, IN UCHAR PartitionType)
Definition: partlist.c:3991
VOID NTAPI DestroyPartitionList(IN PPARTLIST List)
Definition: partlist.c:2130
BOOLEAN IsSuperFloppy(_In_ PDISKENTRY DiskEntry)
Definition: partlist.c:602
static VOID AssignDriveLetters(IN PPARTLIST List)
Definition: partlist.c:140
static ULONG GetPartitionCount(_In_ PLIST_ENTRY PartListHead)
Counts the number of partitioned disk regions in a given partition list.
Definition: partlist.c:2573
static VOID InitPartitionDeviceName(_Inout_ PPARTENTRY PartEntry)
Definition: partlist.c:902
static BOOLEAN IsSamePrimaryLayoutEntry(_In_ PPARTITION_INFORMATION PartitionInfo, _In_ PPARTENTRY PartEntry)
Definition: partlist.c:2557
ULONGLONG AlignDown(IN ULONGLONG Value, IN ULONG Alignment)
Definition: partlist.c:69
PPARTENTRY NTAPI GetAdjUnpartitionedEntry(_In_ PPARTENTRY PartEntry, _In_ BOOLEAN Direction)
Retrieves, if any, the unpartitioned disk region that is adjacent (next or previous) to the specified...
Definition: partlist.c:2856
static VOID SetDiskSignature(IN PPARTLIST List, IN PDISKENTRY DiskEntry)
Definition: partlist.c:1347
PDISKENTRY GetDiskByBiosNumber(_In_ PPARTLIST List, _In_ ULONG HwDiskNumber)
Definition: partlist.c:2193
BOOLEAN NTAPI CreatePartition(_In_ PPARTLIST List, _Inout_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:2975
PDISKENTRY GetDiskBySCSI(_In_ PPARTLIST List, _In_ USHORT Port, _In_ USHORT Bus, _In_ USHORT Id)
Definition: partlist.c:2239
BOOLEAN NTAPI DeletePartition(_In_ PPARTLIST List, _In_ PPARTENTRY PartEntry, _Out_opt_ PPARTENTRY *FreeRegion)
Definition: partlist.c:3075
PDISKENTRY GetDiskBySignature(_In_ PPARTLIST List, _In_ ULONG Signature)
Definition: partlist.c:2269
static NTSTATUS NTAPI DiskConfigurationDataQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:239
#define ROOT_NAME
PPARTENTRY GetPartition(_In_ PDISKENTRY DiskEntry, _In_ ULONG PartitionNumber)
Definition: partlist.c:2292
static VOID AddDiskToList(IN HANDLE FileHandle, IN ULONG DiskNumber, IN PPARTLIST List)
Definition: partlist.c:1500
static VOID ScanForUnpartitionedDiskSpace(IN PDISKENTRY DiskEntry)
Definition: partlist.c:1150
static NTSTATUS NTAPI SystemConfigurationDataQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:282
BOOLEAN IsPartitionActive(IN PPARTENTRY PartEntry)
Definition: partlist.c:1962
PPARTLIST NTAPI CreatePartitionList(VOID)
Definition: partlist.c:2043
static NTSTATUS DismountPartition(_In_ PPARTLIST List, _In_ PPARTENTRY PartEntry)
Definition: partlist.c:3030
static VOID UpdateDiskSignatures(IN PPARTLIST List)
Definition: partlist.c:1409
BOOLEAN SetActivePartition(IN PPARTLIST List, IN PPARTENTRY PartEntry, IN PPARTENTRY OldActivePart OPTIONAL)
Definition: partlist.c:3603
static VOID EnumerateBiosDiskEntries(IN PPARTLIST PartList)
Definition: partlist.c:329
PPARTENTRY NTAPI GetPrevPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2452
static PPARTENTRY CreateInsertBlankRegion(IN PDISKENTRY DiskEntry, IN OUT PLIST_ENTRY ListHead, IN ULONGLONG StartSector, IN ULONGLONG SectorCount, IN BOOLEAN LogicalSpace)
Definition: partlist.c:694
static PPARTENTRY GetActiveDiskPartition(IN PDISKENTRY DiskEntry)
Definition: partlist.c:1985
struct _REG_DISK_MOUNT_INFO REG_DISK_MOUNT_INFO
static PVOLENTRY InitVolume(_In_ PPARTLIST List, _In_opt_ PPARTENTRY PartEntry)
Definition: partlist.c:1001
BOOLEAN IsDiskSuperFloppyEx(_In_ const DRIVE_LAYOUT_INFORMATION_EX *LayoutEx, _In_opt_ const ULONGLONG *DiskSize)
Definition: partlist.c:565
PPARTENTRY SelectPartition(_In_ PPARTLIST List, _In_ ULONG DiskNumber, _In_ ULONG PartitionNumber)
Definition: partlist.c:2333
PPARTENTRY NTAPI GetNextPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2359
static BOOLEAN InsertDiskRegion(IN PDISKENTRY DiskEntry, IN PPARTENTRY PartEntry, IN BOOLEAN LogicalPartition)
Definition: partlist.c:628
static BOOLEAN IsEmptyLayoutEntry(_In_ PPARTITION_INFORMATION PartitionInfo)
Definition: partlist.c:2548
PDISKENTRY GetDiskByNumber(_In_ PPARTLIST List, _In_ ULONG DiskNumber)
Definition: partlist.c:2216
static VOID UpdateHwDiskNumbers(IN PPARTLIST List)
Definition: partlist.c:1439
static BOOLEAN ReAllocateLayoutBuffer(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2602
#define GetLogicalPartitionCount(DiskEntry)
Definition: partlist.c:2595
PPARTENTRY FindSupportedSystemPartition(IN PPARTLIST List, IN BOOLEAN ForceSelect, IN PDISKENTRY AlternativeDisk OPTIONAL, IN PPARTENTRY AlternativePart OPTIONAL)
Definition: partlist.c:3300
static BOOLEAN IsSupportedActivePartition(IN PPARTENTRY PartEntry)
Definition: partlist.c:3212
static BOOLEAN InitializePartitionEntry(_Inout_ PPARTENTRY PartEntry, _In_opt_ ULONGLONG SizeBytes, _In_opt_ ULONG_PTR PartitionInfo)
Definition: partlist.c:772
#define GetPrimaryPartitionCount(DiskEntry)
Definition: partlist.c:2592
static NTSTATUS NTAPI DiskIdentifierQueryRoutine(PWSTR ValueName, ULONG ValueType, PVOID ValueData, ULONG ValueLength, PVOID Context, PVOID EntryContext)
Definition: partlist.c:209
NTSTATUS WritePartitions(IN PDISKENTRY DiskEntry)
Definition: partlist.c:3667
BOOLEAN IsDiskSuperFloppy(_In_ const DRIVE_LAYOUT_INFORMATION *Layout, _In_opt_ const ULONGLONG *DiskSize)
Definition: partlist.c:544
static VOID AddLogicalDiskSpace(_In_ PDISKENTRY DiskEntry)
Definition: partlist.c:742
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
NTSTATUS NTAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key)
#define DPRINT
Definition: sndvol32.h:73
#define _countof(array)
Definition: sndvol32.h:70
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
NTSYSAPI NTSTATUS NTAPI NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInfoClass, OUT PVOID SystemInfoBuffer, IN ULONG SystemInfoBufferSize, OUT PULONG BytesReturned OPTIONAL)
_In_ PVOID Context
Definition: storport.h:2269
base of all file and directory entries
Definition: entries.h:83
ULONG AdapterNumber
Definition: partlist.h:160
ULONG ControllerNumber
Definition: partlist.h:161
ULONG DiskNumber
Definition: partlist.h:162
ULONG Checksum
Definition: partlist.h:164
ULONG Signature
Definition: partlist.h:163
PDISKENTRY DiskEntry
Definition: partlist.h:165
CM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
Definition: partlist.h:166
CM_PARTIAL_RESOURCE_LIST PartialResourceList
Definition: restypes.h:144
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@384 u
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@384::@393 DeviceSpecificData
CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]
Definition: restypes.h:100
ULONG HwAdapterNumber
Definition: partlist.h:121
ULONG SectorAlignment
Definition: partlist.h:116
ULARGE_INTEGER SectorCount
Definition: partlist.h:115
UNICODE_STRING DriverName
Definition: partlist.h:141
ULONG HwControllerNumber
Definition: partlist.h:122
ULONG HwDiskNumber
Definition: partlist.h:123
ULONG SectorsPerTrack
Definition: partlist.h:112
PPARTENTRY ExtendedPartition
Definition: partlist.h:153
LIST_ENTRY LogicalPartListHead
Definition: partlist.h:150
struct _PARTLIST * PartList
Definition: partlist.h:104
BOOLEAN NewDisk
Definition: partlist.h:138
ULONG DiskNumber
Definition: partlist.h:129
ULONG BytesPerSector
Definition: partlist.h:113
BOOLEAN BiosFound
Definition: partlist.h:120
ULONGLONG Cylinders
Definition: partlist.h:110
USHORT Bus
Definition: partlist.h:132
USHORT Id
Definition: partlist.h:133
LIST_ENTRY ListEntry
Definition: partlist.h:101
BOOLEAN Dirty
Definition: partlist.h:136
USHORT Port
Definition: partlist.h:131
PARTITION_STYLE DiskStyle
Definition: partlist.h:139
ULONG TracksPerCylinder
Definition: partlist.h:111
LIST_ENTRY PrimaryPartListHead
Definition: partlist.h:149
MEDIA_TYPE MediaType
Definition: partlist.h:106
ULONG HwFixedDiskNumber
Definition: partlist.h:124
ULONG CylinderAlignment
Definition: partlist.h:117
PDRIVE_LAYOUT_INFORMATION LayoutBuffer
Definition: partlist.h:143
MEDIA_TYPE MediaType
Definition: ntdddisk.h:401
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:400
ULONG TracksPerCylinder
Definition: ntdddisk.h:402
ULONG SectorsPerTrack
Definition: ntdddisk.h:403
ULONG BytesPerSector
Definition: ntdddisk.h:404
PARTITION_INFORMATION PartitionEntry[1]
Definition: ntdddisk.h:421
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
BOOLEAN IsPartitioned
Definition: partlist.h:82
UCHAR PartitionType
Definition: partlist.h:73
BOOLEAN New
Definition: partlist.h:85
ULARGE_INTEGER SectorCount
Definition: partlist.h:70
BOOLEAN BootIndicator
Definition: partlist.h:72
WCHAR DeviceName[MAX_PATH]
NT device name: "\Device\HarddiskM\PartitionN".
Definition: partlist.h:77
PVOLENTRY Volume
Definition: partlist.h:95
struct _DISKENTRY * DiskEntry
Definition: partlist.h:66
BOOLEAN LogicalPartition
Definition: partlist.h:79
ULONG OnDiskPartitionNumber
Definition: partlist.h:74
LIST_ENTRY ListEntry
Definition: partlist.h:63
ULONG PartitionNumber
Definition: partlist.h:75
ULARGE_INTEGER StartSector
Definition: partlist.h:69
ULONG PartitionIndex
Definition: partlist.h:76
LARGE_INTEGER StartingOffset
Definition: imports.h:221
PARTITION_INFORMATION_MBR Mbr
Definition: imports.h:226
LARGE_INTEGER PartitionLength
Definition: imports.h:222
LARGE_INTEGER StartingOffset
Definition: ntdddisk.h:408
LARGE_INTEGER PartitionLength
Definition: ntdddisk.h:409
BOOLEAN RecognizedPartition
Definition: ntdddisk.h:414
BOOLEAN RewritePartition
Definition: ntdddisk.h:415
PARTITION Partition[PARTITION_TBL_SIZE]
Definition: partlist.h:220
unsigned char PartitionType
Definition: partlist.h:207
ULONGLONG StartingOffset
Definition: partlist.c:29
PRTL_QUERY_REGISTRY_ROUTINE QueryRoutine
Definition: nt_native.h:109
UCHAR PathId
Definition: scsi_port.h:149
UCHAR TargetId
Definition: scsi_port.h:150
UCHAR PortNumber
Definition: scsi_port.h:148
USHORT Milliseconds
Definition: env_spec_w32.h:717
$ULONG LowPart
Definition: ntbasedef.h:581
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
USHORT MaximumLength
Definition: env_spec_w32.h:370
VOLINFO Info
Definition: partlist.h:47
WCHAR DriveLetter
Definition: volutil.h:20
#define max(a, b)
Definition: svc.c:63
#define LL
Definition: tui.h:166
uint16_t * PWSTR
Definition: typedefs.h:56
uint32_t * PULONG
Definition: typedefs.h:59
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define ANYSIZE_ARRAY
Definition: typedefs.h:46
#define NTAPI
Definition: typedefs.h:36
const char * PCSTR
Definition: typedefs.h:52
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint16_t * PWCHAR
Definition: typedefs.h:56
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
LONGLONG QuadPart
Definition: typedefs.h:114
ULONG LowPart
Definition: typedefs.h:106
NTSTATUS DismountVolume(_Inout_ PVOLINFO Volume, _In_ BOOLEAN Force)
Attempts to dismount the designated volume.
Definition: volutil.c:152
NTSTATUS MountVolume(_Inout_ PVOLINFO Volume, _In_opt_ UCHAR MbrPartitionType)
Definition: volutil.c:23
#define IsUnknown(VolInfo)
Definition: volutil.h:33
#define IsUnformatted(VolInfo)
Definition: volutil.h:36
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2705
_Must_inspect_result_ _In_ PWDFDEVICE_INIT _In_opt_ PCUNICODE_STRING DeviceName
Definition: wdfdevice.h:3281
WDF_EXTERN_C_START typedef _In_ WDFDEVICE _In_ WDFCONTEXT _In_ WDF_DMA_DIRECTION Direction
_In_ WDFMEMORY _Out_opt_ size_t * BufferSize
Definition: wdfmemory.h:254
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG _Out_opt_ PULONG _Out_opt_ PULONG ValueType
Definition: wdfregistry.h:282
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _In_ ULONG ValueLength
Definition: wdfregistry.h:275
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
NTSYSAPI PVOID WINAPI RtlReAllocateHeap(HANDLE, ULONG, PVOID, SIZE_T) __WINE_ALLOC_SIZE(4) __WINE_DEALLOC(RtlFreeHeap
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
struct _CM_DISK_GEOMETRY_DEVICE_DATA * PCM_DISK_GEOMETRY_DEVICE_DATA
_In_ ULONG _In_ struct _SET_PARTITION_INFORMATION_EX * PartitionInfo
Definition: iofuncs.h:2105
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2061
_In_ LARGE_INTEGER Divisor
Definition: rtlfuncs.h:3061
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180