[SETUPLIB][USETUP] Additional partition validity checks.
[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 ASSERT(Index <= 4);
2207
2208 /* Update the logical partition table */
2209 Index = 4;
2210 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2211 while (ListEntry != &DiskEntry->LogicalPartListHead)
2212 {
2213 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2214
2215 if (PartEntry->IsPartitioned)
2216 {
2217 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2218
2219 DPRINT1("Updating logical partition entry %lu\n", Index);
2220
2221 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2222 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2223 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2224 PartitionInfo->PartitionNumber = PartitionNumber;
2225 PartitionInfo->PartitionType = PartEntry->PartitionType;
2226 PartitionInfo->BootIndicator = FALSE;
2227 PartitionInfo->RecognizedPartition = FALSE;
2228 PartitionInfo->RewritePartition = TRUE;
2229
2230 PartEntry->PartitionNumber = PartitionNumber;
2231 PartEntry->PartitionIndex = Index;
2232
2233 /* Fill the link entry of the previous partition entry */
2234 if (LinkInfo != NULL)
2235 {
2236 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2237 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2238 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2239 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2240 LinkInfo->PartitionNumber = 0;
2241 LinkInfo->PartitionType = PARTITION_EXTENDED;
2242 LinkInfo->BootIndicator = FALSE;
2243 LinkInfo->RecognizedPartition = FALSE;
2244 LinkInfo->RewritePartition = TRUE;
2245 }
2246
2247 /* Save a pointer to the link entry of the current partition entry */
2248 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2249
2250 PartitionNumber++;
2251 Index += 4;
2252 }
2253
2254 ListEntry = ListEntry->Flink;
2255 }
2256
2257 /* Wipe unused primary partition entries */
2258 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2259 {
2260 DPRINT1("Primary partition entry %lu\n", Index);
2261
2262 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2263
2264 if (!IsEmptyLayoutEntry(PartitionInfo))
2265 {
2266 DPRINT1("Wiping primary partition entry %lu\n", Index);
2267
2268 PartitionInfo->StartingOffset.QuadPart = 0;
2269 PartitionInfo->PartitionLength.QuadPart = 0;
2270 PartitionInfo->HiddenSectors = 0;
2271 PartitionInfo->PartitionNumber = 0;
2272 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2273 PartitionInfo->BootIndicator = FALSE;
2274 PartitionInfo->RecognizedPartition = FALSE;
2275 PartitionInfo->RewritePartition = TRUE;
2276 }
2277 }
2278
2279 /* Wipe unused logical partition entries */
2280 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2281 {
2282 if (Index % 4 >= 2)
2283 {
2284 DPRINT1("Logical partition entry %lu\n", Index);
2285
2286 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2287
2288 if (!IsEmptyLayoutEntry(PartitionInfo))
2289 {
2290 DPRINT1("Wiping partition entry %lu\n", Index);
2291
2292 PartitionInfo->StartingOffset.QuadPart = 0;
2293 PartitionInfo->PartitionLength.QuadPart = 0;
2294 PartitionInfo->HiddenSectors = 0;
2295 PartitionInfo->PartitionNumber = 0;
2296 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2297 PartitionInfo->BootIndicator = FALSE;
2298 PartitionInfo->RecognizedPartition = FALSE;
2299 PartitionInfo->RewritePartition = TRUE;
2300 }
2301 }
2302 }
2303
2304 #ifdef DUMP_PARTITION_TABLE
2305 DumpPartitionTable(DiskEntry);
2306 #endif
2307 }
2308
2309 static
2310 PPARTENTRY
2311 GetPrevUnpartitionedEntry(
2312 IN PDISKENTRY DiskEntry,
2313 IN PPARTENTRY PartEntry)
2314 {
2315 PPARTENTRY PrevPartEntry;
2316 PLIST_ENTRY ListHead;
2317
2318 if (PartEntry->LogicalPartition)
2319 ListHead = &DiskEntry->LogicalPartListHead;
2320 else
2321 ListHead = &DiskEntry->PrimaryPartListHead;
2322
2323 if (PartEntry->ListEntry.Blink != ListHead)
2324 {
2325 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2326 PARTENTRY,
2327 ListEntry);
2328 if (PrevPartEntry->IsPartitioned == FALSE)
2329 return PrevPartEntry;
2330 }
2331
2332 return NULL;
2333 }
2334
2335 static
2336 PPARTENTRY
2337 GetNextUnpartitionedEntry(
2338 IN PDISKENTRY DiskEntry,
2339 IN PPARTENTRY PartEntry)
2340 {
2341 PPARTENTRY NextPartEntry;
2342 PLIST_ENTRY ListHead;
2343
2344 if (PartEntry->LogicalPartition)
2345 ListHead = &DiskEntry->LogicalPartListHead;
2346 else
2347 ListHead = &DiskEntry->PrimaryPartListHead;
2348
2349 if (PartEntry->ListEntry.Flink != ListHead)
2350 {
2351 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2352 PARTENTRY,
2353 ListEntry);
2354 if (NextPartEntry->IsPartitioned == FALSE)
2355 return NextPartEntry;
2356 }
2357
2358 return NULL;
2359 }
2360
2361 BOOLEAN
2362 CreatePrimaryPartition(
2363 IN PPARTLIST List,
2364 IN ULONGLONG SectorCount,
2365 IN BOOLEAN AutoCreate)
2366 {
2367 ERROR_NUMBER Error;
2368 PDISKENTRY DiskEntry;
2369 PPARTENTRY PartEntry;
2370 PPARTENTRY NewPartEntry;
2371
2372 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2373
2374 if (List == NULL ||
2375 List->CurrentDisk == NULL ||
2376 List->CurrentPartition == NULL ||
2377 List->CurrentPartition->IsPartitioned)
2378 {
2379 return FALSE;
2380 }
2381
2382 Error = PrimaryPartitionCreationChecks(List);
2383 if (Error != NOT_AN_ERROR)
2384 {
2385 DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
2386 return FALSE;
2387 }
2388
2389 DiskEntry = List->CurrentDisk;
2390 PartEntry = List->CurrentPartition;
2391
2392 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2393
2394 if ((AutoCreate != FALSE) ||
2395 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2396 {
2397 DPRINT1("Convert existing partition entry\n");
2398
2399 /* Convert current entry to 'new (unformatted)' */
2400 PartEntry->IsPartitioned = TRUE;
2401 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2402 PartEntry->FormatState = Unformatted;
2403 PartEntry->FileSystem = NULL;
2404 PartEntry->AutoCreate = AutoCreate;
2405 PartEntry->New = TRUE;
2406 PartEntry->BootIndicator = FALSE;
2407
2408 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2409 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2410 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2411 }
2412 else
2413 {
2414 DPRINT1("Add new partition entry\n");
2415
2416 /* Insert and initialize a new partition entry */
2417 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2418 HEAP_ZERO_MEMORY,
2419 sizeof(PARTENTRY));
2420 if (NewPartEntry == NULL)
2421 return FALSE;
2422
2423 /* Insert the new entry into the list */
2424 InsertTailList(&PartEntry->ListEntry,
2425 &NewPartEntry->ListEntry);
2426
2427 NewPartEntry->DiskEntry = DiskEntry;
2428
2429 NewPartEntry->IsPartitioned = TRUE;
2430 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2431 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2432 NewPartEntry->StartSector.QuadPart;
2433 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2434
2435 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2436 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2437 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2438
2439 NewPartEntry->New = TRUE;
2440 NewPartEntry->FormatState = Unformatted;
2441 NewPartEntry->FileSystem = NULL;
2442 NewPartEntry->BootIndicator = FALSE;
2443
2444 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2445 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2446 }
2447
2448 UpdateDiskLayout(DiskEntry);
2449
2450 DiskEntry->Dirty = TRUE;
2451
2452 AssignDriveLetters(List);
2453
2454 return TRUE;
2455 }
2456
2457 static
2458 VOID
2459 AddLogicalDiskSpace(
2460 IN PDISKENTRY DiskEntry)
2461 {
2462 PPARTENTRY NewPartEntry;
2463
2464 DPRINT1("AddLogicalDiskSpace()\n");
2465
2466 /* Create a partition entry that represents the empty space in the container partition */
2467 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2468 HEAP_ZERO_MEMORY,
2469 sizeof(PARTENTRY));
2470 if (NewPartEntry == NULL)
2471 return;
2472
2473 NewPartEntry->DiskEntry = DiskEntry;
2474 NewPartEntry->LogicalPartition = TRUE;
2475
2476 NewPartEntry->IsPartitioned = FALSE;
2477 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2478 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2479
2480 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2481 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2482 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2483
2484 NewPartEntry->FormatState = Unformatted;
2485 NewPartEntry->FileSystem = NULL;
2486
2487 InsertTailList(&DiskEntry->LogicalPartListHead,
2488 &NewPartEntry->ListEntry);
2489 }
2490
2491 BOOLEAN
2492 CreateExtendedPartition(
2493 IN PPARTLIST List,
2494 IN ULONGLONG SectorCount)
2495 {
2496 ERROR_NUMBER Error;
2497 PDISKENTRY DiskEntry;
2498 PPARTENTRY PartEntry;
2499 PPARTENTRY NewPartEntry;
2500
2501 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2502
2503 if (List == NULL ||
2504 List->CurrentDisk == NULL ||
2505 List->CurrentPartition == NULL ||
2506 List->CurrentPartition->IsPartitioned)
2507 {
2508 return FALSE;
2509 }
2510
2511 Error = ExtendedPartitionCreationChecks(List);
2512 if (Error != NOT_AN_ERROR)
2513 {
2514 DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
2515 return FALSE;
2516 }
2517
2518 DiskEntry = List->CurrentDisk;
2519 PartEntry = List->CurrentPartition;
2520
2521 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2522
2523 if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2524 {
2525 DPRINT1("Convert existing partition entry\n");
2526
2527 /* Convert current entry to 'new (unformatted)' */
2528 PartEntry->IsPartitioned = TRUE;
2529 PartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2530 PartEntry->FileSystem = NULL;
2531 PartEntry->AutoCreate = FALSE;
2532 PartEntry->New = FALSE;
2533 PartEntry->BootIndicator = FALSE;
2534
2535 if (PartEntry->StartSector.QuadPart < 1450560)
2536 {
2537 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2538 PartEntry->PartitionType = PARTITION_EXTENDED;
2539 }
2540 else
2541 {
2542 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2543 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2544 }
2545
2546 DiskEntry->ExtendedPartition = PartEntry;
2547
2548 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2549 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2550 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2551 }
2552 else
2553 {
2554 DPRINT1("Add new partition entry\n");
2555
2556 /* Insert and initialize a new partition entry */
2557 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2558 HEAP_ZERO_MEMORY,
2559 sizeof(PARTENTRY));
2560 if (NewPartEntry == NULL)
2561 return FALSE;
2562
2563 /* Insert the new entry into the list */
2564 InsertTailList(&PartEntry->ListEntry,
2565 &NewPartEntry->ListEntry);
2566
2567 NewPartEntry->DiskEntry = DiskEntry;
2568
2569 NewPartEntry->IsPartitioned = TRUE;
2570 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2571 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2572 NewPartEntry->StartSector.QuadPart;
2573
2574 NewPartEntry->New = FALSE;
2575 NewPartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2576 NewPartEntry->FileSystem = NULL;
2577 NewPartEntry->BootIndicator = FALSE;
2578
2579 if (NewPartEntry->StartSector.QuadPart < 1450560)
2580 {
2581 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2582 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2583 }
2584 else
2585 {
2586 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2587 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2588 }
2589
2590 DiskEntry->ExtendedPartition = NewPartEntry;
2591
2592 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2593 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2594
2595 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2596 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2597 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2598 }
2599
2600 AddLogicalDiskSpace(DiskEntry);
2601
2602 UpdateDiskLayout(DiskEntry);
2603
2604 DiskEntry->Dirty = TRUE;
2605
2606 AssignDriveLetters(List);
2607
2608 return TRUE;
2609 }
2610
2611 BOOLEAN
2612 CreateLogicalPartition(
2613 IN PPARTLIST List,
2614 IN ULONGLONG SectorCount,
2615 IN BOOLEAN AutoCreate)
2616 {
2617 ERROR_NUMBER Error;
2618 PDISKENTRY DiskEntry;
2619 PPARTENTRY PartEntry;
2620 PPARTENTRY NewPartEntry;
2621
2622 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2623
2624 if (List == NULL ||
2625 List->CurrentDisk == NULL ||
2626 List->CurrentPartition == NULL ||
2627 List->CurrentPartition->IsPartitioned)
2628 {
2629 return FALSE;
2630 }
2631
2632 Error = LogicalPartitionCreationChecks(List);
2633 if (Error != NOT_AN_ERROR)
2634 {
2635 DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
2636 return FALSE;
2637 }
2638
2639 DiskEntry = List->CurrentDisk;
2640 PartEntry = List->CurrentPartition;
2641
2642 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2643
2644 if ((AutoCreate != FALSE) ||
2645 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2646 {
2647 DPRINT1("Convert existing partition entry\n");
2648
2649 /* Convert current entry to 'new (unformatted)' */
2650 PartEntry->IsPartitioned = TRUE;
2651 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2652 PartEntry->FormatState = Unformatted;
2653 PartEntry->FileSystem = NULL;
2654 PartEntry->AutoCreate = FALSE;
2655 PartEntry->New = TRUE;
2656 PartEntry->BootIndicator = FALSE;
2657 PartEntry->LogicalPartition = TRUE;
2658
2659 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2660 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2661 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2662 }
2663 else
2664 {
2665 DPRINT1("Add new partition entry\n");
2666
2667 /* Insert and initialize a new partition entry */
2668 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2669 HEAP_ZERO_MEMORY,
2670 sizeof(PARTENTRY));
2671 if (NewPartEntry == NULL)
2672 return FALSE;
2673
2674 /* Insert the new entry into the list */
2675 InsertTailList(&PartEntry->ListEntry,
2676 &NewPartEntry->ListEntry);
2677
2678 NewPartEntry->DiskEntry = DiskEntry;
2679
2680 NewPartEntry->IsPartitioned = TRUE;
2681 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2682 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2683 NewPartEntry->StartSector.QuadPart;
2684 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2685
2686 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2687 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2688 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2689
2690 NewPartEntry->New = TRUE;
2691 NewPartEntry->FormatState = Unformatted;
2692 NewPartEntry->FileSystem = NULL;
2693 NewPartEntry->BootIndicator = FALSE;
2694 NewPartEntry->LogicalPartition = TRUE;
2695
2696 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2697 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2698 }
2699
2700 UpdateDiskLayout(DiskEntry);
2701
2702 DiskEntry->Dirty = TRUE;
2703
2704 AssignDriveLetters(List);
2705
2706 return TRUE;
2707 }
2708
2709 VOID
2710 DeleteCurrentPartition(
2711 IN PPARTLIST List)
2712 {
2713 PDISKENTRY DiskEntry;
2714 PPARTENTRY PartEntry;
2715 PPARTENTRY PrevPartEntry;
2716 PPARTENTRY NextPartEntry;
2717 PPARTENTRY LogicalPartEntry;
2718 PLIST_ENTRY Entry;
2719
2720 if (List == NULL ||
2721 List->CurrentDisk == NULL ||
2722 List->CurrentPartition == NULL ||
2723 List->CurrentPartition->IsPartitioned == FALSE)
2724 {
2725 return;
2726 }
2727
2728 /* Clear the system disk and partition pointers if the system partition is being deleted */
2729 if (List->SystemPartition == List->CurrentPartition)
2730 {
2731 List->SystemPartition = NULL;
2732 }
2733
2734 DiskEntry = List->CurrentDisk;
2735 PartEntry = List->CurrentPartition;
2736
2737 /* Delete all logical partition entries if an extended partition will be deleted */
2738 if (DiskEntry->ExtendedPartition == PartEntry)
2739 {
2740 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2741 {
2742 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2743 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2744
2745 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2746 }
2747
2748 DiskEntry->ExtendedPartition = NULL;
2749 }
2750
2751 /* Adjust unpartitioned disk space entries */
2752
2753 /* Get pointer to previous and next unpartitioned entries */
2754 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2755 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2756
2757 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2758 {
2759 /* Merge previous, current and next unpartitioned entry */
2760
2761 /* Adjust the previous entries length */
2762 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2763
2764 /* Remove the current entry */
2765 RemoveEntryList(&PartEntry->ListEntry);
2766 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2767
2768 /* Remove the next entry */
2769 RemoveEntryList(&NextPartEntry->ListEntry);
2770 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2771
2772 /* Update current partition */
2773 List->CurrentPartition = PrevPartEntry;
2774 }
2775 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2776 {
2777 /* Merge current and previous unpartitioned entry */
2778
2779 /* Adjust the previous entries length */
2780 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2781
2782 /* Remove the current entry */
2783 RemoveEntryList(&PartEntry->ListEntry);
2784 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2785
2786 /* Update current partition */
2787 List->CurrentPartition = PrevPartEntry;
2788 }
2789 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2790 {
2791 /* Merge current and next unpartitioned entry */
2792
2793 /* Adjust the next entries offset and length */
2794 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2795 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2796
2797 /* Remove the current entry */
2798 RemoveEntryList(&PartEntry->ListEntry);
2799 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2800
2801 /* Update current partition */
2802 List->CurrentPartition = NextPartEntry;
2803 }
2804 else
2805 {
2806 /* Nothing to merge but change current entry */
2807 PartEntry->IsPartitioned = FALSE;
2808 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2809 PartEntry->FormatState = Unformatted;
2810 PartEntry->FileSystem = NULL;
2811 PartEntry->DriveLetter = 0;
2812 }
2813
2814 UpdateDiskLayout(DiskEntry);
2815
2816 DiskEntry->Dirty = TRUE;
2817
2818 AssignDriveLetters(List);
2819 }
2820
2821 VOID
2822 CheckActiveSystemPartition(
2823 IN PPARTLIST List)
2824 {
2825 PDISKENTRY DiskEntry;
2826 PPARTENTRY PartEntry;
2827 PLIST_ENTRY ListEntry;
2828
2829 PFILE_SYSTEM FileSystem;
2830
2831 /* Check for empty disk list */
2832 if (IsListEmpty(&List->DiskListHead))
2833 {
2834 List->SystemPartition = NULL;
2835 List->OriginalSystemPartition = NULL;
2836 return;
2837 }
2838
2839 /* Choose the currently selected disk */
2840 DiskEntry = List->CurrentDisk;
2841
2842 /* Check for empty partition list */
2843 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
2844 {
2845 List->SystemPartition = NULL;
2846 List->OriginalSystemPartition = NULL;
2847 return;
2848 }
2849
2850 if (List->SystemPartition != NULL)
2851 {
2852 /* We already have an active system partition */
2853 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2854 List->SystemPartition->PartitionNumber,
2855 List->SystemPartition->DiskEntry->DiskNumber,
2856 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2857 return;
2858 }
2859
2860 DPRINT1("We are here (1)!\n");
2861
2862 List->SystemPartition = NULL;
2863 List->OriginalSystemPartition = NULL;
2864
2865 /* Retrieve the first partition of the disk */
2866 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2867 PARTENTRY,
2868 ListEntry);
2869 ASSERT(DiskEntry == PartEntry->DiskEntry);
2870 List->SystemPartition = PartEntry;
2871
2872 //
2873 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2874 //
2875
2876 /* Check if the disk is new and if so, use its first partition as the active system partition */
2877 if (DiskEntry->NewDisk)
2878 {
2879 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
2880 {
2881 ASSERT(DiskEntry == PartEntry->DiskEntry);
2882 List->SystemPartition = PartEntry;
2883
2884 List->OriginalSystemPartition = List->SystemPartition;
2885
2886 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2887 List->SystemPartition->PartitionNumber,
2888 List->SystemPartition->DiskEntry->DiskNumber,
2889 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2890
2891 goto SetSystemPartition;
2892 }
2893
2894 // FIXME: What to do??
2895 DPRINT1("NewDisk TRUE but first partition is used?\n");
2896 }
2897
2898 DPRINT1("We are here (2)!\n");
2899
2900 /*
2901 * The disk is not new, check if any partition is initialized;
2902 * if not, the first one becomes the system partition.
2903 */
2904 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2905 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2906 {
2907 /* Retrieve the partition and go to the next one */
2908 PartEntry = CONTAINING_RECORD(ListEntry,
2909 PARTENTRY,
2910 ListEntry);
2911
2912 /* Check if the partition is partitioned and is used */
2913 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
2914 {
2915 break;
2916 }
2917
2918 /* Go to the next one */
2919 ListEntry = ListEntry->Flink;
2920 }
2921 if (ListEntry == &DiskEntry->PrimaryPartListHead)
2922 {
2923 /*
2924 * OK we haven't encountered any used and active partition,
2925 * so use the first one as the system partition.
2926 */
2927 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
2928 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
2929
2930 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
2931 List->SystemPartition->PartitionNumber,
2932 List->SystemPartition->DiskEntry->DiskNumber,
2933 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2934
2935 goto SetSystemPartition;
2936 }
2937
2938 List->SystemPartition = NULL;
2939 List->OriginalSystemPartition = NULL;
2940
2941 DPRINT1("We are here (3)!\n");
2942
2943 /* The disk is not new, scan all partitions to find the (active) system partition */
2944 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2945 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2946 {
2947 /* Retrieve the partition and go to the next one */
2948 PartEntry = CONTAINING_RECORD(ListEntry,
2949 PARTENTRY,
2950 ListEntry);
2951 ListEntry = ListEntry->Flink;
2952
2953 /* Check if the partition is partitioned and used */
2954 if (PartEntry->IsPartitioned &&
2955 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
2956 {
2957 /* Check if the partition is active */
2958 if (PartEntry->BootIndicator)
2959 {
2960 /* Yes, we found it */
2961 ASSERT(DiskEntry == PartEntry->DiskEntry);
2962 List->SystemPartition = PartEntry;
2963
2964 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
2965 PartEntry->PartitionNumber,
2966 DiskEntry->DiskNumber,
2967 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
2968 break;
2969 }
2970 }
2971 }
2972
2973 /* Check if we have found the system partition */
2974 if (List->SystemPartition == NULL)
2975 {
2976 /* Nothing, use the alternative system partition */
2977 DPRINT1("No system partition found, use the alternative partition!\n");
2978 goto UseAlternativeSystemPartition;
2979 }
2980
2981 /* Save it */
2982 List->OriginalSystemPartition = List->SystemPartition;
2983
2984 /*
2985 * ADDITIONAL CHECKS / BIG HACK:
2986 *
2987 * Retrieve its file system and check whether we have
2988 * write support for it. If that is the case we are fine
2989 * and we can use it directly. However if we don't have
2990 * write support we will need to change the active system
2991 * partition.
2992 *
2993 * NOTE that this is completely useless on architectures
2994 * where a real system partition is required, as on these
2995 * architectures the partition uses the FAT FS, for which
2996 * we do have write support.
2997 * NOTE also that for those architectures looking for a
2998 * partition boot indicator is insufficient.
2999 */
3000 FileSystem = GetFileSystem(List->OriginalSystemPartition);
3001 if (FileSystem == NULL)
3002 {
3003 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
3004 List->OriginalSystemPartition->PartitionNumber,
3005 List->OriginalSystemPartition->DiskEntry->DiskNumber);
3006 goto FindAndUseAlternativeSystemPartition;
3007 }
3008 // HACK: WARNING: We cannot write on this FS yet!
3009 // See fsutil.c:GetFileSystem()
3010 if (List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
3011 {
3012 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
3013 FileSystem->FileSystemName);
3014 goto FindAndUseAlternativeSystemPartition;
3015 }
3016
3017 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
3018 List->SystemPartition->PartitionNumber,
3019 List->SystemPartition->DiskEntry->DiskNumber,
3020 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3021
3022 return;
3023
3024 FindAndUseAlternativeSystemPartition:
3025 /*
3026 * We are here because we have not found any (active) candidate
3027 * system partition that we know how to support. What we are going
3028 * to do is to change the existing system partition and use the
3029 * partition on which we install ReactOS as the new system partition,
3030 * and then we will need to add in FreeLdr's entry a boot entry to boot
3031 * from the original system partition.
3032 */
3033
3034 /* Unset the old system partition */
3035 List->SystemPartition->BootIndicator = FALSE;
3036 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
3037 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3038 List->SystemPartition->DiskEntry->Dirty = TRUE;
3039
3040 UseAlternativeSystemPartition:
3041 List->SystemPartition = List->CurrentPartition;
3042
3043 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3044 List->SystemPartition->PartitionNumber,
3045 List->SystemPartition->DiskEntry->DiskNumber,
3046 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3047
3048 SetSystemPartition:
3049 /* Set the new active system partition */
3050 List->SystemPartition->BootIndicator = TRUE;
3051 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3052 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3053 List->SystemPartition->DiskEntry->Dirty = TRUE;
3054 }
3055
3056 static
3057 NTSTATUS
3058 WritePartitions(
3059 IN PPARTLIST List,
3060 IN PDISKENTRY DiskEntry)
3061 {
3062 WCHAR DstPath[MAX_PATH];
3063 OBJECT_ATTRIBUTES ObjectAttributes;
3064 IO_STATUS_BLOCK Iosb;
3065 UNICODE_STRING Name;
3066 ULONG BufferSize;
3067 HANDLE FileHandle = NULL;
3068 NTSTATUS Status;
3069
3070 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3071
3072 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
3073 L"\\Device\\Harddisk%lu\\Partition0",
3074 DiskEntry->DiskNumber);
3075 RtlInitUnicodeString(&Name, DstPath);
3076
3077 InitializeObjectAttributes(&ObjectAttributes,
3078 &Name,
3079 OBJ_CASE_INSENSITIVE,
3080 NULL,
3081 NULL);
3082
3083 Status = NtOpenFile(&FileHandle,
3084 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3085 &ObjectAttributes,
3086 &Iosb,
3087 0,
3088 FILE_SYNCHRONOUS_IO_NONALERT);
3089 if (!NT_SUCCESS(Status))
3090 {
3091 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3092 return Status;
3093 }
3094
3095 #ifdef DUMP_PARTITION_TABLE
3096 DumpPartitionTable(DiskEntry);
3097 #endif
3098
3099 //
3100 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3101 // the disk in MBR or GPT format in case the disk was not initialized!!
3102 // For this we must ask the user which format to use.
3103 //
3104
3105 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3106 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3107 Status = NtDeviceIoControlFile(FileHandle,
3108 NULL,
3109 NULL,
3110 NULL,
3111 &Iosb,
3112 IOCTL_DISK_SET_DRIVE_LAYOUT,
3113 DiskEntry->LayoutBuffer,
3114 BufferSize,
3115 NULL,
3116 0);
3117 if (!NT_SUCCESS(Status))
3118 {
3119 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3120 }
3121
3122 if (FileHandle != NULL)
3123 NtClose(FileHandle);
3124
3125 //
3126 // NOTE: Originally (see r40437), we used to install here also a new MBR
3127 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3128 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3129 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3130 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3131 // was called too, the installation test was modified by checking whether
3132 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3133 //
3134
3135 return Status;
3136 }
3137
3138 BOOLEAN
3139 WritePartitionsToDisk(
3140 IN PPARTLIST List)
3141 {
3142 PLIST_ENTRY Entry;
3143 PDISKENTRY DiskEntry;
3144
3145 if (List == NULL)
3146 return TRUE;
3147
3148 Entry = List->DiskListHead.Flink;
3149 while (Entry != &List->DiskListHead)
3150 {
3151 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3152
3153 if (DiskEntry->Dirty != FALSE)
3154 {
3155 WritePartitions(List, DiskEntry);
3156 DiskEntry->Dirty = FALSE;
3157 }
3158
3159 Entry = Entry->Flink;
3160 }
3161
3162 return TRUE;
3163 }
3164
3165 BOOLEAN
3166 SetMountedDeviceValue(
3167 IN WCHAR Letter,
3168 IN ULONG Signature,
3169 IN LARGE_INTEGER StartingOffset)
3170 {
3171 OBJECT_ATTRIBUTES ObjectAttributes;
3172 WCHAR ValueNameBuffer[16];
3173 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3174 UNICODE_STRING ValueName;
3175 REG_DISK_MOUNT_INFO MountInfo;
3176 NTSTATUS Status;
3177 HANDLE KeyHandle;
3178
3179 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3180 L"\\DosDevices\\%c:", Letter);
3181 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3182
3183 InitializeObjectAttributes(&ObjectAttributes,
3184 &KeyName,
3185 OBJ_CASE_INSENSITIVE,
3186 NULL,
3187 NULL);
3188
3189 Status = NtOpenKey(&KeyHandle,
3190 KEY_ALL_ACCESS,
3191 &ObjectAttributes);
3192 if (!NT_SUCCESS(Status))
3193 {
3194 Status = NtCreateKey(&KeyHandle,
3195 KEY_ALL_ACCESS,
3196 &ObjectAttributes,
3197 0,
3198 NULL,
3199 REG_OPTION_NON_VOLATILE,
3200 NULL);
3201 }
3202
3203 if (!NT_SUCCESS(Status))
3204 {
3205 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3206 return FALSE;
3207 }
3208
3209 MountInfo.Signature = Signature;
3210 MountInfo.StartingOffset = StartingOffset;
3211 Status = NtSetValueKey(KeyHandle,
3212 &ValueName,
3213 0,
3214 REG_BINARY,
3215 (PVOID)&MountInfo,