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