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