[USETUP] Remove the PARTITION_EXT2 constant and use PARTITION_LINUX in favour since...
[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 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
823 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
824 NewPartEntry->StartSector.QuadPart;
825
826 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
827 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
828 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
829
830 NewPartEntry->FormatState = Unformatted;
831 NewPartEntry->FileSystem = NULL;
832
833 InsertTailList(&DiskEntry->PrimaryPartListHead,
834 &NewPartEntry->ListEntry);
835
836 return;
837 }
838
839 /* Start partition at head 1, cylinder 0 */
840 LastStartSector = DiskEntry->SectorAlignment;
841 LastSectorCount = 0ULL;
842 LastUnusedSectorCount = 0ULL;
843
844 Entry = DiskEntry->PrimaryPartListHead.Flink;
845 while (Entry != &DiskEntry->PrimaryPartListHead)
846 {
847 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
848
849 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
850 PartEntry->SectorCount.QuadPart != 0ULL)
851 {
852 LastUnusedSectorCount =
853 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
854
855 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
856 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
857 {
858 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
859
860 NewPartEntry = RtlAllocateHeap(ProcessHeap,
861 HEAP_ZERO_MEMORY,
862 sizeof(PARTENTRY));
863 if (NewPartEntry == NULL)
864 return;
865
866 NewPartEntry->DiskEntry = DiskEntry;
867
868 NewPartEntry->IsPartitioned = FALSE;
869 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
870 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
871 NewPartEntry->StartSector.QuadPart;
872
873 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
874 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
875 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
876
877 NewPartEntry->FormatState = Unformatted;
878 NewPartEntry->FileSystem = NULL;
879
880 /* Insert the table into the list */
881 InsertTailList(&PartEntry->ListEntry,
882 &NewPartEntry->ListEntry);
883 }
884
885 LastStartSector = PartEntry->StartSector.QuadPart;
886 LastSectorCount = PartEntry->SectorCount.QuadPart;
887 }
888
889 Entry = Entry->Flink;
890 }
891
892 /* Check for trailing unpartitioned disk space */
893 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
894 {
895 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
896
897 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
898 {
899 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
900
901 NewPartEntry = RtlAllocateHeap(ProcessHeap,
902 HEAP_ZERO_MEMORY,
903 sizeof(PARTENTRY));
904 if (NewPartEntry == NULL)
905 return;
906
907 NewPartEntry->DiskEntry = DiskEntry;
908
909 NewPartEntry->IsPartitioned = FALSE;
910 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
911 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
912 NewPartEntry->StartSector.QuadPart;
913
914 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
915 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
916 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
917
918 NewPartEntry->FormatState = Unformatted;
919 NewPartEntry->FileSystem = NULL;
920
921 /* Append the table to the list */
922 InsertTailList(&DiskEntry->PrimaryPartListHead,
923 &NewPartEntry->ListEntry);
924 }
925 }
926
927 if (DiskEntry->ExtendedPartition != NULL)
928 {
929 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
930 {
931 DPRINT1("No logical partition!\n");
932
933 /* Create a partition entry that represents the empty extended partition */
934 NewPartEntry = RtlAllocateHeap(ProcessHeap,
935 HEAP_ZERO_MEMORY,
936 sizeof(PARTENTRY));
937 if (NewPartEntry == NULL)
938 return;
939
940 NewPartEntry->DiskEntry = DiskEntry;
941 NewPartEntry->LogicalPartition = TRUE;
942
943 NewPartEntry->IsPartitioned = FALSE;
944 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
945 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
946
947 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
948 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
949 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
950
951 NewPartEntry->FormatState = Unformatted;
952 NewPartEntry->FileSystem = NULL;
953
954 InsertTailList(&DiskEntry->LogicalPartListHead,
955 &NewPartEntry->ListEntry);
956
957 return;
958 }
959
960 /* Start partition at head 1, cylinder 0 */
961 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
962 LastSectorCount = 0ULL;
963 LastUnusedSectorCount = 0ULL;
964
965 Entry = DiskEntry->LogicalPartListHead.Flink;
966 while (Entry != &DiskEntry->LogicalPartListHead)
967 {
968 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
969
970 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
971 PartEntry->SectorCount.QuadPart != 0ULL)
972 {
973 LastUnusedSectorCount =
974 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
975
976 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
977 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
978 {
979 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
980
981 NewPartEntry = RtlAllocateHeap(ProcessHeap,
982 HEAP_ZERO_MEMORY,
983 sizeof(PARTENTRY));
984 if (NewPartEntry == NULL)
985 return;
986
987 NewPartEntry->DiskEntry = DiskEntry;
988 NewPartEntry->LogicalPartition = TRUE;
989
990 NewPartEntry->IsPartitioned = FALSE;
991 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
992 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
993 NewPartEntry->StartSector.QuadPart;
994
995 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
996 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
997 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
998
999 NewPartEntry->FormatState = Unformatted;
1000 NewPartEntry->FileSystem = NULL;
1001
1002 /* Insert the table into the list */
1003 InsertTailList(&PartEntry->ListEntry,
1004 &NewPartEntry->ListEntry);
1005 }
1006
1007 LastStartSector = PartEntry->StartSector.QuadPart;
1008 LastSectorCount = PartEntry->SectorCount.QuadPart;
1009 }
1010
1011 Entry = Entry->Flink;
1012 }
1013
1014 /* Check for trailing unpartitioned disk space */
1015 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
1016 {
1017 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
1018
1019 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
1020 {
1021 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
1022
1023 NewPartEntry = RtlAllocateHeap(ProcessHeap,
1024 HEAP_ZERO_MEMORY,
1025 sizeof(PARTENTRY));
1026 if (NewPartEntry == NULL)
1027 return;
1028
1029 NewPartEntry->DiskEntry = DiskEntry;
1030 NewPartEntry->LogicalPartition = TRUE;
1031
1032 NewPartEntry->IsPartitioned = FALSE;
1033 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
1034 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
1035 NewPartEntry->StartSector.QuadPart;
1036
1037 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
1038 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
1039 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
1040
1041 NewPartEntry->FormatState = Unformatted;
1042 NewPartEntry->FileSystem = NULL;
1043
1044 /* Append the table to the list */
1045 InsertTailList(&DiskEntry->LogicalPartListHead,
1046 &NewPartEntry->ListEntry);
1047 }
1048 }
1049 }
1050
1051 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
1052 }
1053
1054 static
1055 VOID
1056 SetDiskSignature(
1057 IN PPARTLIST List,
1058 IN PDISKENTRY DiskEntry)
1059 {
1060 LARGE_INTEGER SystemTime;
1061 TIME_FIELDS TimeFields;
1062 PLIST_ENTRY Entry2;
1063 PDISKENTRY DiskEntry2;
1064 PUCHAR Buffer;
1065
1066 Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
1067
1068 while (TRUE)
1069 {
1070 NtQuerySystemTime(&SystemTime);
1071 RtlTimeToTimeFields(&SystemTime, &TimeFields);
1072
1073 Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
1074 Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
1075 Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
1076 Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
1077
1078 if (DiskEntry->LayoutBuffer->Signature == 0)
1079 {
1080 continue;
1081 }
1082
1083 /* Check if the signature already exist */
1084 /* FIXME:
1085 * Check also signatures from disks, which are
1086 * not visible (bootable) by the bios.
1087 */
1088 Entry2 = List->DiskListHead.Flink;
1089 while (Entry2 != &List->DiskListHead)
1090 {
1091 DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
1092
1093 if (DiskEntry != DiskEntry2 &&
1094 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
1095 break;
1096
1097 Entry2 = Entry2->Flink;
1098 }
1099
1100 if (Entry2 == &List->DiskListHead)
1101 break;
1102 }
1103 }
1104
1105 static
1106 VOID
1107 UpdateDiskSignatures(
1108 IN PPARTLIST List)
1109 {
1110 PLIST_ENTRY Entry;
1111 PDISKENTRY DiskEntry;
1112
1113 /* Print partition lines */
1114 Entry = List->DiskListHead.Flink;
1115 while (Entry != &List->DiskListHead)
1116 {
1117 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1118
1119 if (DiskEntry->LayoutBuffer &&
1120 DiskEntry->LayoutBuffer->Signature == 0)
1121 {
1122 SetDiskSignature(List, DiskEntry);
1123 DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
1124 }
1125
1126 Entry = Entry->Flink;
1127 }
1128 }
1129
1130 static
1131 VOID
1132 AddDiskToList(
1133 IN HANDLE FileHandle,
1134 IN ULONG DiskNumber,
1135 IN PPARTLIST List)
1136 {
1137 DISK_GEOMETRY DiskGeometry;
1138 SCSI_ADDRESS ScsiAddress;
1139 PDISKENTRY DiskEntry;
1140 IO_STATUS_BLOCK Iosb;
1141 NTSTATUS Status;
1142 PPARTITION_SECTOR Mbr;
1143 PULONG Buffer;
1144 LARGE_INTEGER FileOffset;
1145 WCHAR Identifier[20];
1146 ULONG Checksum;
1147 ULONG Signature;
1148 ULONG i;
1149 PLIST_ENTRY ListEntry;
1150 PBIOSDISKENTRY BiosDiskEntry;
1151 ULONG LayoutBufferSize;
1152 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
1153
1154 /* Retrieve the drive geometry */
1155 Status = NtDeviceIoControlFile(FileHandle,
1156 NULL,
1157 NULL,
1158 NULL,
1159 &Iosb,
1160 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1161 NULL,
1162 0,
1163 &DiskGeometry,
1164 sizeof(DiskGeometry));
1165 if (!NT_SUCCESS(Status))
1166 return;
1167
1168 if (DiskGeometry.MediaType != FixedMedia &&
1169 DiskGeometry.MediaType != RemovableMedia)
1170 {
1171 return;
1172 }
1173
1174 /*
1175 * FIXME: Here we suppose the disk is always SCSI. What if it is
1176 * of another type? To check this we need to retrieve the name of
1177 * the driver the disk device belongs to.
1178 */
1179 Status = NtDeviceIoControlFile(FileHandle,
1180 NULL,
1181 NULL,
1182 NULL,
1183 &Iosb,
1184 IOCTL_SCSI_GET_ADDRESS,
1185 NULL,
1186 0,
1187 &ScsiAddress,
1188 sizeof(ScsiAddress));
1189 if (!NT_SUCCESS(Status))
1190 return;
1191
1192 /*
1193 * Check whether the disk is initialized, by looking at its MBR.
1194 * NOTE that this must be generalized to GPT disks as well!
1195 */
1196
1197 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
1198 0,
1199 DiskGeometry.BytesPerSector);
1200 if (Mbr == NULL)
1201 return;
1202
1203 FileOffset.QuadPart = 0;
1204 Status = NtReadFile(FileHandle,
1205 NULL,
1206 NULL,
1207 NULL,
1208 &Iosb,
1209 (PVOID)Mbr,
1210 DiskGeometry.BytesPerSector,
1211 &FileOffset,
1212 NULL);
1213 if (!NT_SUCCESS(Status))
1214 {
1215 RtlFreeHeap(ProcessHeap, 0, Mbr);
1216 DPRINT1("NtReadFile failed, status=%x\n", Status);
1217 return;
1218 }
1219 Signature = Mbr->Signature;
1220
1221 /* Calculate the MBR checksum */
1222 Checksum = 0;
1223 Buffer = (PULONG)Mbr;
1224 for (i = 0; i < 128; i++)
1225 {
1226 Checksum += Buffer[i];
1227 }
1228 Checksum = ~Checksum + 1;
1229
1230 RtlStringCchPrintfW(Identifier, ARRAYSIZE(Identifier),
1231 L"%08x-%08x-A", Checksum, Signature);
1232 DPRINT("Identifier: %S\n", Identifier);
1233
1234 DiskEntry = RtlAllocateHeap(ProcessHeap,
1235 HEAP_ZERO_MEMORY,
1236 sizeof(DISKENTRY));
1237 if (DiskEntry == NULL)
1238 {
1239 RtlFreeHeap(ProcessHeap, 0, Mbr);
1240 DPRINT1("Failed to allocate a new disk entry.\n");
1241 return;
1242 }
1243
1244 // DiskEntry->Checksum = Checksum;
1245 // DiskEntry->Signature = Signature;
1246 DiskEntry->BiosFound = FALSE;
1247
1248 /*
1249 * Check if this disk has a valid MBR: verify its signature,
1250 * and whether its two first bytes are a valid instruction
1251 * (related to this, see IsThereAValidBootSector() in partlist.c).
1252 */
1253 if (Mbr->Magic != 0xaa55 || (*(PUSHORT)Mbr->BootCode) == 0x0000)
1254 DiskEntry->NoMbr = TRUE;
1255 else
1256 DiskEntry->NoMbr = FALSE;
1257
1258 /* Free the MBR sector buffer */
1259 RtlFreeHeap(ProcessHeap, 0, Mbr);
1260
1261
1262 ListEntry = List->BiosDiskListHead.Flink;
1263 while (ListEntry != &List->BiosDiskListHead)
1264 {
1265 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
1266 /* FIXME:
1267 * Compare the size from bios and the reported size from driver.
1268 * If we have more than one disk with a zero or with the same signature
1269 * we must create new signatures and reboot. After the reboot,
1270 * it is possible to identify the disks.
1271 */
1272 if (BiosDiskEntry->Signature == Signature &&
1273 BiosDiskEntry->Checksum == Checksum &&
1274 !BiosDiskEntry->Recognized)
1275 {
1276 if (!DiskEntry->BiosFound)
1277 {
1278 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
1279 DiskEntry->BiosFound = TRUE;
1280 BiosDiskEntry->Recognized = TRUE;
1281 }
1282 else
1283 {
1284 // FIXME: What to do?
1285 }
1286 }
1287 ListEntry = ListEntry->Flink;
1288 }
1289
1290 if (!DiskEntry->BiosFound)
1291 {
1292 #if 0
1293 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1294 return;
1295 #else
1296 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
1297 #endif
1298 }
1299
1300 InitializeListHead(&DiskEntry->PrimaryPartListHead);
1301 InitializeListHead(&DiskEntry->LogicalPartListHead);
1302
1303 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
1304 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
1305 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
1306 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
1307
1308 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
1309 DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
1310 DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
1311 DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
1312
1313 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
1314 (ULONGLONG)DiskGeometry.TracksPerCylinder *
1315 (ULONGLONG)DiskGeometry.SectorsPerTrack;
1316
1317 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
1318 DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
1319 DiskGeometry.SectorsPerTrack;
1320
1321 DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
1322 DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
1323
1324 DiskEntry->DiskNumber = DiskNumber;
1325 DiskEntry->Port = ScsiAddress.PortNumber;
1326 DiskEntry->Bus = ScsiAddress.PathId;
1327 DiskEntry->Id = ScsiAddress.TargetId;
1328
1329 GetDriverName(DiskEntry);
1330 /*
1331 * Actually it would be more correct somehow to use:
1332 *
1333 * OBJECT_NAME_INFORMATION NameInfo; // ObjectNameInfo;
1334 * ULONG ReturnedLength;
1335 *
1336 * Status = NtQueryObject(SomeHandleToTheDisk,
1337 * ObjectNameInformation,
1338 * &NameInfo,
1339 * sizeof(NameInfo),
1340 * &ReturnedLength);
1341 * etc...
1342 *
1343 * See examples in https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/ntoskrnl/io/iomgr/error.c;hb=2f3a93ee9cec8322a86bf74b356f1ad83fc912dc#l267
1344 */
1345
1346 InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
1347
1348
1349 /*
1350 * We now retrieve the disk partition layout
1351 */
1352
1353 /* Allocate a layout buffer with 4 partition entries first */
1354 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
1355 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
1356 DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
1357 HEAP_ZERO_MEMORY,
1358 LayoutBufferSize);
1359 if (DiskEntry->LayoutBuffer == NULL)
1360 {
1361 DPRINT1("Failed to allocate the disk layout buffer!\n");
1362 return;
1363 }
1364
1365 /* Keep looping while the drive layout buffer is too small */
1366 for (;;)
1367 {
1368 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
1369 Status = NtDeviceIoControlFile(FileHandle,
1370 NULL,
1371 NULL,
1372 NULL,
1373 &Iosb,
1374 IOCTL_DISK_GET_DRIVE_LAYOUT,
1375 NULL,
1376 0,
1377 DiskEntry->LayoutBuffer,
1378 LayoutBufferSize);
1379 if (NT_SUCCESS(Status))
1380 break;
1381
1382 if (Status != STATUS_BUFFER_TOO_SMALL)
1383 {
1384 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
1385 return;
1386 }
1387
1388 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
1389 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
1390 HEAP_ZERO_MEMORY,
1391 DiskEntry->LayoutBuffer,
1392 LayoutBufferSize);
1393 if (NewLayoutBuffer == NULL)
1394 {
1395 DPRINT1("Failed to reallocate the disk layout buffer!\n");
1396 return;
1397 }
1398
1399 DiskEntry->LayoutBuffer = NewLayoutBuffer;
1400 }
1401
1402 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
1403
1404 #ifdef DUMP_PARTITION_TABLE
1405 DumpPartitionTable(DiskEntry);
1406 #endif
1407
1408 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1409 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1410 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
1411 {
1412 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1413 {
1414 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1415 }
1416 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1417 {
1418 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1419 }
1420 else
1421 {
1422 DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1423 }
1424 }
1425 else
1426 {
1427 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1428 }
1429
1430
1431 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1432 {
1433 DiskEntry->NewDisk = TRUE;
1434 DiskEntry->LayoutBuffer->PartitionCount = 4;
1435
1436 for (i = 0; i < 4; i++)
1437 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1438 }
1439 else
1440 {
1441 for (i = 0; i < 4; i++)
1442 {
1443 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1444 }
1445
1446 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1447 {
1448 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1449 }
1450 }
1451
1452 ScanForUnpartitionedDiskSpace(DiskEntry);
1453 }
1454
1455 PPARTLIST
1456 CreatePartitionList(VOID)
1457 {
1458 PPARTLIST List;
1459 OBJECT_ATTRIBUTES ObjectAttributes;
1460 SYSTEM_DEVICE_INFORMATION Sdi;
1461 IO_STATUS_BLOCK Iosb;
1462 ULONG ReturnSize;
1463 NTSTATUS Status;
1464 ULONG DiskNumber;
1465 WCHAR Buffer[MAX_PATH];
1466 UNICODE_STRING Name;
1467 HANDLE FileHandle;
1468
1469 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
1470 0,
1471 sizeof(PARTLIST));
1472 if (List == NULL)
1473 return NULL;
1474
1475 List->CurrentDisk = NULL;
1476 List->CurrentPartition = NULL;
1477
1478 List->SystemPartition = NULL;
1479 List->OriginalSystemPartition = NULL;
1480
1481 InitializeListHead(&List->DiskListHead);
1482 InitializeListHead(&List->BiosDiskListHead);
1483
1484 /*
1485 * Enumerate the disks seen by the BIOS; this will be used later
1486 * to map drives seen by NTOS with their corresponding BIOS names.
1487 */
1488 EnumerateBiosDiskEntries(List);
1489
1490 /* Enumerate disks seen by NTOS */
1491 Status = NtQuerySystemInformation(SystemDeviceInformation,
1492 &Sdi,
1493 sizeof(Sdi),
1494 &ReturnSize);
1495 if (!NT_SUCCESS(Status))
1496 {
1497 DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
1498 RtlFreeHeap(ProcessHeap, 0, List);
1499 return NULL;
1500 }
1501
1502 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1503 {
1504 RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
1505 L"\\Device\\Harddisk%lu\\Partition0",
1506 DiskNumber);
1507 RtlInitUnicodeString(&Name, Buffer);
1508
1509 InitializeObjectAttributes(&ObjectAttributes,
1510 &Name,
1511 OBJ_CASE_INSENSITIVE,
1512 NULL,
1513 NULL);
1514
1515 Status = NtOpenFile(&FileHandle,
1516 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1517 &ObjectAttributes,
1518 &Iosb,
1519 FILE_SHARE_READ | FILE_SHARE_WRITE,
1520 FILE_SYNCHRONOUS_IO_NONALERT);
1521 if (NT_SUCCESS(Status))
1522 {
1523 AddDiskToList(FileHandle, DiskNumber, List);
1524 NtClose(FileHandle);
1525 }
1526 }
1527
1528 UpdateDiskSignatures(List);
1529
1530 AssignDriveLetters(List);
1531
1532 /* Search for first usable disk and partition */
1533 if (IsListEmpty(&List->DiskListHead))
1534 {
1535 List->CurrentDisk = NULL;
1536 List->CurrentPartition = NULL;
1537 }
1538 else
1539 {
1540 List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
1541 DISKENTRY,
1542 ListEntry);
1543
1544 if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
1545 {
1546 List->CurrentPartition = NULL;
1547 }
1548 else
1549 {
1550 List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
1551 PARTENTRY,
1552 ListEntry);
1553 }
1554 }
1555
1556 return List;
1557 }
1558
1559 VOID
1560 DestroyPartitionList(
1561 IN PPARTLIST List)
1562 {
1563 PDISKENTRY DiskEntry;
1564 PBIOSDISKENTRY BiosDiskEntry;
1565 PPARTENTRY PartEntry;
1566 PLIST_ENTRY Entry;
1567
1568 /* Release disk and partition info */
1569 while (!IsListEmpty(&List->DiskListHead))
1570 {
1571 Entry = RemoveHeadList(&List->DiskListHead);
1572 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1573
1574 /* Release driver name */
1575 RtlFreeUnicodeString(&DiskEntry->DriverName);
1576
1577 /* Release primary partition list */
1578 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1579 {
1580 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1581 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1582
1583 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1584 }
1585
1586 /* Release logical partition list */
1587 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1588 {
1589 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1590 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1591
1592 RtlFreeHeap(ProcessHeap, 0, PartEntry);
1593 }
1594
1595 /* Release layout buffer */
1596 if (DiskEntry->LayoutBuffer != NULL)
1597 RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
1598
1599 /* Release disk entry */
1600 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
1601 }
1602
1603 /* Release the bios disk info */
1604 while (!IsListEmpty(&List->BiosDiskListHead))
1605 {
1606 Entry = RemoveHeadList(&List->BiosDiskListHead);
1607 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1608
1609 RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
1610 }
1611
1612 /* Release list head */
1613 RtlFreeHeap(ProcessHeap, 0, List);
1614 }
1615
1616 PDISKENTRY
1617 GetDiskByBiosNumber(
1618 IN PPARTLIST List,
1619 IN ULONG BiosDiskNumber)
1620 {
1621 PDISKENTRY DiskEntry;
1622 PLIST_ENTRY Entry;
1623
1624 /* Loop over the disks and find the correct one */
1625 Entry = List->DiskListHead.Flink;
1626 while (Entry != &List->DiskListHead)
1627 {
1628 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1629 Entry = Entry->Flink;
1630
1631 if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
1632 {
1633 /* Disk found */
1634 return DiskEntry;
1635 }
1636 }
1637
1638 /* Disk not found, stop there */
1639 return NULL;
1640 }
1641
1642 PDISKENTRY
1643 GetDiskByNumber(
1644 IN PPARTLIST List,
1645 IN ULONG DiskNumber)
1646 {
1647 PDISKENTRY DiskEntry;
1648 PLIST_ENTRY Entry;
1649
1650 /* Loop over the disks and find the correct one */
1651 Entry = List->DiskListHead.Flink;
1652 while (Entry != &List->DiskListHead)
1653 {
1654 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1655 Entry = Entry->Flink;
1656
1657 if (DiskEntry->DiskNumber == DiskNumber)
1658 {
1659 /* Disk found */
1660 return DiskEntry;
1661 }
1662 }
1663
1664 /* Disk not found, stop there */
1665 return NULL;
1666 }
1667
1668 PDISKENTRY
1669 GetDiskBySCSI(
1670 IN PPARTLIST List,
1671 IN USHORT Port,
1672 IN USHORT Bus,
1673 IN USHORT Id)
1674 {
1675 PDISKENTRY DiskEntry;
1676 PLIST_ENTRY Entry;
1677
1678 /* Loop over the disks and find the correct one */
1679 Entry = List->DiskListHead.Flink;
1680 while (Entry != &List->DiskListHead)
1681 {
1682 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1683 Entry = Entry->Flink;
1684
1685 if (DiskEntry->Port == Port &&
1686 DiskEntry->Bus == Bus &&
1687 DiskEntry->Id == Id)
1688 {
1689 /* Disk found */
1690 return DiskEntry;
1691 }
1692 }
1693
1694 /* Disk not found, stop there */
1695 return NULL;
1696 }
1697
1698 PDISKENTRY
1699 GetDiskBySignature(
1700 IN PPARTLIST List,
1701 IN ULONG Signature)
1702 {
1703 PDISKENTRY DiskEntry;
1704 PLIST_ENTRY Entry;
1705
1706 /* Loop over the disks and find the correct one */
1707 Entry = List->DiskListHead.Flink;
1708 while (Entry != &List->DiskListHead)
1709 {
1710 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1711 Entry = Entry->Flink;
1712
1713 if (DiskEntry->LayoutBuffer->Signature == Signature)
1714 {
1715 /* Disk found */
1716 return DiskEntry;
1717 }
1718 }
1719
1720 /* Disk not found, stop there */
1721 return NULL;
1722 }
1723
1724 PPARTENTRY
1725 GetPartition(
1726 // IN PPARTLIST List,
1727 IN PDISKENTRY DiskEntry,
1728 IN ULONG PartitionNumber)
1729 {
1730 PPARTENTRY PartEntry;
1731 PLIST_ENTRY Entry;
1732
1733 /* Disk found, loop over the primary partitions first... */
1734 Entry = DiskEntry->PrimaryPartListHead.Flink;
1735 while (Entry != &DiskEntry->PrimaryPartListHead)
1736 {
1737 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1738 Entry = Entry->Flink;
1739
1740 if (PartEntry->PartitionNumber == PartitionNumber)
1741 {
1742 /* Partition found */
1743 return PartEntry;
1744 }
1745 }
1746
1747 /* ... then over the logical partitions if needed */
1748 Entry = DiskEntry->LogicalPartListHead.Flink;
1749 while (Entry != &DiskEntry->LogicalPartListHead)
1750 {
1751 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1752 Entry = Entry->Flink;
1753
1754 if (PartEntry->PartitionNumber == PartitionNumber)
1755 {
1756 /* Partition found */
1757 return PartEntry;
1758 }
1759 }
1760
1761 /* The partition was not found on the disk, stop there */
1762 return NULL;
1763 }
1764
1765 BOOLEAN
1766 GetDiskOrPartition(
1767 IN PPARTLIST List,
1768 IN ULONG DiskNumber,
1769 IN ULONG PartitionNumber OPTIONAL,
1770 OUT PDISKENTRY* pDiskEntry,
1771 OUT PPARTENTRY* pPartEntry OPTIONAL)
1772 {
1773 PDISKENTRY DiskEntry;
1774 PPARTENTRY PartEntry = NULL;
1775
1776 /* Find the disk */
1777 DiskEntry = GetDiskByNumber(List, DiskNumber);
1778 if (!DiskEntry)
1779 return FALSE;
1780
1781 /* If we have a partition (PartitionNumber != 0), find it */
1782 if (PartitionNumber != 0)
1783 {
1784 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1785 if (!PartEntry)
1786 return FALSE;
1787 ASSERT(PartEntry->DiskEntry == DiskEntry);
1788 }
1789
1790 /* Return the disk (and optionally the partition) */
1791 *pDiskEntry = DiskEntry;
1792 if (pPartEntry) *pPartEntry = PartEntry;
1793 return TRUE;
1794 }
1795
1796 //
1797 // NOTE: Was introduced broken in r6258 by Casper
1798 //
1799 BOOLEAN
1800 SelectPartition(
1801 IN PPARTLIST List,
1802 IN ULONG DiskNumber,
1803 IN ULONG PartitionNumber)
1804 {
1805 PDISKENTRY DiskEntry;
1806 PPARTENTRY PartEntry;
1807
1808 DiskEntry = GetDiskByNumber(List, DiskNumber);
1809 if (!DiskEntry)
1810 return FALSE;
1811
1812 PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
1813 if (!PartEntry)
1814 return FALSE;
1815
1816 ASSERT(PartEntry->DiskEntry == DiskEntry);
1817 ASSERT(DiskEntry->DiskNumber == DiskNumber);
1818 ASSERT(PartEntry->PartitionNumber == PartitionNumber);
1819
1820 List->CurrentDisk = DiskEntry;
1821 List->CurrentPartition = PartEntry;
1822 return TRUE;
1823 }
1824
1825 PPARTENTRY
1826 GetNextPartition(
1827 IN PPARTLIST List)
1828 {
1829 PLIST_ENTRY DiskListEntry;
1830 PLIST_ENTRY PartListEntry;
1831 PDISKENTRY DiskEntry;
1832 PPARTENTRY PartEntry;
1833
1834 /* Fail if no disks are available */
1835 if (IsListEmpty(&List->DiskListHead))
1836 return NULL;
1837
1838 /* Check for next usable entry on current disk */
1839 if (List->CurrentPartition != NULL)
1840 {
1841 if (List->CurrentPartition->LogicalPartition)
1842 {
1843 /* Logical partition */
1844
1845 PartListEntry = List->CurrentPartition->ListEntry.Flink;
1846 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1847 {
1848 /* Next logical partition */
1849 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1850
1851 List->CurrentPartition = PartEntry;
1852 return List->CurrentPartition;
1853 }
1854 else
1855 {
1856 PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
1857 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1858 {
1859 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1860
1861 List->CurrentPartition = PartEntry;
1862 return List->CurrentPartition;
1863 }
1864 }
1865 }
1866 else
1867 {
1868 /* Primary or extended partition */
1869
1870 if ((List->CurrentPartition->IsPartitioned != FALSE) &&
1871 IsContainerPartition(List->CurrentPartition->PartitionType))
1872 {
1873 /* First logical partition */
1874 PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
1875 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1876 {
1877 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1878
1879 List->CurrentPartition = PartEntry;
1880 return List->CurrentPartition;
1881 }
1882 }
1883 else
1884 {
1885 /* Next primary partition */
1886 PartListEntry = List->CurrentPartition->ListEntry.Flink;
1887 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1888 {
1889 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1890
1891 List->CurrentPartition = PartEntry;
1892 return List->CurrentPartition;
1893 }
1894 }
1895 }
1896 }
1897
1898 /* Search for the first partition entry on the next disk */
1899 DiskListEntry = List->CurrentDisk->ListEntry.Flink;
1900 while (DiskListEntry != &List->DiskListHead)
1901 {
1902 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
1903
1904 PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
1905 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
1906 {
1907 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1908
1909 List->CurrentDisk = DiskEntry;
1910 List->CurrentPartition = PartEntry;
1911 return List->CurrentPartition;
1912 }
1913
1914 DiskListEntry = DiskListEntry->Flink;
1915 }
1916
1917 return NULL;
1918 }
1919
1920 PPARTENTRY
1921 GetPrevPartition(
1922 IN PPARTLIST List)
1923 {
1924 PLIST_ENTRY DiskListEntry;
1925 PLIST_ENTRY PartListEntry;
1926 PDISKENTRY DiskEntry;
1927 PPARTENTRY PartEntry;
1928
1929 /* Fail if no disks are available */
1930 if (IsListEmpty(&List->DiskListHead))
1931 return NULL;
1932
1933 /* Check for previous usable entry on current disk */
1934 if (List->CurrentPartition != NULL)
1935 {
1936 if (List->CurrentPartition->LogicalPartition)
1937 {
1938 /* Logical partition */
1939 PartListEntry = List->CurrentPartition->ListEntry.Blink;
1940 if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
1941 {
1942 /* Previous logical partition */
1943 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1944 }
1945 else
1946 {
1947 /* Extended partition */
1948 PartEntry = List->CurrentDisk->ExtendedPartition;
1949 }
1950
1951 List->CurrentPartition = PartEntry;
1952 return List->CurrentPartition;
1953 }
1954 else
1955 {
1956 /* Primary or extended partition */
1957
1958 PartListEntry = List->CurrentPartition->ListEntry.Blink;
1959 if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
1960 {
1961 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1962
1963 if ((PartEntry->IsPartitioned != FALSE) &&
1964 IsContainerPartition(PartEntry->PartitionType))
1965 {
1966 PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
1967 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1968 }
1969
1970 List->CurrentPartition = PartEntry;
1971 return List->CurrentPartition;
1972 }
1973 }
1974 }
1975
1976 /* Search for the last partition entry on the previous disk */
1977 DiskListEntry = List->CurrentDisk->ListEntry.Blink;
1978 while (DiskListEntry != &List->DiskListHead)
1979 {
1980 DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
1981
1982 PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
1983 if (PartListEntry != &DiskEntry->PrimaryPartListHead)
1984 {
1985 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1986
1987 if ((PartEntry->IsPartitioned != FALSE) &&
1988 IsContainerPartition(PartEntry->PartitionType))
1989 {
1990 PartListEntry = DiskEntry->LogicalPartListHead.Blink;
1991 if (PartListEntry != &DiskEntry->LogicalPartListHead)
1992 {
1993 PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
1994
1995 List->CurrentDisk = DiskEntry;
1996 List->CurrentPartition = PartEntry;
1997 return List->CurrentPartition;
1998 }
1999 }
2000 else
2001 {
2002 List->CurrentDisk = DiskEntry;
2003 List->CurrentPartition = PartEntry;
2004 return List->CurrentPartition;
2005 }
2006 }
2007
2008 DiskListEntry = DiskListEntry->Blink;
2009 }
2010
2011 return NULL;
2012 }
2013
2014 // static
2015 FORCEINLINE
2016 BOOLEAN
2017 IsEmptyLayoutEntry(
2018 IN PPARTITION_INFORMATION PartitionInfo)
2019 {
2020 if (PartitionInfo->StartingOffset.QuadPart == 0 &&
2021 PartitionInfo->PartitionLength.QuadPart == 0)
2022 {
2023 return TRUE;
2024 }
2025
2026 return FALSE;
2027 }
2028
2029 // static
2030 FORCEINLINE
2031 BOOLEAN
2032 IsSamePrimaryLayoutEntry(
2033 IN PPARTITION_INFORMATION PartitionInfo,
2034 IN PDISKENTRY DiskEntry,
2035 IN PPARTENTRY PartEntry)
2036 {
2037 if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
2038 PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
2039 // PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
2040 // PartitionInfo->PartitionType == PartEntry->PartitionType
2041 {
2042 return TRUE;
2043 }
2044
2045 return FALSE;
2046 }
2047
2048 static
2049 ULONG
2050 GetPrimaryPartitionCount(
2051 IN PDISKENTRY DiskEntry)
2052 {
2053 PLIST_ENTRY Entry;
2054 PPARTENTRY PartEntry;
2055 ULONG Count = 0;
2056
2057 Entry = DiskEntry->PrimaryPartListHead.Flink;
2058 while (Entry != &DiskEntry->PrimaryPartListHead)
2059 {
2060 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2061 if (PartEntry->IsPartitioned)
2062 Count++;
2063
2064 Entry = Entry->Flink;
2065 }
2066
2067 return Count;
2068 }
2069
2070 static
2071 ULONG
2072 GetLogicalPartitionCount(
2073 IN PDISKENTRY DiskEntry)
2074 {
2075 PLIST_ENTRY ListEntry;
2076 PPARTENTRY PartEntry;
2077 ULONG Count = 0;
2078
2079 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2080 while (ListEntry != &DiskEntry->LogicalPartListHead)
2081 {
2082 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2083 if (PartEntry->IsPartitioned)
2084 Count++;
2085
2086 ListEntry = ListEntry->Flink;
2087 }
2088
2089 return Count;
2090 }
2091
2092 static
2093 BOOLEAN
2094 ReAllocateLayoutBuffer(
2095 IN PDISKENTRY DiskEntry)
2096 {
2097 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
2098 ULONG NewPartitionCount;
2099 ULONG CurrentPartitionCount = 0;
2100 ULONG LayoutBufferSize;
2101 ULONG i;
2102
2103 DPRINT1("ReAllocateLayoutBuffer()\n");
2104
2105 NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
2106
2107 if (DiskEntry->LayoutBuffer)
2108 CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
2109
2110 DPRINT1("CurrentPartitionCount: %lu NewPartitionCount: %lu\n",
2111 CurrentPartitionCount, NewPartitionCount);
2112
2113 if (CurrentPartitionCount == NewPartitionCount)
2114 return TRUE;
2115
2116 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
2117 ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
2118 NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
2119 HEAP_ZERO_MEMORY,
2120 DiskEntry->LayoutBuffer,
2121 LayoutBufferSize);
2122 if (NewLayoutBuffer == NULL)
2123 {
2124 DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
2125 return FALSE;
2126 }
2127
2128 /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
2129 if (NewPartitionCount > CurrentPartitionCount)
2130 {
2131 for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
2132 NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
2133 }
2134
2135 DiskEntry->LayoutBuffer = NewLayoutBuffer;
2136 DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
2137
2138 return TRUE;
2139 }
2140
2141 static
2142 VOID
2143 UpdateDiskLayout(
2144 IN PDISKENTRY DiskEntry)
2145 {
2146 PPARTITION_INFORMATION PartitionInfo;
2147 PPARTITION_INFORMATION LinkInfo = NULL;
2148 PLIST_ENTRY ListEntry;
2149 PPARTENTRY PartEntry;
2150 LARGE_INTEGER HiddenSectors64;
2151 ULONG Index;
2152 ULONG PartitionNumber = 1;
2153
2154 DPRINT1("UpdateDiskLayout()\n");
2155
2156 /* Resize the layout buffer if necessary */
2157 if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
2158 {
2159 DPRINT("ReAllocateLayoutBuffer() failed.\n");
2160 return;
2161 }
2162
2163 /* Update the primary partition table */
2164 Index = 0;
2165 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2166 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2167 {
2168 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2169
2170 if (PartEntry->IsPartitioned != FALSE)
2171 {
2172 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2173
2174 if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
2175 {
2176 DPRINT1("Updating primary partition entry %lu\n", Index);
2177
2178 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2179 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2180 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
2181 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2182 PartitionInfo->PartitionType = PartEntry->PartitionType;
2183 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
2184 PartitionInfo->RecognizedPartition = FALSE;
2185 PartitionInfo->RewritePartition = TRUE;
2186 }
2187
2188 PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
2189 PartEntry->PartitionIndex = Index;
2190
2191 if (!IsContainerPartition(PartEntry->PartitionType))
2192 PartitionNumber++;
2193
2194 Index++;
2195 }
2196
2197 ListEntry = ListEntry->Flink;
2198 }
2199
2200 /* Update the logical partition table */
2201 Index = 4;
2202 ListEntry = DiskEntry->LogicalPartListHead.Flink;
2203 while (ListEntry != &DiskEntry->LogicalPartListHead)
2204 {
2205 PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
2206
2207 if (PartEntry->IsPartitioned)
2208 {
2209 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2210
2211 DPRINT1("Updating logical partition entry %lu\n", Index);
2212
2213 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
2214 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
2215 PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
2216 PartitionInfo->PartitionNumber = PartitionNumber;
2217 PartitionInfo->PartitionType = PartEntry->PartitionType;
2218 PartitionInfo->BootIndicator = FALSE;
2219 PartitionInfo->RecognizedPartition = FALSE;
2220 PartitionInfo->RewritePartition = TRUE;
2221
2222 PartEntry->PartitionNumber = PartitionNumber;
2223 PartEntry->PartitionIndex = Index;
2224
2225 /* Fill the link entry of the previous partition entry */
2226 if (LinkInfo != NULL)
2227 {
2228 LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2229 LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
2230 HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
2231 LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
2232 LinkInfo->PartitionNumber = 0;
2233 LinkInfo->PartitionType = PARTITION_EXTENDED;
2234 LinkInfo->BootIndicator = FALSE;
2235 LinkInfo->RecognizedPartition = FALSE;
2236 LinkInfo->RewritePartition = TRUE;
2237 }
2238
2239 /* Save a pointer to the link entry of the current partition entry */
2240 LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
2241
2242 PartitionNumber++;
2243 Index += 4;
2244 }
2245
2246 ListEntry = ListEntry->Flink;
2247 }
2248
2249 /* Wipe unused primary partition entries */
2250 for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
2251 {
2252 DPRINT1("Primary partition entry %lu\n", Index);
2253
2254 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2255
2256 if (!IsEmptyLayoutEntry(PartitionInfo))
2257 {
2258 DPRINT1("Wiping primary partition entry %lu\n", Index);
2259
2260 PartitionInfo->StartingOffset.QuadPart = 0;
2261 PartitionInfo->PartitionLength.QuadPart = 0;
2262 PartitionInfo->HiddenSectors = 0;
2263 PartitionInfo->PartitionNumber = 0;
2264 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2265 PartitionInfo->BootIndicator = FALSE;
2266 PartitionInfo->RecognizedPartition = FALSE;
2267 PartitionInfo->RewritePartition = TRUE;
2268 }
2269 }
2270
2271 /* Wipe unused logical partition entries */
2272 for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
2273 {
2274 if (Index % 4 >= 2)
2275 {
2276 DPRINT1("Logical partition entry %lu\n", Index);
2277
2278 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
2279
2280 if (!IsEmptyLayoutEntry(PartitionInfo))
2281 {
2282 DPRINT1("Wiping partition entry %lu\n", Index);
2283
2284 PartitionInfo->StartingOffset.QuadPart = 0;
2285 PartitionInfo->PartitionLength.QuadPart = 0;
2286 PartitionInfo->HiddenSectors = 0;
2287 PartitionInfo->PartitionNumber = 0;
2288 PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
2289 PartitionInfo->BootIndicator = FALSE;
2290 PartitionInfo->RecognizedPartition = FALSE;
2291 PartitionInfo->RewritePartition = TRUE;
2292 }
2293 }
2294 }
2295
2296 #ifdef DUMP_PARTITION_TABLE
2297 DumpPartitionTable(DiskEntry);
2298 #endif
2299 }
2300
2301 static
2302 PPARTENTRY
2303 GetPrevUnpartitionedEntry(
2304 IN PDISKENTRY DiskEntry,
2305 IN PPARTENTRY PartEntry)
2306 {
2307 PPARTENTRY PrevPartEntry;
2308 PLIST_ENTRY ListHead;
2309
2310 if (PartEntry->LogicalPartition)
2311 ListHead = &DiskEntry->LogicalPartListHead;
2312 else
2313 ListHead = &DiskEntry->PrimaryPartListHead;
2314
2315 if (PartEntry->ListEntry.Blink != ListHead)
2316 {
2317 PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
2318 PARTENTRY,
2319 ListEntry);
2320 if (PrevPartEntry->IsPartitioned == FALSE)
2321 return PrevPartEntry;
2322 }
2323
2324 return NULL;
2325 }
2326
2327 static
2328 PPARTENTRY
2329 GetNextUnpartitionedEntry(
2330 IN PDISKENTRY DiskEntry,
2331 IN PPARTENTRY PartEntry)
2332 {
2333 PPARTENTRY NextPartEntry;
2334 PLIST_ENTRY ListHead;
2335
2336 if (PartEntry->LogicalPartition)
2337 ListHead = &DiskEntry->LogicalPartListHead;
2338 else
2339 ListHead = &DiskEntry->PrimaryPartListHead;
2340
2341 if (PartEntry->ListEntry.Flink != ListHead)
2342 {
2343 NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
2344 PARTENTRY,
2345 ListEntry);
2346 if (NextPartEntry->IsPartitioned == FALSE)
2347 return NextPartEntry;
2348 }
2349
2350 return NULL;
2351 }
2352
2353 VOID
2354 CreatePrimaryPartition(
2355 IN PPARTLIST List,
2356 IN ULONGLONG SectorCount,
2357 IN BOOLEAN AutoCreate)
2358 {
2359 PDISKENTRY DiskEntry;
2360 PPARTENTRY PartEntry;
2361 PPARTENTRY NewPartEntry;
2362
2363 DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
2364
2365 if (List == NULL ||
2366 List->CurrentDisk == NULL ||
2367 List->CurrentPartition == NULL ||
2368 List->CurrentPartition->IsPartitioned != FALSE)
2369 {
2370 return;
2371 }
2372
2373 DiskEntry = List->CurrentDisk;
2374 PartEntry = List->CurrentPartition;
2375
2376 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2377
2378 if ((AutoCreate != FALSE) ||
2379 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2380 {
2381 DPRINT1("Convert existing partition entry\n");
2382
2383 /* Convert current entry to 'new (unformatted)' */
2384 PartEntry->IsPartitioned = TRUE;
2385 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2386 PartEntry->FormatState = Unformatted;
2387 PartEntry->FileSystem = NULL;
2388 PartEntry->AutoCreate = AutoCreate;
2389 PartEntry->New = TRUE;
2390 PartEntry->BootIndicator = FALSE;
2391
2392 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2393 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2394 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2395 }
2396 else
2397 {
2398 DPRINT1("Add new partition entry\n");
2399
2400 /* Insert and initialize a new partition entry */
2401 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2402 HEAP_ZERO_MEMORY,
2403 sizeof(PARTENTRY));
2404 if (NewPartEntry == NULL)
2405 return;
2406
2407 /* Insert the new entry into the list */
2408 InsertTailList(&PartEntry->ListEntry,
2409 &NewPartEntry->ListEntry);
2410
2411 NewPartEntry->DiskEntry = DiskEntry;
2412
2413 NewPartEntry->IsPartitioned = TRUE;
2414 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2415 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2416 NewPartEntry->StartSector.QuadPart;
2417 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2418
2419 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2420 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2421 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2422
2423 NewPartEntry->New = TRUE;
2424 NewPartEntry->FormatState = Unformatted;
2425 NewPartEntry->FileSystem = NULL;
2426 NewPartEntry->BootIndicator = FALSE;
2427
2428 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2429 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2430 }
2431
2432 UpdateDiskLayout(DiskEntry);
2433
2434 DiskEntry->Dirty = TRUE;
2435
2436 AssignDriveLetters(List);
2437 }
2438
2439 static
2440 VOID
2441 AddLogicalDiskSpace(
2442 IN PDISKENTRY DiskEntry)
2443 {
2444 PPARTENTRY NewPartEntry;
2445
2446 DPRINT1("AddLogicalDiskSpace()\n");
2447
2448 /* Create a partition entry that represents the empty space in the container partition */
2449 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2450 HEAP_ZERO_MEMORY,
2451 sizeof(PARTENTRY));
2452 if (NewPartEntry == NULL)
2453 return;
2454
2455 NewPartEntry->DiskEntry = DiskEntry;
2456 NewPartEntry->LogicalPartition = TRUE;
2457
2458 NewPartEntry->IsPartitioned = FALSE;
2459 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
2460 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
2461
2462 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2463 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2464 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2465
2466 NewPartEntry->FormatState = Unformatted;
2467 NewPartEntry->FileSystem = NULL;
2468
2469 InsertTailList(&DiskEntry->LogicalPartListHead,
2470 &NewPartEntry->ListEntry);
2471 }
2472
2473 VOID
2474 CreateExtendedPartition(
2475 IN PPARTLIST List,
2476 IN ULONGLONG SectorCount)
2477 {
2478 PDISKENTRY DiskEntry;
2479 PPARTENTRY PartEntry;
2480 PPARTENTRY NewPartEntry;
2481
2482 DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
2483
2484 if (List == NULL ||
2485 List->CurrentDisk == NULL ||
2486 List->CurrentPartition == NULL ||
2487 List->CurrentPartition->IsPartitioned != FALSE)
2488 {
2489 return;
2490 }
2491
2492 DiskEntry = List->CurrentDisk;
2493 PartEntry = List->CurrentPartition;
2494
2495 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2496
2497 if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
2498 {
2499 DPRINT1("Convert existing partition entry\n");
2500
2501 /* Convert current entry to 'new (unformatted)' */
2502 PartEntry->IsPartitioned = TRUE;
2503 PartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2504 PartEntry->FileSystem = NULL;
2505 PartEntry->AutoCreate = FALSE;
2506 PartEntry->New = FALSE;
2507 PartEntry->BootIndicator = FALSE;
2508
2509 if (PartEntry->StartSector.QuadPart < 1450560)
2510 {
2511 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2512 PartEntry->PartitionType = PARTITION_EXTENDED;
2513 }
2514 else
2515 {
2516 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2517 PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2518 }
2519
2520 DiskEntry->ExtendedPartition = PartEntry;
2521
2522 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2523 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2524 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2525 }
2526 else
2527 {
2528 DPRINT1("Add new partition entry\n");
2529
2530 /* Insert and initialize a new partition entry */
2531 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2532 HEAP_ZERO_MEMORY,
2533 sizeof(PARTENTRY));
2534 if (NewPartEntry == NULL)
2535 return;
2536
2537 /* Insert the new entry into the list */
2538 InsertTailList(&PartEntry->ListEntry,
2539 &NewPartEntry->ListEntry);
2540
2541 NewPartEntry->DiskEntry = DiskEntry;
2542
2543 NewPartEntry->IsPartitioned = TRUE;
2544 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2545 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2546 NewPartEntry->StartSector.QuadPart;
2547
2548 NewPartEntry->New = FALSE;
2549 NewPartEntry->FormatState = Formatted; // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
2550 NewPartEntry->FileSystem = NULL;
2551 NewPartEntry->BootIndicator = FALSE;
2552
2553 if (NewPartEntry->StartSector.QuadPart < 1450560)
2554 {
2555 /* Partition starts below the 8.4GB boundary ==> CHS partition */
2556 NewPartEntry->PartitionType = PARTITION_EXTENDED;
2557 }
2558 else
2559 {
2560 /* Partition starts above the 8.4GB boundary ==> LBA partition */
2561 NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
2562 }
2563
2564 DiskEntry->ExtendedPartition = NewPartEntry;
2565
2566 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2567 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2568
2569 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2570 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2571 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2572 }
2573
2574 AddLogicalDiskSpace(DiskEntry);
2575
2576 UpdateDiskLayout(DiskEntry);
2577
2578 DiskEntry->Dirty = TRUE;
2579
2580 AssignDriveLetters(List);
2581 }
2582
2583 VOID
2584 CreateLogicalPartition(
2585 IN PPARTLIST List,
2586 IN ULONGLONG SectorCount,
2587 IN BOOLEAN AutoCreate)
2588 {
2589 PDISKENTRY DiskEntry;
2590 PPARTENTRY PartEntry;
2591 PPARTENTRY NewPartEntry;
2592
2593 DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
2594
2595 if (List == NULL ||
2596 List->CurrentDisk == NULL ||
2597 List->CurrentPartition == NULL ||
2598 List->CurrentPartition->IsPartitioned != FALSE)
2599 {
2600 return;
2601 }
2602
2603 DiskEntry = List->CurrentDisk;
2604 PartEntry = List->CurrentPartition;
2605
2606 DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
2607
2608 if ((AutoCreate != FALSE) ||
2609 (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
2610 {
2611 DPRINT1("Convert existing partition entry\n");
2612
2613 /* Convert current entry to 'new (unformatted)' */
2614 PartEntry->IsPartitioned = TRUE;
2615 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2616 PartEntry->FormatState = Unformatted;
2617 PartEntry->FileSystem = NULL;
2618 PartEntry->AutoCreate = FALSE;
2619 PartEntry->New = TRUE;
2620 PartEntry->BootIndicator = FALSE;
2621 PartEntry->LogicalPartition = TRUE;
2622
2623 DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
2624 DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
2625 DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
2626 }
2627 else
2628 {
2629 DPRINT1("Add new partition entry\n");
2630
2631 /* Insert and initialize a new partition entry */
2632 NewPartEntry = RtlAllocateHeap(ProcessHeap,
2633 HEAP_ZERO_MEMORY,
2634 sizeof(PARTENTRY));
2635 if (NewPartEntry == NULL)
2636 return;
2637
2638 /* Insert the new entry into the list */
2639 InsertTailList(&PartEntry->ListEntry,
2640 &NewPartEntry->ListEntry);
2641
2642 NewPartEntry->DiskEntry = DiskEntry;
2643
2644 NewPartEntry->IsPartitioned = TRUE;
2645 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2646 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
2647 NewPartEntry->StartSector.QuadPart;
2648 NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2649
2650 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
2651 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
2652 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
2653
2654 NewPartEntry->New = TRUE;
2655 NewPartEntry->FormatState = Unformatted;
2656 NewPartEntry->FileSystem = NULL;
2657 NewPartEntry->BootIndicator = FALSE;
2658 NewPartEntry->LogicalPartition = TRUE;
2659
2660 PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
2661 PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
2662 }
2663
2664 UpdateDiskLayout(DiskEntry);
2665
2666 DiskEntry->Dirty = TRUE;
2667
2668 AssignDriveLetters(List);
2669 }
2670
2671 VOID
2672 DeleteCurrentPartition(
2673 IN PPARTLIST List)
2674 {
2675 PDISKENTRY DiskEntry;
2676 PPARTENTRY PartEntry;
2677 PPARTENTRY PrevPartEntry;
2678 PPARTENTRY NextPartEntry;
2679 PPARTENTRY LogicalPartEntry;
2680 PLIST_ENTRY Entry;
2681
2682 if (List == NULL ||
2683 List->CurrentDisk == NULL ||
2684 List->CurrentPartition == NULL ||
2685 List->CurrentPartition->IsPartitioned == FALSE)
2686 {
2687 return;
2688 }
2689
2690 /* Clear the system disk and partition pointers if the system partition is being deleted */
2691 if (List->SystemPartition == List->CurrentPartition)
2692 {
2693 List->SystemPartition = NULL;
2694 }
2695
2696 DiskEntry = List->CurrentDisk;
2697 PartEntry = List->CurrentPartition;
2698
2699 /* Delete all logical partition entries if an extended partition will be deleted */
2700 if (DiskEntry->ExtendedPartition == PartEntry)
2701 {
2702 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
2703 {
2704 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
2705 LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
2706
2707 RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
2708 }
2709
2710 DiskEntry->ExtendedPartition = NULL;
2711 }
2712
2713 /* Adjust unpartitioned disk space entries */
2714
2715 /* Get pointer to previous and next unpartitioned entries */
2716 PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
2717 NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
2718
2719 if (PrevPartEntry != NULL && NextPartEntry != NULL)
2720 {
2721 /* Merge previous, current and next unpartitioned entry */
2722
2723 /* Adjust the previous entries length */
2724 PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
2725
2726 /* Remove the current entry */
2727 RemoveEntryList(&PartEntry->ListEntry);
2728 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2729
2730 /* Remove the next entry */
2731 RemoveEntryList(&NextPartEntry->ListEntry);
2732 RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
2733
2734 /* Update current partition */
2735 List->CurrentPartition = PrevPartEntry;
2736 }
2737 else if (PrevPartEntry != NULL && NextPartEntry == NULL)
2738 {
2739 /* Merge current and previous unpartitioned entry */
2740
2741 /* Adjust the previous entries length */
2742 PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2743
2744 /* Remove the current entry */
2745 RemoveEntryList(&PartEntry->ListEntry);
2746 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2747
2748 /* Update current partition */
2749 List->CurrentPartition = PrevPartEntry;
2750 }
2751 else if (PrevPartEntry == NULL && NextPartEntry != NULL)
2752 {
2753 /* Merge current and next unpartitioned entry */
2754
2755 /* Adjust the next entries offset and length */
2756 NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
2757 NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
2758
2759 /* Remove the current entry */
2760 RemoveEntryList(&PartEntry->ListEntry);
2761 RtlFreeHeap(ProcessHeap, 0, PartEntry);
2762
2763 /* Update current partition */
2764 List->CurrentPartition = NextPartEntry;
2765 }
2766 else
2767 {
2768 /* Nothing to merge but change current entry */
2769 PartEntry->IsPartitioned = FALSE;
2770 PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
2771 PartEntry->FormatState = Unformatted;
2772 PartEntry->FileSystem = NULL;
2773 PartEntry->DriveLetter = 0;
2774 }
2775
2776 UpdateDiskLayout(DiskEntry);
2777
2778 DiskEntry->Dirty = TRUE;
2779
2780 AssignDriveLetters(List);
2781 }
2782
2783 VOID
2784 CheckActiveSystemPartition(
2785 IN PPARTLIST List)
2786 {
2787 PDISKENTRY DiskEntry;
2788 PPARTENTRY PartEntry;
2789 PLIST_ENTRY ListEntry;
2790
2791 PFILE_SYSTEM FileSystem;
2792
2793 /* Check for empty disk list */
2794 if (IsListEmpty(&List->DiskListHead))
2795 {
2796 List->SystemPartition = NULL;
2797 List->OriginalSystemPartition = NULL;
2798 return;
2799 }
2800
2801 /* Choose the currently selected disk */
2802 DiskEntry = List->CurrentDisk;
2803
2804 /* Check for empty partition list */
2805 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
2806 {
2807 List->SystemPartition = NULL;
2808 List->OriginalSystemPartition = NULL;
2809 return;
2810 }
2811
2812 if (List->SystemPartition != NULL)
2813 {
2814 /* We already have an active system partition */
2815 DPRINT1("Use the current system partition %lu in disk %lu, drive letter %C\n",
2816 List->SystemPartition->PartitionNumber,
2817 List->SystemPartition->DiskEntry->DiskNumber,
2818 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2819 return;
2820 }
2821
2822 DPRINT1("We are here (1)!\n");
2823
2824 List->SystemPartition = NULL;
2825 List->OriginalSystemPartition = NULL;
2826
2827 /* Retrieve the first partition of the disk */
2828 PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
2829 PARTENTRY,
2830 ListEntry);
2831 ASSERT(DiskEntry == PartEntry->DiskEntry);
2832 List->SystemPartition = PartEntry;
2833
2834 //
2835 // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
2836 //
2837
2838 /* Check if the disk is new and if so, use its first partition as the active system partition */
2839 if (DiskEntry->NewDisk)
2840 {
2841 if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE)
2842 {
2843 ASSERT(DiskEntry == PartEntry->DiskEntry);
2844 List->SystemPartition = PartEntry;
2845
2846 List->OriginalSystemPartition = List->SystemPartition;
2847
2848 DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %C\n",
2849 List->SystemPartition->PartitionNumber,
2850 List->SystemPartition->DiskEntry->DiskNumber,
2851 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2852
2853 goto SetSystemPartition;
2854 }
2855
2856 // FIXME: What to do??
2857 DPRINT1("NewDisk TRUE but first partition is used?\n");
2858 }
2859
2860 DPRINT1("We are here (2)!\n");
2861
2862 /*
2863 * The disk is not new, check if any partition is initialized;
2864 * if not, the first one becomes the system partition.
2865 */
2866 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2867 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2868 {
2869 /* Retrieve the partition and go to the next one */
2870 PartEntry = CONTAINING_RECORD(ListEntry,
2871 PARTENTRY,
2872 ListEntry);
2873
2874 /* Check if the partition is partitioned and is used */
2875 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
2876 {
2877 break;
2878 }
2879
2880 /* Go to the next one */
2881 ListEntry = ListEntry->Flink;
2882 }
2883 if (ListEntry == &DiskEntry->PrimaryPartListHead)
2884 {
2885 /*
2886 * OK we haven't encountered any used and active partition,
2887 * so use the first one as the system partition.
2888 */
2889 ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
2890 List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
2891
2892 DPRINT1("Use first active system partition %lu in disk %lu, drive letter %C\n",
2893 List->SystemPartition->PartitionNumber,
2894 List->SystemPartition->DiskEntry->DiskNumber,
2895 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2896
2897 goto SetSystemPartition;
2898 }
2899
2900 List->SystemPartition = NULL;
2901 List->OriginalSystemPartition = NULL;
2902
2903 DPRINT1("We are here (3)!\n");
2904
2905 /* The disk is not new, scan all partitions to find the (active) system partition */
2906 ListEntry = DiskEntry->PrimaryPartListHead.Flink;
2907 while (ListEntry != &DiskEntry->PrimaryPartListHead)
2908 {
2909 /* Retrieve the partition and go to the next one */
2910 PartEntry = CONTAINING_RECORD(ListEntry,
2911 PARTENTRY,
2912 ListEntry);
2913 ListEntry = ListEntry->Flink;
2914
2915 /* Check if the partition is partitioned and used */
2916 if (PartEntry->IsPartitioned &&
2917 PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
2918 {
2919 /* Check if the partition is active */
2920 if (PartEntry->BootIndicator)
2921 {
2922 /* Yes, we found it */
2923 ASSERT(DiskEntry == PartEntry->DiskEntry);
2924 List->SystemPartition = PartEntry;
2925
2926 DPRINT1("Found active system partition %lu in disk %lu, drive letter %C\n",
2927 PartEntry->PartitionNumber,
2928 DiskEntry->DiskNumber,
2929 (PartEntry->DriveLetter == 0) ? L'-' : PartEntry->DriveLetter);
2930 break;
2931 }
2932 }
2933 }
2934
2935 /* Check if we have found the system partition */
2936 if (List->SystemPartition == NULL)
2937 {
2938 /* Nothing, use the alternative system partition */
2939 DPRINT1("No system partition found, use the alternative partition!\n");
2940 goto UseAlternativeSystemPartition;
2941 }
2942
2943 /* Save it */
2944 List->OriginalSystemPartition = List->SystemPartition;
2945
2946 /*
2947 * ADDITIONAL CHECKS / BIG HACK:
2948 *
2949 * Retrieve its file system and check whether we have
2950 * write support for it. If that is the case we are fine
2951 * and we can use it directly. However if we don't have
2952 * write support we will need to change the active system
2953 * partition.
2954 *
2955 * NOTE that this is completely useless on architectures
2956 * where a real system partition is required, as on these
2957 * architectures the partition uses the FAT FS, for which
2958 * we do have write support.
2959 * NOTE also that for those architectures looking for a
2960 * partition boot indicator is insufficient.
2961 */
2962 FileSystem = GetFileSystem(List->OriginalSystemPartition);
2963 if (FileSystem == NULL)
2964 {
2965 DPRINT1("System partition %lu in disk %lu with no FS?!\n",
2966 List->OriginalSystemPartition->PartitionNumber,
2967 List->OriginalSystemPartition->DiskEntry->DiskNumber);
2968 goto FindAndUseAlternativeSystemPartition;
2969 }
2970 // HACK: WARNING: We cannot write on this FS yet!
2971 // See fsutil.c:GetFileSystem()
2972 if (List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
2973 {
2974 DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
2975 FileSystem->FileSystemName);
2976 goto FindAndUseAlternativeSystemPartition;
2977 }
2978
2979 DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
2980 List->SystemPartition->PartitionNumber,
2981 List->SystemPartition->DiskEntry->DiskNumber,
2982 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
2983
2984 return;
2985
2986 FindAndUseAlternativeSystemPartition:
2987 /*
2988 * We are here because we have not found any (active) candidate
2989 * system partition that we know how to support. What we are going
2990 * to do is to change the existing system partition and use the
2991 * partition on which we install ReactOS as the new system partition,
2992 * and then we will need to add in FreeLdr's entry a boot entry to boot
2993 * from the original system partition.
2994 */
2995
2996 /* Unset the old system partition */
2997 List->SystemPartition->BootIndicator = FALSE;
2998 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE;
2999 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3000 List->SystemPartition->DiskEntry->Dirty = TRUE;
3001
3002 UseAlternativeSystemPartition:
3003 List->SystemPartition = List->CurrentPartition;
3004
3005 DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
3006 List->SystemPartition->PartitionNumber,
3007 List->SystemPartition->DiskEntry->DiskNumber,
3008 (List->SystemPartition->DriveLetter == 0) ? L'-' : List->SystemPartition->DriveLetter);
3009
3010 SetSystemPartition:
3011 /* Set the new active system partition */
3012 List->SystemPartition->BootIndicator = TRUE;
3013 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
3014 List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
3015 List->SystemPartition->DiskEntry->Dirty = TRUE;
3016 }
3017
3018 static
3019 NTSTATUS
3020 WritePartitions(
3021 IN PPARTLIST List,
3022 IN PDISKENTRY DiskEntry)
3023 {
3024 WCHAR DstPath[MAX_PATH];
3025 OBJECT_ATTRIBUTES ObjectAttributes;
3026 IO_STATUS_BLOCK Iosb;
3027 UNICODE_STRING Name;
3028 ULONG BufferSize;
3029 HANDLE FileHandle = NULL;
3030 NTSTATUS Status;
3031
3032 DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
3033
3034 RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
3035 L"\\Device\\Harddisk%lu\\Partition0",
3036 DiskEntry->DiskNumber);
3037 RtlInitUnicodeString(&Name, DstPath);
3038
3039 InitializeObjectAttributes(&ObjectAttributes,
3040 &Name,
3041 OBJ_CASE_INSENSITIVE,
3042 NULL,
3043 NULL);
3044
3045 Status = NtOpenFile(&FileHandle,
3046 GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
3047 &ObjectAttributes,
3048 &Iosb,
3049 0,
3050 FILE_SYNCHRONOUS_IO_NONALERT);
3051 if (!NT_SUCCESS(Status))
3052 {
3053 DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
3054 return Status;
3055 }
3056
3057 #ifdef DUMP_PARTITION_TABLE
3058 DumpPartitionTable(DiskEntry);
3059 #endif
3060
3061 //
3062 // FIXME: We first *MUST* use IOCTL_DISK_CREATE_DISK to initialize
3063 // the disk in MBR or GPT format in case the disk was not initialized!!
3064 // For this we must ask the user which format to use.
3065 //
3066
3067 BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
3068 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
3069 Status = NtDeviceIoControlFile(FileHandle,
3070 NULL,
3071 NULL,
3072 NULL,
3073 &Iosb,
3074 IOCTL_DISK_SET_DRIVE_LAYOUT,
3075 DiskEntry->LayoutBuffer,
3076 BufferSize,
3077 NULL,
3078 0);
3079 if (!NT_SUCCESS(Status))
3080 {
3081 DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
3082 }
3083
3084 if (FileHandle != NULL)
3085 NtClose(FileHandle);
3086
3087 //
3088 // NOTE: Originally (see r40437), we used to install here also a new MBR
3089 // for this disk (by calling InstallMbrBootCodeToDisk), only if:
3090 // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
3091 // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
3092 // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
3093 // was called too, the installation test was modified by checking whether
3094 // DiskEntry->NoMbr was TRUE (instead of NewDisk).
3095 //
3096
3097 return Status;
3098 }
3099
3100 BOOLEAN
3101 WritePartitionsToDisk(
3102 IN PPARTLIST List)
3103 {
3104 PLIST_ENTRY Entry;
3105 PDISKENTRY DiskEntry;
3106
3107 if (List == NULL)
3108 return TRUE;
3109
3110 Entry = List->DiskListHead.Flink;
3111 while (Entry != &List->DiskListHead)
3112 {
3113 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
3114
3115 if (DiskEntry->Dirty != FALSE)
3116 {
3117 WritePartitions(List, DiskEntry);
3118 DiskEntry->Dirty = FALSE;
3119 }
3120
3121 Entry = Entry->Flink;
3122 }
3123
3124 return TRUE;
3125 }
3126
3127 BOOLEAN
3128 SetMountedDeviceValue(
3129 IN WCHAR Letter,
3130 IN ULONG Signature,
3131 IN LARGE_INTEGER StartingOffset)
3132 {
3133 OBJECT_ATTRIBUTES ObjectAttributes;
3134 WCHAR ValueNameBuffer[16];
3135 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
3136 UNICODE_STRING ValueName;
3137 REG_DISK_MOUNT_INFO MountInfo;
3138 NTSTATUS Status;
3139 HANDLE KeyHandle;
3140
3141 RtlStringCchPrintfW(ValueNameBuffer, ARRAYSIZE(ValueNameBuffer),
3142 L"\\DosDevices\\%c:", Letter);
3143 RtlInitUnicodeString(&ValueName, ValueNameBuffer);
3144
3145 InitializeObjectAttributes(&ObjectAttributes,
3146 &KeyName,
3147 OBJ_CASE_INSENSITIVE,
3148 NULL,
3149 NULL);
3150
3151 Status = NtOpenKey(&KeyHandle,
3152 KEY_ALL_ACCESS,
3153 &ObjectAttributes);
3154 if (!NT_SUCCESS(Status))
3155 {
3156 Status = NtCreateKey(&KeyHandle,
3157 KEY_ALL_ACCESS,
3158 &ObjectAttributes,
3159 0,
3160 NULL,
3161 REG_OPTION_NON_VOLATILE,
3162 NULL);
3163 }
3164
3165 if (!NT_SUCCESS(Status))
3166 {
3167 DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
3168 return FALSE;
3169 }
3170
3171 MountInfo.Signature = Signature;
3172 MountInfo.StartingOffset = StartingOffset;
3173 Status = NtSetValueKey(KeyHandle,
3174 &ValueName,
3175 0,
3176 REG_BINARY,
3177 (PVOID)&MountInfo,
3178 sizeof(MountInfo));
3179 NtClose(KeyHandle);
3180 if (!NT_SUCCESS(Status))
3181 {
3182 DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
3183 return FALSE;
3184 }
3185
3186 return TRUE;
3187 }
3188
3189 BOOLEAN
3190 SetMountedDeviceValues(
3191 IN PPARTLIST List)
3192 {
3193 PLIST_ENTRY Entry1, Entry2;
3194 PDISKENTRY DiskEntry;
3195 PPARTENTRY PartEntry;
3196 LARGE_INTEGER StartingOffset;
3197
3198 if (List == NULL)
3199 return FALSE;
3200
3201 Entry1 = List->DiskListHead.Flink;
3202 while (Entry1 != &List->DiskListHead)
3203 {
3204 DiskEntry = CONTAINING_RECORD(Entry1,
3205 DISKENTRY,
3206 ListEntry);
3207
3208 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3209 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3210 {
3211 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3212 if (PartEntry->IsPartitioned)
3213 {
3214 /* Assign a "\DosDevices\#:" mount point to this partition */
3215 if (PartEntry->DriveLetter)
3216 {
3217 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3218 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3219 DiskEntry->LayoutBuffer->Signature,
3220 StartingOffset))
3221 {
3222 return FALSE;
3223 }
3224 }
3225 }
3226
3227 Entry2 = Entry2->Flink;
3228 }
3229
3230 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3231 while (Entry2 != &DiskEntry->LogicalPartListHead)
3232 {
3233 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3234 if (PartEntry->IsPartitioned)
3235 {
3236 /* Assign a "\DosDevices\#:" mount point to this partition */
3237 if (PartEntry->DriveLetter)
3238 {
3239 StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
3240 if (!SetMountedDeviceValue(PartEntry->DriveLetter,
3241 DiskEntry->LayoutBuffer->Signature,
3242 StartingOffset))
3243 {
3244 return FALSE;
3245 }
3246 }
3247 }
3248
3249 Entry2 = Entry2->Flink;
3250 }
3251
3252 Entry1 = Entry1->Flink;
3253 }
3254
3255 return TRUE;
3256 }
3257
3258 VOID
3259 SetPartitionType(
3260 IN PPARTENTRY PartEntry,
3261 IN UCHAR PartitionType)
3262 {
3263 PDISKENTRY DiskEntry = PartEntry->DiskEntry;
3264
3265 PartEntry->PartitionType = PartitionType;
3266
3267 DiskEntry->Dirty = TRUE;
3268 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
3269 DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
3270 }
3271
3272 ERROR_NUMBER
3273 PrimaryPartitionCreationChecks(
3274 IN PPARTLIST List)
3275 {
3276 PDISKENTRY DiskEntry;
3277 PPARTENTRY PartEntry;
3278
3279 DiskEntry = List->CurrentDisk;
3280 PartEntry = List->CurrentPartition;
3281
3282 /* Fail if the partition is already in use */
3283 if (PartEntry->IsPartitioned != FALSE)
3284 return ERROR_NEW_PARTITION;
3285
3286 /* Fail if there are already 4 primary partitions in the list */
3287 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3288 return ERROR_PARTITION_TABLE_FULL;
3289
3290 return ERROR_SUCCESS;
3291 }
3292
3293 ERROR_NUMBER
3294 ExtendedPartitionCreationChecks(
3295 IN PPARTLIST List)
3296 {
3297 PDISKENTRY DiskEntry;
3298 PPARTENTRY PartEntry;
3299
3300 DiskEntry = List->CurrentDisk;
3301 PartEntry = List->CurrentPartition;
3302
3303 /* Fail if the partition is already in use */
3304 if (PartEntry->IsPartitioned != FALSE)
3305 return ERROR_NEW_PARTITION;
3306
3307 /* Fail if there are already 4 primary partitions in the list */
3308 if (GetPrimaryPartitionCount(DiskEntry) >= 4)
3309 return ERROR_PARTITION_TABLE_FULL;
3310
3311 /* Fail if there is another extended partition in the list */
3312 if (DiskEntry->ExtendedPartition != NULL)
3313 return ERROR_ONLY_ONE_EXTENDED;
3314
3315 return ERROR_SUCCESS;
3316 }
3317
3318 ERROR_NUMBER
3319 LogicalPartitionCreationChecks(
3320 IN PPARTLIST List)
3321 {
3322 // PDISKENTRY DiskEntry;
3323 PPARTENTRY PartEntry;
3324
3325 // DiskEntry = List->CurrentDisk;
3326 PartEntry = List->CurrentPartition;
3327
3328 /* Fail if the partition is already in use */
3329 if (PartEntry->IsPartitioned != FALSE)
3330 return ERROR_NEW_PARTITION;
3331
3332 return ERROR_SUCCESS;
3333 }
3334
3335 BOOLEAN
3336 GetNextUnformattedPartition(
3337 IN PPARTLIST List,
3338 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3339 OUT PPARTENTRY *pPartEntry)
3340 {
3341 PLIST_ENTRY Entry1, Entry2;
3342 PDISKENTRY DiskEntry;
3343 PPARTENTRY PartEntry;
3344
3345 Entry1 = List->DiskListHead.Flink;
3346 while (Entry1 != &List->DiskListHead)
3347 {
3348 DiskEntry = CONTAINING_RECORD(Entry1,
3349 DISKENTRY,
3350 ListEntry);
3351
3352 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3353 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3354 {
3355 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3356 if (PartEntry->IsPartitioned && PartEntry->New)
3357 {
3358 ASSERT(DiskEntry == PartEntry->DiskEntry);
3359 if (pDiskEntry) *pDiskEntry = DiskEntry;
3360 *pPartEntry = PartEntry;
3361 return TRUE;
3362 }
3363
3364 Entry2 = Entry2->Flink;
3365 }
3366
3367 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3368 while (Entry2 != &DiskEntry->LogicalPartListHead)
3369 {
3370 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3371 if (PartEntry->IsPartitioned && PartEntry->New)
3372 {
3373 ASSERT(DiskEntry == PartEntry->DiskEntry);
3374 if (pDiskEntry) *pDiskEntry = DiskEntry;
3375 *pPartEntry = PartEntry;
3376 return TRUE;
3377 }
3378
3379 Entry2 = Entry2->Flink;
3380 }
3381
3382 Entry1 = Entry1->Flink;
3383 }
3384
3385 if (pDiskEntry) *pDiskEntry = NULL;
3386 *pPartEntry = NULL;
3387
3388 return FALSE;
3389 }
3390
3391 BOOLEAN
3392 GetNextUncheckedPartition(
3393 IN PPARTLIST List,
3394 OUT PDISKENTRY *pDiskEntry OPTIONAL,
3395 OUT PPARTENTRY *pPartEntry)
3396 {
3397 PLIST_ENTRY Entry1, Entry2;
3398 PDISKENTRY DiskEntry;
3399 PPARTENTRY PartEntry;
3400
3401 Entry1 = List->DiskListHead.Flink;
3402 while (Entry1 != &List->DiskListHead)
3403 {
3404 DiskEntry = CONTAINING_RECORD(Entry1,
3405 DISKENTRY,
3406 ListEntry);
3407
3408 Entry2 = DiskEntry->PrimaryPartListHead.Flink;
3409 while (Entry2 != &DiskEntry->PrimaryPartListHead)
3410 {
3411 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3412 if (PartEntry->NeedsCheck == TRUE)
3413 {
3414 ASSERT(DiskEntry == PartEntry->DiskEntry);
3415 if (pDiskEntry) *pDiskEntry = DiskEntry;
3416 *pPartEntry = PartEntry;
3417 return TRUE;
3418 }
3419
3420 Entry2 = Entry2->Flink;
3421 }
3422
3423 Entry2 = DiskEntry->LogicalPartListHead.Flink;
3424 while (Entry2 != &DiskEntry->LogicalPartListHead)
3425 {
3426 PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
3427 if (PartEntry->NeedsCheck == TRUE)
3428 {
3429 ASSERT(DiskEntry == PartEntry->DiskEntry);
3430 if (pDiskEntry) *pDiskEntry = DiskEntry;
3431 *pPartEntry = PartEntry;
3432 return TRUE;
3433 }
3434
3435 Entry2 = Entry2->Flink;
3436 }
3437
3438 Entry1 = Entry1->Flink;
3439 }
3440
3441 if (pDiskEntry) *pDiskEntry = NULL;
3442 *pPartEntry = NULL;
3443
3444 return FALSE;
3445 }
3446
3447 /* EOF */