0d66b6c87eef6238f8d13776261e117cf47fa6a5
[reactos.git] / base / setup / lib / utils / partlist.c
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-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 */
7
8 #include "precomp.h"
9 #include <ntddscsi.h>
10
11 #include "partlist.h"
12 #include "fsutil.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 //#define DUMP_PARTITION_TABLE
18
19 #include <pshpack1.h>
20
21 typedef struct _REG_DISK_MOUNT_INFO
22 {
23 ULONG Signature;
24 LARGE_INTEGER StartingOffset;
25 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
26
27 #include <poppack.h>
28
29
30 /* HELPERS FOR PARTITION TYPES **********************************************/
31
32 /*
33 * This partition type list was ripped from the kernelDisk.c module of
34 * the Visopsys Operating System (see license below), and completed with
35 * information from Paragon Hard-Disk Manager, and the following websites:
36 * http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
37 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
38 */
39 /*
40 * kernelDisk.c
41 *
42 * Visopsys Operating System
43 * Copyright (C) 1998-2015 J. Andrew McLaughlin
44 *
45 * This program is free software; you can redistribute it and/or modify it
46 * under the terms of the GNU General Public License as published by the Free
47 * Software Foundation; either version 2 of the License, or (at your option)
48 * any later version.
49 *
50 * This program is distributed in the hope that it will be useful, but
51 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
52 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
53 * for more details.
54 *
55 * You should have received a copy of the GNU General Public License along
56 * with this program; if not, write to the Free Software Foundation, Inc.,
57 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
58 */
59
60 /* This is a table for keeping known partition type codes and descriptions */
61 PARTITION_TYPE PartitionTypes[NUM_PARTITION_TYPE_ENTRIES] =
62 {
63 { 0x00, "(Empty)" },
64 { 0x01, "FAT12" },
65 { 0x02, "XENIX root" },
66 { 0x03, "XENIX usr" },
67 { 0x04, "FAT16 (< 32 MB)" },
68 { 0x05, "Extended" },
69 { 0x06, "FAT16" },
70 { 0x07, "NTFS/HPFS/exFAT" },
71 { 0x08, "OS/2 or AIX boot" },
72 { 0x09, "AIX data" },
73 { 0x0A, "OS/2 Boot Manager" },
74 { 0x0B, "FAT32" },
75 { 0x0C, "FAT32 (LBA)" },
76 { 0x0E, "FAT16 (LBA)" },
77 { 0x0F, "Extended (LBA)" },
78 { 0x10, "OPUS" },
79 { 0x11, "Hidden FAT12" },
80 { 0x12, "FAT diagnostic (Compaq)" },
81 { 0x13, "BTRON" },
82 { 0x14, "Hidden FAT16 (< 32 MB)" },
83 { 0x16, "Hidden FAT16" },
84 { 0x17, "Hidden HPFS or NTFS" },
85 { 0x18, "AST SmartSleep" },
86 { 0x1B, "Hidden FAT32" },
87 { 0x1C, "Hidden FAT32 (LBA)" },
88 { 0x1E, "Hidden FAT16 (LBA)" },
89 { 0x24, "NEC DOS 3.x" },
90 { 0x27, "Hidden WinRE NTFS" },
91 { 0x2A, "AtheOS File System (AFS)" },
92 { 0x2B, "SyllableSecure (SylStor)" },
93 { 0x32, "NOS" },
94 { 0x35, "JFS on OS/2 or eCS" },
95 { 0x38, "THEOS v3.2 2GB partition" },
96 { 0x39, "Plan 9" },
97 { 0x3A, "THEOS v4 4GB partition" },
98 { 0x3B, "THEOS v4 extended partition" },
99 { 0x3C, "PartitionMagic recovery partition" },
100 { 0x3D, "Hidden NetWare" },
101 { 0x40, "Lynx" },
102 { 0x41, "PowerPC PReP boot" },
103 { 0x42, "Win2K Dynamic Volume extended" },
104 { 0x43, "Old Linux" },
105 { 0x44, "GoBack" },
106 { 0x45, "Priam or Boot-US Boot Manager" },
107 { 0x4D, "QNX4.x" },
108 { 0x4E, "QNX4.x 2nd partition" },
109 { 0x4F, "QNX4.x 3rd partition" },
110 { 0x50, "OnTrack Disk Manager R/O" },
111 { 0x51, "OnTrack Disk Manager R/W or Novell" },
112 { 0x52, "CP/M" },
113 { 0x53, "OnTrack DM6 Aux3" },
114 { 0x54, "OnTrack DM6 Dynamic Drive Overlay" },
115 { 0x55, "EZ-Drive" },
116 { 0x56, "Golden Bow VFeature Partitioned Volume" },
117 { 0x5C, "Priam EDisk" },
118 { 0x61, "SpeedStor" },
119 { 0x62, "Pick" },
120 { 0x63, "GNU HURD or Unix System V (SCO, ISC Unix, UnixWare)" },
121 { 0x64, "Novell NetWare 286, 2.xx" },
122 { 0x65, "Novell NetWare 386, 3.xx or 4.xx" },
123 { 0x66, "Novell NetWare SMS Partition" },
124 { 0x67, "Novell" },
125 { 0x68, "Novell" },
126 { 0x69, "Novell NetWare 5+" },
127 { 0x70, "DiskSecure Multi-Boot" },
128 { 0x75, "IBM PC/IX" },
129 { 0x7E, "Veritas VxVM public" },
130 { 0x7F, "Veritas VxVM private" },
131 { 0x80, "Old MINIX" },
132 { 0x81, "Linux or MINIX" },
133 { 0x82, "Linux swap or Solaris" },
134 { 0x83, "Linux Native" },
135 { 0x84, "Hibernate" },
136 { 0x85, "Extended Linux" },
137 { 0x86, "FAT16 mirrored" },
138 { 0x87, "HPFS or NTFS mirrored" },
139 { 0x88, "Linux plaintext partition table" },
140 { 0x8B, "FAT32 mirrored" },
141 { 0x8C, "FAT32 (LBA) mirrored" },
142 { 0x8E, "Linux LVM" },
143 { 0x93, "Hidden Linux" },
144 { 0x94, "Amoeba BBT" },
145 { 0x96, "CDFS/ISO-9660" },
146 { 0x9F, "BSD/OS" },
147 { 0xA0, "Laptop Hibernate" },
148 { 0xA1, "Laptop Hibernate (NEC 6000H)" },
149 { 0xA5, "BSD, NetBSD, FreeBSD" },
150 { 0xA6, "OpenBSD" },
151 { 0xA7, "NeXTStep" },
152 { 0xA8, "Darwin UFS" }, // Also known as "OS-X"
153 { 0xA9, "NetBSD" },
154 { 0xAB, "Darwin boot" },
155 { 0xAF, "Apple HFS" },
156 { 0xB6, "NT FAT16 corrupt mirror" },
157 { 0xB7, "BSDI BSD/386 FS" }, // Alternatively, "NT NTFS corrupt mirror"
158 { 0xB8, "BSDI BSD/386 swap" },
159 { 0xBB, "Boot Wizard hidden" },
160 { 0xBC, "Paragon Backup capsule" },
161 { 0xBE, "Solaris 8 boot partition" },
162 { 0xBF, "Solaris 10 x86" },
163 { 0xC0, "NTFT" }, // Alternatively, "CTOS" or "REAL/32 or DR-DOS or Novell-DOS secure partition"
164 { 0xC1, "DR-DOS FAT12" },
165 { 0xC2, "Hidden Linux" },
166 { 0xC3, "Hidden Linux swap" },
167 { 0xC4, "DR-DOS FAT16 (< 32 MB)" },
168 { 0xC5, "DR-DOS Extended" },
169 { 0xC6, "DR-DOS FAT16" },
170 { 0xC7, "HPFS mirrored" }, // Alternatively, "Syrinx boot"
171 { 0xCB, "DR-DOS FAT32" },
172 { 0xCC, "DR-DOS FAT32 (LBA)" },
173 { 0xCE, "DR-DOS FAT16 (LBA)" },
174 { 0xD0, "MDOS" },
175 { 0xD1, "MDOS FAT12" },
176 { 0xD4, "MDOS FAT16 (< 32 MB)" },
177 { 0xD5, "MDOS Extended" },
178 { 0xD6, "MDOS FAT16" },
179 { 0xD8, "CP/M-86" },
180 { 0xDB, "Digital Research CP/M" },
181 { 0xDE, "Dell OEM" },
182 { 0xDF, "BootIt EMBRM (FAT16/32)" },
183 { 0xE1, "SpeedStor FAT12" },
184 { 0xE3, "SpeedStor (0xE3)" },
185 { 0xE4, "SpeedStor FAT16" },
186 { 0xE5, "Tandy MSDOS" },
187 { 0xE6, "SpeedStor (0xE6)" },
188 { 0xE8, "Linux Unified Key Setup partition" },
189 { 0xEA, "Rufus private partition" },
190 { 0xEB, "BeOS BFS" },
191 { 0xEC, "SkyOS SkyFS" },
192 { 0xEE, "EFI GPT protective" },
193 { 0xEF, "EFI System partition" },
194 { 0xF0, "Linux/PA-RISC boot loader" },
195 { 0xF1, "SpeedStor (0xF1)" },
196 { 0xF2, "DOS 3.3+ second" },
197 { 0xF4, "SpeedStor (0xF4)" },
198 { 0xF5, "SpeedStor (0xF5)" },
199 { 0xF6, "SpeedStor (0xF6)" },
200 { 0xFA, "Bochs" },
201 { 0xFB, "VMware FS" },
202 { 0xFC, "VMware swap" },
203 { 0xFD, "Linux RAID auto" },
204 { 0xFE, "NT hidden partition" },
205 { 0xFF, "XENIX Bad Block Table" },
206 };
207
208
209 /* FUNCTIONS ****************************************************************/
210
211 #ifdef DUMP_PARTITION_TABLE
212 static
213 VOID
214 DumpPartitionTable(
215 PDISKENTRY DiskEntry)
216 {
217 PPARTITION_INFORMATION PartitionInfo;
218 ULONG i;
219
220 DbgPrint("\n");
221 DbgPrint("Index Start Length Hidden Nr Type Boot RW\n");
222 DbgPrint("----- ------------ ------------ ---------- -- ---- ---- --\n");
223
224 for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
225 {
226 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
227 DbgPrint(" %3lu %12I64u %12I64u %10lu %2lu %2x %c %c\n",
228 i,
229 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
230 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
231 PartitionInfo->HiddenSectors,
232 PartitionInfo->PartitionNumber,
233 PartitionInfo->PartitionType,
234 PartitionInfo->BootIndicator ? '*': ' ',
235 PartitionInfo->RewritePartition ? 'Y': 'N');
236 }
237
238 DbgPrint("\n");
239 }
240 #endif
241
242
243 ULONGLONG
244 AlignDown(
245 IN ULONGLONG Value,
246 IN ULONG Alignment)
247 {
248 ULONGLONG Temp;
249
250 Temp = Value / Alignment;
251
252 return Temp * Alignment;
253 }
254
255 ULONGLONG
256 AlignUp(
257 IN ULONGLONG Value,
258 IN ULONG Alignment)
259 {
260 ULONGLONG Temp, Result;
261
262 Temp = Value / Alignment;
263
264 Result = Temp * Alignment;
265 if (Value % Alignment)
266 Result += Alignment;
267
268 return Result;
269 }
270
271 ULONGLONG
272 RoundingDivide(
273 IN ULONGLONG Dividend,
274 IN ULONGLONG Divisor)
275 {
276 return (Dividend + Divisor / 2) / Divisor;
277 }
278
279
280 static
281 VOID
282 GetDriverName(
283 IN PDISKENTRY DiskEntry)
284 {
285 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
286 WCHAR KeyName[32];
287 NTSTATUS Status;
288
289 RtlInitUnicodeString(&DiskEntry->DriverName, NULL);
290
291 RtlStringCchPrintfW(KeyName, ARRAYSIZE(KeyName),
292 L"\\Scsi\\Scsi Port %hu",
293 DiskEntry->Port);
294
295 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
296
297 QueryTable[0].Name = L"Driver";
298 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
299 QueryTable[0].EntryContext = &DiskEntry->DriverName;
300
301 /* This will allocate DiskEntry->DriverName if needed */
302 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
303 KeyName,
304 QueryTable,
305 NULL,
306 NULL);
307 if (!NT_SUCCESS(Status))
308 {
309 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
310 }
311 }
312
313 static
314 VOID
315 AssignDriveLetters(
316 IN PPARTLIST List)
317 {
318 PDISKENTRY DiskEntry;
319 PPARTENTRY PartEntry;
320 PLIST_ENTRY Entry1;
321 PLIST_ENTRY Entry2;
322 WCHAR Letter;
323
324 Letter = L'C';
325
326 /* Assign drive letters to primary partitions */
327 Entry1 = List->DiskListHead.Flink;
328 while (Entry1 != &List->DiskListHead)
329 {
330 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
331
332 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
333 while (Entry2 != &DiskEntry->PrimaryPartListHead)
334 {
335 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
336
337 PartEntry->DriveLetter = 0;
338
339 if (PartEntry->IsPartitioned &&
340 !IsContainerPartition(PartEntry->PartitionType))
341 {
342 if (IsRecognizedPartition(PartEntry->PartitionType) ||
343 (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
344 PartEntry->SectorCount.QuadPart != 0LL))
345 {
346 if (Letter <= L'Z')
347 {
348 PartEntry->DriveLetter = Letter;
349 Letter++;
350 }
351 }
352 }
353
354 Entry2 = Entry2->Flink;
355 }
356
357 Entry1 = Entry1->Flink;
358 }
359
360 /* Assign drive letters to logical drives */
361 Entry1 = List->DiskListHead.Flink;
362 while (Entry1 != &List->DiskListHead)
363 {
364 DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
365
366 Entry2 = DiskEntry->LogicalPartListHead.Flink;
367 while (Entry2 != &DiskEntry->LogicalPartListHead)
368 {
369 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
370
371 PartEntry->DriveLetter = 0;
372
373 if (PartEntry->IsPartitioned)
374 {
375 if (IsRecognizedPartition(PartEntry->PartitionType) ||
376 (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
377 PartEntry->SectorCount.QuadPart != 0LL))
378 {
379 if (Letter <= L'Z')
380 {
381 PartEntry->DriveLetter = Letter;
382 Letter++;
383 }
384 }
385 }
386
387 Entry2 = Entry2->Flink;
388 }
389
390 Entry1 = Entry1->Flink;
391 }
392 }
393
394 static NTSTATUS
395 NTAPI
396 DiskIdentifierQueryRoutine(
397 PWSTR ValueName,
398 ULONG ValueType,
399 PVOID ValueData,
400 ULONG ValueLength,
401 PVOID Context,
402 PVOID EntryContext)
403 {
404 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
405 UNICODE_STRING NameU;
406
407 if (ValueType == REG_SZ &&
408 ValueLength == 20 * sizeof(WCHAR))
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
425 DiskConfigurationDataQueryRoutine(
426 PWSTR ValueName,
427 ULONG ValueType,
428 PVOID ValueData,
429 ULONG ValueLength,
430 PVOID Context,
431 PVOID EntryContext)
432 {
433 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
434 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
435 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
436 ULONG i;
437
438 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
439 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
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 {
453 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
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
468 SystemConfigurationDataQueryRoutine(
469 PWSTR ValueName,
470 ULONG ValueType,
471 PVOID ValueData,
472 ULONG ValueLength,
473 PVOID Context,
474 PVOID EntryContext)
475 {
476 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
477 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
478 ULONG i;
479
480 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
481 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
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 {
495 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
496 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
497 continue;
498
499 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
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
515 EnumerateBiosDiskEntries(
516 IN PPARTLIST PartList)
517 {
518 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
519 WCHAR Name[120];
520 ULONG AdapterCount;
521 ULONG DiskCount;
522 NTSTATUS Status;
523 PCM_INT13_DRIVE_PARAMETER Int13Drives;
524 PBIOSDISKENTRY BiosDiskEntry;
525
526 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
527
528 memset(QueryTable, 0, sizeof(QueryTable));
529
530 QueryTable[1].Name = L"Configuration Data";
531 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
532 Int13Drives = NULL;
533 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
534 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
535 &QueryTable[1],
536 (PVOID)&Int13Drives,
537 NULL);
538 if (!NT_SUCCESS(Status))
539 {
540 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
541 return;
542 }
543
544 AdapterCount = 0;
545 while (TRUE)
546 {
547 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
548 L"%s\\%lu",
549 ROOT_NAME, AdapterCount);
550 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
551 Name,
552 &QueryTable[2],
553 NULL,
554 NULL);
555 if (!NT_SUCCESS(Status))
556 {
557 break;
558 }
559
560 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
561 L"%s\\%lu\\DiskController",
562 ROOT_NAME, AdapterCount);
563 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
564 Name,
565 &QueryTable[2],
566 NULL,
567 NULL);
568 if (NT_SUCCESS(Status))
569 {
570 while (TRUE)
571 {
572 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
573 L"%s\\%lu\\DiskController\\0",
574 ROOT_NAME, AdapterCount);
575 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
576 Name,
577 &QueryTable[2],
578 NULL,
579 NULL);
580 if (!NT_SUCCESS(Status))
581 {
582 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
583 return;
584 }
585
586 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
587 L"%s\\%lu\\DiskController\\0\\DiskPeripheral",
588 ROOT_NAME, AdapterCount);
589 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
590 Name,
591 &QueryTable[2],
592 NULL,
593 NULL);
594 if (NT_SUCCESS(Status))
595 {
596 QueryTable[0].Name = L"Identifier";
597 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
598 QueryTable[1].Name = L"Configuration Data";
599 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
600
601 DiskCount = 0;
602 while (TRUE)
603 {
604 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
605 if (BiosDiskEntry == NULL)
606 {
607 break;
608 }
609
610 RtlStringCchPrintfW(Name, ARRAYSIZE(Name),
611 L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu",
612 ROOT_NAME, AdapterCount, DiskCount);
613 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
614 Name,
615 QueryTable,
616 (PVOID)BiosDiskEntry,
617 NULL);
618 if (!NT_SUCCESS(Status))
619 {
620 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
621 break;
622 }
623
624 BiosDiskEntry->DiskNumber = DiskCount;
625 BiosDiskEntry->Recognized = FALSE;
626
627 if (DiskCount < Int13Drives[0].NumberDrives)
628 {
629 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
630 }
631 else
632 {
633 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
634 }
635
636 InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
637
638 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
639 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
640 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
641 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
642 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
643 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
644 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
645 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
646 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
647 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
648 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
649
650 DiskCount++;
651 }
652 }
653
654 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
655 return;
656 }
657 }
658
659 AdapterCount++;
660 }
661
662 RtlFreeHeap(ProcessHeap, 0, Int13Drives);
663
664 #undef ROOT_NAME
665 }
666
667 static
668 VOID
669 AddPartitionToDisk(
670 IN ULONG DiskNumber,
671 IN PDISKENTRY DiskEntry,
672 IN ULONG PartitionIndex,
673 IN BOOLEAN LogicalPartition)
674 {
675 NTSTATUS Status;
676 PPARTITION_INFORMATION PartitionInfo;
677 PPARTENTRY PartEntry;
678 HANDLE FileHandle;
679 OBJECT_ATTRIBUTES ObjectAttributes;
680 IO_STATUS_BLOCK IoStatusBlock;
681 WCHAR Buffer[MAX_PATH];
682 UNICODE_STRING Name;
683 UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
684 PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer;
685
686 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
687
688 if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
689 ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
690 {
691 return;
692 }
693
694 PartEntry = RtlAllocateHeap(ProcessHeap,
695 HEAP_ZERO_MEMORY,
696 sizeof(PARTENTRY));
697 if (PartEntry == NULL)
698 return;
699
700 PartEntry->DiskEntry = DiskEntry;
701
702 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
703 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
704
705 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
706 PartEntry->PartitionType = PartitionInfo->PartitionType;
707 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
708
709 PartEntry->LogicalPartition = LogicalPartition;
710 PartEntry->IsPartitioned = TRUE;
711 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
712 PartEntry->PartitionIndex = PartitionIndex;
713
714 if (IsContainerPartition(PartEntry->PartitionType))
715 {
716 PartEntry->FormatState = Unformatted;
717 PartEntry->FileSystem = NULL;
718
719 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
720 DiskEntry->ExtendedPartition = PartEntry;
721 }
722 else if (IsRecognizedPartition(PartEntry->PartitionType))
723 {
724 PartEntry->FileSystem = GetFileSystem(PartEntry);
725 if (PartEntry->FileSystem)
726 PartEntry->FormatState = Preformatted;
727 else
728 PartEntry->FormatState = Unformatted;
729 // PartEntry->FormatState = UnknownFormat;
730 }
731 else
732 {
733 /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
734 PartEntry->FormatState = UnknownFormat;
735 }
736
737 /* Initialize the partition volume label */
738 RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
739
740 /* Open the volume, ignore any errors */
741 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
742 L"\\Device\\Harddisk%lu\\Partition%lu",
743 DiskEntry->DiskNumber, PartEntry->PartitionNumber);
744 RtlInitUnicodeString(&Name, Buffer);
745
746 InitializeObjectAttributes(&ObjectAttributes,
747 &Name,
748 OBJ_CASE_INSENSITIVE,
749 NULL,
750 NULL);
751
752 Status = NtOpenFile(&FileHandle,
753 FILE_READ_DATA | SYNCHRONIZE,
754 &ObjectAttributes,
755 &IoStatusBlock,
756 FILE_SHARE_READ | FILE_SHARE_WRITE,
757 FILE_SYNCHRONOUS_IO_NONALERT);
758 if (NT_SUCCESS(Status))
759 {
760 /* Retrieve the partition volume label */
761 Status = NtQueryVolumeInformationFile(FileHandle,
762 &IoStatusBlock,
763 &LabelBuffer,
764 sizeof(LabelBuffer),
765 FileFsVolumeInformation);
766 /* Close the handle */
767 NtClose(FileHandle);
768
769 /* Check for success */
770 if (NT_SUCCESS(Status))
771 {
772 /* Copy the (possibly truncated) volume label and NULL-terminate it */
773 RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
774 LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
775 }
776 else
777 {
778 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
779 }
780 }
781 else
782 {
783 DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
784 }
785
786 if (LogicalPartition)
787 InsertTailList(&DiskEntry->LogicalPartListHead,
788 &PartEntry->ListEntry);
789 else
790 InsertTailList(&DiskEntry->PrimaryPartListHead,
791 &PartEntry->ListEntry);
792 }
793
794 static
795 VOID
796 ScanForUnpartitionedDiskSpace(
797 IN PDISKENTRY DiskEntry)
798 {
799 ULONGLONG LastStartSector;
800 ULONGLONG LastSectorCount;
801 ULONGLONG LastUnusedSectorCount;
802 PPARTENTRY PartEntry;
803 PPARTENTRY NewPartEntry;
804 PLIST_ENTRY Entry;
805
806 DPRINT("ScanForUnpartitionedDiskSpace()\n");
807
808 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
809 {
810 DPRINT1("No primary partition!\n");
811
812 /* Create a partition entry that represents the empty disk */
813 NewPartEntry = RtlAllocateHeap(ProcessHeap,
814 HEAP_ZERO_MEMORY,
815 sizeof(PARTENTRY));
816 if (NewPartEntry == NULL)
817 return;
818
819 NewPartEntry->DiskEntry = DiskEntry;
820
821 NewPartEntry->IsPartitioned = FALSE;
822 if (DiskEntry->SectorAlignment < 2048)
823 NewPartEntry->StartSector.QuadPart = 2048ULL;
824 else
825 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
826 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
827 NewPartEntry->StartSector.QuadPart;
828
829 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
830 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
831 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
832
833 NewPartEntry->FormatState = Unformatted;
834 NewPartEntry->FileSystem = NULL;
835
836 InsertTailList(&DiskEntry->PrimaryPartListHead,
837 &NewPartEntry->ListEntry);
838
839 return;
840 }
841
842 /* Start partition at head 1, cylinder 0 */
843 if (DiskEntry->SectorAlignment < 2048)
844 LastStartSector = 2048ULL;
845 else
846 LastStartSector = DiskEntry->SectorAlignment;
847 LastSectorCount = 0ULL;
848 LastUnusedSectorCount = 0ULL;
849
850 Entry = DiskEntry->PrimaryPartListHead.Flink;
851 while (Entry != &DiskEntry->PrimaryPartListHead)
852 {
853 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
854
855 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
856 PartEntry->SectorCount.QuadPart != 0ULL)
857 {
858 LastUnusedSectorCount =
859 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
860
861 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
862 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
863 {
864 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
865
866 NewPartEntry = RtlAllocateHeap(ProcessHeap,
867 HEAP_ZERO_MEMORY,
868 sizeof(PARTENTRY));
869 if (NewPartEntry == NULL)
870 return;
871
872 NewPartEntry->DiskEntry = DiskEntry;
873
874 NewPartEntry->IsPartitioned = FALSE;
875 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
876 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
877 NewPartEntry->StartSector.QuadPart;
878
879 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
880 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
881 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
882
883 NewPartEntry->FormatState = Unformatted;
884 NewPartEntry->FileSystem = NULL;
885
886 /* Insert the table into the list */
887 InsertTailList(&PartEntry->ListEntry,
888 &NewPartEntry->ListEntry);
889 }
890
891 LastStartSector = PartEntry->StartSector.QuadPart;
892 LastSectorCount = PartEntry->SectorCount.QuadPart;
893 }
894
895 Entry = Entry->Flink;
896 }
897
898 /* Check for trailing unpartitioned disk space */
899 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
900 {
901 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
902
903 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
904 {
905 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
906
907 NewPartEntry = RtlAllocateHeap(ProcessHeap,
908 HEAP_ZERO_MEMORY,
909 sizeof(PARTENTRY));
910 if (NewPartEntry == NULL)
911 return;
912
913 NewPartEntry->DiskEntry = DiskEntry;
914
915 NewPartEntry->IsPartitioned = FALSE;
916 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
917 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
918 NewPartEntry->StartSector.QuadPart;
919
920 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
921 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
922 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
923
924 NewPartEntry->FormatState = Unformatted;
925 NewPartEntry->FileSystem = NULL;
926
927 /* Append the table to the list */
928 InsertTailList(&DiskEntry->PrimaryPartListHead,
929 &NewPartEntry->ListEntry);
930 }
931 }
932
933 if (DiskEntry->ExtendedPartition != NULL)
934 {
935 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
936 {
937 DPRINT1("No logical partition!\n");
938
939 /* Create a partition entry that represents the empty extended partition */
940 NewPartEntry = RtlAllocateHeap(ProcessHeap,
941 HEAP_ZERO_MEMORY,
942 sizeof(PARTENTRY));
943 if (NewPartEntry == NULL)
944 return;
945
946 NewPartEntry->DiskEntry = DiskEntry;
947 NewPartEntry->LogicalPartition = TRUE;
948
949 NewPartEntry->IsPartitioned = FALSE;
950 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
951 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
952
953 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
954 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
955 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
956
957 NewPartEntry->FormatState = Unformatted;
958 NewPartEntry->FileSystem = NULL;
959
960 InsertTailList(&DiskEntry->LogicalPartListHead,
961 &NewPartEntry->ListEntry);
962
963 return;
964 }
965
966 /* Start partition at head 1, cylinder 0 */
967 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
968 LastSectorCount = 0ULL;
969 LastUnusedSectorCount = 0ULL;
970
971 Entry = DiskEntry->LogicalPartListHead.Flink;
972 while (Entry != &DiskEntry->LogicalPartListHead)
973 {
974 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
975
976 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
977 PartEntry->SectorCount.QuadPart != 0ULL)
978 {
979 LastUnusedSectorCount =
980 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
981
982 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
983 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
984 {
985 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
986
987 NewPartEntry = RtlAllocateHeap(ProcessHeap,
988 HEAP_ZERO_MEMORY,
989 sizeof(PARTENTRY));
990 if (NewPartEntry == NULL)
991 return;
992
993 NewPartEntry->DiskEntry = DiskEntry;
994 NewPartEntry->LogicalPartition = TRUE;
995
996 NewPartEntry->IsPartitioned = FALSE;
997 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
998 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
999 NewPartEntry->StartSector.QuadPart;
1000
1001 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1002 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1003 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1004
1005 NewPartEntry->FormatState = Unformatted;
1006 NewPartEntry->FileSystem = NULL;
1007
1008 /* Insert the table into the list */
1009 InsertTailList(&PartEntry->ListEntry,
1010 &NewPartEntry->ListEntry);
1011 }
1012
1013 LastStartSector = PartEntry->StartSector.QuadPart;
1014 LastSectorCount = PartEntry->SectorCount.QuadPart;
1015 }
1016
1017 Entry = Entry->Flink;
1018 }
1019
1020 /* Check for trailing unpartitioned disk space */
1021 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1022 {
1023 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1024
1025 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1026 {
1027 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1028
1029 NewPartEntry = RtlAllocateHeap(ProcessHeap,
1030 HEAP_ZERO_MEMORY,
1031 sizeof(PARTENTRY));
1032 if (NewPartEntry == NULL)
1033 return;
1034
1035 NewPartEntry->DiskEntry = DiskEntry;
1036 NewPartEntry->LogicalPartition = TRUE;
1037
1038 NewPartEntry->IsPartitioned = FALSE;
1039 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
1040 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
1041 NewPartEntry->StartSector.QuadPart;
1042
1043 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1044 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1045 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1046
1047 NewPartEntry->FormatState = Unformatted;
1048 NewPartEntry->FileSystem = NULL;
1049
1050 /* Append the table to the list */
1051 InsertTailList(&DiskEntry->LogicalPartListHead,
1052 &NewPartEntry->ListEntry);
1053 }
1054 }
1055 }
1056
1057 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1058 }
1059
1060 static
1061 VOID
1062 SetDiskSignature(
1063 IN PPARTLIST List,
1064 IN PDISKENTRY DiskEntry)
1065 {
1066 LARGE_INTEGER SystemTime;
1067 TIME_FIELDS TimeFields;
1068 PLIST_ENTRY Entry2;
1069 PDISKENTRY DiskEntry2;
1070 PUCHAR Buffer;
1071
1072 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1073
1074 while (TRUE)
1075 {
1076 NtQuerySystemTime(&SystemTime);
1077 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1078
1079 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1080 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1081 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1082 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1083
1084 if (DiskEntry->LayoutBuffer->Signature == 0)
1085 {
1086 continue;
1087 }
1088
1089 /* Check if the signature already exist */
1090 /* FIXME:
1091 * Check also signatures from disks, which are
1092 * not visible (bootable) by the bios.
1093 */
1094 Entry2 = List->DiskListHead.Flink;
1095 while (Entry2 != &List->DiskListHead)
1096 {
1097 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1098
1099 if (DiskEntry != DiskEntry2 &&
1100 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1101 break;
1102
1103 Entry2 = Entry2->Flink;
1104 }
1105
1106 if (Entry2 == &List->DiskListHead)
1107 break;
1108 }
1109 }
1110
1111 static
1112 VOID
1113 UpdateDiskSignatures(
1114 IN PPARTLIST List)
1115 {
1116 PLIST_ENTRY Entry;
1117 PDISKENTRY DiskEntry;
1118
1119 /* Print partition lines */
1120 Entry = List->DiskListHead.Flink;
1121 while (Entry != &List->DiskListHead)
1122 {
1123 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1124
1125 if (DiskEntry->LayoutBuffer &&
1126 DiskEntry->LayoutBuffer->Signature == 0)
1127 {
1128 SetDiskSignature(List, DiskEntry);
1129 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1130 }
1131
1132 Entry = Entry->Flink;
1133 }
1134 }
1135
1136 static
1137 VOID
1138 AddDiskToList(
1139 IN HANDLE FileHandle,
1140 IN ULONG DiskNumber,
1141 IN PPARTLIST List)
1142 {
1143 DISK_GEOMETRY DiskGeometry;
1144 SCSI_ADDRESS ScsiAddress;
1145 PDISKENTRY DiskEntry;
1146 IO_STATUS_BLOCK Iosb;
1147 NTSTATUS Status;
1148 PPARTITION_SECTOR Mbr;
1149 PULONG Buffer;
1150 LARGE_INTEGER FileOffset;
1151 WCHAR Identifier[20];
1152 ULONG Checksum;
1153 ULONG Signature;
1154 ULONG i;
1155 PLIST_ENTRY ListEntry;
1156 PBIOSDISKENTRY BiosDiskEntry;
1157 ULONG LayoutBufferSize;
1158 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1159
1160 /* Retrieve the drive geometry */
1161 Status = NtDeviceIoControlFile(FileHandle,
1162 NULL,
1163 NULL,
1164 NULL,
1165 &Iosb,
1166 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1167 NULL,
1168 0,
1169 &DiskGeometry,
1170 sizeof(DiskGeometry));
1171 if (!NT_SUCCESS(Status))
1172 return;
1173
1174 if (DiskGeometry.MediaType != FixedMedia &&
1175 DiskGeometry.MediaType != RemovableMedia)
1176 {
1177 return;
1178 }
1179
1180 /*
1181 * FIXME: Here we suppose the disk is always SCSI. What if it is
1182 * of another type? To check this we need to retrieve the name of
1183 * the driver the disk device belongs to.
1184 */
1185 Status = NtDeviceIoControlFile(FileHandle,
1186 NULL,
1187 NULL,
1188 NULL,
1189 &Iosb,
1190 IOCTL_SCSI_GET_ADDRESS,
1191 NULL,
1192 0,
1193 &ScsiAddress,
1194 sizeof(ScsiAddress));
1195 if (!NT_SUCCESS(Status))
1196 return;
1197
1198 /*
1199 * Check whether the disk is initialized, by looking at its MBR.
1200 * NOTE that this must be generalized to GPT disks as well!
1201 */
1202
1203 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1204 0,
1205 DiskGeometry.BytesPerSector);
1206 if (Mbr == NULL)
1207 return;
1208
1209 FileOffset.QuadPart = 0;
1210 Status = NtReadFile(FileHandle,
1211 NULL,
1212 NULL,
1213 NULL,
1214 &Iosb,
1215 (PVOID)Mbr,
1216 DiskGeometry.BytesPerSector,
1217 &FileOffset,
1218 NULL);
1219 if (!NT_SUCCESS(Status))
1220 {
1221 RtlFreeHeap(ProcessHeap, 0, Mbr);
1222 DPRINT1("NtReadFile failed, status=%x\n", Status);
1223 return;
1224 }
1225 Signature = Mbr->Signature;
1226
1227 /* Calculate the MBR checksum */
1228 Checksum = 0;
1229 Buffer = (PULONG)Mbr;
1230 for (i = 0; i < 128; i++)
1231 {
1232 Checksum += Buffer[i];
1233 }
1234 Checksum = ~Checksum + 1;
1235
1236 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1237 L"%08x-%08x-A", Checksum, Signature);
1238 DPRINT("Identifier: %S\n", Identifier);
1239
1240 DiskEntry = RtlAllocateHeap(ProcessHeap,
1241 HEAP_ZERO_MEMORY,
1242 sizeof(DISKENTRY));
1243 if (DiskEntry == NULL)
1244 {
1245 RtlFreeHeap(ProcessHeap, 0, Mbr);
1246 DPRINT1("Failed to allocate a new disk entry.\n");
1247 return;
1248 }
1249
1250 // DiskEntry->Checksum = Checksum;
1251 // DiskEntry->Signature = Signature;
1252 DiskEntry->BiosFound = FALSE;
1253
1254 /*
1255 * Check if this disk has a valid MBR: verify its signature,
1256 * and whether its two first bytes are a valid instruction
1257 * (related to this, see IsThereAValidBootSector() in partlist.c).
1258 */
1259 if (Mbr->Magic != 0xaa55 || (*(PUSHORT)Mbr->BootCode) == 0x0000)
1260 DiskEntry->NoMbr = TRUE;
1261 else
1262 DiskEntry->NoMbr = FALSE;
1263
1264 /* Free the MBR sector buffer */
1265 RtlFreeHeap(ProcessHeap, 0, Mbr);
1266
1267
1268 ListEntry = List->BiosDiskListHead.Flink;
1269 while (ListEntry != &List->BiosDiskListHead)
1270 {
1271 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1272 /* FIXME:
1273 * Compare the size from bios and the reported size from driver.
1274 * If we have more than one disk with a zero or with the same signature
1275 * we must create new signatures and reboot. After the reboot,
1276 * it is possible to identify the disks.
1277 */
1278 if (BiosDiskEntry->Signature == Signature &&
1279 BiosDiskEntry->Checksum == Checksum &&
1280 !BiosDiskEntry->Recognized)
1281 {
1282 if (!DiskEntry->BiosFound)
1283 {
1284 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1285 DiskEntry->BiosFound = TRUE;
1286 BiosDiskEntry->Recognized = TRUE;
1287 }
1288 else
1289 {
1290 // FIXME: What to do?
1291 }
1292 }
1293 ListEntry = ListEntry->Flink;
1294 }
1295
1296 if (!DiskEntry->BiosFound)
1297 {
1298 #if 0
1299 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1300 return;
1301 #else
1302 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1303 #endif
1304 }
1305
1306 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1307 InitializeListHead(&DiskEntry->LogicalPartListHead);
1308
1309 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1310 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1311 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1312 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1313
1314 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1315 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1316 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1317 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1318
1319 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1320 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1321 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1322
1323 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1324 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1325 DiskGeometry.SectorsPerTrack;
1326
1327 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1328 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1329
1330 DiskEntry->DiskNumber = DiskNumber;
1331 DiskEntry->Port = ScsiAddress.PortNumber;
1332 DiskEntry->Bus = ScsiAddress.PathId;
1333 DiskEntry->Id = ScsiAddress.TargetId;
1334
1335 GetDriverName(DiskEntry);
1336 /*
1337 * Actually it would be more correct somehow to use:
1338 *
1339 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1340 * ULONG ReturnedLength;
1341 *
1342 * Status = NtQueryObject(SomeHandleToTheDisk,
1343 * ObjectNameInformation,
1344 * &NameInfo,
1345 * sizeof(NameInfo),
1346 * &ReturnedLength);
1347 * etc...
1348 *
1349 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1350 */
1351
1352 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1353
1354
1355 /*
1356 * We now retrieve the disk partition layout
1357 */
1358
1359 /* Allocate a layout buffer with 4 partition entries first */
1360 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1361 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1362 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1363 HEAP_ZERO_MEMORY,
1364 LayoutBufferSize);
1365 if (DiskEntry->LayoutBuffer == NULL)
1366 {
1367 DPRINT1("Failed to allocate the disk layout buffer!\n");
1368 return;
1369 }
1370
1371 /* Keep looping while the drive layout buffer is too small */
1372 for (;;)
1373 {
1374 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1375 Status = NtDeviceIoControlFile(FileHandle,
1376 NULL,
1377 NULL,
1378 NULL,
1379 &Iosb,
1380 IOCTL_DISK_GET_DRIVE_LAYOUT,
1381 NULL,
1382 0,
1383 DiskEntry->LayoutBuffer,
1384 LayoutBufferSize);
1385 if (NT_SUCCESS(Status))
1386 break;
1387
1388 if (Status != STATUS_BUFFER_TOO_SMALL)
1389 {
1390 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1391 return;
1392 }
1393
1394 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1395 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1396 HEAP_ZERO_MEMORY,
1397 DiskEntry->LayoutBuffer,
1398 LayoutBufferSize);
1399 if (NewLayoutBuffer == NULL)
1400 {
1401 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1402 return;
1403 }
1404
1405 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1406 }
1407
1408 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1409
1410 #ifdef DUMP_PARTITION_TABLE
1411 DumpPartitionTable(DiskEntry);
1412 #endif
1413
1414 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1415 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1416 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
1417 {
1418 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1419 {
1420 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1421 }
1422 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1423 {
1424 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1425 }
1426 else
1427 {
1428 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1429 }
1430 }
1431 else
1432 {
1433 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1434 }
1435
1436
1437 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1438 {
1439 DiskEntry->NewDisk = TRUE;
1440 DiskEntry->LayoutBuffer->PartitionCount = 4;
1441
1442 for (i = 0; i < 4; i++)
1443 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1444 }
1445 else
1446 {
1447 for (i = 0; i < 4; i++)
1448 {
1449 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1450 }
1451
1452 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1453 {
1454 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1455 }
1456 }
1457
1458 ScanForUnpartitionedDiskSpace(DiskEntry);
1459 }
1460
1461 PPARTLIST
1462 CreatePartitionList(VOID)
1463 {
1464 PPARTLIST List;
1465 OBJECT_ATTRIBUTES ObjectAttributes;
1466 SYSTEM_DEVICE_INFORMATION Sdi;
1467 IO_STATUS_BLOCK Iosb;
1468 ULONG ReturnSize;
1469 NTSTATUS Status;
1470 ULONG DiskNumber;
1471 WCHAR Buffer[MAX_PATH];
1472 UNICODE_STRING Name;
1473 HANDLE FileHandle;
1474
1475 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1476 0,
1477 sizeof(PARTLIST));
1478 if (List == NULL)
1479 return NULL;
1480
1481 List->CurrentDisk = NULL;
1482 List->CurrentPartition = NULL;
1483
1484 List->SystemPartition = NULL;
1485 List->OriginalSystemPartition = NULL;
1486
1487 InitializeListHead(&List->DiskListHead);
1488 InitializeListHead(&List->BiosDiskListHead);
1489
1490 /*
1491 * Enumerate the disks seen by the BIOS; this will be used later
1492 * to map drives seen by NTOS with their corresponding BIOS names.
1493 */
1494 EnumerateBiosDiskEntries(List);
1495
1496 /* Enumerate disks seen by NTOS */
1497 Status = NtQuerySystemInformation(SystemDeviceInformation,
1498 &Sdi,
1499 sizeof(Sdi),
1500 &ReturnSize);
1501 if (!NT_SUCCESS(Status))
1502 {
1503 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
1504 RtlFreeHeap(ProcessHeap, 0, List);
1505 return NULL;
1506 }
1507
1508 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1509 {
1510 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1511 L"\\Device\\Harddisk%lu\\Partition0",
1512 DiskNumber);
1513 RtlInitUnicodeString(&Name, Buffer);
1514
1515 InitializeObjectAttributes(&ObjectAttributes,
1516 &Name,
1517 OBJ_CASE_INSENSITIVE,
1518 NULL,
1519 NULL);
1520
1521 Status = NtOpenFile(&FileHandle,
1522 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1523 &ObjectAttributes,
1524 &Iosb,
1525 FILE_SHARE_READ | FILE_SHARE_WRITE,
1526 FILE_SYNCHRONOUS_IO_NONALERT);
1527 if (NT_SUCCESS(Status))
1528 {
1529 AddDiskToList(FileHandle, DiskNumber, List);
1530 NtClose(FileHandle);
1531 }
1532 }
1533
1534 UpdateDiskSignatures(List);
1535
1536 AssignDriveLetters(List);
1537
1538 /* Search for first usable disk and partition */
1539 if (IsListEmpty(&List->DiskListHead))
1540 {
1541 List->CurrentDisk = NULL;
1542 List->CurrentPartition = NULL;
1543 }
1544 else
1545 {
1546 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1547 DISKENTRY,
1548 ListEntry);
1549
1550 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1551 {
1552 List->CurrentPartition = NULL;
1553 }
1554 else
1555 {
1556 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1557 PARTENTRY,
1558 ListEntry);
1559 }
1560 }
1561
1562 return List;
1563 }
1564
1565 VOID
1566 DestroyPartitionList(
1567 IN PPARTLIST List)
1568 {
1569 PDISKENTRY DiskEntry;
1570 PBIOSDISKENTRY BiosDiskEntry;
1571 PPARTENTRY PartEntry;
1572 PLIST_ENTRY Entry;
1573
1574 /* Release disk and partition info */
1575 while (!IsListEmpty(&List->DiskListHead))
1576 {
1577 Entry = RemoveHeadList(&List->DiskListHead);
1578 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1579
1580 /* Release driver name */
1581 RtlFreeUnicodeString(&DiskEntry->DriverName);
1582
1583 /* Release primary partition list */
1584 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1585 {
1586 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1587 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1588
1589 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1590 }
1591
1592 /* Release logical partition list */
1593 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1594 {
1595 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1596 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1597
1598 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1599 }
1600
1601 /* Release layout buffer */
1602 if (DiskEntry->LayoutBuffer != NULL)
1603 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1604
1605 /* Release disk entry */
1606 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1607 }
1608
1609 /* Release the bios disk info */
1610 while (!IsListEmpty(&List->BiosDiskListHead))
1611 {
1612 Entry = RemoveHeadList(&List->BiosDiskListHead);
1613 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1614
1615 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1616 }
1617
1618 /* Release list head */
1619 RtlFreeHeap(ProcessHeap, 0, List);
1620 }
1621
1622 PDISKENTRY
1623 GetDiskByBiosNumber(
1624 IN PPARTLIST List,
1625 IN ULONG BiosDiskNumber)
1626 {
1627 PDISKENTRY DiskEntry;
1628 PLIST_ENTRY Entry;
1629
1630 /* Loop over the disks and find the correct one */
1631 Entry = List->DiskListHead.Flink;
1632 while (Entry != &List->DiskListHead)
1633 {
1634 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1635 Entry = Entry->Flink;
1636
1637 if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
1638 {
1639 /* Disk found */
1640 return DiskEntry;
1641 }
1642 }
1643
1644 /* Disk not found, stop there */
1645 return NULL;
1646 }
1647
1648 PDISKENTRY
1649 GetDiskByNumber(
1650 IN PPARTLIST List,
1651 IN ULONG DiskNumber)
1652 {
1653 PDISKENTRY DiskEntry;
1654 PLIST_ENTRY Entry;
1655
1656 /* Loop over the disks and find the correct one */
1657 Entry = List->DiskListHead.Flink;
1658 while (Entry != &List->DiskListHead)
1659 {
1660 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1661 Entry = Entry->Flink;
1662
1663 if (DiskEntry->DiskNumber == DiskNumber)
1664 {
1665 /* Disk found */
1666 return DiskEntry;
1667 }
1668 }
1669
1670 /* Disk not found, stop there */
1671 return NULL;
1672 }
1673
1674 PDISKENTRY
1675 GetDiskBySCSI(
1676 IN PPARTLIST List,
1677 IN USHORT Port,
1678 IN USHORT Bus,
1679 IN USHORT Id)
1680 {
1681 PDISKENTRY DiskEntry;
1682 PLIST_ENTRY Entry;
1683
1684 /* Loop over the disks and find the correct one */
1685 Entry = List->DiskListHead.Flink;
1686 while (Entry != &List->DiskListHead)
1687 {
1688 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1689 Entry = Entry->Flink;
1690
1691 if (DiskEntry->Port == Port &&
1692 DiskEntry->Bus == Bus &&
1693 DiskEntry->Id == Id)
1694 {
1695 /* Disk found */
1696 return DiskEntry;
1697 }
1698 }
1699
1700 /* Disk not found, stop there */
1701 return NULL;
1702 }
1703
1704 PDISKENTRY
1705 GetDiskBySignature(
1706 IN PPARTLIST List,
1707 IN ULONG Signature)
1708 {
1709 PDISKENTRY DiskEntry;
1710 PLIST_ENTRY Entry;
1711
1712 /* Loop over the disks and find the correct one */
1713 Entry = List->DiskListHead.Flink;
1714 while (Entry != &List->DiskListHead)
1715 {
1716 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1717 Entry = Entry->Flink;
1718
1719 if (DiskEntry->LayoutBuffer->Signature == Signature)
1720 {
1721 /* Disk found */
1722 return DiskEntry;
1723 }
1724 }
1725
1726 /* Disk not found, stop there */
1727 return NULL;
1728 }
1729
1730 PPARTENTRY
1731 GetPartition(
1732 // IN PPARTLIST List,
1733 IN PDISKENTRY DiskEntry,
1734 IN ULONG PartitionNumber)
1735 {
1736 PPARTENTRY PartEntry;
1737 PLIST_ENTRY Entry;
1738
1739 /* Disk found, loop over the primary partitions first... */
1740 Entry = DiskEntry->PrimaryPartListHead.Flink;
1741 while (Entry != &DiskEntry->PrimaryPartListHead)
1742 {
1743 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1744 Entry = Entry->Flink;
1745
1746 if (PartEntry->PartitionNumber == PartitionNumber)
1747 {
1748 /* Partition found */
1749 return PartEntry;
1750 }
1751 }
1752
1753 /* ... then over the logical partitions if needed */
1754 Entry = DiskEntry->LogicalPartListHead.Flink;
1755 while (Entry != &DiskEntry->LogicalPartListHead)
1756 {
1757 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1758 Entry = Entry->Flink;
1759
1760 if (PartEntry->PartitionNumber == PartitionNumber)
1761 {
1762 /* Partition found */
1763 return PartEntry;
1764 }
1765 }
1766
1767 /* The partition was not found on the disk, stop there */
1768 return NULL;
1769 }
1770
1771 BOOLEAN
1772 GetDiskOrPartition(
1773 IN PPARTLIST List,
1774 IN ULONG DiskNumber,
1775 IN ULONG PartitionNumber OPTIONAL,
1776 OUT PDISKENTRY* pDiskEntry,
1777 OUT PPARTENTRY* pPartEntry OPTIONAL)
1778 {
1779 PDISKENTRY DiskEntry;
1780 PPARTENTRY PartEntry = NULL;
1781
1782 /* Find the disk */
1783 DiskEntry = GetDiskByNumber(List, DiskNumber);
1784 if (!DiskEntry)
1785 return FALSE;
1786
1787 /* If we have a partition (PartitionNumber != 0), find it */
1788 if (PartitionNumber != 0)
1789 {
1790 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1791 if (!PartEntry)
1792 return FALSE;
1793 ASSERT(PartEntry->DiskEntry == DiskEntry);
1794 }
1795
1796 /* Return the disk (and optionally the partition) */
1797 *pDiskEntry = DiskEntry;
1798 if (pPartEntry) *pPartEntry = PartEntry;
1799 return TRUE;
1800 }
1801
1802 //
1803 // NOTE: Was introduced broken in r6258 by Casper
1804 //
1805 BOOLEAN
1806 SelectPartition(
1807 IN PPARTLIST List,
1808 IN ULONG DiskNumber,
1809 IN ULONG PartitionNumber)
1810 {
1811 PDISKENTRY DiskEntry;
1812 PPARTENTRY PartEntry;
1813
1814 DiskEntry = GetDiskByNumber(List, DiskNumber);
1815 if (!DiskEntry)
1816 return FALSE;
1817
1818 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1819 if (!PartEntry)
1820 return FALSE;
1821
1822 ASSERT(PartEntry->DiskEntry == DiskEntry);
1823 ASSERT(DiskEntry->DiskNumber == DiskNumber);
1824 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
1825
1826 List->CurrentDisk = DiskEntry;
1827 List->CurrentPartition = PartEntry;
1828 return TRUE;
1829 }
1830
1831 PPARTENTRY
1832 GetNextPartition(
1833 IN PPARTLIST List)
1834 {
1835 PLIST_ENTRY DiskListEntry;
1836 PLIST_ENTRY PartListEntry;
1837 PDISKENTRY DiskEntry;
1838 PPARTENTRY PartEntry;
1839
1840 /* Fail if no disks are available */
1841 if (IsListEmpty(&List->DiskListHead))
1842 return NULL;
1843
1844 /* Check for next usable entry on current disk */
1845 if (List->CurrentPartition != NULL)
1846 {
1847 if (List->CurrentPartition->LogicalPartition)
1848 {
1849 /* Logical partition */
1850
1851 PartListEntry = List->CurrentPartition->ListEntry.Flink;
1852 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1853 {
1854 /* Next logical partition */
1855 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1856
1857 List->CurrentPartition = PartEntry;
1858 return List->CurrentPartition;
1859 }
1860 else
1861 {
1862 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
1863 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1864 {
1865 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1866
1867 List->CurrentPartition = PartEntry;
1868 return List->CurrentPartition;
1869 }
1870 }
1871 }
1872 else
1873 {
1874 /* Primary or extended partition */
1875
1876 if ((List->CurrentPartition->IsPartitioned != FALSE) &&
1877 IsContainerPartition(List->CurrentPartition->PartitionType))
1878 {
1879 /* First logical partition */
1880 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
1881 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1882 {
1883 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1884
1885 List->CurrentPartition = PartEntry;
1886 return List->CurrentPartition;
1887 }
1888 }
1889 else
1890 {
1891 /* Next primary partition */
1892 PartListEntry = List->CurrentPartition->ListEntry.Flink;
1893 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1894 {
1895 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1896
1897 List->CurrentPartition = PartEntry;
1898 return List->CurrentPartition;
1899 }
1900 }
1901 }
1902 }
1903
1904 /* Search for the first partition entry on the next disk */
1905 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
1906 while (DiskListEntry != &List->DiskListHead)
1907 {
1908 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
1909
1910 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
1911 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
1912 {
1913 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1914
1915 List->CurrentDisk = DiskEntry;
1916 List->CurrentPartition = PartEntry;
1917 return List->CurrentPartition;
1918 }
1919
1920 DiskListEntry = DiskListEntry->Flink;
1921 }
1922
1923 return NULL;
1924 }
1925
1926 PPARTENTRY
1927 GetPrevPartition(
1928 IN PPARTLIST List)
1929 {
1930 PLIST_ENTRY DiskListEntry;
1931 PLIST_ENTRY PartListEntry;
1932 PDISKENTRY DiskEntry;
1933 PPARTENTRY PartEntry;
1934
1935 /* Fail if no disks are available */
1936 if (IsListEmpty(&List->DiskListHead))
1937 return NULL;
1938
1939 /* Check for previous usable entry on current disk */
1940 if (List->CurrentPartition != NULL)
1941 {
1942 if (List->CurrentPartition->LogicalPartition)
1943 {
1944 /* Logical partition */
1945 PartListEntry = List->CurrentPartition->ListEntry.Blink;
1946 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1947 {
1948 /* Previous logical partition */
1949 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1950 }
1951 else
1952 {
1953 /* Extended partition */
1954 PartEntry = List->CurrentDisk->ExtendedPartition;
1955 }
1956
1957 List->CurrentPartition = PartEntry;
1958 return List->CurrentPartition;
1959 }
1960 else
1961 {
1962 /* Primary or extended partition */
1963
1964 PartListEntry = List->CurrentPartition->ListEntry.Blink;
1965 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1966 {
1967 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1968
1969 if ((PartEntry->IsPartitioned != FALSE) &&
1970 IsContainerPartition(PartEntry->PartitionType))
1971 {
1972 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
1973 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1974 }
1975
1976 List->CurrentPartition = PartEntry;
1977 return List->CurrentPartition;
1978 }
1979 }
1980 }
1981
1982 /* Search for the last partition entry on the previous disk */
1983 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
1984 while (DiskListEntry != &List->DiskListHead)
1985 {
1986 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
1987
1988 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
1989 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
1990 {
1991 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1992
1993 if ((PartEntry->IsPartitioned != FALSE) &&
1994 IsContainerPartition(PartEntry->PartitionType))
1995 {
1996 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
1997 if (PartListEntry != &DiskEntry->LogicalPartListHead)
1998 {
1999 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
2000
2001 List->CurrentDisk = DiskEntry;
2002 List->CurrentPartition = PartEntry;
2003 return List->CurrentPartition;
2004 }
2005 }
2006 else
2007 {
2008 List->CurrentDisk = DiskEntry;
2009 List->CurrentPartition = PartEntry;
2010 return List->CurrentPartition;
2011 }
2012 }
2013
2014 DiskListEntry = DiskListEntry->Blink;
2015 }
2016
2017 return NULL;
2018 }
2019
2020 // static
2021 FORCEINLINE
2022 BOOLEAN
2023 IsEmptyLayoutEntry(
2024 IN PPARTITION_INFORMATION PartitionInfo)
2025 {
2026 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2027 PartitionInfo->PartitionLength.QuadPart == 0)
2028 {
2029 return TRUE;
2030 }
2031
2032 return FALSE;
2033 }
2034
2035 // static
2036 FORCEINLINE
2037 BOOLEAN
2038 IsSamePrimaryLayoutEntry(
2039 IN PPARTITION_INFORMATION PartitionInfo,
2040 IN PDISKENTRY DiskEntry,
2041 IN PPARTENTRY PartEntry)
2042 {
2043 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2044 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2045 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2046 // PartitionInfo->PartitionType == PartEntry->PartitionType
2047 {
2048 return TRUE;
2049 }
2050
2051 return FALSE;
2052 }
2053
2054 static
2055 ULONG
2056 GetPrimaryPartitionCount(
2057 IN PDISKENTRY DiskEntry)
2058 {
2059 PLIST_ENTRY Entry;
2060 PPARTENTRY PartEntry;
2061 ULONG Count = 0;
2062
2063 Entry = DiskEntry->PrimaryPartListHead.Flink;
2064 while (Entry != &DiskEntry->PrimaryPartListHead)
2065 {
2066 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2067 if (PartEntry->IsPartitioned)
2068 Count++;
2069
2070 Entry = Entry->Flink;
2071 }
2072
2073 return Count;
2074 }
2075
2076 static
2077 ULONG
2078 GetLogicalPartitionCount(
2079 IN PDISKENTRY DiskEntry)
2080 {
2081 PLIST_ENTRY ListEntry;
2082 PPARTENTRY PartEntry;
2083 ULONG Count = 0;
2084
2085 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2086 while (ListEntry != &DiskEntry->LogicalPartListHead)
2087 {
2088 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2089 if (PartEntry->IsPartitioned)
2090 Count++;
2091
2092 ListEntry = ListEntry->Flink;
2093 }
2094
2095 return Count;
2096 }
2097
2098 static
2099 BOOLEAN
2100 ReAllocateLayoutBuffer(
2101 IN PDISKENTRY DiskEntry)
2102 {
2103 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2104 ULONG NewPartitionCount;
2105 ULONG CurrentPartitionCount = 0;
2106 ULONG LayoutBufferSize;
2107 ULONG i;
2108
2109 DPRINT1("ReAllocateLayoutBuffer()\n");
2110
2111 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2112
2113 if (DiskEntry->LayoutBuffer)
2114 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2115
2116 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2117 CurrentPartitionCount, NewPartitionCount);
2118
2119 if (CurrentPartitionCount == NewPartitionCount)
2120 return TRUE;
2121
2122 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2123 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2124 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2125 HEAP_ZERO_MEMORY,
2126 DiskEntry->LayoutBuffer,
2127 LayoutBufferSize);
2128 if (NewLayoutBuffer == NULL)
2129 {
2130 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2131 return FALSE;
2132 }
2133
2134 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2135 if (NewPartitionCount > CurrentPartitionCount)
2136 {
2137 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2138 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2139 }
2140
2141 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2142 DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
2143
2144 return TRUE;
2145 }
2146
2147 static
2148 VOID
2149 UpdateDiskLayout(
2150 IN PDISKENTRY DiskEntry)
2151 {
2152 PPARTITION_INFORMATION PartitionInfo;
2153 PPARTITION_INFORMATION LinkInfo = NULL;
2154 PLIST_ENTRY ListEntry;
2155 PPARTENTRY PartEntry;
2156 LARGE_INTEGER HiddenSectors64;
2157 ULONG Index;
2158 ULONG PartitionNumber = 1;
2159
2160 DPRINT1("UpdateDiskLayout()\n");
2161
2162 /* Resize the layout buffer if necessary */
2163 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2164 {
2165 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2166 return;
2167 }
2168
2169 /* Update the primary partition table */
2170 Index = 0;
2171 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2172 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2173 {
2174 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2175
2176 if (PartEntry->IsPartitioned != FALSE)
2177 {
2178 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2179
2180 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2181 {
2182 DPRINT1("Updating primary partition entry %lu\n", Index);
2183
2184 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2185 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2186 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2187 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2188 PartitionInfo->PartitionType = PartEntry->PartitionType;
2189 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2190 PartitionInfo->RecognizedPartition = FALSE;
2191 PartitionInfo->RewritePartition = TRUE;
2192 }
2193
2194 PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2195 PartEntry->PartitionIndex = Index;
2196
2197 if (!IsContainerPartition(PartEntry->PartitionType))
2198 PartitionNumber++;
2199
2200 Index++;
2201 }
2202
2203 ListEntry = ListEntry->Flink;
2204 }
2205
2206 /* Update the logical partition table */
2207 Index = 4;
2208 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2209 while (ListEntry != &DiskEntry->LogicalPartListHead)
2210 {
2211 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2212
2213 if (PartEntry->IsPartitioned)
2214 {
2215 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2216
2217 DPRINT1("Updating logical partition entry %lu\n", Index);
2218
2219 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2220 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2221 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2222 PartitionInfo->PartitionNumber = PartitionNumber;
2223 PartitionInfo->PartitionType = PartEntry->PartitionType;
2224 PartitionInfo->BootIndicator = FALSE;
2225 PartitionInfo->RecognizedPartition = FALSE;
2226 PartitionInfo->RewritePartition = TRUE;
2227
2228 PartEntry->PartitionNumber = PartitionNumber;
2229 PartEntry->PartitionIndex = Index;
2230
2231 /* Fill the link entry of the previous partition entry */
2232 if (LinkInfo != NULL)
2233 {
2234 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2235 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2236 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2237 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2238 LinkInfo->PartitionNumber = 0;
2239 LinkInfo->PartitionType = PARTITION_EXTENDED;
2240 LinkInfo->BootIndicator = FALSE;
2241 LinkInfo->RecognizedPartition = FALSE;
2242 LinkInfo->RewritePartition = TRUE;
2243 }
2244
2245 /* Save a pointer to the link entry of the current partition entry */
2246 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2247
2248 PartitionNumber++;
2249 Index += 4;
2250 }
2251
2252 ListEntry = ListEntry->Flink;
2253 }
2254
2255 /* Wipe unused primary partition entries */
2256 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2257 {
2258 DPRINT1("Primary partition entry %lu\n", Index);
2259
2260 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2261
2262 if (!IsEmptyLayoutEntry(PartitionInfo))
2263 {
2264 DPRINT1("Wiping primary partition entry %lu\n", Index);
2265
2266 PartitionInfo->StartingOffset.QuadPart = 0;
2267 PartitionInfo->PartitionLength.QuadPart = 0;
2268 PartitionInfo->HiddenSectors = 0;
2269 PartitionInfo->PartitionNumber = 0;
2270 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2271 PartitionInfo->BootIndicator = FALSE;
2272 PartitionInfo->RecognizedPartition = FALSE;
2273 PartitionInfo->RewritePartition = TRUE;
2274 }
2275 }
2276
2277 /* Wipe unused logical partition entries */
2278 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2279 {
2280 if (Index % 4 >= 2)
2281 {
2282 DPRINT1("Logical partition entry %lu\n", Index);
2283
2284 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2285
2286 if (!IsEmptyLayoutEntry(PartitionInfo))
2287 {
2288 DPRINT1("Wiping partition entry %lu\n", Index);
2289
2290 PartitionInfo->StartingOffset.QuadPart = 0;
2291 PartitionInfo->PartitionLength.QuadPart = 0;
2292 PartitionInfo->HiddenSectors = 0;
2293 PartitionInfo->PartitionNumber = 0;
2294 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2295 PartitionInfo->BootIndicator = FALSE;
2296 PartitionInfo->RecognizedPartition = FALSE;
2297 PartitionInfo->RewritePartition = TRUE;
2298 }
2299 }
2300 }
2301
2302 #ifdef DUMP_PARTITION_TABLE
2303 DumpPartitionTable(DiskEntry);
2304 #endif
2305 }
2306
2307 static
2308 PPARTENTRY
2309 GetPrevUnpartitionedEntry(
2310 IN PDISKENTRY DiskEntry,
2311 IN PPARTENTRY PartEntry)
2312 {
2313 PPARTENTRY PrevPartEntry;
2314 PLIST_ENTRY ListHead;
2315
2316 if (PartEntry->LogicalPartition)
2317 ListHead = &DiskEntry->LogicalPartListHead;
2318 else
2319 ListHead = &DiskEntry->PrimaryPartListHead;
2320
2321 if (PartEntry->ListEntry.Blink != ListHead)
2322 {
2323 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2324 PARTENTRY,
2325 ListEntry);
2326 if (PrevPartEntry->IsPartitioned == FALSE)
2327 return PrevPartEntry;
2328 }
2329
2330 return NULL;
2331 }
2332
2333 static
2334 PPARTENTRY
2335 GetNextUnpartitionedEntry(
2336 IN PDISKENTRY DiskEntry,
2337 IN PPARTENTRY PartEntry)
2338 {
2339 PPARTENTRY NextPartEntry;
2340 PLIST_ENTRY ListHead;
2341
2342 if (PartEntry->LogicalPartition)
2343 ListHead = &DiskEntry->LogicalPartListHead;
2344 else
2345 ListHead = &DiskEntry->PrimaryPartListHead;
2346
2347 if (PartEntry->ListEntry.Flink != ListHead)
2348 {
2349 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2350 PARTENTRY,
2351 ListEntry);
2352 if (NextPartEntry->IsPartitioned == FALSE)
2353 return NextPartEntry;
2354 }
2355
2356 return NULL;
2357 }
2358
2359 VOID
2360 CreatePrimaryPartition(
2361 IN PPARTLIST List,
2362 IN ULONGLONG SectorCount,
2363 IN BOOLEAN AutoCreate)
2364 {
2365 PDISKENTRY DiskEntry;
2366 PPARTENTRY PartEntry;
2367 PPARTENTRY NewPartEntry;
2368
2369 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2370
2371 if (List == NULL ||
2372 List->CurrentDisk == NULL ||
2373 List->CurrentPartition == NULL ||
2374 List->CurrentPartition->IsPartitioned != FALSE)
2375 {
2376 return;
2377 }
2378
2379 DiskEntry = List->CurrentDisk;
2380 PartEntry = List->CurrentPartition;
2381
2382 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2383
2384 if ((AutoCreate != FALSE) ||
2385 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2386 {
2387 DPRINT1("Convert existing partition entry\n");
2388
2389 /* Convert current entry to 'new (unformatted)' */
2390 PartEntry->IsPartitioned = TRUE;
2391 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2392 PartEntry->FormatState = Unformatted;
2393 PartEntry->FileSystem = NULL;
2394 PartEntry->AutoCreate = AutoCreate;
2395 PartEntry->New = TRUE;
2396 PartEntry->BootIndicator = FALSE;
2397
2398 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2399 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2400 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2401 }
2402 else
2403 {
2404 DPRINT1("Add new partition entry\n");
2405
2406 /* Insert and initialize a new partition entry */
2407 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2408 HEAP_ZERO_MEMORY,
2409 sizeof(PARTENTRY));
2410 if (NewPartEntry == NULL)
2411 return;
2412
2413 /* Insert the new entry into the list */
2414 InsertTailList(&PartEntry->ListEntry,
2415 &NewPartEntry->ListEntry);
2416
2417 NewPartEntry->DiskEntry = DiskEntry;
2418
2419 NewPartEntry->IsPartitioned = TRUE;
2420 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2421 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2422 NewPartEntry->StartSector.QuadPart;
2423 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2424
2425 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2426 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2427 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2428
2429 NewPartEntry->New = TRUE;
2430 NewPartEntry->FormatState = Unformatted;
2431 NewPartEntry->FileSystem = NULL;
2432 NewPartEntry->BootIndicator = FALSE;
2433
2434 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2435 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2436 }
2437
2438 UpdateDiskLayout(DiskEntry);
2439
2440 DiskEntry->Dirty = TRUE;
2441
2442 AssignDriveLetters(List);
2443 }
2444
2445 static
2446 VOID
2447 AddLogicalDiskSpace(
2448 IN PDISKENTRY DiskEntry)
2449 {
2450 PPARTENTRY NewPartEntry;
2451
2452 DPRINT1("AddLogicalDiskSpace()\n");
2453
2454 /* Create a partition entry that represents the empty space in the container partition */
2455 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2456 HEAP_ZERO_MEMORY,
2457 sizeof(PARTENTRY));
2458 if (NewPartEntry == NULL)
2459 return;
2460
2461 NewPartEntry->DiskEntry = DiskEntry;
2462 NewPartEntry->LogicalPartition = TRUE;
2463
2464 NewPartEntry->IsPartitioned = FALSE;
2465 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2466 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2467
2468 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2469 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2470 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2471
2472 NewPartEntry->FormatState = Unformatted;
2473 NewPartEntry->FileSystem = NULL;
2474
2475 InsertTailList(&DiskEntry->LogicalPartListHead,
2476 &NewPartEntry->ListEntry);
2477 }
2478
2479 VOID
2480 CreateExtendedPartition(
2481 IN PPARTLIST List,
2482 IN ULONGLONG SectorCount)
2483 {
2484 PDISKENTRY DiskEntry;
2485 PPARTENTRY PartEntry;
2486 PPARTENTRY NewPartEntry;
2487
2488 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2489
2490 if (List == NULL ||
2491 List->CurrentDisk == NULL ||
2492 List->CurrentPartition == NULL ||
2493 List->CurrentPartition->IsPartitioned != FALSE)
2494 {
2495 return;
2496 }
2497
2498 DiskEntry = List->CurrentDisk;
2499 PartEntry = List->CurrentPartition;
2500
2501 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2502
2503 if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2504 {
2505 DPRINT1("Convert existing partition entry\n");
2506
2507 /* Convert current entry to 'new (unformatted)' */
2508 PartEntry->IsPartitioned = TRUE;
2509 PartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2510 PartEntry->FileSystem = NULL;
2511 PartEntry->AutoCreate = FALSE;
2512 PartEntry->New = FALSE;
2513 PartEntry->BootIndicator = FALSE;
2514
2515 if (PartEntry->StartSector.QuadPart < 1450560)
2516 {
2517 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2518 PartEntry->PartitionType = PARTITION_EXTENDED;
2519 }
2520 else
2521 {
2522 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2523 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2524 }
2525
2526 DiskEntry->ExtendedPartition = PartEntry;
2527
2528 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2529 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2530 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2531 }
2532 else
2533 {
2534 DPRINT1("Add new partition entry\n");
2535
2536 /* Insert and initialize a new partition entry */
2537 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2538 HEAP_ZERO_MEMORY,
2539 sizeof(PARTENTRY));
2540 if (NewPartEntry == NULL)
2541 return;
2542
2543 /* Insert the new entry into the list */
2544 InsertTailList(&PartEntry->ListEntry,
2545 &NewPartEntry->ListEntry);
2546
2547 NewPartEntry->DiskEntry = DiskEntry;
2548
2549 NewPartEntry->IsPartitioned = TRUE;
2550 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2551 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2552 NewPartEntry->StartSector.QuadPart;
2553
2554 NewPartEntry->New = FALSE;
2555 NewPartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2556 NewPartEntry->FileSystem = NULL;
2557 NewPartEntry->BootIndicator = FALSE;
2558
2559 if (NewPartEntry->StartSector.QuadPart < 1450560)
2560 {
2561 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2562 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2563 }
2564 else
2565 {
2566 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2567 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2568 }
2569
2570 DiskEntry->ExtendedPartition = NewPartEntry;
2571
2572 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2573 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2574
2575 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2576 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2577 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2578 }
2579
2580 AddLogicalDiskSpace(DiskEntry);
2581
2582 UpdateDiskLayout(DiskEntry);
2583
2584 DiskEntry->Dirty = TRUE;
2585
2586 AssignDriveLetters(List);
2587 }
2588
2589 VOID
2590 CreateLogicalPartition(
2591 IN PPARTLIST List,
2592 IN ULONGLONG SectorCount,
2593 IN BOOLEAN AutoCreate)
2594 {
2595 PDISKENTRY DiskEntry;
2596 PPARTENTRY PartEntry;
2597 PPARTENTRY NewPartEntry;
2598
2599 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2600
2601 if (List == NULL ||
2602 List->CurrentDisk == NULL ||
2603 List->CurrentPartition == NULL ||
2604 List->CurrentPartition->IsPartitioned != FALSE)
2605 {
2606 return;
2607 }
2608
2609 DiskEntry = List->CurrentDisk;
2610 PartEntry = List->CurrentPartition;
2611
2612 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2613
2614 if ((AutoCreate != FALSE) ||
2615 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2616 {
2617 DPRINT1("Convert existing partition entry\n");
2618
2619 /* Convert current entry to 'new (unformatted)' */
2620 PartEntry->IsPartitioned = TRUE;
2621 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2622 PartEntry->FormatState = Unformatted;
2623 PartEntry->FileSystem = NULL;
2624 PartEntry->AutoCreate = FALSE;
2625 PartEntry->New = TRUE;
2626 PartEntry->BootIndicator = FALSE;
2627 PartEntry->LogicalPartition = TRUE;
2628
2629 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2630 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2631 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2632 }
2633 else
2634 {
2635 DPRINT1("Add new partition entry\n");
2636
2637 /* Insert and initialize a new partition entry */
2638 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2639 HEAP_ZERO_MEMORY,
2640 sizeof(PARTENTRY));
2641 if (NewPartEntry == NULL)
2642 return;
2643
2644 /* Insert the new entry into the list */
2645 InsertTailList(&PartEntry->ListEntry,
2646 &NewPartEntry->ListEntry);
2647
2648 NewPartEntry->DiskEntry = DiskEntry;
2649
2650 NewPartEntry->IsPartitioned = TRUE;
2651 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2652 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2653 NewPartEntry->StartSector.QuadPart;
2654 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2655
2656 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2657 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2658 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2659
2660 NewPartEntry->New = TRUE;
2661 NewPartEntry->FormatState = Unformatted;
2662 NewPartEntry->FileSystem = NULL;
2663 NewPartEntry->BootIndicator = FALSE;
2664 NewPartEntry->LogicalPartition = TRUE;
2665
2666 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2667 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2668 }
2669
2670 UpdateDiskLayout(DiskEntry);
2671
2672 DiskEntry->Dirty = TRUE;
2673
2674 AssignDriveLetters(List);
2675 }
2676
2677 VOID
2678 DeleteCurrentPartition(
2679 IN PPARTLIST List)
2680 {
2681 PDISKENTRY DiskEntry;
2682 PPARTENTRY PartEntry;
2683 PPARTENTRY PrevPartEntry;
2684 PPARTENTRY NextPartEntry;
2685 PPARTENTRY LogicalPartEntry;
2686 PLIST_ENTRY Entry;
2687
2688 if (List == NULL ||
2689 List->CurrentDisk == NULL ||
2690 List->CurrentPartition == NULL ||
2691 List->CurrentPartition->IsPartitioned == FALSE)
2692 {
2693 return;
2694 }
2695
2696 /* Clear the system disk and partition pointers if the system partition is being deleted */
2697 if (List->SystemPartition == List->CurrentPartition)
2698 {
2699 List->SystemPartition = NULL;
2700 }
2701
2702 DiskEntry = List->CurrentDisk;
2703 PartEntry = List->CurrentPartition;
2704
2705 /* Delete all logical partition entries if an extended partition will be deleted */
2706 if (DiskEntry->ExtendedPartition == PartEntry)
2707 {
2708 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2709 {
2710 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2711 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2712
2713 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2714 }
2715
2716 DiskEntry->ExtendedPartition = NULL;
2717 }
2718
2719 /* Adjust unpartitioned disk space entries */
2720
2721 /* Get pointer to previous and next unpartitioned entries */
2722 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2723 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2724
2725 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2726 {
2727 /* Merge previous, current and next unpartitioned entry */
2728
2729 /* Adjust the previous entries length */
2730 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2731
2732 /* Remove the current entry */
2733 RemoveEntryList(&PartEntry->ListEntry);
2734 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2735
2736 /* Remove the next entry */
2737 RemoveEntryList(&NextPartEntry->ListEntry);
2738 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2739
2740 /* Update current partition */
2741 List->CurrentPartition = PrevPartEntry;
2742 }
2743 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2744 {
2745 /* Merge current and previous unpartitioned entry */
2746
2747 /* Adjust the previous entries length */
2748 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2749
2750 /* Remove the current entry */
2751 RemoveEntryList(&PartEntry->ListEntry);
2752 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2753
2754 /* Update current partition */
2755 List->CurrentPartition = PrevPartEntry;
2756 }
2757 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2758 {
2759 /* Merge current and next unpartitioned entry */
2760
2761 /* Adjust the next entries offset and length */
2762 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2763 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2764
2765 /* Remove the current entry */
2766 RemoveEntryList(&PartEntry->ListEntry);
2767 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2768
2769 /* Update current partition */
2770 List->CurrentPartition = NextPartEntry;
2771 }
2772 else
2773 {
2774 /* Nothing to merge but change current entry */
2775 PartEntry->IsPartitioned = FALSE;
2776 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2777 PartEntry->FormatState = Unformatted;
2778 PartEntry->FileSystem = NULL;
2779 PartEntry->DriveLetter = 0;
2780 }
2781
2782 UpdateDiskLayout(DiskEntry);
2783
2784 DiskEntry->Dirty = TRUE;
2785
2786 AssignDriveLetters(List);
2787 }
2788
2789 VOID
2790 CheckActiveSystemPartition(
2791 IN PPARTLIST List)
2792 {
2793 PDISKENTRY DiskEntry;
2794 PPARTENTRY PartEntry;
2795 PLIST_ENTRY ListEntry;
2796
2797 PFILE_SYSTEM FileSystem;
2798
2799 /* Check for empty disk list */
2800 if (IsListEmpty(&List->DiskListHead))
2801 {
2802 List->SystemPartition = NULL;
2803 List->OriginalSystemPartition = NULL;
2804 return;
2805 }
2806
2807 /* Choose the currently selected disk */
2808 DiskEntry = List->CurrentDisk;
2809
2810 /* Check for empty partition list */
2811 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
2812 {
2813 List->SystemPartition = NULL;
2814 List->OriginalSystemPartition = NULL;
2815 return;
2816 }
2817
2818 if (List->SystemPartition != NULL)
2819 {
2820 /* We already have an active system partition */
2821 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2822 List->SystemPartition->PartitionNumber,
2823 List->SystemPartition->DiskEntry->DiskNumber,
2824 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2825 return;
2826 }
2827
2828 DPRINT1("We are here (1)!\n");
2829
2830 List->SystemPartition = NULL;
2831 List->OriginalSystemPartition = NULL;
2832
2833 /* Retrieve the first partition of the disk */
2834 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2835 PARTENTRY,
2836 ListEntry);
2837 ASSERT(DiskEntry == PartEntry->DiskEntry);
2838 List->SystemPartition = PartEntry;
2839
2840 //
2841 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2842 //
2843
2844 /* Check if the disk is new and if so, use its first partition as the active system partition */
2845 if (DiskEntry->NewDisk)
2846 {
2847 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
2848 {
2849 ASSERT(DiskEntry == PartEntry->DiskEntry);
2850 List->SystemPartition = PartEntry;
2851
2852 List->OriginalSystemPartition = List->SystemPartition;
2853
2854 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2855 List->SystemPartition->PartitionNumber,
2856 List->SystemPartition->DiskEntry->DiskNumber,
2857 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2858
2859 goto SetSystemPartition;
2860 }
2861
2862 // FIXME: What to do??
2863 DPRINT1("NewDisk TRUE but first partition is used?\n");
2864 }
2865
2866 DPRINT1("We are here (2)!\n");
2867
2868 /*
2869 * The disk is not new, check if any partition is initialized;
2870 * if not, the first one becomes the system partition.
2871 */
2872 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2873 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2874 {
2875 /* Retrieve the partition and go to the next one */
2876 PartEntry = CONTAINING_RECORD(ListEntry,
2877 PARTENTRY,
2878 ListEntry);
2879
2880 /* Check if the partition is partitioned and is used */
2881 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
2882 {
2883 break;
2884 }
2885
2886 /* Go to the next one */
2887 ListEntry = ListEntry->Flink;
2888 }
2889 if (ListEntry == &DiskEntry->PrimaryPartListHead)
2890 {
2891 /*
2892 * OK we haven't encountered any used and active partition,
2893 * so use the first one as the system partition.
2894 */
2895 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
2896 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
2897
2898 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
2899 List->SystemPartition->PartitionNumber,
2900 List->SystemPartition->DiskEntry->DiskNumber,
2901 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2902
2903 goto SetSystemPartition;
2904 }
2905
2906 List->SystemPartition = NULL;
2907 List->OriginalSystemPartition = NULL;
2908
2909 DPRINT1("We are here (3)!\n");
2910
2911 /* The disk is not new, scan all partitions to find the (active) system partition */
2912 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2913 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2914 {
2915 /* Retrieve the partition and go to the next one */
2916 PartEntry = CONTAINING_RECORD(ListEntry,
2917 PARTENTRY,
2918 ListEntry);
2919 ListEntry = ListEntry->Flink;
2920
2921 /* Check if the partition is partitioned and used */
2922 if (PartEntry->IsPartitioned &&
2923 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
2924 {
2925 /* Check if the partition is active */
2926 if (PartEntry->BootIndicator)
2927 {
2928 /* Yes, we found it */
2929 ASSERT(DiskEntry == PartEntry->DiskEntry);
2930 List->SystemPartition = PartEntry;
2931
2932 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
2933 PartEntry->PartitionNumber,
2934 DiskEntry->DiskNumber,
2935 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
2936 break;
2937 }
2938 }
2939 }
2940
2941 /* Check if we have found the system partition */
2942 if (List->SystemPartition == NULL)
2943 {
2944 /* Nothing, use the alternative system partition */
2945 DPRINT1("No system partition found, use the alternative partition!\n");
2946 goto UseAlternativeSystemPartition;
2947 }
2948
2949 /* Save it */
2950 List->OriginalSystemPartition = List->SystemPartition;
2951
2952 /*
2953 * ADDITIONAL CHECKS / BIG HACK:
2954 *
2955 * Retrieve its file system and check whether we have
2956 * write support for it. If that is the case we are fine
2957 * and we can use it directly. However if we don't have
2958 * write support we will need to change the active system
2959 * partition.
2960 *
2961 * NOTE that this is completely useless on architectures
2962 * where a real system partition is required, as on these
2963 * architectures the partition uses the FAT FS, for which
2964 * we do have write support.
2965 * NOTE also that for those architectures looking for a
2966 * partition boot indicator is insufficient.
2967 */
2968 FileSystem = GetFileSystem(List->OriginalSystemPartition);
2969 if (FileSystem == NULL)
2970 {
2971 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
2972 List->OriginalSystemPartition->PartitionNumber,
2973 List->OriginalSystemPartition->DiskEntry->DiskNumber);
2974 goto FindAndUseAlternativeSystemPartition;
2975 }
2976 // HACK: WARNING: We cannot write on this FS yet!
2977 // See fsutil.c:GetFileSystem()
2978 if (List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
2979 {
2980 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
2981 FileSystem->FileSystemName);
2982 goto FindAndUseAlternativeSystemPartition;
2983 }
2984
2985 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
2986 List->SystemPartition->PartitionNumber,
2987 List->SystemPartition->DiskEntry->DiskNumber,
2988 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2989
2990 return;
2991
2992 FindAndUseAlternativeSystemPartition:
2993 /*
2994 * We are here because we have not found any (active) candidate
2995 * system partition that we know how to support. What we are going
2996 * to do is to change the existing system partition and use the
2997 * partition on which we install ReactOS as the new system partition,
2998 * and then we will need to add in FreeLdr's entry a boot entry to boot
2999 * from the original system partition.
3000 */
3001
3002 /* Unset the old system partition */
3003 List->SystemPartition->BootIndicator = FALSE;
3004 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
3005 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3006 List->SystemPartition->DiskEntry->Dirty = TRUE;
3007
3008 UseAlternativeSystemPartition:
3009 List->SystemPartition = List->CurrentPartition;
3010
3011 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3012 List->SystemPartition->PartitionNumber,
3013 List->SystemPartition->DiskEntry->DiskNumber,
3014 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3015
3016 SetSystemPartition:
3017 /* Set the new active system partition */
3018 List->SystemPartition->BootIndicator = TRUE;
3019 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3020 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3021 List->SystemPartition->DiskEntry->Dirty = TRUE;
3022 }
3023
3024 static
3025 NTSTATUS
3026 WritePartitions(
3027 IN PPARTLIST List,
3028 IN PDISKENTRY DiskEntry)
3029 {
3030 WCHAR DstPath[MAX_PATH];
3031 OBJECT_ATTRIBUTES ObjectAttributes;
3032 IO_STATUS_BLOCK Iosb;
3033 UNICODE_STRING Name;
3034 ULONG BufferSize;
3035 HANDLE FileHandle = NULL;
3036 NTSTATUS Status;
3037
3038 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3039
3040 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
3041 L"\\Device\\Harddisk%lu\\Partition0",
3042 DiskEntry->DiskNumber);
3043 RtlInitUnicodeString(&Name, DstPath);
3044
3045 InitializeObjectAttributes(&ObjectAttributes,
3046 &Name,
3047 OBJ_CASE_INSENSITIVE,
3048 NULL,
3049 NULL);
3050
3051 Status = NtOpenFile(&FileHandle,
3052 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3053 &ObjectAttributes,
3054 &Iosb,
3055 0,
3056 FILE_SYNCHRONOUS_IO_NONALERT);
3057 if (!NT_SUCCESS(Status))
3058 {
3059 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3060 return Status;
3061 }
3062
3063 #ifdef DUMP_PARTITION_TABLE
3064 DumpPartitionTable(DiskEntry);
3065 #endif
3066
3067 //
3068 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3069 // the disk in MBR or GPT format in case the disk was not initialized!!
3070 // For this we must ask the user which format to use.
3071 //
3072
3073 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3074 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3075 Status = NtDeviceIoControlFile(FileHandle,
3076 NULL,
3077 NULL,
3078 NULL,
3079 &Iosb,
3080 IOCTL_DISK_SET_DRIVE_LAYOUT,
3081 DiskEntry->LayoutBuffer,
3082 BufferSize,
3083 NULL,
3084 0);
3085 if (!NT_SUCCESS(Status))
3086 {
3087 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3088 }
3089
3090 if (FileHandle != NULL)
3091 NtClose(FileHandle);
3092
3093 //
3094 // NOTE: Originally (see r40437), we used to install here also a new MBR
3095 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3096 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3097 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3098 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3099 // was called too, the installation test was modified by checking whether
3100 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3101 //
3102
3103 return Status;
3104 }
3105
3106 BOOLEAN
3107 WritePartitionsToDisk(
3108 IN PPARTLIST List)
3109 {
3110 PLIST_ENTRY Entry;
3111 PDISKENTRY DiskEntry;
3112
3113 if (List == NULL)
3114 return TRUE;
3115
3116 Entry = List->DiskListHead.Flink;
3117 while (Entry != &List->DiskListHead)
3118 {
3119 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3120
3121 if (DiskEntry->Dirty != FALSE)
3122 {
3123 WritePartitions(List, DiskEntry);
3124 DiskEntry->Dirty = FALSE;
3125 }
3126
3127 Entry = Entry->Flink;
3128 }
3129
3130 return TRUE;
3131 }
3132
3133 BOOLEAN
3134 SetMountedDeviceValue(
3135 IN WCHAR Letter,
3136 IN ULONG Signature,
3137 IN LARGE_INTEGER StartingOffset)
3138 {
3139 OBJECT_ATTRIBUTES ObjectAttributes;
3140 WCHAR ValueNameBuffer[16];
3141 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3142 UNICODE_STRING ValueName;
3143 REG_DISK_MOUNT_INFO MountInfo;
3144 NTSTATUS Status;
3145 HANDLE KeyHandle;
3146
3147 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3148 L"\\DosDevices\\%c:", Letter);
3149 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3150
3151 InitializeObjectAttributes(&ObjectAttributes,
3152 &KeyName,
3153 OBJ_CASE_INSENSITIVE,
3154 NULL,
3155 NULL);
3156
3157 Status = NtOpenKey(&KeyHandle,
3158 KEY_ALL_ACCESS,
3159 &ObjectAttributes);
3160 if (!NT_SUCCESS(Status))
3161 {
3162 Status = NtCreateKey(&KeyHandle,
3163 KEY_ALL_ACCESS,
3164 &ObjectAttributes,
3165 0,
3166 NULL,
3167 REG_OPTION_NON_VOLATILE,
3168 NULL);
3169 }
3170
3171 if (!NT_SUCCESS(Status))
3172 {
3173 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3174 return FALSE;
3175 }
3176
3177 MountInfo.Signature = Signature;
3178 MountInfo.StartingOffset = StartingOffset;
3179 Status = NtSetValueKey(KeyHandle,
3180 &ValueName,
3181 0,
3182 REG_BINARY,
3183 (PVOID)&MountInfo,
3184 sizeof(MountInfo));
3185 NtClose(KeyHandle);
3186 if (!NT_SUCCESS(Status))
3187 {
3188 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3189 return FALSE;
3190 }
3191
3192 return TRUE;
3193 }
3194
3195 BOOLEAN
3196 SetMountedDeviceValues(
3197 IN PPARTLIST List)
3198 {
3199 PLIST_ENTRY Entry1, Entry2;
3200 PDISKENTRY DiskEntry;
3201 PPARTENTRY PartEntry;
3202 LARGE_INTEGER StartingOffset;
3203
3204 if (List == NULL)
3205 return FALSE;
3206
3207 Entry1 = List->DiskListHead.Flink;
3208 while (Entry1 != &List->DiskListHead)
3209 {
3210 DiskEntry = CONTAINING_RECORD(Entry1,
3211 DISKENTRY,
3212 ListEntry);
3213
3214 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3215 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3216 {
3217 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3218 if (PartEntry->IsPartitioned)
3219 {
3220 /* Assign a "\DosDevices\#:" mount point to this partition */
3221 if (PartEntry->DriveLetter)
3222 {
3223 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3224 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3225 DiskEntry->LayoutBuffer->Signature,
3226 StartingOffset))
3227 {
3228 return FALSE;
3229 }
3230 }
3231 }
3232
3233 Entry2 = Entry2->Flink;
3234 }
3235
3236 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3237 while (Entry2 != &DiskEntry->LogicalPartListHead)
3238 {
3239 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3240 if (PartEntry->IsPartitioned)
3241 {
3242 /* Assign a "\DosDevices\#:" mount point to this partition */
3243 if (PartEntry->DriveLetter)
3244 {
3245 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3246 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3247 DiskEntry->LayoutBuffer->Signature,
3248 StartingOffset))
3249 {
3250 return FALSE;
3251 }
3252 }
3253 }
3254
3255 Entry2 = Entry2->Flink;
3256 }
3257
3258 Entry1 = Entry1->Flink;
3259 }
3260
3261 return TRUE;
3262 }
3263
3264 VOID
3265 SetPartitionType(
3266 IN PPARTENTRY PartEntry,
3267 IN UCHAR PartitionType)
3268 {
3269 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3270
3271 PartEntry->PartitionType = PartitionType;
3272
3273 DiskEntry->Dirty = TRUE;
3274 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
3275 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3276 }
3277
3278 ERROR_NUMBER
3279 PrimaryPartitionCreationChecks(
3280 IN PPARTLIST List)
3281 {
3282 PDISKENTRY DiskEntry;
3283 PPARTENTRY PartEntry;
3284
3285 DiskEntry = List->CurrentDisk;
3286 PartEntry = List->CurrentPartition;
3287
3288 /* Fail if the partition is already in use */
3289 if (PartEntry->IsPartitioned != FALSE)
3290 return ERROR_NEW_PARTITION;
3291
3292 /* Fail if there are already 4 primary partitions in the list */
3293 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3294 return ERROR_PARTITION_TABLE_FULL;
3295
3296 return ERROR_SUCCESS;
3297 }
3298
3299 ERROR_NUMBER
3300 ExtendedPartitionCreationChecks(
3301 IN PPARTLIST List)
3302 {
3303 PDISKENTRY DiskEntry;
3304 PPARTENTRY PartEntry;
3305
3306 DiskEntry = List->CurrentDisk;
3307 PartEntry = List->CurrentPartition;
3308
3309 /* Fail if the partition is already in use */
3310 if (PartEntry->IsPartitioned != FALSE)
3311 return ERROR_NEW_PARTITION;
3312
3313 /* Fail if there are already 4 primary partitions in the list */
3314 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3315 return ERROR_PARTITION_TABLE_FULL;
3316
3317 /* Fail if there is another extended partition in the list */
3318 if (DiskEntry->ExtendedPartition != NULL)
3319 return ERROR_ONLY_ONE_EXTENDED;
3320
3321 return ERROR_SUCCESS;
3322 }
3323
3324 ERROR_NUMBER
3325 LogicalPartitionCreationChecks(
3326 IN PPARTLIST List)
3327 {
3328 // PDISKENTRY DiskEntry;
3329 PPARTENTRY PartEntry;
3330
3331 // DiskEntry = List->CurrentDisk;
3332 PartEntry = List->CurrentPartition;
3333
3334 /* Fail if the partition is already in use */
3335 if (PartEntry->IsPartitioned != FALSE)
3336 return ERROR_NEW_PARTITION;
3337
3338 return ERROR_SUCCESS;
3339 }
3340
3341 BOOLEAN
3342 GetNextUnformattedPartition(
3343 IN PPARTLIST List,
3344 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3345 OUT PPARTENTRY *pPartEntry)
3346 {
3347 PLIST_ENTRY Entry1, Entry2;
3348 PDISKENTRY DiskEntry;
3349 PPARTENTRY PartEntry;
3350
3351 Entry1 = List->DiskListHead.Flink;
3352 while (Entry1 != &List->DiskListHead)
3353 {
3354 DiskEntry = CONTAINING_RECORD(Entry1,
3355 DISKENTRY,
3356 ListEntry);
3357
3358 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3359 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3360 {
3361 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3362 if (PartEntry->IsPartitioned && PartEntry->New)
3363 {
3364 ASSERT(DiskEntry == PartEntry->DiskEntry);
3365 if (pDiskEntry) *pDiskEntry = DiskEntry;
3366 *pPartEntry = PartEntry;
3367 return TRUE;
3368 }
3369
3370 Entry2 = Entry2->Flink;
3371 }
3372
3373 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3374 while (Entry2 != &DiskEntry->LogicalPartListHead)
3375 {
3376 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3377 if (PartEntry->IsPartitioned && PartEntry->New)
3378 {
3379 ASSERT(DiskEntry == PartEntry->DiskEntry);
3380 if (pDiskEntry) *pDiskEntry = DiskEntry;
3381 *pPartEntry = PartEntry;
3382 return TRUE;
3383 }
3384
3385 Entry2 = Entry2->Flink;
3386 }
3387
3388 Entry1 = Entry1->Flink;
3389 }
3390
3391 if (pDiskEntry) *pDiskEntry = NULL;
3392 *pPartEntry = NULL;
3393
3394 return FALSE;
3395 }
3396
3397 BOOLEAN
3398 GetNextUncheckedPartition(
3399 IN PPARTLIST List,
3400 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3401 OUT PPARTENTRY *pPartEntry)
3402 {
3403 PLIST_ENTRY Entry1, Entry2;
3404 PDISKENTRY DiskEntry;
3405 PPARTENTRY PartEntry;
3406
3407 Entry1 = List->DiskListHead.Flink;
3408 while (Entry1 != &List->DiskListHead)
3409 {
3410 DiskEntry = CONTAINING_RECORD(Entry1,
3411 DISKENTRY,
3412 ListEntry);
3413
3414 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3415 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3416 {
3417 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3418 if (PartEntry->NeedsCheck == TRUE)
3419 {
3420 ASSERT(DiskEntry == PartEntry->DiskEntry);
3421 if (pDiskEntry) *pDiskEntry = DiskEntry;
3422 *pPartEntry = PartEntry;
3423 return TRUE;
3424 }
3425
3426 Entry2 = Entry2->Flink;
3427 }
3428
3429 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3430 while (Entry2 != &DiskEntry->LogicalPartListHead)
3431 {
3432 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3433 if (PartEntry->NeedsCheck == TRUE)
3434 {
3435 ASSERT(DiskEntry == PartEntry->DiskEntry);
3436 if (pDiskEntry) *pDiskEntry = DiskEntry;
3437 *pPartEntry = PartEntry;
3438 return TRUE;
3439 }
3440
3441 Entry2 = Entry2->Flink;
3442 }
3443
3444 Entry1 = Entry1->Flink;
3445 }
3446
3447 if (pDiskEntry) *pDiskEntry = NULL;
3448 *pPartEntry = NULL;
3449
3450 return FALSE;
3451 }
3452
3453 /* EOF */