ReactOS  0.4.15-dev-1206-g731eddf
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  PartEntry->PartitionType = FileSystemToPartitionType(L"RAW", &PartEntry->StartSector, &PartEntry->SectorCount);
910  ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
911 
912  PartEntry->FormatState = Unformatted;
913  PartEntry->FileSystem[0] = L'\0';
914  // PartEntry->AutoCreate = AutoCreate;
915  PartEntry->BootIndicator = FALSE;
916 
917  DPRINT1("First Sector : %I64u\n", PartEntry->StartSector.QuadPart);
918  DPRINT1("Last Sector : %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
919  DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
920 
921  return TRUE;
922 }
923 
924 
925 static
926 VOID
928  IN ULONG DiskNumber,
929  IN PDISKENTRY DiskEntry,
930  IN ULONG PartitionIndex,
932 {
935  PPARTENTRY PartEntry;
936  HANDLE PartitionHandle;
939  WCHAR PathBuffer[MAX_PATH];
941  UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
943 
944  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
945 
946  if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
947  ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
948  {
949  return;
950  }
951 
952  PartEntry = RtlAllocateHeap(ProcessHeap,
954  sizeof(PARTENTRY));
955  if (PartEntry == NULL)
956  return;
957 
958  PartEntry->DiskEntry = DiskEntry;
959 
960  PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
961  PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
962 
963  PartEntry->BootIndicator = PartitionInfo->BootIndicator;
964  PartEntry->PartitionType = PartitionInfo->PartitionType;
965 
966  PartEntry->LogicalPartition = LogicalPartition;
967  PartEntry->IsPartitioned = TRUE;
968  PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
969  PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
970  PartEntry->PartitionIndex = PartitionIndex;
971 
972  /* Specify the partition as initially unformatted */
973  PartEntry->FormatState = Unformatted;
974  PartEntry->FileSystem[0] = L'\0';
975 
976  /* Initialize the partition volume label */
977  RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
978 
979  if (IsContainerPartition(PartEntry->PartitionType))
980  {
981  PartEntry->FormatState = Unformatted;
982 
983  if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
984  DiskEntry->ExtendedPartition = PartEntry;
985  }
986  else if (IsRecognizedPartition(PartEntry->PartitionType))
987  {
988  ASSERT(PartitionInfo->RecognizedPartition);
989  ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
990 
991  /* Try to open the volume so as to mount it */
992  RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
993  L"\\Device\\Harddisk%lu\\Partition%lu",
994  DiskEntry->DiskNumber,
995  PartEntry->PartitionNumber);
996  RtlInitUnicodeString(&Name, PathBuffer);
997 
999  &Name,
1001  NULL,
1002  NULL);
1003 
1004  PartitionHandle = NULL;
1005  Status = NtOpenFile(&PartitionHandle,
1008  &IoStatusBlock,
1011  if (!NT_SUCCESS(Status))
1012  {
1013  DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
1014  }
1015 
1016  if (PartitionHandle)
1017  {
1019 
1020  /* We don't have a FS, try to guess one */
1021  Status = InferFileSystemByHandle(PartitionHandle,
1022  PartEntry->PartitionType,
1023  PartEntry->FileSystem,
1024  sizeof(PartEntry->FileSystem));
1025  if (!NT_SUCCESS(Status))
1026  DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status);
1027  }
1028  if (*PartEntry->FileSystem)
1029  {
1030  ASSERT(PartitionHandle);
1031 
1032  /*
1033  * Handle partition mounted with RawFS: it is
1034  * either unformatted or has an unknown format.
1035  */
1036  if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
1037  {
1038  /*
1039  * True unformatted partitions on NT are created with their
1040  * partition type set to either one of the following values,
1041  * and are mounted with RawFS. This is done this way since we
1042  * are assured to have FAT support, which is the only FS that
1043  * uses these partition types. Therefore, having a partition
1044  * mounted with RawFS and with these partition types means that
1045  * the FAT FS was unable to mount it beforehand and thus the
1046  * partition is unformatted.
1047  * However, any partition mounted by RawFS that does NOT have
1048  * any of these partition types must be considered as having
1049  * an unknown format.
1050  */
1051  if (PartEntry->PartitionType == PARTITION_FAT_12 ||
1052  PartEntry->PartitionType == PARTITION_FAT_16 ||
1053  PartEntry->PartitionType == PARTITION_HUGE ||
1054  PartEntry->PartitionType == PARTITION_XINT13 ||
1055  PartEntry->PartitionType == PARTITION_FAT32 ||
1056  PartEntry->PartitionType == PARTITION_FAT32_XINT13)
1057  {
1058  PartEntry->FormatState = Unformatted;
1059  }
1060  else
1061  {
1062  /* Close the partition before dismounting */
1063  NtClose(PartitionHandle);
1064  PartitionHandle = NULL;
1065  /*
1066  * Dismount the partition since RawFS owns it, and set its
1067  * format to unknown (may or may not be actually formatted).
1068  */
1069  DismountVolume(PartEntry);
1070  PartEntry->FormatState = UnknownFormat;
1071  PartEntry->FileSystem[0] = L'\0';
1072  }
1073  }
1074  else
1075  {
1076  PartEntry->FormatState = Preformatted;
1077  }
1078  }
1079  else
1080  {
1081  PartEntry->FormatState = UnknownFormat;
1082  }
1083 
1084  /* Retrieve the partition volume label */
1085  if (PartitionHandle)
1086  {
1087  Status = NtQueryVolumeInformationFile(PartitionHandle,
1088  &IoStatusBlock,
1089  &LabelBuffer,
1090  sizeof(LabelBuffer),
1092  if (NT_SUCCESS(Status))
1093  {
1094  /* Copy the (possibly truncated) volume label and NULL-terminate it */
1095  RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
1096  LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
1097  }
1098  else
1099  {
1100  DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
1101  }
1102  }
1103 
1104  /* Close the partition */
1105  if (PartitionHandle)
1106  NtClose(PartitionHandle);
1107  }
1108  else
1109  {
1110  /* Unknown partition, hence unknown format (may or may not be actually formatted) */
1111  PartEntry->FormatState = UnknownFormat;
1112  }
1113 
1114  InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
1115 }
1116 
1117 static
1118 VOID
1120  IN PDISKENTRY DiskEntry)
1121 {
1122  ULONGLONG StartSector;
1124  ULONGLONG LastStartSector;
1125  ULONGLONG LastSectorCount;
1126  ULONGLONG LastUnusedSectorCount;
1127  PPARTENTRY PartEntry;
1128  PPARTENTRY NewPartEntry;
1130 
1131  DPRINT("ScanForUnpartitionedDiskSpace()\n");
1132 
1133  if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1134  {
1135  DPRINT1("No primary partition!\n");
1136 
1137  /* Create a partition entry that represents the empty disk */
1138 
1139  if (DiskEntry->SectorAlignment < 2048)
1140  StartSector = 2048ULL;
1141  else
1142  StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1143  SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
1144 
1145  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1146  &DiskEntry->PrimaryPartListHead,
1147  StartSector,
1148  SectorCount,
1149  FALSE);
1150  if (NewPartEntry == NULL)
1151  DPRINT1("Failed to create a new empty region for full disk space!\n");
1152 
1153  return;
1154  }
1155 
1156  /* Start partition at head 1, cylinder 0 */
1157  if (DiskEntry->SectorAlignment < 2048)
1158  LastStartSector = 2048ULL;
1159  else
1160  LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
1161  LastSectorCount = 0ULL;
1162  LastUnusedSectorCount = 0ULL;
1163 
1164  for (Entry = DiskEntry->PrimaryPartListHead.Flink;
1165  Entry != &DiskEntry->PrimaryPartListHead;
1166  Entry = Entry->Flink)
1167  {
1168  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1169 
1170  if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1171  PartEntry->SectorCount.QuadPart != 0ULL)
1172  {
1173  LastUnusedSectorCount =
1174  PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
1175 
1176  if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
1177  LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1178  {
1179  DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1180 
1181  StartSector = LastStartSector + LastSectorCount;
1182  SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1183 
1184  /* Insert the table into the list */
1185  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1186  &PartEntry->ListEntry,
1187  StartSector,
1188  SectorCount,
1189  FALSE);
1190  if (NewPartEntry == NULL)
1191  {
1192  DPRINT1("Failed to create a new empty region for disk space!\n");
1193  return;
1194  }
1195  }
1196 
1197  LastStartSector = PartEntry->StartSector.QuadPart;
1198  LastSectorCount = PartEntry->SectorCount.QuadPart;
1199  }
1200  }
1201 
1202  /* Check for trailing unpartitioned disk space */
1203  if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
1204  {
1205  LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1206 
1207  if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1208  {
1209  DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1210 
1211  StartSector = LastStartSector + LastSectorCount;
1212  SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1213 
1214  /* Append the table to the list */
1215  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1216  &DiskEntry->PrimaryPartListHead,
1217  StartSector,
1218  SectorCount,
1219  FALSE);
1220  if (NewPartEntry == NULL)
1221  {
1222  DPRINT1("Failed to create a new empty region for trailing disk space!\n");
1223  return;
1224  }
1225  }
1226  }
1227 
1228  if (DiskEntry->ExtendedPartition != NULL)
1229  {
1230  if (IsListEmpty(&DiskEntry->LogicalPartListHead))
1231  {
1232  DPRINT1("No logical partition!\n");
1233 
1234  /* Create a partition entry that represents the empty extended partition */
1235 
1236  StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1237  SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
1238 
1239  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1240  &DiskEntry->LogicalPartListHead,
1241  StartSector,
1242  SectorCount,
1243  TRUE);
1244  if (NewPartEntry == NULL)
1245  {
1246  DPRINT1("Failed to create a new empty region for full extended partition space!\n");
1247  return;
1248  }
1249 
1250  return;
1251  }
1252 
1253  /* Start partition at head 1, cylinder 0 */
1254  LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
1255  LastSectorCount = 0ULL;
1256  LastUnusedSectorCount = 0ULL;
1257 
1258  for (Entry = DiskEntry->LogicalPartListHead.Flink;
1259  Entry != &DiskEntry->LogicalPartListHead;
1260  Entry = Entry->Flink)
1261  {
1262  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1263 
1264  if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
1265  PartEntry->SectorCount.QuadPart != 0ULL)
1266  {
1267  LastUnusedSectorCount =
1268  PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
1269 
1270  if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
1271  LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1272  {
1273  DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
1274 
1275  StartSector = LastStartSector + LastSectorCount;
1276  SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1277 
1278  /* Insert the table into the list */
1279  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1280  &PartEntry->ListEntry,
1281  StartSector,
1282  SectorCount,
1283  TRUE);
1284  if (NewPartEntry == NULL)
1285  {
1286  DPRINT1("Failed to create a new empty region for extended partition space!\n");
1287  return;
1288  }
1289  }
1290 
1291  LastStartSector = PartEntry->StartSector.QuadPart;
1292  LastSectorCount = PartEntry->SectorCount.QuadPart;
1293  }
1294  }
1295 
1296  /* Check for trailing unpartitioned disk space */
1297  if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1298  {
1299  LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
1300  DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
1301  DiskEntry->SectorAlignment);
1302 
1303  if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1304  {
1305  DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1306 
1307  StartSector = LastStartSector + LastSectorCount;
1308  SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
1309 
1310  /* Append the table to the list */
1311  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
1312  &DiskEntry->LogicalPartListHead,
1313  StartSector,
1314  SectorCount,
1315  TRUE);
1316  if (NewPartEntry == NULL)
1317  {
1318  DPRINT1("Failed to create a new empty region for extended partition space!\n");
1319  return;
1320  }
1321  }
1322  }
1323  }
1324 
1325  DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1326 }
1327 
1328 static
1329 VOID
1331  IN PPARTLIST List,
1332  IN PDISKENTRY DiskEntry)
1333 {
1334  LARGE_INTEGER SystemTime;
1336  PLIST_ENTRY Entry2;
1337  PDISKENTRY DiskEntry2;
1338  PUCHAR Buffer;
1339 
1340  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1341  {
1342  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1343  return;
1344  }
1345 
1346  Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1347 
1348  while (TRUE)
1349  {
1350  NtQuerySystemTime(&SystemTime);
1351  RtlTimeToTimeFields(&SystemTime, &TimeFields);
1352 
1353  Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1354  Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1355  Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1356  Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1357 
1358  if (DiskEntry->LayoutBuffer->Signature == 0)
1359  {
1360  continue;
1361  }
1362 
1363  /* Check if the signature already exist */
1364  /* FIXME:
1365  * Check also signatures from disks, which are
1366  * not visible (bootable) by the bios.
1367  */
1368  for (Entry2 = List->DiskListHead.Flink;
1369  Entry2 != &List->DiskListHead;
1370  Entry2 = Entry2->Flink)
1371  {
1372  DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1373 
1374  if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
1375  {
1376  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1377  continue;
1378  }
1379 
1380  if (DiskEntry != DiskEntry2 &&
1381  DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1382  break;
1383  }
1384 
1385  if (Entry2 == &List->DiskListHead)
1386  break;
1387  }
1388 }
1389 
1390 static
1391 VOID
1393  IN PPARTLIST List)
1394 {
1396  PDISKENTRY DiskEntry;
1397 
1398  /* Update each disk */
1399  for (Entry = List->DiskListHead.Flink;
1400  Entry != &List->DiskListHead;
1401  Entry = Entry->Flink)
1402  {
1403  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1404 
1405  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1406  {
1407  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1408  continue;
1409  }
1410 
1411  if (DiskEntry->LayoutBuffer &&
1412  DiskEntry->LayoutBuffer->Signature == 0)
1413  {
1414  SetDiskSignature(List, DiskEntry);
1416  }
1417  }
1418 }
1419 
1420 static
1421 VOID
1423  IN PPARTLIST List)
1424 {
1425  PLIST_ENTRY ListEntry;
1426  PBIOSDISKENTRY BiosDiskEntry;
1427  PDISKENTRY DiskEntry;
1428  ULONG HwAdapterNumber = 0;
1429  ULONG HwControllerNumber = 0;
1430  ULONG RemovableDiskCount = 0;
1431 
1432  /*
1433  * Enumerate the disks recognized by the BIOS and recompute the disk
1434  * numbers on the system when *ALL* removable disks are not connected.
1435  * The entries are inserted in increasing order of AdapterNumber,
1436  * ControllerNumber and DiskNumber.
1437  */
1438  for (ListEntry = List->BiosDiskListHead.Flink;
1439  ListEntry != &List->BiosDiskListHead;
1440  ListEntry = ListEntry->Flink)
1441  {
1442  BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1443  DiskEntry = BiosDiskEntry->DiskEntry;
1444 
1445  /*
1446  * If the adapter or controller numbers change, update them and reset
1447  * the number of removable disks on this adapter/controller.
1448  */
1449  if (HwAdapterNumber != BiosDiskEntry->AdapterNumber ||
1450  HwControllerNumber != BiosDiskEntry->ControllerNumber)
1451  {
1452  HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1453  HwControllerNumber = BiosDiskEntry->ControllerNumber;
1454  RemovableDiskCount = 0;
1455  }
1456 
1457  /* Adjust the actual hardware disk number */
1458  if (DiskEntry)
1459  {
1460  ASSERT(DiskEntry->HwDiskNumber == BiosDiskEntry->DiskNumber);
1461 
1462  if (DiskEntry->MediaType == RemovableMedia)
1463  {
1464  /* Increase the number of removable disks and set the disk number to zero */
1465  ++RemovableDiskCount;
1466  DiskEntry->HwFixedDiskNumber = 0;
1467  }
1468  else // if (DiskEntry->MediaType == FixedMedia)
1469  {
1470  /* Adjust the fixed disk number, offset by the number of removable disks found before this one */
1471  DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber - RemovableDiskCount;
1472  }
1473  }
1474  else
1475  {
1476  DPRINT1("BIOS disk %lu is not recognized by NTOS!\n", BiosDiskEntry->DiskNumber);
1477  }
1478  }
1479 }
1480 
1481 static
1482 VOID
1485  IN ULONG DiskNumber,
1486  IN PPARTLIST List)
1487 {
1488  DISK_GEOMETRY DiskGeometry;
1489  SCSI_ADDRESS ScsiAddress;
1490  PDISKENTRY DiskEntry;
1492  NTSTATUS Status;
1493  PPARTITION_SECTOR Mbr;
1494  PULONG Buffer;
1496  WCHAR Identifier[20];
1497  ULONG Checksum;
1498  ULONG Signature;
1499  ULONG i;
1500  PLIST_ENTRY ListEntry;
1501  PBIOSDISKENTRY BiosDiskEntry;
1502  ULONG LayoutBufferSize;
1503  PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1504 
1505  /* Retrieve the drive geometry */
1507  NULL,
1508  NULL,
1509  NULL,
1510  &Iosb,
1512  NULL,
1513  0,
1514  &DiskGeometry,
1515  sizeof(DiskGeometry));
1516  if (!NT_SUCCESS(Status))
1517  return;
1518 
1519  if (DiskGeometry.MediaType != FixedMedia &&
1520  DiskGeometry.MediaType != RemovableMedia)
1521  {
1522  return;
1523  }
1524 
1525  /*
1526  * FIXME: Here we suppose the disk is always SCSI. What if it is
1527  * of another type? To check this we need to retrieve the name of
1528  * the driver the disk device belongs to.
1529  */
1531  NULL,
1532  NULL,
1533  NULL,
1534  &Iosb,
1536  NULL,
1537  0,
1538  &ScsiAddress,
1539  sizeof(ScsiAddress));
1540  if (!NT_SUCCESS(Status))
1541  return;
1542 
1543  /*
1544  * Check whether the disk is initialized, by looking at its MBR.
1545  * NOTE that this must be generalized to GPT disks as well!
1546  */
1547 
1549  0,
1550  DiskGeometry.BytesPerSector);
1551  if (Mbr == NULL)
1552  return;
1553 
1554  FileOffset.QuadPart = 0;
1556  NULL,
1557  NULL,
1558  NULL,
1559  &Iosb,
1560  (PVOID)Mbr,
1561  DiskGeometry.BytesPerSector,
1562  &FileOffset,
1563  NULL);
1564  if (!NT_SUCCESS(Status))
1565  {
1566  RtlFreeHeap(ProcessHeap, 0, Mbr);
1567  DPRINT1("NtReadFile failed, status=%x\n", Status);
1568  return;
1569  }
1570  Signature = Mbr->Signature;
1571 
1572  /* Calculate the MBR checksum */
1573  Checksum = 0;
1574  Buffer = (PULONG)Mbr;
1575  for (i = 0; i < 128; i++)
1576  {
1577  Checksum += Buffer[i];
1578  }
1579  Checksum = ~Checksum + 1;
1580 
1581  RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1582  L"%08x-%08x-%c",
1583  Checksum, Signature,
1584  (Mbr->Magic == PARTITION_MAGIC) ? L'A' : L'X');
1585  DPRINT("Identifier: %S\n", Identifier);
1586 
1587  DiskEntry = RtlAllocateHeap(ProcessHeap,
1589  sizeof(DISKENTRY));
1590  if (DiskEntry == NULL)
1591  {
1592  RtlFreeHeap(ProcessHeap, 0, Mbr);
1593  DPRINT1("Failed to allocate a new disk entry.\n");
1594  return;
1595  }
1596 
1597  DiskEntry->PartList = List;
1598 
1599 #if 0
1600  {
1601  FILE_FS_DEVICE_INFORMATION FileFsDevice;
1602 
1603  /* Query the device for its type */
1605  &Iosb,
1606  &FileFsDevice,
1607  sizeof(FileFsDevice),
1609  if (!NT_SUCCESS(Status))
1610  {
1611  DPRINT1("Couldn't detect device type for disk %lu of identifier '%S'...\n", DiskNumber, Identifier);
1612  }
1613  else
1614  {
1615  DPRINT1("Disk %lu : DeviceType: 0x%08x ; Characteristics: 0x%08x\n", DiskNumber, FileFsDevice.DeviceType, FileFsDevice.Characteristics);
1616  }
1617  }
1618  // NOTE: We may also use NtQueryVolumeInformationFile(FileFsDeviceInformation).
1619 #endif
1620  DiskEntry->MediaType = DiskGeometry.MediaType;
1621  if (DiskEntry->MediaType == RemovableMedia)
1622  {
1623  DPRINT1("Disk %lu of identifier '%S' is removable\n", DiskNumber, Identifier);
1624  }
1625  else // if (DiskEntry->MediaType == FixedMedia)
1626  {
1627  DPRINT1("Disk %lu of identifier '%S' is fixed\n", DiskNumber, Identifier);
1628  }
1629 
1630 // DiskEntry->Checksum = Checksum;
1631 // DiskEntry->Signature = Signature;
1632  DiskEntry->BiosFound = FALSE;
1633 
1634  /*
1635  * Check if this disk has a valid MBR: verify its signature,
1636  * and whether its two first bytes are a valid instruction
1637  * (related to this, see IsThereAValidBootSector() in partlist.c).
1638  *
1639  * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
1640  */
1641 
1642  // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
1643 
1644  /* If we have not the 0xAA55 then it's raw partition */
1645  if (Mbr->Magic != PARTITION_MAGIC)
1646  {
1647  DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
1648  }
1649  /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
1650  else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
1651  Mbr->Partition[1].PartitionType == 0 &&
1652  Mbr->Partition[2].PartitionType == 0 &&
1653  Mbr->Partition[3].PartitionType == 0)
1654  {
1655  DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
1656  }
1657  /* Otherwise, partition table is in MBR */
1658  else
1659  {
1660  DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
1661  }
1662 
1663  /* Free the MBR sector buffer */
1664  RtlFreeHeap(ProcessHeap, 0, Mbr);
1665 
1666 
1667  for (ListEntry = List->BiosDiskListHead.Flink;
1668  ListEntry != &List->BiosDiskListHead;
1669  ListEntry = ListEntry->Flink)
1670  {
1671  BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1672  /* FIXME:
1673  * Compare the size from bios and the reported size from driver.
1674  * If we have more than one disk with a zero or with the same signature
1675  * we must create new signatures and reboot. After the reboot,
1676  * it is possible to identify the disks.
1677  */
1678  if (BiosDiskEntry->Signature == Signature &&
1679  BiosDiskEntry->Checksum == Checksum &&
1680  BiosDiskEntry->DiskEntry == NULL)
1681  {
1682  if (!DiskEntry->BiosFound)
1683  {
1684  DiskEntry->HwAdapterNumber = BiosDiskEntry->AdapterNumber;
1685  DiskEntry->HwControllerNumber = BiosDiskEntry->ControllerNumber;
1686  DiskEntry->HwDiskNumber = BiosDiskEntry->DiskNumber;
1687 
1688  if (DiskEntry->MediaType == RemovableMedia)
1689  {
1690  /* Set the removable disk number to zero */
1691  DiskEntry->HwFixedDiskNumber = 0;
1692  }
1693  else // if (DiskEntry->MediaType == FixedMedia)
1694  {
1695  /* The fixed disk number will later be adjusted using the number of removable disks */
1696  DiskEntry->HwFixedDiskNumber = BiosDiskEntry->DiskNumber;
1697  }
1698 
1699  DiskEntry->BiosFound = TRUE;
1700  BiosDiskEntry->DiskEntry = DiskEntry;
1701  break;
1702  }
1703  else
1704  {
1705  // FIXME: What to do?
1706  DPRINT1("Disk %lu of identifier '%S' has already been found?!\n", DiskNumber, Identifier);
1707  }
1708  }
1709  }
1710 
1711  if (!DiskEntry->BiosFound)
1712  {
1713  DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %lu may not be bootable by the BIOS!\n", DiskNumber);
1714  }
1715 
1716  DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1717  DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1718  DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1719  DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1720 
1721  DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1722  DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1723  DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1724  DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1725 
1726  DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1727  (ULONGLONG)DiskGeometry.TracksPerCylinder *
1728  (ULONGLONG)DiskGeometry.SectorsPerTrack;
1729 
1730  DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1731  DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1732  DiskGeometry.SectorsPerTrack;
1733 
1734  DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1735  DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1736 
1737  DiskEntry->DiskNumber = DiskNumber;
1738  DiskEntry->Port = ScsiAddress.PortNumber;
1739  DiskEntry->Bus = ScsiAddress.PathId;
1740  DiskEntry->Id = ScsiAddress.TargetId;
1741 
1742  GetDriverName(DiskEntry);
1743  /*
1744  * Actually it would be more correct somehow to use:
1745  *
1746  * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1747  * ULONG ReturnedLength;
1748  *
1749  * Status = NtQueryObject(SomeHandleToTheDisk,
1750  * ObjectNameInformation,
1751  * &NameInfo,
1752  * sizeof(NameInfo),
1753  * &ReturnedLength);
1754  * etc...
1755  *
1756  * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1757  */
1758 
1761 
1762  InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1763 
1764 
1765  /*
1766  * We now retrieve the disk partition layout
1767  */
1768 
1769  /*
1770  * Stop there now if the disk is GPT-partitioned,
1771  * since we currently do not support such disks.
1772  */
1773  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1774  {
1775  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1776  return;
1777  }
1778 
1779  /* Allocate a layout buffer with 4 partition entries first */
1780  LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1781  ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1784  LayoutBufferSize);
1785  if (DiskEntry->LayoutBuffer == NULL)
1786  {
1787  DPRINT1("Failed to allocate the disk layout buffer!\n");
1788  return;
1789  }
1790 
1791  /* Keep looping while the drive layout buffer is too small */
1792  for (;;)
1793  {
1794  DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1796  NULL,
1797  NULL,
1798  NULL,
1799  &Iosb,
1801  NULL,
1802  0,
1803  DiskEntry->LayoutBuffer,
1804  LayoutBufferSize);
1805  if (NT_SUCCESS(Status))
1806  break;
1807 
1809  {
1810  DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1811  return;
1812  }
1813 
1814  LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1815  NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1817  DiskEntry->LayoutBuffer,
1818  LayoutBufferSize);
1819  if (NewLayoutBuffer == NULL)
1820  {
1821  DPRINT1("Failed to reallocate the disk layout buffer!\n");
1822  return;
1823  }
1824 
1825  DiskEntry->LayoutBuffer = NewLayoutBuffer;
1826  }
1827 
1828  DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1829 
1830 #ifdef DUMP_PARTITION_TABLE
1831  DumpPartitionTable(DiskEntry);
1832 #endif
1833 
1834  if (IsSuperFloppy(DiskEntry))
1835  DPRINT1("Disk %lu is a super-floppy\n", DiskNumber);
1836 
1837  if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1838  DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1840  {
1841  if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1842  {
1843  DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1844  }
1845  else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1846  {
1847  DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1848  }
1849  else
1850  {
1851  DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1852  }
1853  }
1854  else
1855  {
1856  DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1857  }
1858 
1859  if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1860  {
1861  DiskEntry->NewDisk = TRUE;
1862  DiskEntry->LayoutBuffer->PartitionCount = 4;
1863 
1864  for (i = 0; i < 4; i++)
1865  {
1867  }
1868  }
1869  else
1870  {
1871  /* Enumerate and add the first four primary partitions */
1872  for (i = 0; i < 4; i++)
1873  {
1874  AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1875  }
1876 
1877  /* Enumerate and add the remaining partitions as logical ones */
1878  for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1879  {
1880  AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1881  }
1882  }
1883 
1884  ScanForUnpartitionedDiskSpace(DiskEntry);
1885 }
1886 
1887 /*
1888  * Retrieve the system disk, i.e. the fixed disk that is accessible by the
1889  * firmware during boot time and where the system partition resides.
1890  * If no system partition has been determined, we retrieve the first disk
1891  * that verifies the mentioned criteria above.
1892  */
1893 static
1894 PDISKENTRY
1896  IN PPARTLIST List)
1897 {
1899  PDISKENTRY DiskEntry;
1900 
1901  /* Check for empty disk list */
1902  if (IsListEmpty(&List->DiskListHead))
1903  return NULL;
1904 
1905  /*
1906  * If we already have a system partition, the system disk
1907  * is the one on which the system partition resides.
1908  */
1909  if (List->SystemPartition)
1910  return List->SystemPartition->DiskEntry;
1911 
1912  /* Loop over the disks and find the correct one */
1913  for (Entry = List->DiskListHead.Flink;
1914  Entry != &List->DiskListHead;
1915  Entry = Entry->Flink)
1916  {
1917  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1918 
1919  /* The disk must be a fixed disk and be found by the firmware */
1920  if (DiskEntry->MediaType == FixedMedia && DiskEntry->BiosFound)
1921  {
1922  break;
1923  }
1924  }
1925  if (Entry == &List->DiskListHead)
1926  {
1927  /* We haven't encountered any suitable disk */
1928  return NULL;
1929  }
1930 
1931  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1932  {
1933  DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
1934  }
1935 
1936  return DiskEntry;
1937 }
1938 
1939 /*
1940  * Retrieve the actual "active" partition of the given disk.
1941  * On MBR disks, partition with the Active/Boot flag set;
1942  * on GPT disks, partition with the correct GUID.
1943  */
1944 BOOLEAN
1946  IN PPARTENTRY PartEntry)
1947 {
1948  // TODO: Support for GPT disks!
1949 
1950  if (IsContainerPartition(PartEntry->PartitionType))
1951  return FALSE;
1952 
1953  /* Check if the partition is partitioned, used and active */
1954  if (PartEntry->IsPartitioned &&
1955  // !IsContainerPartition(PartEntry->PartitionType) &&
1956  PartEntry->BootIndicator)
1957  {
1958  /* Yes it is */
1959  ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
1960  return TRUE;
1961  }
1962 
1963  return FALSE;
1964 }
1965 
1966 static
1967 PPARTENTRY
1969  IN PDISKENTRY DiskEntry)
1970 {
1971  PLIST_ENTRY ListEntry;
1972  PPARTENTRY PartEntry;
1973  PPARTENTRY ActivePartition = NULL;
1974 
1975  /* Check for empty disk list */
1976  // ASSERT(DiskEntry);
1977  if (!DiskEntry)
1978  return NULL;
1979 
1980  /* Check for empty partition list */
1981  if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
1982  return NULL;
1983 
1984  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
1985  {
1986  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
1987  return NULL;
1988  }
1989 
1990  /* Scan all (primary) partitions to find the active disk partition */
1991  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
1992  ListEntry != &DiskEntry->PrimaryPartListHead;
1993  ListEntry = ListEntry->Flink)
1994  {
1995  /* Retrieve the partition */
1996  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
1997  if (IsPartitionActive(PartEntry))
1998  {
1999  /* Yes, we've found it */
2000  ASSERT(DiskEntry == PartEntry->DiskEntry);
2001  ASSERT(PartEntry->IsPartitioned);
2002 
2003  ActivePartition = PartEntry;
2004 
2005  DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
2006  PartEntry->PartitionNumber, DiskEntry->DiskNumber,
2007  (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
2008  break;
2009  }
2010  }
2011 
2012  /* Check if the disk is new and if so, use its first partition as the active system partition */
2013  if (DiskEntry->NewDisk && ActivePartition != NULL)
2014  {
2015  // FIXME: What to do??
2016  DPRINT1("NewDisk TRUE but already existing active partition?\n");
2017  }
2018 
2019  /* Return the active partition found (or none) */
2020  return ActivePartition;
2021 }
2022 
2023 PPARTLIST
2025 {
2026  PPARTLIST List;
2027  PDISKENTRY SystemDisk;
2031  ULONG ReturnSize;
2032  NTSTATUS Status;
2033  ULONG DiskNumber;
2037 
2039  0,
2040  sizeof(PARTLIST));
2041  if (List == NULL)
2042  return NULL;
2043 
2044  List->SystemPartition = NULL;
2045 
2046  InitializeListHead(&List->DiskListHead);
2047  InitializeListHead(&List->BiosDiskListHead);
2048 
2049  /*
2050  * Enumerate the disks seen by the BIOS; this will be used later
2051  * to map drives seen by NTOS with their corresponding BIOS names.
2052  */
2054 
2055  /* Enumerate disks seen by NTOS */
2057  &Sdi,
2058  sizeof(Sdi),
2059  &ReturnSize);
2060  if (!NT_SUCCESS(Status))
2061  {
2062  DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
2064  return NULL;
2065  }
2066 
2067  for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
2068  {
2070  L"\\Device\\Harddisk%lu\\Partition0",
2071  DiskNumber);
2073 
2075  &Name,
2077  NULL,
2078  NULL);
2079 
2083  &Iosb,
2086  if (NT_SUCCESS(Status))
2087  {
2088  AddDiskToList(FileHandle, DiskNumber, List);
2090  }
2091  }
2092 
2096 
2097  /*
2098  * Retrieve the system partition: the active partition on the system
2099  * disk (the one that will be booted by default by the hardware).
2100  */
2101  SystemDisk = GetSystemDisk(List);
2102  List->SystemPartition = (SystemDisk ? GetActiveDiskPartition(SystemDisk) : NULL);
2103 
2104  return List;
2105 }
2106 
2107 VOID
2109  IN PPARTLIST List)
2110 {
2111  PDISKENTRY DiskEntry;
2112  PBIOSDISKENTRY BiosDiskEntry;
2113  PPARTENTRY PartEntry;
2115 
2116  /* Release disk and partition info */
2117  while (!IsListEmpty(&List->DiskListHead))
2118  {
2119  Entry = RemoveHeadList(&List->DiskListHead);
2120  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2121 
2122  /* Release driver name */
2123  RtlFreeUnicodeString(&DiskEntry->DriverName);
2124 
2125  /* Release primary partition list */
2126  while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
2127  {
2128  Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
2129  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2130 
2131  RtlFreeHeap(ProcessHeap, 0, PartEntry);
2132  }
2133 
2134  /* Release logical partition list */
2135  while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2136  {
2137  Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2138  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2139 
2140  RtlFreeHeap(ProcessHeap, 0, PartEntry);
2141  }
2142 
2143  /* Release layout buffer */
2144  if (DiskEntry->LayoutBuffer != NULL)
2145  RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
2146 
2147  /* Release disk entry */
2148  RtlFreeHeap(ProcessHeap, 0, DiskEntry);
2149  }
2150 
2151  /* Release the bios disk info */
2152  while (!IsListEmpty(&List->BiosDiskListHead))
2153  {
2154  Entry = RemoveHeadList(&List->BiosDiskListHead);
2155  BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
2156 
2157  RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
2158  }
2159 
2160  /* Release list head */
2162 }
2163 
2164 PDISKENTRY
2166  IN PPARTLIST List,
2167  IN ULONG HwDiskNumber)
2168 {
2169  PDISKENTRY DiskEntry;
2171 
2172  /* Loop over the disks and find the correct one */
2173  for (Entry = List->DiskListHead.Flink;
2174  Entry != &List->DiskListHead;
2175  Entry = Entry->Flink)
2176  {
2177  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2178 
2179  if (DiskEntry->HwDiskNumber == HwDiskNumber)
2180  {
2181  /* Disk found */
2182  return DiskEntry;
2183  }
2184  }
2185 
2186  /* Disk not found, stop there */
2187  return NULL;
2188 }
2189 
2190 PDISKENTRY
2192  IN PPARTLIST List,
2193  IN ULONG DiskNumber)
2194 {
2195  PDISKENTRY DiskEntry;
2197 
2198  /* Loop over the disks and find the correct one */
2199  for (Entry = List->DiskListHead.Flink;
2200  Entry != &List->DiskListHead;
2201  Entry = Entry->Flink)
2202  {
2203  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2204 
2205  if (DiskEntry->DiskNumber == DiskNumber)
2206  {
2207  /* Disk found */
2208  return DiskEntry;
2209  }
2210  }
2211 
2212  /* Disk not found, stop there */
2213  return NULL;
2214 }
2215 
2216 PDISKENTRY
2218  IN PPARTLIST List,
2219  IN USHORT Port,
2220  IN USHORT Bus,
2221  IN USHORT Id)
2222 {
2223  PDISKENTRY DiskEntry;
2225 
2226  /* Loop over the disks and find the correct one */
2227  for (Entry = List->DiskListHead.Flink;
2228  Entry != &List->DiskListHead;
2229  Entry = Entry->Flink)
2230  {
2231  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2232 
2233  if (DiskEntry->Port == Port &&
2234  DiskEntry->Bus == Bus &&
2235  DiskEntry->Id == Id)
2236  {
2237  /* Disk found */
2238  return DiskEntry;
2239  }
2240  }
2241 
2242  /* Disk not found, stop there */
2243  return NULL;
2244 }
2245 
2246 PDISKENTRY
2248  IN PPARTLIST List,
2249  IN ULONG Signature)
2250 {
2251  PDISKENTRY DiskEntry;
2253 
2254  /* Loop over the disks and find the correct one */
2255  for (Entry = List->DiskListHead.Flink;
2256  Entry != &List->DiskListHead;
2257  Entry = Entry->Flink)
2258  {
2259  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
2260 
2261  if (DiskEntry->LayoutBuffer->Signature == Signature)
2262  {
2263  /* Disk found */
2264  return DiskEntry;
2265  }
2266  }
2267 
2268  /* Disk not found, stop there */
2269  return NULL;
2270 }
2271 
2272 PPARTENTRY
2274  // IN PPARTLIST List,
2275  IN PDISKENTRY DiskEntry,
2277 {
2278  PPARTENTRY PartEntry;
2280 
2281  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2282  {
2283  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2284  return NULL;
2285  }
2286 
2287  /* Disk found, loop over the primary partitions first... */
2288  for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2289  Entry != &DiskEntry->PrimaryPartListHead;
2290  Entry = Entry->Flink)
2291  {
2292  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2293 
2294  if (PartEntry->PartitionNumber == PartitionNumber)
2295  {
2296  /* Partition found */
2297  return PartEntry;
2298  }
2299  }
2300 
2301  /* ... then over the logical partitions if needed */
2302  for (Entry = DiskEntry->LogicalPartListHead.Flink;
2303  Entry != &DiskEntry->LogicalPartListHead;
2304  Entry = Entry->Flink)
2305  {
2306  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2307 
2308  if (PartEntry->PartitionNumber == PartitionNumber)
2309  {
2310  /* Partition found */
2311  return PartEntry;
2312  }
2313  }
2314 
2315  /* The partition was not found on the disk, stop there */
2316  return NULL;
2317 }
2318 
2319 BOOLEAN
2321  IN PPARTLIST List,
2322  IN ULONG DiskNumber,
2324  OUT PDISKENTRY* pDiskEntry,
2325  OUT PPARTENTRY* pPartEntry OPTIONAL)
2326 {
2327  PDISKENTRY DiskEntry;
2328  PPARTENTRY PartEntry = NULL;
2329 
2330  /* Find the disk */
2331  DiskEntry = GetDiskByNumber(List, DiskNumber);
2332  if (!DiskEntry)
2333  return FALSE;
2334 
2335  /* If we have a partition (PartitionNumber != 0), find it */
2336  if (PartitionNumber != 0)
2337  {
2338  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2339  {
2340  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2341  return FALSE;
2342  }
2343 
2344  PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
2345  if (!PartEntry)
2346  return FALSE;
2347  ASSERT(PartEntry->DiskEntry == DiskEntry);
2348  }
2349 
2350  /* Return the disk (and optionally the partition) */
2351  *pDiskEntry = DiskEntry;
2352  if (pPartEntry) *pPartEntry = PartEntry;
2353  return TRUE;
2354 }
2355 
2356 //
2357 // NOTE: Was introduced broken in r6258 by Casper
2358 //
2359 PPARTENTRY
2361  IN PPARTLIST List,
2362  IN ULONG DiskNumber,
2364 {
2365  PDISKENTRY DiskEntry;
2366  PPARTENTRY PartEntry;
2367 
2368  DiskEntry = GetDiskByNumber(List, DiskNumber);
2369  if (!DiskEntry)
2370  return NULL;
2371 
2372  PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
2373  if (!PartEntry)
2374  return NULL;
2375 
2376  ASSERT(PartEntry->DiskEntry == DiskEntry);
2377  ASSERT(DiskEntry->DiskNumber == DiskNumber);
2378  ASSERT(PartEntry->PartitionNumber == PartitionNumber);
2379 
2380  return PartEntry;
2381 }
2382 
2383 PPARTENTRY
2385  IN PPARTLIST List,
2386  IN PPARTENTRY CurrentPart OPTIONAL)
2387 {
2388  PLIST_ENTRY DiskListEntry;
2389  PLIST_ENTRY PartListEntry;
2391 
2392  /* Fail if no disks are available */
2393  if (IsListEmpty(&List->DiskListHead))
2394  return NULL;
2395 
2396  /* Check for the next usable entry on the current partition's disk */
2397  if (CurrentPart != NULL)
2398  {
2399  CurrentDisk = CurrentPart->DiskEntry;
2400 
2401  if (CurrentPart->LogicalPartition)
2402  {
2403  /* Logical partition */
2404 
2405  PartListEntry = CurrentPart->ListEntry.Flink;
2406  if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2407  {
2408  /* Next logical partition */
2409  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2410  return CurrentPart;
2411  }
2412  else
2413  {
2414  PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink;
2415  if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2416  {
2417  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2418  return CurrentPart;
2419  }
2420  }
2421  }
2422  else
2423  {
2424  /* Primary or extended partition */
2425 
2426  if (CurrentPart->IsPartitioned &&
2427  IsContainerPartition(CurrentPart->PartitionType))
2428  {
2429  /* First logical partition */
2430  PartListEntry = CurrentDisk->LogicalPartListHead.Flink;
2431  if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2432  {
2433  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2434  return CurrentPart;
2435  }
2436  }
2437  else
2438  {
2439  /* Next primary partition */
2440  PartListEntry = CurrentPart->ListEntry.Flink;
2441  if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2442  {
2443  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2444  return CurrentPart;
2445  }
2446  }
2447  }
2448  }
2449 
2450  /* Search for the first partition entry on the next disk */
2451  for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink
2452  : List->DiskListHead.Flink);
2453  DiskListEntry != &List->DiskListHead;
2454  DiskListEntry = DiskListEntry->Flink)
2455  {
2456  CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2457 
2459  {
2460  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2461  continue;
2462  }
2463 
2464  PartListEntry = CurrentDisk->PrimaryPartListHead.Flink;
2465  if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2466  {
2467  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2468  return CurrentPart;
2469  }
2470  }
2471 
2472  return NULL;
2473 }
2474 
2475 PPARTENTRY
2477  IN PPARTLIST List,
2478  IN PPARTENTRY CurrentPart OPTIONAL)
2479 {
2480  PLIST_ENTRY DiskListEntry;
2481  PLIST_ENTRY PartListEntry;
2483 
2484  /* Fail if no disks are available */
2485  if (IsListEmpty(&List->DiskListHead))
2486  return NULL;
2487 
2488  /* Check for the previous usable entry on the current partition's disk */
2489  if (CurrentPart != NULL)
2490  {
2491  CurrentDisk = CurrentPart->DiskEntry;
2492 
2493  if (CurrentPart->LogicalPartition)
2494  {
2495  /* Logical partition */
2496 
2497  PartListEntry = CurrentPart->ListEntry.Blink;
2498  if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2499  {
2500  /* Previous logical partition */
2501  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2502  }
2503  else
2504  {
2505  /* Extended partition */
2506  CurrentPart = CurrentDisk->ExtendedPartition;
2507  }
2508  return CurrentPart;
2509  }
2510  else
2511  {
2512  /* Primary or extended partition */
2513 
2514  PartListEntry = CurrentPart->ListEntry.Blink;
2515  if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2516  {
2517  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2518 
2519  if (CurrentPart->IsPartitioned &&
2520  IsContainerPartition(CurrentPart->PartitionType))
2521  {
2522  PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2523  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2524  }
2525 
2526  return CurrentPart;
2527  }
2528  }
2529  }
2530 
2531  /* Search for the last partition entry on the previous disk */
2532  for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink
2533  : List->DiskListHead.Blink);
2534  DiskListEntry != &List->DiskListHead;
2535  DiskListEntry = DiskListEntry->Blink)
2536  {
2537  CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
2538 
2540  {
2541  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2542  continue;
2543  }
2544 
2545  PartListEntry = CurrentDisk->PrimaryPartListHead.Blink;
2546  if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
2547  {
2548  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2549 
2550  if (CurrentPart->IsPartitioned &&
2551  IsContainerPartition(CurrentPart->PartitionType))
2552  {
2553  PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
2554  if (PartListEntry != &CurrentDisk->LogicalPartListHead)
2555  {
2556  CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2557  return CurrentPart;
2558  }
2559  }
2560  else
2561  {
2562  return CurrentPart;
2563  }
2564  }
2565  }
2566 
2567  return NULL;
2568 }
2569 
2570 // static
2572 BOOLEAN
2575 {
2576  if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2577  PartitionInfo->PartitionLength.QuadPart == 0)
2578  {
2579  return TRUE;
2580  }
2581 
2582  return FALSE;
2583 }
2584 
2585 // static
2587 BOOLEAN
2590  IN PDISKENTRY DiskEntry,
2591  IN PPARTENTRY PartEntry)
2592 {
2593  if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2594  PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2595 // PartitionInfo->PartitionType == PartEntry->PartitionType
2596  {
2597  return TRUE;
2598  }
2599 
2600  return FALSE;
2601 }
2602 
2603 static
2604 ULONG
2606  IN PDISKENTRY DiskEntry)
2607 {
2609  PPARTENTRY PartEntry;
2610  ULONG Count = 0;
2611 
2612  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2613  {
2614  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2615  return 0;
2616  }
2617 
2618  for (Entry = DiskEntry->PrimaryPartListHead.Flink;
2619  Entry != &DiskEntry->PrimaryPartListHead;
2620  Entry = Entry->Flink)
2621  {
2622  PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2623  if (PartEntry->IsPartitioned)
2624  Count++;
2625  }
2626 
2627  return Count;
2628 }
2629 
2630 static
2631 ULONG
2633  IN PDISKENTRY DiskEntry)
2634 {
2635  PLIST_ENTRY ListEntry;
2636  PPARTENTRY PartEntry;
2637  ULONG Count = 0;
2638 
2639  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2640  {
2641  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2642  return 0;
2643  }
2644 
2645  for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2646  ListEntry != &DiskEntry->LogicalPartListHead;
2647  ListEntry = ListEntry->Flink)
2648  {
2649  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2650  if (PartEntry->IsPartitioned)
2651  Count++;
2652  }
2653 
2654  return Count;
2655 }
2656 
2657 static
2658 BOOLEAN
2660  IN PDISKENTRY DiskEntry)
2661 {
2662  PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2663  ULONG NewPartitionCount;
2664  ULONG CurrentPartitionCount = 0;
2665  ULONG LayoutBufferSize;
2666  ULONG i;
2667 
2668  DPRINT1("ReAllocateLayoutBuffer()\n");
2669 
2670  NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2671 
2672  if (DiskEntry->LayoutBuffer)
2673  CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2674 
2675  DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
2676  CurrentPartitionCount, NewPartitionCount);
2677 
2678  if (CurrentPartitionCount == NewPartitionCount)
2679  return TRUE;
2680 
2681  LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2682  ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2683  NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2685  DiskEntry->LayoutBuffer,
2686  LayoutBufferSize);
2687  if (NewLayoutBuffer == NULL)
2688  {
2689  DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2690  return FALSE;
2691  }
2692 
2693  NewLayoutBuffer->PartitionCount = NewPartitionCount;
2694 
2695  /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2696  if (NewPartitionCount > CurrentPartitionCount)
2697  {
2698  for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2699  {
2700  NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2701  }
2702  }
2703 
2704  DiskEntry->LayoutBuffer = NewLayoutBuffer;
2705 
2706  return TRUE;
2707 }
2708 
2709 static
2710 VOID
2712  IN PDISKENTRY DiskEntry)
2713 {
2715  PPARTITION_INFORMATION LinkInfo = NULL;
2716  PLIST_ENTRY ListEntry;
2717  PPARTENTRY PartEntry;
2718  LARGE_INTEGER HiddenSectors64;
2719  ULONG Index;
2720  ULONG PartitionNumber = 1;
2721 
2722  DPRINT1("UpdateDiskLayout()\n");
2723 
2724  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2725  {
2726  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2727  return;
2728  }
2729 
2730  /* Resize the layout buffer if necessary */
2731  if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2732  {
2733  DPRINT("ReAllocateLayoutBuffer() failed.\n");
2734  return;
2735  }
2736 
2737  /* Update the primary partition table */
2738  Index = 0;
2739  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2740  ListEntry != &DiskEntry->PrimaryPartListHead;
2741  ListEntry = ListEntry->Flink)
2742  {
2743  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2744 
2745  if (PartEntry->IsPartitioned)
2746  {
2748 
2749  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2750  PartEntry->PartitionIndex = Index;
2751 
2752  /* Reset the current partition number only for newly-created (unmounted) partitions */
2753  if (PartEntry->New)
2754  PartEntry->PartitionNumber = 0;
2755 
2756  PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0);
2757 
2758  if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2759  {
2760  DPRINT1("Updating primary partition entry %lu\n", Index);
2761 
2762  PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2763  PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2764  PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2765  PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2766  PartitionInfo->PartitionType = PartEntry->PartitionType;
2767  PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2768  PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2769  PartitionInfo->RewritePartition = TRUE;
2770  }
2771 
2772  if (!IsContainerPartition(PartEntry->PartitionType))
2773  PartitionNumber++;
2774 
2775  Index++;
2776  }
2777  }
2778 
2779  ASSERT(Index <= 4);
2780 
2781  /* Update the logical partition table */
2782  Index = 4;
2783  for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
2784  ListEntry != &DiskEntry->LogicalPartListHead;
2785  ListEntry = ListEntry->Flink)
2786  {
2787  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2788 
2789  if (PartEntry->IsPartitioned)
2790  {
2792 
2793  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2794  PartEntry->PartitionIndex = Index;
2795 
2796  /* Reset the current partition number only for newly-created (unmounted) partitions */
2797  if (PartEntry->New)
2798  PartEntry->PartitionNumber = 0;
2799 
2801 
2802  DPRINT1("Updating logical partition entry %lu\n", Index);
2803 
2804  PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2805  PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2806  PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2807  PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
2808  PartitionInfo->PartitionType = PartEntry->PartitionType;
2809  PartitionInfo->BootIndicator = FALSE;
2810  PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
2811  PartitionInfo->RewritePartition = TRUE;
2812 
2813  /* Fill the link entry of the previous partition entry */
2814  if (LinkInfo != NULL)
2815  {
2816  LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2817  LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2818  HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2819  LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2820  LinkInfo->PartitionNumber = 0;
2821  LinkInfo->PartitionType = PARTITION_EXTENDED;
2822  LinkInfo->BootIndicator = FALSE;
2823  LinkInfo->RecognizedPartition = FALSE;
2824  LinkInfo->RewritePartition = TRUE;
2825  }
2826 
2827  /* Save a pointer to the link entry of the current partition entry */
2828  LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2829 
2830  PartitionNumber++;
2831  Index += 4;
2832  }
2833  }
2834 
2835  /* Wipe unused primary partition entries */
2836  for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2837  {
2838  DPRINT1("Primary partition entry %lu\n", Index);
2839 
2840  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2841 
2843  {
2844  DPRINT1("Wiping primary partition entry %lu\n", Index);
2845 
2846  PartitionInfo->StartingOffset.QuadPart = 0;
2847  PartitionInfo->PartitionLength.QuadPart = 0;
2848  PartitionInfo->HiddenSectors = 0;
2849  PartitionInfo->PartitionNumber = 0;
2850  PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2851  PartitionInfo->BootIndicator = FALSE;
2852  PartitionInfo->RecognizedPartition = FALSE;
2853  PartitionInfo->RewritePartition = TRUE;
2854  }
2855  }
2856 
2857  /* Wipe unused logical partition entries */
2858  for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2859  {
2860  if (Index % 4 >= 2)
2861  {
2862  DPRINT1("Logical partition entry %lu\n", Index);
2863 
2864  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2865 
2867  {
2868  DPRINT1("Wiping partition entry %lu\n", Index);
2869 
2870  PartitionInfo->StartingOffset.QuadPart = 0;
2871  PartitionInfo->PartitionLength.QuadPart = 0;
2872  PartitionInfo->HiddenSectors = 0;
2873  PartitionInfo->PartitionNumber = 0;
2874  PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2875  PartitionInfo->BootIndicator = FALSE;
2876  PartitionInfo->RecognizedPartition = FALSE;
2877  PartitionInfo->RewritePartition = TRUE;
2878  }
2879  }
2880  }
2881 
2882  DiskEntry->Dirty = TRUE;
2883 
2884 #ifdef DUMP_PARTITION_TABLE
2885  DumpPartitionTable(DiskEntry);
2886 #endif
2887 }
2888 
2889 static
2890 PPARTENTRY
2892  IN PPARTENTRY PartEntry)
2893 {
2894  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2895  PPARTENTRY PrevPartEntry;
2896  PLIST_ENTRY ListHead;
2897 
2898  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2899  {
2900  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2901  return NULL;
2902  }
2903 
2904  if (PartEntry->LogicalPartition)
2905  ListHead = &DiskEntry->LogicalPartListHead;
2906  else
2907  ListHead = &DiskEntry->PrimaryPartListHead;
2908 
2909  if (PartEntry->ListEntry.Blink != ListHead)
2910  {
2911  PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2912  PARTENTRY,
2913  ListEntry);
2914  if (!PrevPartEntry->IsPartitioned)
2915  {
2916  ASSERT(PrevPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2917  return PrevPartEntry;
2918  }
2919  }
2920 
2921  return NULL;
2922 }
2923 
2924 static
2925 PPARTENTRY
2927  IN PPARTENTRY PartEntry)
2928 {
2929  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
2930  PPARTENTRY NextPartEntry;
2931  PLIST_ENTRY ListHead;
2932 
2933  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
2934  {
2935  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
2936  return NULL;
2937  }
2938 
2939  if (PartEntry->LogicalPartition)
2940  ListHead = &DiskEntry->LogicalPartListHead;
2941  else
2942  ListHead = &DiskEntry->PrimaryPartListHead;
2943 
2944  if (PartEntry->ListEntry.Flink != ListHead)
2945  {
2946  NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2947  PARTENTRY,
2948  ListEntry);
2949  if (!NextPartEntry->IsPartitioned)
2950  {
2951  ASSERT(NextPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
2952  return NextPartEntry;
2953  }
2954  }
2955 
2956  return NULL;
2957 }
2958 
2959 BOOLEAN
2961  IN PPARTLIST List,
2962  IN OUT PPARTENTRY PartEntry,
2964  IN BOOLEAN AutoCreate)
2965 {
2967 
2968  DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2969 
2970  if (List == NULL || PartEntry == NULL ||
2971  PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned)
2972  {
2973  return FALSE;
2974  }
2975 
2977  if (Error != NOT_AN_ERROR)
2978  {
2979  DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
2980  return FALSE;
2981  }
2982 
2983  /* Initialize the partition entry, inserting a new blank region if needed */
2984  if (!InitializePartitionEntry(PartEntry, SectorCount, AutoCreate))
2985  return FALSE;
2986 
2987  ASSERT(PartEntry->LogicalPartition == FALSE);
2988 
2989  UpdateDiskLayout(PartEntry->DiskEntry);
2991 
2992  return TRUE;
2993 }
2994 
2995 static
2996 VOID
2998  IN PDISKENTRY DiskEntry)
2999 {
3000  ULONGLONG StartSector;
3002  PPARTENTRY NewPartEntry;
3003 
3004  DPRINT1("AddLogicalDiskSpace()\n");
3005 
3006  /* Create a partition entry that represents the empty space in the container partition */
3007 
3008  StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
3009  SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
3010 
3011  NewPartEntry = CreateInsertBlankRegion(DiskEntry,
3012  &DiskEntry->LogicalPartListHead,
3013  StartSector,
3014  SectorCount,
3015  TRUE);
3016  if (NewPartEntry == NULL)
3017  {
3018  DPRINT1("Failed to create a new empty region for extended partition space!\n");
3019  return;
3020  }
3021 }
3022 
3023 BOOLEAN
3025  IN PPARTLIST List,
3026  IN OUT PPARTENTRY PartEntry,
3028 {
3030 
3031  DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
3032 
3033  if (List == NULL || PartEntry == NULL ||
3034  PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned)
3035  {
3036  return FALSE;
3037  }
3038 
3040  if (Error != NOT_AN_ERROR)
3041  {
3042  DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
3043  return FALSE;
3044  }
3045 
3046  /* Initialize the partition entry, inserting a new blank region if needed */
3047  if (!InitializePartitionEntry(PartEntry, SectorCount, FALSE))
3048  return FALSE;
3049 
3050  ASSERT(PartEntry->LogicalPartition == FALSE);
3051 
3052  if (PartEntry->StartSector.QuadPart < 1450560)
3053  {
3054  /* Partition starts below the 8.4GB boundary ==> CHS partition */
3055  PartEntry->PartitionType = PARTITION_EXTENDED;
3056  }
3057  else
3058  {
3059  /* Partition starts above the 8.4GB boundary ==> LBA partition */
3060  PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
3061  }
3062 
3063  // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
3064  PartEntry->New = FALSE;
3065  PartEntry->FormatState = Formatted;
3066 
3067  PartEntry->DiskEntry->ExtendedPartition = PartEntry;
3068 
3069  AddLogicalDiskSpace(PartEntry->DiskEntry);
3070 
3071  UpdateDiskLayout(PartEntry->DiskEntry);
3073 
3074  return TRUE;
3075 }
3076 
3077 BOOLEAN
3079  IN PPARTLIST List,
3080  IN OUT PPARTENTRY PartEntry,
3082  IN BOOLEAN AutoCreate)
3083 {
3085 
3086  DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
3087 
3088  if (List == NULL || PartEntry == NULL ||
3089  PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned)
3090  {
3091  return FALSE;
3092  }
3093 
3095  if (Error != NOT_AN_ERROR)
3096  {
3097  DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
3098  return FALSE;
3099  }
3100 
3101  /* Initialize the partition entry, inserting a new blank region if needed */
3102  if (!InitializePartitionEntry(PartEntry, SectorCount, AutoCreate))
3103  return FALSE;
3104 
3105  ASSERT(PartEntry->LogicalPartition == TRUE);
3106 
3107  UpdateDiskLayout(PartEntry->DiskEntry);
3109 
3110  return TRUE;
3111 }
3112 
3113 NTSTATUS
3115  IN PPARTENTRY PartEntry)
3116 {
3117  NTSTATUS Status;
3118  NTSTATUS LockStatus;
3122  HANDLE PartitionHandle;
3124 
3125  /* Check whether the partition is valid and was mounted by the system */
3126  if (!PartEntry->IsPartitioned ||
3127  IsContainerPartition(PartEntry->PartitionType) ||
3128  !IsRecognizedPartition(PartEntry->PartitionType) ||
3129  PartEntry->FormatState == UnknownFormat ||
3130  // NOTE: If FormatState == Unformatted but *FileSystem != 0 this means
3131  // it has been usually mounted with RawFS and thus needs to be dismounted.
3132  !*PartEntry->FileSystem ||
3133  PartEntry->PartitionNumber == 0)
3134  {
3135  /* The partition is not mounted, so just return success */
3136  return STATUS_SUCCESS;
3137  }
3138 
3139  ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
3140 
3141  /* Open the volume */
3143  L"\\Device\\Harddisk%lu\\Partition%lu",
3144  PartEntry->DiskEntry->DiskNumber,
3145  PartEntry->PartitionNumber);
3147 
3149  &Name,
3151  NULL,
3152  NULL);
3153 
3154  Status = NtOpenFile(&PartitionHandle,
3157  &IoStatusBlock,
3160  if (!NT_SUCCESS(Status))
3161  {
3162  DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
3163  return Status;
3164  }
3165 
3166  /* Lock the volume */
3167  LockStatus = NtFsControlFile(PartitionHandle,
3168  NULL,
3169  NULL,
3170  NULL,
3171  &IoStatusBlock,
3173  NULL,
3174  0,
3175  NULL,
3176  0);
3177  if (!NT_SUCCESS(LockStatus))
3178  {
3179  DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
3180  }
3181 
3182  /* Dismount the volume */
3183  Status = NtFsControlFile(PartitionHandle,
3184  NULL,
3185  NULL,
3186  NULL,
3187  &IoStatusBlock,
3189  NULL,
3190  0,
3191  NULL,
3192  0);
3193  if (!NT_SUCCESS(Status))
3194  {
3195  DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
3196  }
3197 
3198  /* Unlock the volume */
3199  LockStatus = NtFsControlFile(PartitionHandle,
3200  NULL,
3201  NULL,
3202  NULL,
3203  &IoStatusBlock,
3205  NULL,
3206  0,
3207  NULL,
3208  0);
3209  if (!NT_SUCCESS(LockStatus))
3210  {
3211  DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
3212  }
3213 
3214  /* Close the volume */
3215  NtClose(PartitionHandle);
3216 
3217  return Status;
3218 }
3219 
3220 BOOLEAN
3222  IN PPARTLIST List,
3223  IN PPARTENTRY PartEntry,
3224  OUT PPARTENTRY* FreeRegion OPTIONAL)
3225 {
3226  PDISKENTRY DiskEntry;
3227  PPARTENTRY PrevPartEntry;
3228  PPARTENTRY NextPartEntry;
3229  PPARTENTRY LogicalPartEntry;
3231 
3232  if (List == NULL || PartEntry == NULL ||
3233  PartEntry->DiskEntry == NULL || PartEntry->IsPartitioned == FALSE)
3234  {
3235  return FALSE;
3236  }
3237 
3238  ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
3239 
3240  /* Clear the system partition if it is being deleted */
3241  if (List->SystemPartition == PartEntry)
3242  {
3243  ASSERT(List->SystemPartition);
3244  List->SystemPartition = NULL;
3245  }
3246 
3247  DiskEntry = PartEntry->DiskEntry;
3248 
3249  /* Check which type of partition (primary/logical or extended) is being deleted */
3250  if (DiskEntry->ExtendedPartition == PartEntry)
3251  {
3252  /* An extended partition is being deleted: delete all logical partition entries */
3253  while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
3254  {
3255  Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
3256  LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
3257 
3258  /* Dismount the logical partition */
3259  DismountVolume(LogicalPartEntry);
3260 
3261  /* Delete it */
3262  RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
3263  }
3264 
3265  DiskEntry->ExtendedPartition = NULL;
3266  }
3267  else
3268  {
3269  /* A primary partition is being deleted: dismount it */
3270  DismountVolume(PartEntry);
3271  }
3272 
3273  /* Adjust the unpartitioned disk space entries */
3274 
3275  /* Get pointer to previous and next unpartitioned entries */
3276  PrevPartEntry = GetPrevUnpartitionedEntry(PartEntry);
3277  NextPartEntry = GetNextUnpartitionedEntry(PartEntry);
3278 
3279  if (PrevPartEntry != NULL && NextPartEntry != NULL)
3280  {
3281  /* Merge the previous, current and next unpartitioned entries */
3282 
3283  /* Adjust the previous entry length */
3284  PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
3285 
3286  /* Remove the current and next entries */
3287  RemoveEntryList(&PartEntry->ListEntry);
3288  RtlFreeHeap(ProcessHeap, 0, PartEntry);
3289  RemoveEntryList(&NextPartEntry->ListEntry);
3290  RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
3291 
3292  /* Optionally return the freed region */
3293  if (FreeRegion)
3294  *FreeRegion = PrevPartEntry;
3295  }
3296  else if (PrevPartEntry != NULL && NextPartEntry == NULL)
3297  {
3298  /* Merge the current and the previous unpartitioned entries */
3299 
3300  /* Adjust the previous entry length */
3301  PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3302 
3303  /* Remove the current entry */
3304  RemoveEntryList(&PartEntry->ListEntry);
3305  RtlFreeHeap(ProcessHeap, 0, PartEntry);
3306 
3307  /* Optionally return the freed region */
3308  if (FreeRegion)
3309  *FreeRegion = PrevPartEntry;
3310  }
3311  else if (PrevPartEntry == NULL && NextPartEntry != NULL)
3312  {
3313  /* Merge the current and the next unpartitioned entries */
3314 
3315  /* Adjust the next entry offset and length */
3316  NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
3317  NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
3318 
3319  /* Remove the current entry */
3320  RemoveEntryList(&PartEntry->ListEntry);
3321  RtlFreeHeap(ProcessHeap, 0, PartEntry);
3322 
3323  /* Optionally return the freed region */
3324  if (FreeRegion)
3325  *FreeRegion = NextPartEntry;
3326  }
3327  else
3328  {
3329  /* Nothing to merge but change the current entry */
3330  PartEntry->IsPartitioned = FALSE;
3331  PartEntry->OnDiskPartitionNumber = 0;
3332  PartEntry->PartitionNumber = 0;
3333  // PartEntry->PartitionIndex = 0;
3334  PartEntry->BootIndicator = FALSE;
3335  PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
3336  PartEntry->FormatState = Unformatted;
3337  PartEntry->FileSystem[0] = L'\0';
3338  PartEntry->DriveLetter = 0;
3339  RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
3340 
3341  /* Optionally return the freed region */
3342  if (FreeRegion)
3343  *FreeRegion = PartEntry;
3344  }
3345 
3346  UpdateDiskLayout(DiskEntry);
3348 
3349  return TRUE;
3350 }
3351 
3352 static
3353 BOOLEAN
3355  IN PPARTENTRY PartEntry)
3356 {
3357  /* Check the type and the file system of this partition */
3358 
3359  /*
3360  * We do not support extended partition containers (on MBR disks) marked
3361  * as active, and containing code inside their extended boot records.
3362  */
3363  if (IsContainerPartition(PartEntry->PartitionType))
3364  {
3365  DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
3366  PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3367  return FALSE;
3368  }
3369 
3370  /*
3371  * ADDITIONAL CHECKS / BIG HACK:
3372  *
3373  * Retrieve its file system and check whether we have
3374  * write support for it. If that is the case we are fine
3375  * and we can use it directly. However if we don't have
3376  * write support we will need to change the active system
3377  * partition.
3378  *
3379  * NOTE that this is completely useless on architectures
3380  * where a real system partition is required, as on these
3381  * architectures the partition uses the FAT FS, for which
3382  * we do have write support.
3383  * NOTE also that for those architectures looking for a
3384  * partition boot indicator is insufficient.
3385  */
3386  if (PartEntry->FormatState == Unformatted)
3387  {
3388  /* If this partition is mounted, it would use RawFS ("RAW") */
3389  return TRUE;
3390  }
3391  else if ((PartEntry->FormatState == Preformatted) ||
3392  (PartEntry->FormatState == Formatted))
3393  {
3394  ASSERT(*PartEntry->FileSystem);
3395 
3396  /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
3397  if (wcsicmp(PartEntry->FileSystem, L"FAT") == 0 ||
3398  wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 ||
3399  // wcsicmp(PartEntry->FileSystem, L"NTFS") == 0 ||
3400  wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0)
3401  {
3402  return TRUE;
3403  }
3404  else
3405  {
3406  // WARNING: We cannot write on this FS yet!
3407  DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3408  PartEntry->FileSystem);
3409  return FALSE;
3410  }
3411  }
3412  else // if (PartEntry->FormatState == UnknownFormat)
3413  {
3414  ASSERT(!*PartEntry->FileSystem);
3415 
3416  DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
3417  PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
3418  return FALSE;
3419  }
3420 
3421  // HACK: WARNING: We cannot write on this FS yet!
3422  // See fsutil.c:InferFileSystem()
3423  if (PartEntry->PartitionType == PARTITION_IFS)
3424  {
3425  DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
3426  PartEntry->FileSystem);
3427  return FALSE;
3428  }
3429 
3430  return TRUE;
3431 }
3432 
3433 PPARTENTRY
3435  IN PPARTLIST List,
3436  IN BOOLEAN ForceSelect,
3437  IN PDISKENTRY AlternativeDisk OPTIONAL,
3438  IN PPARTENTRY AlternativePart OPTIONAL)
3439 {
3440  PLIST_ENTRY ListEntry;
3441  PDISKENTRY DiskEntry;
3442  PPARTENTRY PartEntry;
3443  PPARTENTRY ActivePartition;
3444  PPARTENTRY CandidatePartition = NULL;
3445 
3446  /* Check for empty disk list */
3447  if (IsListEmpty(&List->DiskListHead))
3448  {
3449  /* No system partition! */
3450  ASSERT(List->SystemPartition == NULL);
3451  goto NoSystemPartition;
3452  }
3453 
3454  /* Adjust the optional alternative disk if needed */
3455  if (!AlternativeDisk && AlternativePart)
3456  AlternativeDisk = AlternativePart->DiskEntry;
3457 
3458  /* Ensure that the alternative partition is on the alternative disk */
3459  if (AlternativePart)
3460  ASSERT(AlternativeDisk && (AlternativePart->DiskEntry == AlternativeDisk));
3461 
3462  /* Ensure that the alternative disk is in the list */
3463  if (AlternativeDisk)
3464  ASSERT(AlternativeDisk->PartList == List);
3465 
3466  /* Start fresh */
3467  CandidatePartition = NULL;
3468 
3469 //
3470 // Step 1 : Check the system disk.
3471 //
3472 
3473  /*
3474  * First, check whether the system disk, i.e. the one that will be booted
3475  * by default by the hardware, contains an active partition. If so this
3476  * should be our system partition.
3477  */
3478  DiskEntry = GetSystemDisk(List);
3479 
3480  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3481  {
3482  DPRINT1("System disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3483  goto UseAlternativeDisk;
3484  }
3485 
3486  /* If we have a system partition (in the system disk), validate it */
3487  ActivePartition = List->SystemPartition;
3488  if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3489  {
3490  CandidatePartition = ActivePartition;
3491 
3492  DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
3493  CandidatePartition->PartitionNumber,
3494  CandidatePartition->DiskEntry->DiskNumber,
3495  (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter);
3496 
3497  /* Return the candidate system partition */
3498  return CandidatePartition;
3499  }
3500 
3501  /* If the system disk is not the optional alternative disk, perform the minimal checks */
3502  if (DiskEntry != AlternativeDisk)
3503  {
3504  /*
3505  * No active partition has been recognized. Enumerate all the (primary)
3506  * partitions in the system disk, excluding the possible current active
3507  * partition, to find a new candidate.
3508  */
3509  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3510  ListEntry != &DiskEntry->PrimaryPartListHead;
3511  ListEntry = ListEntry->Flink)
3512  {
3513  /* Retrieve the partition */
3514  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3515 
3516  /* Skip the current active partition */
3517  if (PartEntry == ActivePartition)
3518  continue;
3519 
3520  /* Check if the partition is partitioned and used */
3521  if (PartEntry->IsPartitioned &&
3522  !IsContainerPartition(PartEntry->PartitionType))
3523  {
3525 
3526  /* If we get a candidate active partition in the disk, validate it */
3527  if (IsSupportedActivePartition(PartEntry))
3528  {
3529  CandidatePartition = PartEntry;
3530  goto UseAlternativePartition;
3531  }
3532  }
3533 
3534 #if 0
3535  /* Check if the partition is partitioned and used */
3536  if (!PartEntry->IsPartitioned)
3537  {
3539 
3540  // TODO: Check for minimal size!!
3541  CandidatePartition = PartEntry;
3542  goto UseAlternativePartition;
3543  }
3544 #endif
3545  }
3546 
3547  /*
3548  * Still nothing, look whether there is some free space that we can use
3549  * for the new system partition. We must be sure that the total number
3550  * of partition is less than the maximum allowed, and that the minimal
3551  * size is fine.
3552  */
3553 //
3554 // TODO: Fix the handling of system partition being created in unpartitioned space!!
3555 // --> When to partition it? etc...
3556 //
3557  if (GetPrimaryPartitionCount(DiskEntry) < 4)
3558  {
3559  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3560  ListEntry != &DiskEntry->PrimaryPartListHead;
3561  ListEntry = ListEntry->Flink)
3562  {
3563  /* Retrieve the partition */
3564  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3565 
3566  /* Skip the current active partition */
3567  if (PartEntry == ActivePartition)
3568  continue;
3569 
3570  /* Check for unpartitioned space */
3571  if (!PartEntry->IsPartitioned)
3572  {
3574 
3575  // TODO: Check for minimal size!!
3576  CandidatePartition = PartEntry;
3577  goto UseAlternativePartition;
3578  }
3579  }
3580  }
3581  }
3582 
3583 
3584 //
3585 // Step 2 : No active partition found: Check the alternative disk if specified.
3586 //
3587 
3588 UseAlternativeDisk:
3589  if (!AlternativeDisk || (!ForceSelect && (DiskEntry != AlternativeDisk)))
3590  goto NoSystemPartition;
3591 
3592  if (AlternativeDisk->DiskStyle == PARTITION_STYLE_GPT)
3593  {
3594  DPRINT1("Alternative disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
3595  goto NoSystemPartition;
3596  }
3597 
3598  if (DiskEntry != AlternativeDisk)
3599  {
3600  /* Choose the alternative disk */
3601  DiskEntry = AlternativeDisk;
3602 
3603  /* If we get a candidate active partition, validate it */
3604  ActivePartition = GetActiveDiskPartition(DiskEntry);
3605  if (ActivePartition && IsSupportedActivePartition(ActivePartition))
3606  {
3607  CandidatePartition = ActivePartition;
3608  goto UseAlternativePartition;
3609  }
3610  }
3611 
3612  /* We now may have an unsupported active partition, or none */
3613 
3614 /***
3615  *** TODO: Improve the selection:
3616  *** - If we want a really separate system partition from the partition where
3617  *** we install, do something similar to what's done below in the code.
3618  *** - Otherwise if we allow for the system partition to be also the partition
3619  *** where we install, just directly fall down to using AlternativePart.
3620  ***/
3621 
3622  /* Retrieve the first partition of the disk */
3623  PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
3624  PARTENTRY, ListEntry);
3625  ASSERT(DiskEntry == PartEntry->DiskEntry);
3626 
3627  CandidatePartition = PartEntry;
3628 
3629  //
3630  // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
3631  //
3632 
3633  /* Check if the disk is new and if so, use its first partition as the active system partition */
3634  if (DiskEntry->NewDisk)
3635  {
3636  // !IsContainerPartition(PartEntry->PartitionType);
3637  if (!CandidatePartition->IsPartitioned || !CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */
3638  {
3639  ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3640 
3641  DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
3642  CandidatePartition->PartitionNumber,
3643  CandidatePartition->DiskEntry->DiskNumber,
3644  (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter);
3645 
3646  /* Return the candidate system partition */
3647  return CandidatePartition;
3648  }
3649 
3650  // FIXME: What to do??
3651  DPRINT1("NewDisk TRUE but first partition is used?\n");
3652  }
3653 
3654  /*
3655  * The disk is not new, check if any partition is initialized;
3656  * if not, the first one becomes the system partition.
3657  */
3658  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3659  ListEntry != &DiskEntry->PrimaryPartListHead;
3660  ListEntry = ListEntry->Flink)
3661  {
3662  /* Retrieve the partition */
3663  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3664 
3665  /* Check if the partition is partitioned and is used */
3666  // !IsContainerPartition(PartEntry->PartitionType);
3667  if (/* PartEntry->IsPartitioned && */
3668  PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator)
3669  {
3670  break;
3671  }
3672  }
3673  if (ListEntry == &DiskEntry->PrimaryPartListHead)
3674  {
3675  /*
3676  * OK we haven't encountered any used and active partition,
3677  * so use the first one as the system partition.
3678  */
3679  ASSERT(DiskEntry == CandidatePartition->DiskEntry);
3680 
3681  DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
3682  CandidatePartition->PartitionNumber,
3683  CandidatePartition->DiskEntry->DiskNumber,
3684  (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter);
3685 
3686  /* Return the candidate system partition */
3687  return CandidatePartition;
3688  }
3689 
3690  /*
3691  * The disk is not new, we did not find any actual active partition,
3692  * or the one we found was not supported, or any possible other candidate
3693  * is not supported. We then use the alternative partition if specified.
3694  */
3695  if (AlternativePart)
3696  {
3697  DPRINT1("No valid or supported system partition has been found, use the alternative partition!\n");
3698  CandidatePartition = AlternativePart;
3699  goto UseAlternativePartition;
3700  }
3701  else
3702  {
3703 NoSystemPartition:
3704  DPRINT1("No valid or supported system partition has been found on this system!\n");
3705  return NULL;
3706  }
3707 
3708 UseAlternativePartition:
3709  /*
3710  * We are here because we did not find any (active) candidate system
3711  * partition that we know how to support. What we are going to do is
3712  * to change the existing system partition and use the alternative partition
3713  * (e.g. on which we install ReactOS) as the new system partition.
3714  * Then we will need to add in FreeLdr's boot menu an entry for booting
3715  * from the original system partition.
3716  */
3717  ASSERT(CandidatePartition);
3718 
3719  DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3720  CandidatePartition->PartitionNumber,
3721  CandidatePartition->DiskEntry->DiskNumber,
3722  (CandidatePartition->DriveLetter == 0) ? L'-' : CandidatePartition->DriveLetter);
3723 
3724  /* Return the candidate system partition */
3725  return CandidatePartition;
3726 }
3727 
3728 BOOLEAN
3730  IN PPARTLIST List,
3731  IN PPARTENTRY PartEntry,
3732  IN PPARTENTRY OldActivePart OPTIONAL)
3733 {
3734  /* Check for empty disk list */
3735  if (IsListEmpty(&List->DiskListHead))
3736  return FALSE;
3737 
3738  /* Validate the partition entry */
3739  if (!PartEntry)
3740  return FALSE;
3741 
3742  /*
3743  * If the partition entry is already the system partition, or if it is
3744  * the same as the old active partition hint the user provided (and if
3745  * it is already active), just return success.
3746  */
3747  if ((PartEntry == List->SystemPartition) ||
3748  ((PartEntry == OldActivePart) && IsPartitionActive(OldActivePart)))
3749  {
3750  return TRUE;
3751  }
3752 
3753  ASSERT(PartEntry->DiskEntry);
3754 
3755  /* Ensure that the partition's disk is in the list */
3756  ASSERT(PartEntry->DiskEntry->PartList == List);
3757 
3758  /*
3759  * If the user provided an old active partition hint, verify that it is
3760  * indeeed active and belongs to the same disk where the new partition
3761  * belongs. Otherwise determine the current active partition on the disk
3762  * where the new partition belongs.
3763  */
3764  if (!(OldActivePart && IsPartitionActive(OldActivePart) && (OldActivePart->DiskEntry == PartEntry->DiskEntry)))
3765  {
3766  /* It's not, determine the current active partition for the disk */
3767  OldActivePart = GetActiveDiskPartition(PartEntry->DiskEntry);
3768  }
3769 
3770  /* Unset the old active partition if it exists */
3771  if (OldActivePart)
3772  {
3773  OldActivePart->BootIndicator = FALSE;
3774  OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].BootIndicator = FALSE;
3775  OldActivePart->DiskEntry->LayoutBuffer->PartitionEntry[OldActivePart->PartitionIndex].RewritePartition = TRUE;
3776  OldActivePart->DiskEntry->Dirty = TRUE;
3777  }
3778 
3779  /* Modify the system partition if the new partition is on the system disk */
3780  if (PartEntry->DiskEntry == GetSystemDisk(List))
3781  List->SystemPartition = PartEntry;
3782 
3783  /* Set the new active partition */
3784  PartEntry->BootIndicator = TRUE;
3785  PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE;
3786  PartEntry->DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3787  PartEntry->DiskEntry->Dirty = TRUE;
3788 
3789  return TRUE;
3790 }
3791 
3792 NTSTATUS
3794  IN PDISKENTRY DiskEntry)
3795 {
3796  NTSTATUS Status;
3801  ULONG BufferSize;
3803  ULONG PartitionCount;
3804  PLIST_ENTRY ListEntry;
3805  PPARTENTRY PartEntry;
3807 
3808  DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3809 
3810  /* If the disk is not dirty, there is nothing to do */
3811  if (!DiskEntry->Dirty)
3812  return STATUS_SUCCESS;
3813 
3815  L"\\Device\\Harddisk%lu\\Partition0",
3816  DiskEntry->DiskNumber);
3818 
3820  &Name,
3822  NULL,
3823  NULL);
3824 
3828  &Iosb,
3829  0,
3831  if (!NT_SUCCESS(Status))
3832  {
3833  DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3834  return Status;
3835  }
3836 
3837 #ifdef DUMP_PARTITION_TABLE
3838  DumpPartitionTable(DiskEntry);
3839 #endif
3840 
3841  //
3842  // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3843  // the disk in MBR or GPT format in case the disk was not initialized!!
3844  // For this we must ask the user which format to use.
3845  //
3846 
3847  /* Save the original partition count to be restored later (see comment below) */
3848  PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
3849 
3850  /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
3852  ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3854  NULL,
3855  NULL,
3856  NULL,
3857  &Iosb,
3859  DiskEntry->LayoutBuffer,
3860  BufferSize,
3861  DiskEntry->LayoutBuffer,
3862  BufferSize);
3864 
3865  /*
3866  * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
3867  * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
3868  * where such a table is expected to enumerate up to 4 partitions:
3869  * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
3870  * Due to this we need to restore the original PartitionCount number.
3871  */
3872  DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
3873 
3874  /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
3875  if (!NT_SUCCESS(Status))
3876  {
3877  DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3878  return Status;
3879  }
3880 
3881 #ifdef DUMP_PARTITION_TABLE
3882  DumpPartitionTable(DiskEntry);
3883 #endif
3884 
3885  /* Update the partition numbers */
3886 
3887  /* Update the primary partition table */
3888  for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
3889  ListEntry != &DiskEntry->PrimaryPartListHead;
3890  ListEntry = ListEntry->Flink)
3891  {
3892  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3893 
3894  if (PartEntry->IsPartitioned)
3895  {
3897  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3898  PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3899  }
3900  }
3901 
3902  /* Update the logical partition table */
3903  for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
3904  ListEntry != &DiskEntry->LogicalPartListHead;
3905  ListEntry = ListEntry->Flink)
3906  {
3907  PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
3908 
3909  if (PartEntry->IsPartitioned)
3910  {
3912  PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
3913  PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
3914  }
3915  }
3916 
3917  //
3918  // NOTE: Originally (see r40437), we used to install here also a new MBR
3919  // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3920  // DiskEntry->NewDisk == TRUE and DiskEntry->HwDiskNumber == 0.
3921  // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3922  // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3923  // was called too, the installation test was modified by checking whether
3924  // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3925  //
3926 
3927  /* The layout has been successfully updated, the disk is not dirty anymore */
3928  DiskEntry->Dirty = FALSE;
3929 
3930  return Status;
3931 }
3932 
3933 BOOLEAN
3935  IN PPARTLIST List)
3936 {
3937  NTSTATUS Status;
3939  PDISKENTRY DiskEntry;
3940 
3941  if (List == NULL)
3942  return TRUE;
3943 
3944  for (Entry = List->DiskListHead.Flink;
3945  Entry != &List->DiskListHead;
3946  Entry = Entry->Flink)
3947  {
3948  DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3949 
3950  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
3951  {
3952  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
3953  continue;
3954  }
3955 
3956  if (DiskEntry->Dirty != FALSE)
3957  {
3958  Status = WritePartitions(DiskEntry);
3959  if (!NT_SUCCESS(Status))
3960  {
3961  DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
3962  DiskEntry->DiskNumber, Status);
3963  }
3964  }
3965  }
3966 
3967  return TRUE;
3968 }
3969 
3970 BOOLEAN
3972  IN WCHAR Letter,
3973  IN ULONG Signature,
3975 {
3976  NTSTATUS Status;
3978  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices");
3980  WCHAR ValueNameBuffer[16];
3981  HANDLE KeyHandle;
3982  REG_DISK_MOUNT_INFO MountInfo;
3983 
3984  RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3985  L"\\DosDevices\\%c:", Letter);
3986  RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3987 
3989  &KeyName,
3992  NULL);
3993 
3996  &ObjectAttributes);
3997  if (!NT_SUCCESS(Status))
3998  {
4002  0,
4003  NULL,
4005  NULL);
4006  }
4007  if (!NT_SUCCESS(Status))
4008  {
4009  DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
4010  return FALSE;
4011  }
4012 
4013  MountInfo.Signature = Signature;
4014  MountInfo.StartingOffset = StartingOffset;
4016  &ValueName,
4017  0,
4018  REG_BINARY,
4019  (PVOID)&MountInfo,
4020  sizeof(MountInfo));
4021  NtClose(KeyHandle);
4022  if (!NT_SUCCESS(Status))
4023  {
4024  DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
4025  return FALSE;
4026  }
4027 
4028  return TRUE;
4029 }
4030 
4031 BOOLEAN
4033  IN PPARTLIST List)
4034 {
4035  PLIST_ENTRY Entry1, Entry2;
4036  PDISKENTRY DiskEntry;
4037  PPARTENTRY PartEntry;
4039 
4040  if (List == NULL)
4041  return FALSE;
4042 
4043  for (Entry1 = List->DiskListHead.Flink;
4044  Entry1 != &List->DiskListHead;
4045  Entry1 = Entry1->Flink)
4046  {
4047  DiskEntry = CONTAINING_RECORD(Entry1,
4048  DISKENTRY,
4049  ListEntry);
4050 
4051  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4052  {
4053  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4054  continue;
4055  }
4056 
4057  for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
4058  Entry2 != &DiskEntry->PrimaryPartListHead;
4059  Entry2 = Entry2->Flink)
4060  {
4061  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4062  if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType)
4063  {
4065 
4066  /* Assign a "\DosDevices\#:" mount point to this partition */
4067  if (PartEntry->DriveLetter)
4068  {
4069  StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
4070  if (!SetMountedDeviceValue(PartEntry->DriveLetter,
4071  DiskEntry->LayoutBuffer->Signature,
4072  StartingOffset))
4073  {
4074  return FALSE;
4075  }
4076  }
4077  }
4078  }
4079 
4080  for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
4081  Entry2 != &DiskEntry->LogicalPartListHead;
4082  Entry2 = Entry2->Flink)
4083  {
4084  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4085  if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType)
4086  {
4088 
4089  /* Assign a "\DosDevices\#:" mount point to this partition */
4090  if (PartEntry->DriveLetter)
4091  {
4092  StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
4093  if (!SetMountedDeviceValue(PartEntry->DriveLetter,
4094  DiskEntry->LayoutBuffer->Signature,
4095  StartingOffset))
4096  {
4097  return FALSE;
4098  }
4099  }
4100  }
4101  }
4102  }
4103 
4104  return TRUE;
4105 }
4106 
4107 VOID
4109  IN PPARTENTRY PartEntry,
4111 {
4112  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
4113 
4114  PartEntry->PartitionType = PartitionType;
4115 
4116  DiskEntry->Dirty = TRUE;
4117  DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
4118  DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
4119  DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
4120 }
4121 
4124  IN PPARTENTRY PartEntry)
4125 {
4126  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
4127 
4128  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4129  {
4130  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4131  return ERROR_WARN_PARTITION;
4132  }
4133 
4134  /* Fail if the partition is already in use */
4135  if (PartEntry->IsPartitioned)
4136  return ERROR_NEW_PARTITION;
4137 
4138  /* Only one primary partition is allowed on super-floppy */
4139  if (IsSuperFloppy(DiskEntry))
4141 
4142  /* Fail if there are already 4 primary partitions in the list */
4143  if (GetPrimaryPartitionCount(DiskEntry) >= 4)
4145 
4146  return ERROR_SUCCESS;
4147 }
4148 
4151  IN PPARTENTRY PartEntry)
4152 {
4153  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
4154 
4155  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4156  {
4157  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4158  return ERROR_WARN_PARTITION;
4159  }
4160 
4161  /* Fail if the partition is already in use */
4162  if (PartEntry->IsPartitioned)
4163  return ERROR_NEW_PARTITION;
4164 
4165  /* Only one primary partition is allowed on super-floppy */
4166  if (IsSuperFloppy(DiskEntry))
4168 
4169  /* Fail if there are already 4 primary partitions in the list */
4170  if (GetPrimaryPartitionCount(DiskEntry) >= 4)
4172 
4173  /* Fail if there is another extended partition in the list */
4174  if (DiskEntry->ExtendedPartition != NULL)
4175  return ERROR_ONLY_ONE_EXTENDED;
4176 
4177  return ERROR_SUCCESS;
4178 }
4179 
4182  IN PPARTENTRY PartEntry)
4183 {
4184  PDISKENTRY DiskEntry = PartEntry->DiskEntry;
4185 
4186  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4187  {
4188  DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4189  return ERROR_WARN_PARTITION;
4190  }
4191 
4192  /* Fail if the partition is already in use */
4193  if (PartEntry->IsPartitioned)
4194  return ERROR_NEW_PARTITION;
4195 
4196  /* Only one primary partition is allowed on super-floppy */
4197  if (IsSuperFloppy(DiskEntry))
4199 
4200  return ERROR_SUCCESS;
4201 }
4202 
4203 BOOLEAN
4205  IN PPARTLIST List,
4206  OUT PDISKENTRY *pDiskEntry OPTIONAL,
4207  OUT PPARTENTRY *pPartEntry)
4208 {
4209  PLIST_ENTRY Entry1, Entry2;
4210  PDISKENTRY DiskEntry;
4211  PPARTENTRY PartEntry;
4212 
4213  for (Entry1 = List->DiskListHead.Flink;
4214  Entry1 != &List->DiskListHead;
4215  Entry1 = Entry1->Flink)
4216  {
4217  DiskEntry = CONTAINING_RECORD(Entry1,
4218  DISKENTRY,
4219  ListEntry);
4220 
4221  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4222  {
4223  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4224  continue;
4225  }
4226 
4227  for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
4228  Entry2 != &DiskEntry->PrimaryPartListHead;
4229  Entry2 = Entry2->Flink)
4230  {
4231  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4232  if (PartEntry->IsPartitioned && PartEntry->New)
4233  {
4234  ASSERT(DiskEntry == PartEntry->DiskEntry);
4235  if (pDiskEntry) *pDiskEntry = DiskEntry;
4236  *pPartEntry = PartEntry;
4237  return TRUE;
4238  }
4239  }
4240 
4241  for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
4242  Entry2 != &DiskEntry->LogicalPartListHead;
4243  Entry2 = Entry2->Flink)
4244  {
4245  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4246  if (PartEntry->IsPartitioned && PartEntry->New)
4247  {
4248  ASSERT(DiskEntry == PartEntry->DiskEntry);
4249  if (pDiskEntry) *pDiskEntry = DiskEntry;
4250  *pPartEntry = PartEntry;
4251  return TRUE;
4252  }
4253  }
4254  }
4255 
4256  if (pDiskEntry) *pDiskEntry = NULL;
4257  *pPartEntry = NULL;
4258 
4259  return FALSE;
4260 }
4261 
4262 BOOLEAN
4264  IN PPARTLIST List,
4265  OUT PDISKENTRY *pDiskEntry OPTIONAL,
4266  OUT PPARTENTRY *pPartEntry)
4267 {
4268  PLIST_ENTRY Entry1, Entry2;
4269  PDISKENTRY DiskEntry;
4270  PPARTENTRY PartEntry;
4271 
4272  for (Entry1 = List->DiskListHead.Flink;
4273  Entry1 != &List->DiskListHead;
4274  Entry1 = Entry1->Flink)
4275  {
4276  DiskEntry = CONTAINING_RECORD(Entry1,
4277  DISKENTRY,
4278  ListEntry);
4279 
4280  if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
4281  {
4282  DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
4283  continue;
4284  }
4285 
4286  for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
4287  Entry2 != &DiskEntry->PrimaryPartListHead;
4288  Entry2 = Entry2->Flink)
4289  {
4290  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4291  if (PartEntry->IsPartitioned && PartEntry->NeedsCheck)
4292  {
4293  ASSERT(DiskEntry == PartEntry->DiskEntry);
4294  if (pDiskEntry) *pDiskEntry = DiskEntry;
4295  *pPartEntry = PartEntry;
4296  return TRUE;
4297  }
4298  }
4299 
4300  for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
4301  Entry2 != &DiskEntry->LogicalPartListHead;
4302  Entry2 = Entry2->Flink)
4303  {
4304  PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
4305  if (PartEntry->IsPartitioned && PartEntry->NeedsCheck)
4306  {
4307  ASSERT(DiskEntry == PartEntry->DiskEntry);
4308  if (pDiskEntry) *pDiskEntry = DiskEntry;
4309  *pPartEntry = PartEntry;
4310  return TRUE;
4311  }
4312  }
4313  }
4314 
4315  if (pDiskEntry) *pDiskEntry = NULL;
4316  *pPartEntry = NULL;
4317 
4318  return FALSE;
4319 }
4320 
4321 /* EOF */
UCHAR PathId
Definition: scsi_port.h:149
LIST_ENTRY PrimaryPartListHead
Definition: partlist.h:124
#define PARTITION_FAT32
Definition: disk.h:95
struct _PARTLIST * PartList
Definition: partlist.h:79
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
PPARTLIST CreatePartitionList(VOID)
Definition: partlist.c:2024
UCHAR PortNumber
Definition: scsi_port.h:148
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
PDISKENTRY GetDiskBySignature(IN PPARTLIST List, IN ULONG Signature)
Definition: partlist.c:2247
WCHAR DriveLetter
Definition: partlist.h:51
CPPORT Port[4]
Definition: headless.c:34
#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:48
#define max(a, b)
Definition: svc.c:63
ULARGE_INTEGER StartSector
Definition: partlist.h:42
UCHAR FileSystemToPartitionType(IN PCWSTR FileSystem, IN PULARGE_INTEGER StartSector, IN PULARGE_INTEGER SectorCount)
Definition: fsrec.c:234
USHORT Id
Definition: partlist.h:108
ERROR_NUMBER ExtendedPartitionCreationChecks(IN PPARTENTRY PartEntry)
Definition: partlist.c:4150
#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:469
#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:52
ULONG HwControllerNumber
Definition: partlist.h:97
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:1968
_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:92
#define DbgPrint
Definition: loader.c:25
static BOOLEAN ReAllocateLayoutBuffer(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2659
USHORT MaximumLength
Definition: env_spec_w32.h:370
#define ANYSIZE_ARRAY
Definition: typedefs.h:46
#define REG_BINARY
Definition: nt_native.h:1496
BOOLEAN DeletePartition(IN PPARTLIST List, IN PPARTENTRY PartEntry, OUT PPARTENTRY *FreeRegion OPTIONAL)
Definition: partlist.c:3221
#define TRUE
Definition: types.h:120
USHORT Bus
Definition: partlist.h:107
uint16_t * PWSTR
Definition: typedefs.h:56
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
ULONG HwAdapterNumber
Definition: partlist.h:96
ULARGE_INTEGER SectorCount
Definition: partlist.h:43
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:139
BOOLEAN SetMountedDeviceValue(IN WCHAR Letter, IN ULONG Signature, IN LARGE_INTEGER StartingOffset)
Definition: partlist.c:3971
_In_ PCWSTR _In_z_ PCWSTR _In_ ULONG ValueType
Definition: rtlfuncs.h:4154
FORCEINLINE BOOLEAN IsEmptyLayoutEntry(IN PPARTITION_INFORMATION PartitionInfo)
Definition: partlist.c:2573
ULONG Signature
Definition: partlist.h:138
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:4181
ULONG ControllerNumber
Definition: partlist.h:136
ULONG DiskNumber
Definition: partlist.h:104
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1223
$ULONG LowPart
Definition: ntbasedef.h:570
static BOOLEAN IsSupportedActivePartition(IN PPARTENTRY PartEntry)
Definition: partlist.c:3354
#define IsContainerPartition(PartitionType)
Definition: ntdddisk.h:316
NTSYSCALLAPI NTSTATUS NTAPI NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, ULONG OutputBufferLength)
ULONG BytesPerSector
Definition: ntdddisk.h:442
BOOLEAN WritePartitionsToDisk(IN PPARTLIST List)
Definition: partlist.c:3934
ULONG TracksPerCylinder
Definition: ntdddisk.h:440
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
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:1392
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
IN UCHAR Value
Definition: halp.h:394
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
DWORD Id
#define PARTITION_XINT13
Definition: disk.h:97
PPARTENTRY ExtendedPartition
Definition: partlist.h:128
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
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
LIST_ENTRY ListEntry
Definition: partlist.h:36
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:56
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
NTSTATUS DismountVolume(IN PPARTENTRY PartEntry)
Definition: partlist.c:3114
PPARTENTRY GetPartition(IN PDISKENTRY DiskEntry, IN ULONG PartitionNumber)
Definition: partlist.c:2273
PARTITION_STYLE DiskStyle
Definition: partlist.h:114
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:54
#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:111
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
smooth NULL
Definition: ftsmooth.c:416
PARTITION_INFORMATION PartitionEntry[1]
Definition: ntdddisk.h:549
#define FORCEINLINE
Definition: ntbasedef.h:216
_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:4263
BOOLEAN CreateLogicalPartition(IN PPARTLIST List, IN OUT PPARTENTRY PartEntry, IN ULONGLONG SectorCount, IN BOOLEAN AutoCreate)
Definition: partlist.c:3078
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:81
#define REG_FULL_RESOURCE_DESCRIPTOR
Definition: nt_native.h:1503
USHORT Milliseconds
Definition: env_spec_w32.h:717
BOOLEAN SetMountedDeviceValues(IN PPARTLIST List)
Definition: partlist.c:4032
PPARTENTRY FindSupportedSystemPartition(IN PPARTLIST List, IN BOOLEAN ForceSelect, IN PDISKENTRY AlternativeDisk OPTIONAL, IN PPARTENTRY AlternativePart OPTIONAL)
Definition: partlist.c:3434
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:2711
#define ULL(a, b)
Definition: format_msg.c:27
ULARGE_INTEGER SectorCount
Definition: partlist.h:90
#define PARTITION_EXTENDED
Definition: disk.h:91
PPARTENTRY GetNextPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2384
ULONG SectorAlignment
Definition: partlist.h:91
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
#define FSCTL_DISMOUNT_VOLUME
Definition: nt_native.h:834
PPARTENTRY SelectPartition(IN PPARTLIST List, IN ULONG DiskNumber, IN ULONG PartitionNumber)
Definition: partlist.c:2360
struct _FILE_FS_VOLUME_INFORMATION * PFILE_FS_VOLUME_INFORMATION
#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:2191
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:4123
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:135
UCHAR PartitionType
Definition: partlist.h:46
BOOLEAN BiosFound
Definition: partlist.h:95
struct _DISKENTRY * DiskEntry
Definition: partlist.h:39
ULONG BytesPerSector
Definition: partlist.h:88
LIST_ENTRY List
Definition: psmgr.c:57
#define EFI_PMBR_OSTYPE_EFI
Definition: partlist.h:168
__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:1422
LARGE_INTEGER StartingOffset
Definition: ntdddisk.h:468
UNICODE_STRING DriverName
Definition: partlist.h:116
uint64_t ULONGLONG
Definition: typedefs.h:67
LARGE_INTEGER Cylinders
Definition: ntdddisk.h:438
ULONG OnDiskPartitionNumber
Definition: partlist.h:47
ULONG SectorsPerTrack
Definition: ntdddisk.h:441
#define IsRecognizedPartition(PartitionType)
Definition: ntdddisk.h:342
#define MAX_PATH
Definition: compat.h:34
CM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry
Definition: partlist.h:141
static const UCHAR Index[8]
Definition: usbohci.c:18
_In_ GUID _In_ PVOID ValueData
Definition: hubbusif.h:311
_In_ ULONG _In_ struct _SET_PARTITION_INFORMATION_EX * PartitionInfo
Definition: iofuncs.h:2101
#define BufferSize
Definition: mmc.h:75
LIST_ENTRY ListEntry
Definition: partlist.h:76
#define for
Definition: utility.h:88
MEDIA_TYPE MediaType
Definition: ntdddisk.h:439
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
ULONG HwDiskNumber
Definition: partlist.h:98
BOOL Error
Definition: chkdsk.c:66
WCHAR FileSystem[MAX_PATH+1]
Definition: partlist.h:53
#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
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
BOOLEAN RewritePartition
Definition: ntdddisk.h:475
#define wcsicmp
Definition: compat.h:15
static VOID ScanForUnpartitionedDiskSpace(IN PDISKENTRY DiskEntry)
Definition: partlist.c:1119
unsigned char UCHAR
Definition: xmlstorage.h:181
PDISKENTRY DiskEntry
Definition: partlist.h:140
static ULONG GetPrimaryPartitionCount(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2605
static PDISKENTRY GetSystemDisk(IN PPARTLIST List)
Definition: partlist.c:1895
CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1]
Definition: hwresource.cpp:119
Status
Definition: gdiplustypes.h:24
static VOID SetDiskSignature(IN PPARTLIST List, IN PDISKENTRY DiskEntry)
Definition: partlist.c:1330
static const WCHAR L[]
Definition: oid.c:1250
ULONG SectorsPerTrack
Definition: partlist.h:87
enum _ERROR_NUMBER ERROR_NUMBER
struct _CM_PARTIAL_RESOURCE_DESCRIPTOR::@384::@393 DeviceSpecificData
_In_ GUID _In_ PVOID _In_ ULONG ValueLength
Definition: hubbusif.h:311
WCHAR Letter
PARTITION_TYPE PartitionTypes[NUM_PARTITION_TYPE_ENTRIES]
Definition: partlist.c:63
PPARTENTRY GetPrevPartition(IN PPARTLIST List, IN PPARTENTRY CurrentPart OPTIONAL)
Definition: partlist.c:2476
ULONG LowPart
Definition: typedefs.h:106
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
VOID DestroyPartitionList(IN PPARTLIST List)
Definition: partlist.c:2108
#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:85
VOID SetPartitionType(IN PPARTENTRY PartEntry, IN UCHAR PartitionType)
Definition: partlist.c:4108
HANDLE ProcessHeap
Definition: servman.c:15
BOOLEAN New
Definition: partlist.h:64
BOOLEAN CreatePrimaryPartition(IN PPARTLIST List, IN OUT PPARTENTRY PartEntry, IN ULONGLONG SectorCount, IN BOOLEAN AutoCreate)
Definition: partlist.c:2960
#define IOCTL_DISK_GET_DRIVE_LAYOUT
Definition: ntdddisk.h:91
BOOLEAN NeedsCheck
Definition: partlist.h:70
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:1483
unsigned short USHORT
Definition: pedump.c:61
ULONG DiskNumber
Definition: partlist.h:137
#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:2320
static PPARTENTRY GetPrevUnpartitionedEntry(IN PPARTENTRY PartEntry)
Definition: partlist.c:2891
ULONG HwFixedDiskNumber
Definition: partlist.h:99
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
struct _REG_DISK_MOUNT_INFO * PREG_DISK_MOUNT_INFO
USHORT Port
Definition: partlist.h:106
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:3729
unsigned int * PULONG
Definition: retypes.h:1
#define min(a, b)
Definition: monoChain.cc:55
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:2165
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
ULONG TracksPerCylinder
Definition: partlist.h:86
#define DPRINT1
Definition: precomp.h:8
LIST_ENTRY LogicalPartListHead
Definition: partlist.h:125
BOOLEAN BootIndicator
Definition: partlist.h:45
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:2926
struct _FILE_FS_VOLUME_INFORMATION FILE_FS_VOLUME_INFORMATION
NTSTATUS WritePartitions(IN PDISKENTRY DiskEntry)
Definition: partlist.c:3793
#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:3024
#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:2217
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:474
static VOID AddLogicalDiskSpace(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2997
#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
BOOLEAN IsPartitionActive(IN PPARTENTRY PartEntry)
Definition: partlist.c:1945
union _CM_PARTIAL_RESOURCE_DESCRIPTOR::@384 u
#define RTL_REGISTRY_DEVICEMAP
Definition: nt_native.h:165
static ULONG GetLogicalPartitionCount(IN PDISKENTRY DiskEntry)
Definition: partlist.c:2632
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
static PTIME_FIELDS TimeFields
Definition: time.c:104
BOOLEAN GetNextUnformattedPartition(IN PPARTLIST List, OUT PDISKENTRY *pDiskEntry OPTIONAL, OUT PPARTENTRY *pPartEntry)
Definition: partlist.c:4204
#define PARTITION_MAGIC
Definition: partlist.h:165
return STATUS_SUCCESS
Definition: btrfs.c:3014
static const WCHAR Signature[]
Definition: parser.c:141
PDRIVE_LAYOUT_INFORMATION LayoutBuffer
Definition: partlist.h:118
#define memset(x, y, z)
Definition: compat.h:39
NTSTATUS InferFileSystemByHandle(IN HANDLE PartitionHandle, IN UCHAR PartitionType, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:111
FORCEINLINE BOOLEAN IsSamePrimaryLayoutEntry(IN PPARTITION_INFORMATION PartitionInfo, IN PDISKENTRY DiskEntry, IN PPARTENTRY PartEntry)
Definition: partlist.c:2588
BOOLEAN NewDisk
Definition: partlist.h:113
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)
LONGLONG QuadPart
Definition: typedefs.h:114
BOOLEAN IsPartitioned
Definition: partlist.h:59
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
ULONG PartitionIndex
Definition: partlist.h:49
#define REG_SZ
Definition: layer.c:22
static VOID AddPartitionToDisk(IN ULONG DiskNumber, IN PDISKENTRY DiskEntry, IN ULONG PartitionIndex, IN BOOLEAN LogicalPartition)
Definition: partlist.c:927
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
#define NUM_PARTITION_TYPE_ENTRIES
Definition: partlist.h:19