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