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